mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:03:03 +01:00
Feature #6815 - Support multiple rows for DML RETURNING.
This commit is contained in:
parent
7e88b82a46
commit
b32f96f2a9
@ -121,6 +121,7 @@
|
|||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\FullTableScan.cpp" />
|
<ClCompile Include="..\..\..\src\jrd\recsrc\FullTableScan.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\HashJoin.cpp" />
|
<ClCompile Include="..\..\..\src\jrd\recsrc\HashJoin.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\IndexTableScan.cpp" />
|
<ClCompile Include="..\..\..\src\jrd\recsrc\IndexTableScan.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\src\jrd\recsrc\LocalTableStream.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\LockedStream.cpp" />
|
<ClCompile Include="..\..\..\src\jrd\recsrc\LockedStream.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\MergeJoin.cpp" />
|
<ClCompile Include="..\..\..\src\jrd\recsrc\MergeJoin.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\NestedLoopJoin.cpp" />
|
<ClCompile Include="..\..\..\src\jrd\recsrc\NestedLoopJoin.cpp" />
|
||||||
|
@ -81,6 +81,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\IndexTableScan.cpp">
|
<ClCompile Include="..\..\..\src\jrd\recsrc\IndexTableScan.cpp">
|
||||||
<Filter>JRD files\Data Access</Filter>
|
<Filter>JRD files\Data Access</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\jrd\recsrc\LocalTableStream.cpp">
|
||||||
|
<Filter>JRD files\Data Access</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\src\jrd\recsrc\LockedStream.cpp">
|
<ClCompile Include="..\..\..\src\jrd\recsrc\LockedStream.cpp">
|
||||||
<Filter>JRD files\Data Access</Filter>
|
<Filter>JRD files\Data Access</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -7,7 +7,7 @@ MERGE statement
|
|||||||
condition.
|
condition.
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
Adriano dos Santos Fernandes <adrianosf@gmail.com>
|
||||||
|
|
||||||
Format:
|
Format:
|
||||||
<merge statement> ::=
|
<merge statement> ::=
|
||||||
@ -16,6 +16,8 @@ MERGE statement
|
|||||||
USING <table or view or derived table> [ [AS] <correlation name> ]
|
USING <table or view or derived table> [ [AS] <correlation name> ]
|
||||||
ON <condition>
|
ON <condition>
|
||||||
<merge when>...
|
<merge when>...
|
||||||
|
[<plan clause>]
|
||||||
|
[<order by clause>]
|
||||||
<returning clause>
|
<returning clause>
|
||||||
|
|
||||||
<merge when> ::=
|
<merge when> ::=
|
||||||
|
@ -39,11 +39,12 @@ RETURNING clause
|
|||||||
Note(s):
|
Note(s):
|
||||||
1. The INTO part (i.e. the variable list) is allowed in PSQL only (to assign local variables)
|
1. The INTO part (i.e. the variable list) is allowed in PSQL only (to assign local variables)
|
||||||
and rejected in DSQL.
|
and rejected in DSQL.
|
||||||
2. In DSQL, values are being returned within the same protocol roundtrip as the INSERT itself
|
2. In DSQL, INSERT INTO ... VALUES are returned within the same protocol roundtrip as the
|
||||||
is executed.
|
INSERT is executed - this is not the case for INSERT INTO ... SELECT.
|
||||||
3. If the RETURNING clause is present, then the statement is described as
|
3. If the RETURNING clause is present, then the statement is described as
|
||||||
isc_info_sql_stmt_exec_procedure by the API (instead of isc_info_sql_stmt_insert),
|
isc_info_sql_stmt_exec_procedure by the API (for INSERT INTO ... VALUES and statements
|
||||||
so the existing connectivity drivers should support this feature automagically.
|
with WHERE CURRENT OF) and isc_info_sql_stmt_select for the others statements, so the
|
||||||
|
existing connectivity drivers should support this feature automagically.
|
||||||
4. Any explicit record change (update or delete) performed by AFTER-triggers is ignored by
|
4. Any explicit record change (update or delete) performed by AFTER-triggers is ignored by
|
||||||
the RETURNING clause.
|
the RETURNING clause.
|
||||||
5. OLD and NEW could be used in RETURNING clause of UPDATE, INSERT OR UPDATE and MERGE statements.
|
5. OLD and NEW could be used in RETURNING clause of UPDATE, INSERT OR UPDATE and MERGE statements.
|
||||||
@ -53,9 +54,13 @@ RETURNING clause
|
|||||||
by table name/alias fields are resolved to NEW. In MERGE WHEN MATCHED DELETE they are
|
by table name/alias fields are resolved to NEW. In MERGE WHEN MATCHED DELETE they are
|
||||||
resolved to OLD.
|
resolved to OLD.
|
||||||
8. Since v4 it's possible to use * and alias.*, as well OLD.* and NEW.* where applicable.
|
8. Since v4 it's possible to use * and alias.*, as well OLD.* and NEW.* where applicable.
|
||||||
|
9. ORDER BY works with fields from the OLD context (the original record source before changes are applied).
|
||||||
|
|
||||||
Limitations:
|
Limitations:
|
||||||
1. The modify statement (INSERT, UPDATE, DELETE, MERGE) should operate in no more than one record
|
1. The modify statement (INSERT, UPDATE, DELETE, UPDATE OR INSERT, MERGE) in PSQL should
|
||||||
(i.e. should be singleton).
|
operate in no more than one record (i.e. should be singleton).
|
||||||
2. The statement always return one row in DSQL, even if no record is inserted/updated/deleted.
|
|
||||||
This may be changed in the future (i.e. return empty resultset).
|
Changes in v5:
|
||||||
|
1. Ability to return multiple rows (or no row) in DSQL.
|
||||||
|
2. Added PLAN and ORDER BY subclauses to MERGE.
|
||||||
|
3. Added PLAN, ORDER BY and ROWS subclauses to UPDATE OR INSERT.
|
||||||
|
@ -6,12 +6,15 @@ UPDATE OR INSERT statement
|
|||||||
Allow to update or insert a record based on the existence (checked with IS NOT DISTINCT) or not of it.
|
Allow to update or insert a record based on the existence (checked with IS NOT DISTINCT) or not of it.
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
Adriano dos Santos Fernandes <adrianosf@uol.com.br>
|
Adriano dos Santos Fernandes <adrianosf@gmail.com>
|
||||||
|
|
||||||
Syntax rules:
|
Syntax rules:
|
||||||
UPDATE OR INSERT INTO <table or view> [(<column_list>)]
|
UPDATE OR INSERT INTO <table or view> [(<column_list>)]
|
||||||
VALUES (<value_list>)
|
VALUES (<value_list>)
|
||||||
[MATCHING (<column_list>)]
|
[MATCHING (<column_list>)]
|
||||||
|
[<plan clause>]
|
||||||
|
[<order by clause>]
|
||||||
|
[<rows clause>]
|
||||||
[RETURNING <value_list> [INTO <variable_list>]]
|
[RETURNING <value_list> [INTO <variable_list>]]
|
||||||
|
|
||||||
Scope:
|
Scope:
|
||||||
@ -27,11 +30,9 @@ UPDATE OR INSERT statement
|
|||||||
1. When MATCHING is omitted, the existence of a primary key is required.
|
1. When MATCHING is omitted, the existence of a primary key is required.
|
||||||
2. INSERT and UPDATE permissions are needed on <table or view>.
|
2. INSERT and UPDATE permissions are needed on <table or view>.
|
||||||
3. If the RETURNING clause is present, then the statement is described as
|
3. If the RETURNING clause is present, then the statement is described as
|
||||||
isc_info_sql_stmt_exec_procedure by the API. Otherwise it is described
|
isc_info_sql_stmt_select by the API. Otherwise it is described
|
||||||
as isc_info_sql_stmt_insert.
|
as isc_info_sql_stmt_insert.
|
||||||
|
|
||||||
Limitation:
|
Limitation:
|
||||||
1. A singleton error will be raised if the RETURNING clause is present and more than
|
1. There is no "UPDATE OR INSERT ... SELECT ..." as "INSERT ... SELECT". Use MERGE for
|
||||||
one record match the condition.
|
|
||||||
2. There is no "UPDATE OR INSERT ... SELECT ..." as "INSERT ... SELECT". Use MERGE for
|
|
||||||
this type of functionality.
|
this type of functionality.
|
||||||
|
@ -1959,6 +1959,8 @@ const
|
|||||||
gds_inf_invalid_args = 335545275;
|
gds_inf_invalid_args = 335545275;
|
||||||
isc_sysf_invalid_null_empty = 335545276;
|
isc_sysf_invalid_null_empty = 335545276;
|
||||||
gds_sysf_invalid_null_empty = 335545276;
|
gds_sysf_invalid_null_empty = 335545276;
|
||||||
|
isc_bad_loctab_num = 335545277;
|
||||||
|
gds_bad_loctab_num = 335545277;
|
||||||
isc_gfix_db_name = 335740929;
|
isc_gfix_db_name = 335740929;
|
||||||
gds_gfix_db_name = 335740929;
|
gds_gfix_db_name = 335740929;
|
||||||
isc_gfix_invalid_sw = 335740930;
|
isc_gfix_invalid_sw = 335740930;
|
||||||
|
@ -999,6 +999,7 @@ string CountAggNode::internalPrint(NodePrinter& printer) const
|
|||||||
return "CountAggNode";
|
return "CountAggNode";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// TODO: Improve count(*) in local tables.
|
||||||
void CountAggNode::aggInit(thread_db* tdbb, jrd_req* request) const
|
void CountAggNode::aggInit(thread_db* tdbb, jrd_req* request) const
|
||||||
{
|
{
|
||||||
AggNode::aggInit(tdbb, request);
|
AggNode::aggInit(tdbb, request);
|
||||||
|
@ -960,6 +960,7 @@ RseNode* DsqlCompilerScratch::pass1RseIsRecursive(RseNode* input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (nodeIs<ProcedureSourceNode>(*pDstTable) || nodeIs<RelationSourceNode>(*pDstTable))
|
else if (nodeIs<ProcedureSourceNode>(*pDstTable) || nodeIs<RelationSourceNode>(*pDstTable))
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
{
|
{
|
||||||
if (pass1RelProcIsRecursive(*pDstTable))
|
if (pass1RelProcIsRecursive(*pDstTable))
|
||||||
{
|
{
|
||||||
@ -990,19 +991,18 @@ bool DsqlCompilerScratch::pass1RelProcIsRecursive(RecordSourceNode* input)
|
|||||||
{
|
{
|
||||||
MetaName relName;
|
MetaName relName;
|
||||||
string relAlias;
|
string relAlias;
|
||||||
ProcedureSourceNode* procNode;
|
|
||||||
RelationSourceNode* relNode;
|
|
||||||
|
|
||||||
if ((procNode = nodeAs<ProcedureSourceNode>(input)))
|
if (auto procNode = nodeAs<ProcedureSourceNode>(input))
|
||||||
{
|
{
|
||||||
relName = procNode->dsqlName.identifier;
|
relName = procNode->dsqlName.identifier;
|
||||||
relAlias = procNode->alias;
|
relAlias = procNode->alias;
|
||||||
}
|
}
|
||||||
else if ((relNode = nodeAs<RelationSourceNode>(input)))
|
else if (auto relNode = nodeAs<RelationSourceNode>(input))
|
||||||
{
|
{
|
||||||
relName = relNode->dsqlName;
|
relName = relNode->dsqlName;
|
||||||
relAlias = relNode->alias;
|
relAlias = relNode->alias;
|
||||||
}
|
}
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ namespace Jrd
|
|||||||
class BinaryBoolNode;
|
class BinaryBoolNode;
|
||||||
class CompoundStmtNode;
|
class CompoundStmtNode;
|
||||||
class DeclareCursorNode;
|
class DeclareCursorNode;
|
||||||
|
class DeclareLocalTableNode;
|
||||||
class DeclareVariableNode;
|
class DeclareVariableNode;
|
||||||
class ParameterClause;
|
class ParameterClause;
|
||||||
class RseNode;
|
class RseNode;
|
||||||
@ -44,6 +45,9 @@ class TypeClause;
|
|||||||
class VariableNode;
|
class VariableNode;
|
||||||
class WithClause;
|
class WithClause;
|
||||||
|
|
||||||
|
typedef Firebird::Pair<
|
||||||
|
Firebird::NonPooled<NestConst<ValueListNode>, NestConst<ValueListNode>>> ReturningClause;
|
||||||
|
|
||||||
|
|
||||||
// DSQL Compiler scratch block - may be discarded after compilation in the future.
|
// DSQL Compiler scratch block - may be discarded after compilation in the future.
|
||||||
class DsqlCompilerScratch : public BlrDebugWriter
|
class DsqlCompilerScratch : public BlrDebugWriter
|
||||||
@ -57,7 +61,6 @@ public:
|
|||||||
static const unsigned FLAG_BLOCK = 0x0020;
|
static const unsigned FLAG_BLOCK = 0x0020;
|
||||||
static const unsigned FLAG_RECURSIVE_CTE = 0x0040;
|
static const unsigned FLAG_RECURSIVE_CTE = 0x0040;
|
||||||
static const unsigned FLAG_UPDATE_OR_INSERT = 0x0080;
|
static const unsigned FLAG_UPDATE_OR_INSERT = 0x0080;
|
||||||
static const unsigned FLAG_MERGE = 0x0100;
|
|
||||||
static const unsigned FLAG_FUNCTION = 0x0200;
|
static const unsigned FLAG_FUNCTION = 0x0200;
|
||||||
static const unsigned FLAG_SUB_ROUTINE = 0x0400;
|
static const unsigned FLAG_SUB_ROUTINE = 0x0400;
|
||||||
static const unsigned FLAG_INTERNAL_REQUEST = 0x0800;
|
static const unsigned FLAG_INTERNAL_REQUEST = 0x0800;
|
||||||
@ -91,6 +94,8 @@ public:
|
|||||||
labels(p),
|
labels(p),
|
||||||
cursorNumber(0),
|
cursorNumber(0),
|
||||||
cursors(p),
|
cursors(p),
|
||||||
|
localTableNumber(0),
|
||||||
|
localTables(p),
|
||||||
inSelectList(0),
|
inSelectList(0),
|
||||||
inWhereClause(0),
|
inWhereClause(0),
|
||||||
inGroupByClause(0),
|
inGroupByClause(0),
|
||||||
@ -110,6 +115,7 @@ public:
|
|||||||
hiddenVariables(p),
|
hiddenVariables(p),
|
||||||
variables(p),
|
variables(p),
|
||||||
outputVariables(p),
|
outputVariables(p),
|
||||||
|
returningClause(nullptr),
|
||||||
currCteAlias(NULL),
|
currCteAlias(NULL),
|
||||||
ctes(p),
|
ctes(p),
|
||||||
cteAliases(p),
|
cteAliases(p),
|
||||||
@ -283,6 +289,8 @@ public:
|
|||||||
Firebird::Stack<MetaName*> labels; // Loop labels
|
Firebird::Stack<MetaName*> labels; // Loop labels
|
||||||
USHORT cursorNumber; // Cursor number
|
USHORT cursorNumber; // Cursor number
|
||||||
Firebird::Array<DeclareCursorNode*> cursors; // Cursors
|
Firebird::Array<DeclareCursorNode*> cursors; // Cursors
|
||||||
|
USHORT localTableNumber; // Local table number
|
||||||
|
Firebird::Array<DeclareLocalTableNode*> localTables; // Local tables
|
||||||
USHORT inSelectList; // now processing "select list"
|
USHORT inSelectList; // now processing "select list"
|
||||||
USHORT inWhereClause; // processing "where clause"
|
USHORT inWhereClause; // processing "where clause"
|
||||||
USHORT inGroupByClause; // processing "group by clause"
|
USHORT inGroupByClause; // processing "group by clause"
|
||||||
@ -303,6 +311,7 @@ public:
|
|||||||
Firebird::Array<dsql_var*> hiddenVariables; // hidden variables
|
Firebird::Array<dsql_var*> hiddenVariables; // hidden variables
|
||||||
Firebird::Array<dsql_var*> variables;
|
Firebird::Array<dsql_var*> variables;
|
||||||
Firebird::Array<dsql_var*> outputVariables;
|
Firebird::Array<dsql_var*> outputVariables;
|
||||||
|
ReturningClause* returningClause;
|
||||||
const Firebird::string* const* currCteAlias;
|
const Firebird::string* const* currCteAlias;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -6085,6 +6085,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec
|
|||||||
procNode->dsqlContext = stackContext;
|
procNode->dsqlContext = stackContext;
|
||||||
*list = procNode;
|
*list = procNode;
|
||||||
}
|
}
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
|
|
||||||
fb_assert(*list);
|
fb_assert(*list);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -9457,14 +9458,7 @@ ValueExprNode* OverNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
static RegisterNode<ParameterNode> regParameterNode({blr_parameter, blr_parameter2, blr_parameter3});
|
static RegisterNode<ParameterNode> regParameterNode({blr_parameter, blr_parameter2, blr_parameter3});
|
||||||
|
|
||||||
ParameterNode::ParameterNode(MemoryPool& pool)
|
ParameterNode::ParameterNode(MemoryPool& pool)
|
||||||
: TypedNode<ValueExprNode, ExprNode::TYPE_PARAMETER>(pool),
|
: TypedNode<ValueExprNode, ExprNode::TYPE_PARAMETER>(pool)
|
||||||
dsqlParameter(NULL),
|
|
||||||
message(NULL),
|
|
||||||
argFlag(NULL),
|
|
||||||
argIndicator(NULL),
|
|
||||||
argInfo(NULL),
|
|
||||||
dsqlParameterIndex(0),
|
|
||||||
argNumber(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9536,11 +9530,12 @@ ValueExprNode* ParameterNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
Arg::Gds(isc_dsql_command_err));
|
Arg::Gds(isc_dsql_command_err));
|
||||||
}
|
}
|
||||||
|
|
||||||
dsql_msg* tempMsg = dsqlParameter ?
|
auto msg = dsqlMessage ? dsqlMessage :
|
||||||
dsqlParameter->par_message : dsqlScratch->getStatement()->getSendMsg();
|
dsqlParameter ? dsqlParameter->par_message :
|
||||||
|
dsqlScratch->getStatement()->getSendMsg();
|
||||||
|
|
||||||
ParameterNode* node = FB_NEW_POOL(dsqlScratch->getPool()) ParameterNode(dsqlScratch->getPool());
|
auto node = FB_NEW_POOL(dsqlScratch->getPool()) ParameterNode(dsqlScratch->getPool());
|
||||||
node->dsqlParameter = MAKE_parameter(tempMsg, true, true, dsqlParameterIndex, NULL);
|
node->dsqlParameter = MAKE_parameter(msg, true, true, dsqlParameterIndex, nullptr);
|
||||||
node->dsqlParameterIndex = dsqlParameterIndex;
|
node->dsqlParameterIndex = dsqlParameterIndex;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -9923,11 +9918,12 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
PASS1_ambiguity_check(dsqlScratch, getAlias(true), contexts);
|
PASS1_ambiguity_check(dsqlScratch, getAlias(true), contexts);
|
||||||
|
|
||||||
RelationSourceNode* relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(
|
//// TODO: LocalTableSourceNode
|
||||||
|
auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(
|
||||||
dsqlScratch->getPool());
|
dsqlScratch->getPool());
|
||||||
relNode->dsqlContext = context;
|
relNode->dsqlContext = context;
|
||||||
|
|
||||||
RecordKeyNode* node = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(dsqlScratch->getPool(), blrOp);
|
auto node = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(dsqlScratch->getPool(), blrOp);
|
||||||
node->dsqlRelation = relNode;
|
node->dsqlRelation = relNode;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -9959,11 +9955,12 @@ ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
if (context->ctx_flags & CTX_null)
|
if (context->ctx_flags & CTX_null)
|
||||||
return NullNode::instance();
|
return NullNode::instance();
|
||||||
|
|
||||||
RelationSourceNode* relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(
|
//// TODO: LocalTableSourceNode
|
||||||
|
auto relNode = FB_NEW_POOL(dsqlScratch->getPool()) RelationSourceNode(
|
||||||
dsqlScratch->getPool());
|
dsqlScratch->getPool());
|
||||||
relNode->dsqlContext = context;
|
relNode->dsqlContext = context;
|
||||||
|
|
||||||
RecordKeyNode* node = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(dsqlScratch->getPool(), blrOp);
|
auto node = FB_NEW_POOL(dsqlScratch->getPool()) RecordKeyNode(dsqlScratch->getPool(), blrOp);
|
||||||
node->dsqlRelation = relNode;
|
node->dsqlRelation = relNode;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
@ -1585,13 +1585,14 @@ public:
|
|||||||
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
|
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
dsql_par* dsqlParameter;
|
dsql_msg* dsqlMessage = nullptr;
|
||||||
|
dsql_par* dsqlParameter = nullptr;
|
||||||
NestConst<MessageNode> message;
|
NestConst<MessageNode> message;
|
||||||
NestConst<ValueExprNode> argFlag;
|
NestConst<ValueExprNode> argFlag;
|
||||||
NestConst<ValueExprNode> argIndicator;
|
NestConst<ValueExprNode> argIndicator;
|
||||||
NestConst<ItemInfo> argInfo;
|
NestConst<ItemInfo> argInfo;
|
||||||
USHORT dsqlParameterIndex;
|
USHORT dsqlParameterIndex = 0;
|
||||||
USHORT argNumber;
|
USHORT argNumber = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -508,6 +508,7 @@ public:
|
|||||||
|
|
||||||
// RecordSource types
|
// RecordSource types
|
||||||
TYPE_AGGREGATE_SOURCE,
|
TYPE_AGGREGATE_SOURCE,
|
||||||
|
TYPE_LOCAL_TABLE,
|
||||||
TYPE_PROCEDURE,
|
TYPE_PROCEDURE,
|
||||||
TYPE_RELATION,
|
TYPE_RELATION,
|
||||||
TYPE_RSE,
|
TYPE_RSE,
|
||||||
@ -1380,6 +1381,7 @@ public:
|
|||||||
TYPE_CONTINUE_LEAVE,
|
TYPE_CONTINUE_LEAVE,
|
||||||
TYPE_CURSOR_STMT,
|
TYPE_CURSOR_STMT,
|
||||||
TYPE_DECLARE_CURSOR,
|
TYPE_DECLARE_CURSOR,
|
||||||
|
TYPE_DECLARE_LOCAL_TABLE,
|
||||||
TYPE_DECLARE_SUBFUNC,
|
TYPE_DECLARE_SUBFUNC,
|
||||||
TYPE_DECLARE_SUBPROC,
|
TYPE_DECLARE_SUBPROC,
|
||||||
TYPE_DECLARE_VARIABLE,
|
TYPE_DECLARE_VARIABLE,
|
||||||
@ -1412,6 +1414,7 @@ public:
|
|||||||
TYPE_STALL,
|
TYPE_STALL,
|
||||||
TYPE_STORE,
|
TYPE_STORE,
|
||||||
TYPE_SUSPEND,
|
TYPE_SUSPEND,
|
||||||
|
TYPE_TRUNCATE_LOCAL_TABLE,
|
||||||
TYPE_UPDATE_OR_INSERT,
|
TYPE_UPDATE_OR_INSERT,
|
||||||
TYPE_USER_SAVEPOINT,
|
TYPE_USER_SAVEPOINT,
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -38,13 +38,11 @@ class CompoundStmtNode;
|
|||||||
class ExecBlockNode;
|
class ExecBlockNode;
|
||||||
class ForNode;
|
class ForNode;
|
||||||
class PlanNode;
|
class PlanNode;
|
||||||
|
class RecordBuffer;
|
||||||
class RelationSourceNode;
|
class RelationSourceNode;
|
||||||
class SelectNode;
|
class SelectNode;
|
||||||
class GeneratorItem;
|
class GeneratorItem;
|
||||||
|
|
||||||
typedef Firebird::Pair<
|
|
||||||
Firebird::NonPooled<NestConst<ValueListNode>, NestConst<ValueListNode> > > ReturningClause;
|
|
||||||
|
|
||||||
|
|
||||||
class ExceptionItem : public Firebird::PermanentStorage, public Printable
|
class ExceptionItem : public Firebird::PermanentStorage, public Printable
|
||||||
{
|
{
|
||||||
@ -414,6 +412,45 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DeclareLocalTableNode : public TypedNode<StmtNode, StmtNode::TYPE_DECLARE_LOCAL_TABLE>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Impure
|
||||||
|
{
|
||||||
|
RecordBuffer* recordBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeclareLocalTableNode(MemoryPool& pool)
|
||||||
|
: TypedNode<StmtNode, StmtNode::TYPE_DECLARE_LOCAL_TABLE>(pool)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
|
||||||
|
|
||||||
|
Firebird::string internalPrint(NodePrinter& printer) const override;
|
||||||
|
DeclareLocalTableNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override;
|
||||||
|
void genBlr(DsqlCompilerScratch* dsqlScratch) override;
|
||||||
|
DeclareLocalTableNode* copy(thread_db* tdbb, NodeCopier& copier) const override;
|
||||||
|
|
||||||
|
DeclareLocalTableNode* pass1(thread_db* tdbb, CompilerScratch* csb) override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclareLocalTableNode* pass2(thread_db* tdbb, CompilerScratch* csb) override;
|
||||||
|
const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Impure* getImpure(thread_db* tdbb, jrd_req* request, bool createWhenDead = true) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NestConst<Format> format;
|
||||||
|
USHORT tableNumber = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class DeclareSubFuncNode : public TypedNode<StmtNode, StmtNode::TYPE_DECLARE_SUBFUNC>
|
class DeclareSubFuncNode : public TypedNode<StmtNode, StmtNode::TYPE_DECLARE_SUBFUNC>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1075,38 +1112,42 @@ public:
|
|||||||
struct Matched
|
struct Matched
|
||||||
{
|
{
|
||||||
explicit Matched(MemoryPool& pool)
|
explicit Matched(MemoryPool& pool)
|
||||||
: assignments(NULL),
|
: processedFields(pool),
|
||||||
condition(NULL)
|
processedValues(pool)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NestConst<CompoundStmtNode> assignments;
|
NestConst<CompoundStmtNode> assignments;
|
||||||
NestConst<BoolExprNode> condition;
|
NestConst<BoolExprNode> condition;
|
||||||
|
|
||||||
|
NestConst<Jrd::RecordSourceNode> modifyRelation;
|
||||||
|
NestValueArray processedFields;
|
||||||
|
NestValueArray processedValues;
|
||||||
|
NestConst<ReturningClause> processedReturning;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NotMatched
|
struct NotMatched
|
||||||
{
|
{
|
||||||
explicit NotMatched(MemoryPool& pool)
|
explicit NotMatched(MemoryPool& pool)
|
||||||
: fields(pool),
|
: fields(pool),
|
||||||
values(NULL),
|
processedFields(pool)
|
||||||
condition(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Firebird::Array<NestConst<FieldNode> > fields;
|
Firebird::Array<NestConst<FieldNode>> fields;
|
||||||
NestConst<ValueListNode> values;
|
NestConst<ValueListNode> values;
|
||||||
NestConst<BoolExprNode> condition;
|
NestConst<BoolExprNode> condition;
|
||||||
Nullable<OverrideClause> overrideClause;
|
Nullable<OverrideClause> overrideClause;
|
||||||
|
|
||||||
|
NestConst<Jrd::RecordSourceNode> storeRelation;
|
||||||
|
NestValueArray processedFields;
|
||||||
|
NestConst<ReturningClause> processedReturning;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit MergeNode(MemoryPool& pool)
|
explicit MergeNode(MemoryPool& pool)
|
||||||
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_MERGE>(pool),
|
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_MERGE>(pool),
|
||||||
relation(NULL),
|
|
||||||
usingClause(NULL),
|
|
||||||
condition(NULL),
|
|
||||||
whenMatched(pool),
|
whenMatched(pool),
|
||||||
whenNotMatched(pool),
|
whenNotMatched(pool)
|
||||||
returning(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1120,7 +1161,12 @@ public:
|
|||||||
NestConst<BoolExprNode> condition;
|
NestConst<BoolExprNode> condition;
|
||||||
Firebird::ObjectsArray<Matched> whenMatched;
|
Firebird::ObjectsArray<Matched> whenMatched;
|
||||||
Firebird::ObjectsArray<NotMatched> whenNotMatched;
|
Firebird::ObjectsArray<NotMatched> whenNotMatched;
|
||||||
|
NestConst<PlanNode> plan;
|
||||||
|
NestConst<ValueListNode> order;
|
||||||
NestConst<ReturningClause> returning;
|
NestConst<ReturningClause> returning;
|
||||||
|
|
||||||
|
NestConst<RseNode> rse;
|
||||||
|
dsql_ctx* targetContext = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1163,24 +1209,8 @@ class ModifyNode : public TypedNode<StmtNode, StmtNode::TYPE_MODIFY>
|
|||||||
public:
|
public:
|
||||||
explicit ModifyNode(MemoryPool& pool)
|
explicit ModifyNode(MemoryPool& pool)
|
||||||
: TypedNode<StmtNode, StmtNode::TYPE_MODIFY>(pool),
|
: TypedNode<StmtNode, StmtNode::TYPE_MODIFY>(pool),
|
||||||
dsqlRelation(NULL),
|
|
||||||
dsqlBoolean(NULL),
|
|
||||||
dsqlPlan(NULL),
|
|
||||||
dsqlOrder(NULL),
|
|
||||||
dsqlRows(NULL),
|
|
||||||
dsqlCursorName(pool),
|
dsqlCursorName(pool),
|
||||||
dsqlReturning(NULL),
|
validations(pool)
|
||||||
dsqlRse(NULL),
|
|
||||||
dsqlContext(NULL),
|
|
||||||
statement(NULL),
|
|
||||||
statement2(NULL),
|
|
||||||
subMod(NULL),
|
|
||||||
validations(pool),
|
|
||||||
mapView(NULL),
|
|
||||||
orgStream(0),
|
|
||||||
newStream(0),
|
|
||||||
marks(0),
|
|
||||||
dsqlRseFlags(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,17 +1238,18 @@ public:
|
|||||||
MetaName dsqlCursorName;
|
MetaName dsqlCursorName;
|
||||||
NestConst<ReturningClause> dsqlReturning;
|
NestConst<ReturningClause> dsqlReturning;
|
||||||
NestConst<RecordSourceNode> dsqlRse;
|
NestConst<RecordSourceNode> dsqlRse;
|
||||||
dsql_ctx* dsqlContext;
|
dsql_ctx* dsqlContext = nullptr;
|
||||||
NestConst<StmtNode> statement;
|
NestConst<StmtNode> statement;
|
||||||
NestConst<StmtNode> statement2;
|
NestConst<StmtNode> statement2;
|
||||||
NestConst<StmtNode> subMod;
|
NestConst<StmtNode> subMod;
|
||||||
Firebird::Array<ValidateInfo> validations;
|
Firebird::Array<ValidateInfo> validations;
|
||||||
NestConst<StmtNode> mapView;
|
NestConst<StmtNode> mapView;
|
||||||
NestConst<ForNode> forNode; // parent implicit cursor, if present
|
NestConst<ForNode> forNode; // parent implicit cursor, if present
|
||||||
StreamType orgStream;
|
StreamType orgStream = 0;
|
||||||
StreamType newStream;
|
StreamType newStream = 0;
|
||||||
unsigned marks; // see StmtNode::IUD_MARK_xxx
|
unsigned marks = 0; // see StmtNode::IUD_MARK_xxx
|
||||||
USHORT dsqlRseFlags;
|
USHORT dsqlRseFlags = 0;
|
||||||
|
Nullable<USHORT> dsqlReturningLocalTableNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1281,16 +1312,8 @@ class StoreNode : public TypedNode<StmtNode, StmtNode::TYPE_STORE>
|
|||||||
public:
|
public:
|
||||||
explicit StoreNode(MemoryPool& pool)
|
explicit StoreNode(MemoryPool& pool)
|
||||||
: TypedNode<StmtNode, StmtNode::TYPE_STORE>(pool),
|
: TypedNode<StmtNode, StmtNode::TYPE_STORE>(pool),
|
||||||
dsqlRelation(NULL),
|
|
||||||
dsqlFields(pool),
|
dsqlFields(pool),
|
||||||
dsqlValues(NULL),
|
validations(pool)
|
||||||
dsqlReturning(NULL),
|
|
||||||
dsqlRse(NULL),
|
|
||||||
statement(NULL),
|
|
||||||
statement2(NULL),
|
|
||||||
subStore(NULL),
|
|
||||||
validations(pool),
|
|
||||||
relationSource(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1311,8 +1334,8 @@ private:
|
|||||||
const StmtNode* store(thread_db* tdbb, jrd_req* request, WhichTrigger whichTrig) const;
|
const StmtNode* store(thread_db* tdbb, jrd_req* request, WhichTrigger whichTrig) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NestConst<RecordSourceNode> dsqlRelation;
|
NestConst<RecordSourceNode> target;
|
||||||
Firebird::Array<NestConst<FieldNode> > dsqlFields;
|
Firebird::Array<NestConst<FieldNode>> dsqlFields;
|
||||||
NestConst<ValueListNode> dsqlValues;
|
NestConst<ValueListNode> dsqlValues;
|
||||||
NestConst<ReturningClause> dsqlReturning;
|
NestConst<ReturningClause> dsqlReturning;
|
||||||
NestConst<RecordSourceNode> dsqlRse;
|
NestConst<RecordSourceNode> dsqlRse;
|
||||||
@ -1320,7 +1343,7 @@ public:
|
|||||||
NestConst<StmtNode> statement2;
|
NestConst<StmtNode> statement2;
|
||||||
NestConst<StmtNode> subStore;
|
NestConst<StmtNode> subStore;
|
||||||
Firebird::Array<ValidateInfo> validations;
|
Firebird::Array<ValidateInfo> validations;
|
||||||
NestConst<RelationSourceNode> relationSource;
|
Nullable<USHORT> dsqlReturningLocalTableNumber;
|
||||||
Nullable<OverrideClause> overrideClause;
|
Nullable<OverrideClause> overrideClause;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1865,16 +1888,52 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TruncateLocalTableNode : public TypedNode<StmtNode, StmtNode::TYPE_TRUNCATE_LOCAL_TABLE>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit TruncateLocalTableNode(MemoryPool& pool)
|
||||||
|
: TypedNode<StmtNode, StmtNode::TYPE_TRUNCATE_LOCAL_TABLE>(pool)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
|
||||||
|
|
||||||
|
Firebird::string internalPrint(NodePrinter& printer) const override;
|
||||||
|
|
||||||
|
TruncateLocalTableNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void genBlr(DsqlCompilerScratch* dsqlScratch) override;
|
||||||
|
TruncateLocalTableNode* copy(thread_db* tdbb, NodeCopier& copier) const override;
|
||||||
|
|
||||||
|
TruncateLocalTableNode* pass1(thread_db* tdbb, CompilerScratch* csb) override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TruncateLocalTableNode* pass2(thread_db* tdbb, CompilerScratch* csb) override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
USHORT tableNumber = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class UpdateOrInsertNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT>
|
class UpdateOrInsertNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit UpdateOrInsertNode(MemoryPool& pool)
|
explicit UpdateOrInsertNode(MemoryPool& pool)
|
||||||
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT>(pool),
|
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT>(pool),
|
||||||
relation(NULL),
|
|
||||||
fields(pool),
|
fields(pool),
|
||||||
values(NULL),
|
|
||||||
matching(pool),
|
matching(pool),
|
||||||
returning(NULL)
|
varAssignments(pool)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1884,11 +1943,17 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
NestConst<RelationSourceNode> relation;
|
NestConst<RelationSourceNode> relation;
|
||||||
Firebird::Array<NestConst<FieldNode> > fields;
|
Firebird::Array<NestConst<FieldNode>> fields;
|
||||||
NestConst<ValueListNode> values;
|
NestConst<ValueListNode> values;
|
||||||
Firebird::Array<NestConst<FieldNode> > matching;
|
Firebird::Array<NestConst<FieldNode>> matching;
|
||||||
|
NestConst<PlanNode> plan;
|
||||||
|
NestConst<ValueListNode> order;
|
||||||
|
NestConst<RowsClause> rows;
|
||||||
NestConst<ReturningClause> returning;
|
NestConst<ReturningClause> returning;
|
||||||
Nullable<OverrideClause> overrideClause;
|
Nullable<OverrideClause> overrideClause;
|
||||||
|
NestConst<StoreNode> storeNode;
|
||||||
|
NestConst<ModifyNode> modifyNode;
|
||||||
|
Firebird::Array<NestConst<AssignmentNode>> varAssignments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ static inline bool reqTypeWithCursor(DsqlCompiledStatement::Type type)
|
|||||||
case DsqlCompiledStatement::TYPE_SELECT:
|
case DsqlCompiledStatement::TYPE_SELECT:
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
||||||
|
case DsqlCompiledStatement::TYPE_RETURNING_CURSOR:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2062,6 +2063,7 @@ static void sql_info(thread_db* tdbb,
|
|||||||
case DsqlCompiledStatement::TYPE_SELECT:
|
case DsqlCompiledStatement::TYPE_SELECT:
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
||||||
|
case DsqlCompiledStatement::TYPE_RETURNING_CURSOR:
|
||||||
value |= IStatement::FLAG_HAS_CURSOR;
|
value |= IStatement::FLAG_HAS_CURSOR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2075,6 +2077,7 @@ static void sql_info(thread_db* tdbb,
|
|||||||
switch (statement->getType())
|
switch (statement->getType())
|
||||||
{
|
{
|
||||||
case DsqlCompiledStatement::TYPE_SELECT:
|
case DsqlCompiledStatement::TYPE_SELECT:
|
||||||
|
case DsqlCompiledStatement::TYPE_RETURNING_CURSOR:
|
||||||
number = isc_info_sql_stmt_select;
|
number = isc_info_sql_stmt_select;
|
||||||
break;
|
break;
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
||||||
|
@ -461,7 +461,8 @@ public:
|
|||||||
TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR,
|
TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR,
|
||||||
TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS,
|
TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS,
|
||||||
TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR,
|
TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR,
|
||||||
TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SESSION_MANAGEMENT
|
TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SESSION_MANAGEMENT,
|
||||||
|
TYPE_RETURNING_CURSOR
|
||||||
};
|
};
|
||||||
|
|
||||||
// Statement flags.
|
// Statement flags.
|
||||||
|
@ -267,6 +267,8 @@ void GEN_request(DsqlCompilerScratch* scratch, DmlNode* node)
|
|||||||
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
||||||
node->genBlr(scratch);
|
node->genBlr(scratch);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
///case DsqlCompiledStatement::TYPE_RETURNING_CURSOR:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
dsql_msg* message = statement->getSendMsg();
|
dsql_msg* message = statement->getSendMsg();
|
||||||
@ -660,3 +662,13 @@ void GEN_stuff_context(DsqlCompilerScratch* dsqlScratch, const dsql_ctx* context
|
|||||||
dsqlScratch->appendUChar(context->ctx_recursive);
|
dsqlScratch->appendUChar(context->ctx_recursive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write a context number into the BLR buffer. Check for possible overflow.
|
||||||
|
void GEN_stuff_context_number(DsqlCompilerScratch* dsqlScratch, USHORT contextNumber)
|
||||||
|
{
|
||||||
|
if (contextNumber > MAX_UCHAR)
|
||||||
|
ERRD_post(Arg::Gds(isc_too_many_contexts));
|
||||||
|
|
||||||
|
dsqlScratch->appendUChar(contextNumber);
|
||||||
|
}
|
||||||
|
@ -39,5 +39,6 @@ void GEN_request(Jrd::DsqlCompilerScratch*, Jrd::DmlNode*);
|
|||||||
void GEN_rse(Jrd::DsqlCompilerScratch*, Jrd::RseNode*);
|
void GEN_rse(Jrd::DsqlCompilerScratch*, Jrd::RseNode*);
|
||||||
void GEN_sort(Jrd::DsqlCompilerScratch*, UCHAR, Jrd::ValueListNode*);
|
void GEN_sort(Jrd::DsqlCompilerScratch*, UCHAR, Jrd::ValueListNode*);
|
||||||
void GEN_stuff_context(Jrd::DsqlCompilerScratch*, const Jrd::dsql_ctx*);
|
void GEN_stuff_context(Jrd::DsqlCompilerScratch*, const Jrd::dsql_ctx*);
|
||||||
|
void GEN_stuff_context_number(Jrd::DsqlCompilerScratch*, USHORT);
|
||||||
|
|
||||||
#endif // DSQL_GEN_PROTO_H
|
#endif // DSQL_GEN_PROTO_H
|
||||||
|
@ -6524,7 +6524,7 @@ insert_start
|
|||||||
: INSERT INTO simple_table_name
|
: INSERT INTO simple_table_name
|
||||||
{
|
{
|
||||||
StoreNode* node = newNode<StoreNode>();
|
StoreNode* node = newNode<StoreNode>();
|
||||||
node->dsqlRelation = $3;
|
node->target = $3;
|
||||||
$$ = node;
|
$$ = node;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -6559,10 +6559,13 @@ merge
|
|||||||
node->usingClause = $5;
|
node->usingClause = $5;
|
||||||
node->condition = $7;
|
node->condition = $7;
|
||||||
}
|
}
|
||||||
merge_when_clause($8) returning_clause
|
merge_when_clause($8)
|
||||||
|
plan_clause order_clause_opt returning_clause
|
||||||
{
|
{
|
||||||
MergeNode* node = $$ = $8;
|
MergeNode* node = $$ = $8;
|
||||||
node->returning = $10;
|
node->plan = $10;
|
||||||
|
node->order = $11;
|
||||||
|
node->returning = $12;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -6705,12 +6708,16 @@ update_or_insert
|
|||||||
node->relation = $5;
|
node->relation = $5;
|
||||||
}
|
}
|
||||||
ins_column_parens_opt(NOTRIAL(&$6->fields)) override_opt VALUES '(' value_or_default_list ')'
|
ins_column_parens_opt(NOTRIAL(&$6->fields)) override_opt VALUES '(' value_or_default_list ')'
|
||||||
update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause
|
update_or_insert_matching_opt(NOTRIAL(&$6->matching))
|
||||||
|
plan_clause order_clause_opt rows_clause_optional returning_clause
|
||||||
{
|
{
|
||||||
UpdateOrInsertNode* node = $$ = $6;
|
UpdateOrInsertNode* node = $$ = $6;
|
||||||
node->overrideClause = $8;
|
node->overrideClause = $8;
|
||||||
node->values = $11;
|
node->values = $11;
|
||||||
node->returning = $14;
|
node->plan = $14;
|
||||||
|
node->order = $15;
|
||||||
|
node->rows = $16;
|
||||||
|
node->returning = $17;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -362,6 +362,7 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode*
|
|||||||
relation_name = procNode->dsqlName.identifier;
|
relation_name = procNode->dsqlName.identifier;
|
||||||
else if ((relNode = nodeAs<RelationSourceNode>(relationNode)))
|
else if ((relNode = nodeAs<RelationSourceNode>(relationNode)))
|
||||||
relation_name = relNode->dsqlName;
|
relation_name = relNode->dsqlName;
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
else if ((selNode = nodeAs<SelectExprNode>(relationNode)))
|
else if ((selNode = nodeAs<SelectExprNode>(relationNode)))
|
||||||
relation_name = selNode->alias.c_str();
|
relation_name = selNode->alias.c_str();
|
||||||
|
|
||||||
@ -683,12 +684,9 @@ void PASS1_check_unique_fields_names(StrArray& names, const CompoundStmtNode* fi
|
|||||||
{
|
{
|
||||||
const char* name = NULL;
|
const char* name = NULL;
|
||||||
|
|
||||||
const DeclareVariableNode* varNode;
|
if (auto varNode = nodeAs<DeclareVariableNode>(*ptr))
|
||||||
const DeclareCursorNode* cursorNode;
|
|
||||||
|
|
||||||
if ((varNode = nodeAs<DeclareVariableNode>(*ptr)))
|
|
||||||
name = varNode->dsqlDef->name.c_str();
|
name = varNode->dsqlDef->name.c_str();
|
||||||
else if ((cursorNode = nodeAs<DeclareCursorNode>(*ptr)))
|
else if (auto cursorNode = nodeAs<DeclareCursorNode>(*ptr))
|
||||||
name = cursorNode->dsqlName.c_str();
|
name = cursorNode->dsqlName.c_str();
|
||||||
else if (nodeAs<DeclareSubProcNode>(*ptr) || nodeAs<DeclareSubFuncNode>(*ptr))
|
else if (nodeAs<DeclareSubProcNode>(*ptr) || nodeAs<DeclareSubFuncNode>(*ptr))
|
||||||
continue;
|
continue;
|
||||||
@ -1326,12 +1324,10 @@ ValueListNode* PASS1_expand_select_list(DsqlCompilerScratch* dsqlScratch, ValueL
|
|||||||
void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, ValueListNode* list,
|
void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, ValueListNode* list,
|
||||||
bool hide_using)
|
bool hide_using)
|
||||||
{
|
{
|
||||||
RseNode* rseNode;
|
|
||||||
ProcedureSourceNode* procNode;
|
|
||||||
RelationSourceNode* relNode;
|
|
||||||
FieldNode* fieldNode;
|
FieldNode* fieldNode;
|
||||||
|
|
||||||
if ((rseNode = nodeAs<RseNode>(node)))
|
//// TODO: LocalTableSourceNode
|
||||||
|
if (auto rseNode = nodeAs<RseNode>(node))
|
||||||
{
|
{
|
||||||
ValueListNode* sub_items = rseNode->dsqlSelectList;
|
ValueListNode* sub_items = rseNode->dsqlSelectList;
|
||||||
|
|
||||||
@ -1375,7 +1371,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((procNode = nodeAs<ProcedureSourceNode>(node)))
|
else if (auto procNode = nodeAs<ProcedureSourceNode>(node))
|
||||||
{
|
{
|
||||||
dsql_ctx* context = procNode->dsqlContext;
|
dsql_ctx* context = procNode->dsqlContext;
|
||||||
|
|
||||||
@ -1395,7 +1391,7 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((relNode = nodeAs<RelationSourceNode>(node)))
|
else if (auto relNode = nodeAs<RelationSourceNode>(node))
|
||||||
{
|
{
|
||||||
dsql_ctx* context = relNode->dsqlContext;
|
dsql_ctx* context = relNode->dsqlContext;
|
||||||
|
|
||||||
@ -1730,6 +1726,7 @@ RecordSourceNode* PASS1_relation(DsqlCompilerScratch* dsqlScratch, RecordSourceN
|
|||||||
procNode->dsqlContext = context;
|
procNode->dsqlContext = context;
|
||||||
return procNode;
|
return procNode;
|
||||||
}
|
}
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
|
|
||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2928,31 +2925,26 @@ static void remap_streams_to_parent_context(ExprNode* input, dsql_ctx* parent_co
|
|||||||
{
|
{
|
||||||
DEV_BLKCHK(parent_context, dsql_type_ctx);
|
DEV_BLKCHK(parent_context, dsql_type_ctx);
|
||||||
|
|
||||||
RecSourceListNode* listNode;
|
if (auto listNode = nodeAs<RecSourceListNode>(input))
|
||||||
ProcedureSourceNode* procNode;
|
|
||||||
RelationSourceNode* relNode;
|
|
||||||
RseNode* rseNode;
|
|
||||||
UnionSourceNode* unionNode;
|
|
||||||
|
|
||||||
if ((listNode = nodeAs<RecSourceListNode>(input)))
|
|
||||||
{
|
{
|
||||||
NestConst<RecordSourceNode>* ptr = listNode->items.begin();
|
NestConst<RecordSourceNode>* ptr = listNode->items.begin();
|
||||||
for (const NestConst<RecordSourceNode>* const end = listNode->items.end(); ptr != end; ++ptr)
|
for (const NestConst<RecordSourceNode>* const end = listNode->items.end(); ptr != end; ++ptr)
|
||||||
remap_streams_to_parent_context(*ptr, parent_context);
|
remap_streams_to_parent_context(*ptr, parent_context);
|
||||||
}
|
}
|
||||||
else if ((procNode = nodeAs<ProcedureSourceNode>(input)))
|
else if (auto procNode = nodeAs<ProcedureSourceNode>(input))
|
||||||
{
|
{
|
||||||
DEV_BLKCHK(procNode->dsqlContext, dsql_type_ctx);
|
DEV_BLKCHK(procNode->dsqlContext, dsql_type_ctx);
|
||||||
procNode->dsqlContext->ctx_parent = parent_context;
|
procNode->dsqlContext->ctx_parent = parent_context;
|
||||||
}
|
}
|
||||||
else if ((relNode = nodeAs<RelationSourceNode>(input)))
|
else if (auto relNode = nodeAs<RelationSourceNode>(input))
|
||||||
{
|
{
|
||||||
DEV_BLKCHK(relNode->dsqlContext, dsql_type_ctx);
|
DEV_BLKCHK(relNode->dsqlContext, dsql_type_ctx);
|
||||||
relNode->dsqlContext->ctx_parent = parent_context;
|
relNode->dsqlContext->ctx_parent = parent_context;
|
||||||
}
|
}
|
||||||
else if ((rseNode = nodeAs<RseNode>(input)))
|
//// TODO: LocalTableSourceNode
|
||||||
|
else if (auto rseNode = nodeAs<RseNode>(input))
|
||||||
remap_streams_to_parent_context(rseNode->dsqlStreams, parent_context);
|
remap_streams_to_parent_context(rseNode->dsqlStreams, parent_context);
|
||||||
else if ((unionNode = nodeAs<UnionSourceNode>(input)))
|
else if (auto unionNode = nodeAs<UnionSourceNode>(input))
|
||||||
remap_streams_to_parent_context(unionNode->dsqlClauses, parent_context);
|
remap_streams_to_parent_context(unionNode->dsqlClauses, parent_context);
|
||||||
else
|
else
|
||||||
fb_assert(nodeAs<AggregateSourceNode>(input));
|
fb_assert(nodeAs<AggregateSourceNode>(input));
|
||||||
|
@ -451,4 +451,12 @@
|
|||||||
|
|
||||||
#define blr_marks (unsigned char) 217 // mark some blr code with specific flags
|
#define blr_marks (unsigned char) 217 // mark some blr code with specific flags
|
||||||
|
|
||||||
|
#define blr_dcl_local_table (unsigned char) 218
|
||||||
|
|
||||||
|
// subcodes of blr_dcl_local_table
|
||||||
|
#define blr_dcl_local_table_format (unsigned char) 1
|
||||||
|
|
||||||
|
#define blr_local_table_truncate (unsigned char) 219
|
||||||
|
#define blr_local_table_id (unsigned char) 220
|
||||||
|
|
||||||
#endif // FIREBIRD_IMPL_BLR_H
|
#endif // FIREBIRD_IMPL_BLR_H
|
||||||
|
@ -769,6 +769,7 @@
|
|||||||
#define fb_dbg_subproc 5
|
#define fb_dbg_subproc 5
|
||||||
#define fb_dbg_subfunc 6
|
#define fb_dbg_subfunc 6
|
||||||
#define fb_dbg_map_curname 7
|
#define fb_dbg_map_curname 7
|
||||||
|
//// TODO: LocalTable name.
|
||||||
|
|
||||||
// sub code for fb_dbg_map_argument
|
// sub code for fb_dbg_map_argument
|
||||||
#define fb_dbg_arg_input 0
|
#define fb_dbg_arg_input 0
|
||||||
|
@ -5135,6 +5135,7 @@ const
|
|||||||
isc_tom_key_length = 335545274;
|
isc_tom_key_length = 335545274;
|
||||||
isc_inf_invalid_args = 335545275;
|
isc_inf_invalid_args = 335545275;
|
||||||
isc_sysf_invalid_null_empty = 335545276;
|
isc_sysf_invalid_null_empty = 335545276;
|
||||||
|
isc_bad_loctab_num = 335545276;
|
||||||
isc_gfix_db_name = 335740929;
|
isc_gfix_db_name = 335740929;
|
||||||
isc_gfix_invalid_sw = 335740930;
|
isc_gfix_invalid_sw = 335740930;
|
||||||
isc_gfix_incmp_sw = 335740932;
|
isc_gfix_incmp_sw = 335740932;
|
||||||
|
@ -978,6 +978,7 @@ static const struct {
|
|||||||
{"tom_key_length", 335545274},
|
{"tom_key_length", 335545274},
|
||||||
{"inf_invalid_args", 335545275},
|
{"inf_invalid_args", 335545275},
|
||||||
{"sysf_invalid_null_empty", 335545276},
|
{"sysf_invalid_null_empty", 335545276},
|
||||||
|
{"bad_loctab_num", 335545277},
|
||||||
{"gfix_db_name", 335740929},
|
{"gfix_db_name", 335740929},
|
||||||
{"gfix_invalid_sw", 335740930},
|
{"gfix_invalid_sw", 335740930},
|
||||||
{"gfix_incmp_sw", 335740932},
|
{"gfix_incmp_sw", 335740932},
|
||||||
|
@ -1012,6 +1012,7 @@ const ISC_STATUS isc_block_size = 335545273L;
|
|||||||
const ISC_STATUS isc_tom_key_length = 335545274L;
|
const ISC_STATUS isc_tom_key_length = 335545274L;
|
||||||
const ISC_STATUS isc_inf_invalid_args = 335545275L;
|
const ISC_STATUS isc_inf_invalid_args = 335545275L;
|
||||||
const ISC_STATUS isc_sysf_invalid_null_empty = 335545276L;
|
const ISC_STATUS isc_sysf_invalid_null_empty = 335545276L;
|
||||||
|
const ISC_STATUS isc_bad_loctab_num = 335545277L;
|
||||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||||
@ -1504,7 +1505,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
|
|||||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||||
const ISC_STATUS isc_err_max = 1448;
|
const ISC_STATUS isc_err_max = 1449;
|
||||||
|
|
||||||
#else /* c definitions */
|
#else /* c definitions */
|
||||||
|
|
||||||
@ -2486,6 +2487,7 @@ const ISC_STATUS isc_err_max = 1448;
|
|||||||
#define isc_tom_key_length 335545274L
|
#define isc_tom_key_length 335545274L
|
||||||
#define isc_inf_invalid_args 335545275L
|
#define isc_inf_invalid_args 335545275L
|
||||||
#define isc_sysf_invalid_null_empty 335545276L
|
#define isc_sysf_invalid_null_empty 335545276L
|
||||||
|
#define isc_bad_loctab_num 335545277L
|
||||||
#define isc_gfix_db_name 335740929L
|
#define isc_gfix_db_name 335740929L
|
||||||
#define isc_gfix_invalid_sw 335740930L
|
#define isc_gfix_invalid_sw 335740930L
|
||||||
#define isc_gfix_incmp_sw 335740932L
|
#define isc_gfix_incmp_sw 335740932L
|
||||||
@ -2978,7 +2980,7 @@ const ISC_STATUS isc_err_max = 1448;
|
|||||||
#define isc_trace_switch_param_miss 337182758L
|
#define isc_trace_switch_param_miss 337182758L
|
||||||
#define isc_trace_param_act_notcompat 337182759L
|
#define isc_trace_param_act_notcompat 337182759L
|
||||||
#define isc_trace_mandatory_switch_miss 337182760L
|
#define isc_trace_mandatory_switch_miss 337182760L
|
||||||
#define isc_err_max 1448
|
#define isc_err_max 1449
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -981,6 +981,7 @@ Data source : @4"}, /* eds_statement */
|
|||||||
{335545274, "Invalid key length @1, need >@2"}, /* tom_key_length */
|
{335545274, "Invalid key length @1, need >@2"}, /* tom_key_length */
|
||||||
{335545275, "Invalid information arguments"}, /* inf_invalid_args */
|
{335545275, "Invalid information arguments"}, /* inf_invalid_args */
|
||||||
{335545276, "Empty or NULL parameter @1 is not accepted"}, /* sysf_invalid_null_empty */
|
{335545276, "Empty or NULL parameter @1 is not accepted"}, /* sysf_invalid_null_empty */
|
||||||
|
{335545277, "Undefined local table number @1"}, /* bad_loctab_num */
|
||||||
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||||
|
@ -977,6 +977,7 @@ static const struct {
|
|||||||
{335545274, -901}, /* 954 tom_key_length */
|
{335545274, -901}, /* 954 tom_key_length */
|
||||||
{335545275, -901}, /* 955 inf_invalid_args */
|
{335545275, -901}, /* 955 inf_invalid_args */
|
||||||
{335545276, -901}, /* 956 sysf_invalid_null_empty */
|
{335545276, -901}, /* 956 sysf_invalid_null_empty */
|
||||||
|
{335545277, -901}, /* 957 bad_loctab_num */
|
||||||
{335740929, -901}, /* 1 gfix_db_name */
|
{335740929, -901}, /* 1 gfix_db_name */
|
||||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||||
|
@ -977,6 +977,7 @@ static const struct {
|
|||||||
{335545274, "22023"}, // 954 tom_key_length
|
{335545274, "22023"}, // 954 tom_key_length
|
||||||
{335545275, "HY000"}, // 955 inf_invalid_args
|
{335545275, "HY000"}, // 955 inf_invalid_args
|
||||||
{335545276, "22023"}, // 956 sysf_invalid_null_empty
|
{335545276, "22023"}, // 956 sysf_invalid_null_empty
|
||||||
|
{335545277, "HY000"}, // 957 bad_loctab_num
|
||||||
{335740929, "00000"}, // 1 gfix_db_name
|
{335740929, "00000"}, // 1 gfix_db_name
|
||||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||||
|
@ -71,6 +71,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
|
|||||||
parentStatement(NULL),
|
parentStatement(NULL),
|
||||||
subStatements(*p),
|
subStatements(*p),
|
||||||
fors(*p),
|
fors(*p),
|
||||||
|
localTables(*p),
|
||||||
invariants(*p),
|
invariants(*p),
|
||||||
blr(*p),
|
blr(*p),
|
||||||
mapFieldInfo(*p),
|
mapFieldInfo(*p),
|
||||||
@ -155,6 +156,8 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
|
|||||||
// make a vector of all used RSEs
|
// make a vector of all used RSEs
|
||||||
fors = csb->csb_fors;
|
fors = csb->csb_fors;
|
||||||
|
|
||||||
|
localTables = csb->csb_localTables;
|
||||||
|
|
||||||
// make a vector of all invariant-type nodes, so that we will
|
// make a vector of all invariant-type nodes, so that we will
|
||||||
// be able to easily reinitialize them when we restart the request
|
// be able to easily reinitialize them when we restart the request
|
||||||
invariants.join(csb->csb_invariants);
|
invariants.join(csb->csb_invariants);
|
||||||
|
@ -81,6 +81,7 @@ public:
|
|||||||
Firebird::Array<JrdStatement*> subStatements; // Array of subroutines' statements
|
Firebird::Array<JrdStatement*> subStatements; // Array of subroutines' statements
|
||||||
const StmtNode* topNode; // top of execution tree
|
const StmtNode* topNode; // top of execution tree
|
||||||
Firebird::Array<const RecordSource*> fors; // record sources
|
Firebird::Array<const RecordSource*> fors; // record sources
|
||||||
|
Firebird::Array<const DeclareLocalTableNode*> localTables; // local tables
|
||||||
Firebird::Array<ULONG*> invariants; // pointer to nodes invariant offsets
|
Firebird::Array<ULONG*> invariants; // pointer to nodes invariant offsets
|
||||||
Firebird::RefStrPtr sqlText; // SQL text (encoded in the metadata charset)
|
Firebird::RefStrPtr sqlText; // SQL text (encoded in the metadata charset)
|
||||||
Firebird::Array<UCHAR> blr; // BLR for non-SQL query
|
Firebird::Array<UCHAR> blr; // BLR for non-SQL query
|
||||||
|
@ -187,6 +187,7 @@ namespace Jrd
|
|||||||
alias = csb_tail->csb_relation->rel_name.c_str();
|
alias = csb_tail->csb_relation->rel_name.c_str();
|
||||||
else if (csb_tail->csb_procedure)
|
else if (csb_tail->csb_procedure)
|
||||||
alias = csb_tail->csb_procedure->getName().toString();
|
alias = csb_tail->csb_procedure->getName().toString();
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
else
|
else
|
||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
|
|
||||||
|
@ -256,6 +256,7 @@ PlanNode* PlanNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
procNode->dsqlContext = context;
|
procNode->dsqlContext = context;
|
||||||
node->dsqlRecordSourceNode = procNode;
|
node->dsqlRecordSourceNode = procNode;
|
||||||
}
|
}
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
|
|
||||||
// ASF: I think it's a error to let node->dsqlRecordSourceNode be NULL here, but it happens
|
// ASF: I think it's a error to let node->dsqlRecordSourceNode be NULL here, but it happens
|
||||||
// at least since v2.5. See gen.cpp/gen_plan for more information.
|
// at least since v2.5. See gen.cpp/gen_plan for more information.
|
||||||
@ -453,6 +454,144 @@ RecSourceListNode* RecSourceListNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
//--------------------
|
//--------------------
|
||||||
|
|
||||||
|
|
||||||
|
// Parse a local table reference.
|
||||||
|
LocalTableSourceNode* LocalTableSourceNode::parse(thread_db* tdbb, CompilerScratch* csb,
|
||||||
|
const SSHORT blrOp, bool parseContext)
|
||||||
|
{
|
||||||
|
const USHORT tableNumber = csb->csb_blr_reader.getWord();
|
||||||
|
|
||||||
|
if (tableNumber >= csb->csb_localTables.getCount())
|
||||||
|
PAR_error(csb, Arg::Gds(isc_bad_loctab_num) << Arg::Num(tableNumber));
|
||||||
|
|
||||||
|
// Make a relation reference node
|
||||||
|
|
||||||
|
const auto node = FB_NEW_POOL(*tdbb->getDefaultPool()) LocalTableSourceNode(
|
||||||
|
*tdbb->getDefaultPool());
|
||||||
|
|
||||||
|
node->tableNumber = tableNumber;
|
||||||
|
|
||||||
|
AutoPtr<string> aliasString(FB_NEW_POOL(csb->csb_pool) string(csb->csb_pool));
|
||||||
|
csb->csb_blr_reader.getString(*aliasString);
|
||||||
|
|
||||||
|
if (aliasString->hasData())
|
||||||
|
node->alias = *aliasString;
|
||||||
|
else
|
||||||
|
aliasString.reset();
|
||||||
|
|
||||||
|
// generate a stream for the relation reference, assuming it is a real reference
|
||||||
|
|
||||||
|
if (parseContext)
|
||||||
|
{
|
||||||
|
node->stream = PAR_context(csb, &node->context);
|
||||||
|
|
||||||
|
if (tableNumber >= csb->csb_localTables.getCount() || !csb->csb_localTables[tableNumber])
|
||||||
|
PAR_error(csb, Arg::Gds(isc_bad_loctab_num) << Arg::Num(tableNumber));
|
||||||
|
|
||||||
|
csb->csb_rpt[node->stream].csb_format = csb->csb_localTables[tableNumber]->format;
|
||||||
|
csb->csb_rpt[node->stream].csb_alias = aliasString.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
string LocalTableSourceNode::internalPrint(NodePrinter& printer) const
|
||||||
|
{
|
||||||
|
RecordSourceNode::internalPrint(printer);
|
||||||
|
|
||||||
|
NODE_PRINT(printer, alias);
|
||||||
|
NODE_PRINT(printer, tableNumber);
|
||||||
|
NODE_PRINT(printer, context);
|
||||||
|
|
||||||
|
return "LocalTableSourceNode";
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordSourceNode* LocalTableSourceNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||||
|
{
|
||||||
|
return dsqlPassRelProc(dsqlScratch, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalTableSourceNode::dsqlMatch(DsqlCompilerScratch* /*dsqlScratch*/, const ExprNode* other,
|
||||||
|
bool /*ignoreMapCast*/) const
|
||||||
|
{
|
||||||
|
const auto o = nodeAs<LocalTableSourceNode>(other);
|
||||||
|
return o && dsqlContext == o->dsqlContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTableSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
||||||
|
{
|
||||||
|
dsqlScratch->appendUChar(blr_local_table_id);
|
||||||
|
dsqlScratch->appendUShort(tableNumber);
|
||||||
|
dsqlScratch->appendMetaString(alias.c_str()); // dsqlContext->ctx_alias?
|
||||||
|
|
||||||
|
GEN_stuff_context(dsqlScratch, dsqlContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalTableSourceNode* LocalTableSourceNode::copy(thread_db* tdbb, NodeCopier& copier) const
|
||||||
|
{
|
||||||
|
if (!copier.remap)
|
||||||
|
BUGCHECK(221); // msg 221 (CMP) copy: cannot remap
|
||||||
|
|
||||||
|
const auto newSource = FB_NEW_POOL(*tdbb->getDefaultPool()) LocalTableSourceNode(
|
||||||
|
*tdbb->getDefaultPool());
|
||||||
|
|
||||||
|
newSource->stream = copier.csb->nextStream();
|
||||||
|
copier.remap[stream] = newSource->stream;
|
||||||
|
|
||||||
|
newSource->context = context;
|
||||||
|
|
||||||
|
if (tableNumber >= copier.csb->csb_localTables.getCount() || !copier.csb->csb_localTables[tableNumber])
|
||||||
|
ERR_post(Arg::Gds(isc_bad_loctab_num) << Arg::Num(tableNumber));
|
||||||
|
|
||||||
|
const auto element = CMP_csb_element(copier.csb, newSource->stream);
|
||||||
|
|
||||||
|
element->csb_format = copier.csb->csb_localTables[tableNumber]->format;
|
||||||
|
element->csb_view_stream = copier.remap[0];
|
||||||
|
|
||||||
|
if (alias.hasData())
|
||||||
|
{
|
||||||
|
element->csb_alias = FB_NEW_POOL(*tdbb->getDefaultPool())
|
||||||
|
string(*tdbb->getDefaultPool(), alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTableSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* /*rse*/,
|
||||||
|
BoolExprNode** /*boolean*/, RecordSourceNodeStack& stack)
|
||||||
|
{
|
||||||
|
fb_assert(!csb->csb_view); // local tables cannot be inside a view
|
||||||
|
|
||||||
|
stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
|
||||||
|
|
||||||
|
pass1(tdbb, csb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTableSourceNode::pass2Rse(thread_db* tdbb, CompilerScratch* csb)
|
||||||
|
{
|
||||||
|
csb->csb_rpt[stream].activate();
|
||||||
|
|
||||||
|
pass2(tdbb, csb);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordSource* LocalTableSourceNode::compile(thread_db* tdbb, OptimizerBlk* opt, bool /*innerSubStream*/)
|
||||||
|
{
|
||||||
|
opt->beds.add(stream);
|
||||||
|
opt->localStreams.add(stream);
|
||||||
|
|
||||||
|
const auto csb = opt->opt_csb;
|
||||||
|
|
||||||
|
if (tableNumber >= opt->opt_csb->csb_localTables.getCount() || !opt->opt_csb->csb_localTables[tableNumber])
|
||||||
|
ERR_post(Arg::Gds(isc_bad_loctab_num) << Arg::Num(tableNumber));
|
||||||
|
|
||||||
|
auto localTable = csb->csb_localTables[tableNumber];
|
||||||
|
|
||||||
|
return FB_NEW_POOL(*tdbb->getDefaultPool()) LocalTableStream(csb, stream, localTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
|
||||||
// Parse a relation reference.
|
// Parse a relation reference.
|
||||||
RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* csb,
|
RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* csb,
|
||||||
const SSHORT blrOp, bool parseContext)
|
const SSHORT blrOp, bool parseContext)
|
||||||
@ -3345,26 +3484,24 @@ RseNode* SelectExprNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* source)
|
static RecordSourceNode* dsqlPassRelProc(DsqlCompilerScratch* dsqlScratch, RecordSourceNode* source)
|
||||||
{
|
{
|
||||||
ProcedureSourceNode* procNode = nodeAs<ProcedureSourceNode>(source);
|
|
||||||
RelationSourceNode* relNode = nodeAs<RelationSourceNode>(source);
|
|
||||||
|
|
||||||
fb_assert(procNode || relNode);
|
|
||||||
|
|
||||||
bool couldBeCte = true;
|
bool couldBeCte = true;
|
||||||
MetaName relName;
|
MetaName relName;
|
||||||
string relAlias;
|
string relAlias;
|
||||||
|
|
||||||
if (procNode)
|
if (auto procNode = nodeAs<ProcedureSourceNode>(source))
|
||||||
{
|
{
|
||||||
relName = procNode->dsqlName.identifier;
|
relName = procNode->dsqlName.identifier;
|
||||||
relAlias = procNode->alias;
|
relAlias = procNode->alias;
|
||||||
couldBeCte = !procNode->sourceList && procNode->dsqlName.package.isEmpty();
|
couldBeCte = !procNode->sourceList && procNode->dsqlName.package.isEmpty();
|
||||||
}
|
}
|
||||||
else if (relNode)
|
else if (auto relNode = nodeAs<RelationSourceNode>(source))
|
||||||
{
|
{
|
||||||
relName = relNode->dsqlName;
|
relName = relNode->dsqlName;
|
||||||
relAlias = relNode->alias;
|
relAlias = relNode->alias;
|
||||||
}
|
}
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
|
else
|
||||||
|
fb_assert(false);
|
||||||
|
|
||||||
if (relAlias.isEmpty())
|
if (relAlias.isEmpty())
|
||||||
relAlias = relName.c_str();
|
relAlias = relName.c_str();
|
||||||
|
@ -283,6 +283,75 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LocalTableSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_LOCAL_TABLE>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LocalTableSourceNode(MemoryPool& pool, const MetaName& aDsqlName = NULL)
|
||||||
|
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_LOCAL_TABLE>(pool),
|
||||||
|
alias(pool)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static LocalTableSourceNode* parse(thread_db* tdbb, CompilerScratch* csb, const SSHORT blrOp,
|
||||||
|
bool parseContext);
|
||||||
|
|
||||||
|
Firebird::string internalPrint(NodePrinter& printer) const override;
|
||||||
|
RecordSourceNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override;
|
||||||
|
|
||||||
|
bool dsqlSubSelectFinder(SubSelectFinder& /*visitor*/) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const override;
|
||||||
|
void genBlr(DsqlCompilerScratch* dsqlScratch) override;
|
||||||
|
|
||||||
|
LocalTableSourceNode* copy(thread_db* tdbb, NodeCopier& copier) const override;
|
||||||
|
|
||||||
|
RecordSourceNode* pass1(thread_db* tdbb, CompilerScratch* csb) override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
|
||||||
|
BoolExprNode** boolean, RecordSourceNodeStack& stack) override;
|
||||||
|
|
||||||
|
RecordSourceNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass2Rse(thread_db* tdbb, CompilerScratch* csb) override;
|
||||||
|
|
||||||
|
bool containsStream(StreamType checkStream) const override
|
||||||
|
{
|
||||||
|
return checkStream == stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeDbKeyStreams(StreamList& streamList) const override
|
||||||
|
{
|
||||||
|
streamList.add(getStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool computable(CompilerScratch* /*csb*/, StreamType /*stream*/,
|
||||||
|
bool /*allowOnlyCurrentStream*/, ValueExprNode* /*value*/) override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void findDependentFromStreams(const OptimizerRetrieval* /*optRet*/,
|
||||||
|
SortedStreamList* /*streamList*/) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordSource* compile(thread_db* tdbb, OptimizerBlk* opt, bool innerSubStream) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Firebird::string alias;
|
||||||
|
USHORT tableNumber = 0;
|
||||||
|
SSHORT context = 0; // user-specified context number for the local table reference
|
||||||
|
};
|
||||||
|
|
||||||
class RelationSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RELATION>
|
class RelationSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RELATION>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -51,7 +51,7 @@ static const struct
|
|||||||
{"field", field},
|
{"field", field},
|
||||||
{"fid", parm},
|
{"fid", parm},
|
||||||
{"parameter", parm},
|
{"parameter", parm},
|
||||||
{"variable", variable},
|
{"variable", one_word},
|
||||||
{"average", two},
|
{"average", two},
|
||||||
{"count", one},
|
{"count", one},
|
||||||
{"maximum", two},
|
{"maximum", two},
|
||||||
@ -213,7 +213,7 @@ static const struct
|
|||||||
{"strlen", strlength},
|
{"strlen", strlength},
|
||||||
{"trim", trim},
|
{"trim", trim},
|
||||||
// New BLR in FB2.1
|
// New BLR in FB2.1
|
||||||
{"init_variable", variable},
|
{"init_variable", one_word},
|
||||||
{"recurse", union_ops},
|
{"recurse", union_ops},
|
||||||
{"sys_function", function},
|
{"sys_function", function},
|
||||||
// New BLR in FB2.5
|
// New BLR in FB2.5
|
||||||
@ -248,5 +248,9 @@ static const struct
|
|||||||
{"local_time", byte_line},
|
{"local_time", byte_line},
|
||||||
{"at", verb_byte_verb},
|
{"at", verb_byte_verb},
|
||||||
{"marks", marks},
|
{"marks", marks},
|
||||||
|
// New BLR in FB5.0
|
||||||
|
{"dcl_local_table", dcl_local_table},
|
||||||
|
{"local_table_truncate", one_word},
|
||||||
|
{"local_table_id", local_table},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
@ -257,17 +257,12 @@ const Format* CMP_format(thread_db* tdbb, CompilerScratch* csb, StreamType strea
|
|||||||
if (!tail->csb_format)
|
if (!tail->csb_format)
|
||||||
{
|
{
|
||||||
if (tail->csb_relation)
|
if (tail->csb_relation)
|
||||||
{
|
|
||||||
tail->csb_format = MET_current(tdbb, tail->csb_relation);
|
tail->csb_format = MET_current(tdbb, tail->csb_relation);
|
||||||
}
|
|
||||||
else if (tail->csb_procedure)
|
else if (tail->csb_procedure)
|
||||||
{
|
|
||||||
tail->csb_format = tail->csb_procedure->prc_record_format;
|
tail->csb_format = tail->csb_procedure->prc_record_format;
|
||||||
}
|
//// TODO: LocalTableSourceNode
|
||||||
else
|
else
|
||||||
{
|
|
||||||
IBERROR(222); // msg 222 bad blr - invalid stream
|
IBERROR(222); // msg 222 bad blr - invalid stream
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fb_assert(tail->csb_format);
|
fb_assert(tail->csb_format);
|
||||||
|
@ -982,6 +982,17 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
|
|||||||
tdbb->setRequest(old_request);
|
tdbb->setRequest(old_request);
|
||||||
tdbb->setTransaction(old_transaction);
|
tdbb->setTransaction(old_transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto localTable : statement->localTables)
|
||||||
|
{
|
||||||
|
if (!localTable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto impure = localTable->getImpure(tdbb, request, false);
|
||||||
|
delete impure->recordBuffer;
|
||||||
|
impure->recordBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
release_blobs(tdbb, request);
|
release_blobs(tdbb, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,7 +448,7 @@ public:
|
|||||||
csb_resources(p),
|
csb_resources(p),
|
||||||
csb_dependencies(p),
|
csb_dependencies(p),
|
||||||
csb_fors(p),
|
csb_fors(p),
|
||||||
csb_cursors(p),
|
csb_localTables(p),
|
||||||
csb_invariants(p),
|
csb_invariants(p),
|
||||||
csb_current_nodes(p),
|
csb_current_nodes(p),
|
||||||
csb_current_for_nodes(p),
|
csb_current_for_nodes(p),
|
||||||
@ -511,7 +511,7 @@ public:
|
|||||||
ResourceList csb_resources; // Resources (relations and indexes)
|
ResourceList csb_resources; // Resources (relations and indexes)
|
||||||
Firebird::Array<Dependency> csb_dependencies; // objects that this statement depends upon
|
Firebird::Array<Dependency> csb_dependencies; // objects that this statement depends upon
|
||||||
Firebird::Array<const RecordSource*> csb_fors; // record sources
|
Firebird::Array<const RecordSource*> csb_fors; // record sources
|
||||||
Firebird::Array<const Cursor*> csb_cursors; // named cursors
|
Firebird::Array<const DeclareLocalTableNode*> csb_localTables; // local tables
|
||||||
Firebird::Array<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets
|
Firebird::Array<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets
|
||||||
Firebird::Array<ExprNode*> csb_current_nodes; // RseNode's and other invariant
|
Firebird::Array<ExprNode*> csb_current_nodes; // RseNode's and other invariant
|
||||||
// candidates within whose scope we are
|
// candidates within whose scope we are
|
||||||
|
@ -548,6 +548,7 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
|
|||||||
switch (statement->getType())
|
switch (statement->getType())
|
||||||
{
|
{
|
||||||
case DsqlCompiledStatement::TYPE_SELECT:
|
case DsqlCompiledStatement::TYPE_SELECT:
|
||||||
|
case DsqlCompiledStatement::TYPE_RETURNING_CURSOR:
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
||||||
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
||||||
m_stmt_selectable = true;
|
m_stmt_selectable = true;
|
||||||
|
@ -1281,7 +1281,7 @@ static void check_sorts(CompilerScratch* csb, RseNode* rse)
|
|||||||
{
|
{
|
||||||
RecordSourceNode* subNode = new_rse->rse_relations[i];
|
RecordSourceNode* subNode = new_rse->rse_relations[i];
|
||||||
|
|
||||||
if (nodeIs<RelationSourceNode>(subNode) &&
|
if ((nodeIs<RelationSourceNode>(subNode) || nodeIs<LocalTableSourceNode>(subNode)) &&
|
||||||
subNode->getStream() == sort_stream &&
|
subNode->getStream() == sort_stream &&
|
||||||
new_rse != rse)
|
new_rse != rse)
|
||||||
{
|
{
|
||||||
@ -1289,7 +1289,6 @@ static void check_sorts(CompilerScratch* csb, RseNode* rse)
|
|||||||
sortStreamFound = true;
|
sortStreamFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortStreamFound)
|
if (sortStreamFound)
|
||||||
@ -1309,7 +1308,7 @@ static void check_sorts(CompilerScratch* csb, RseNode* rse)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (nodeIs<RelationSourceNode>(node) &&
|
if ((nodeIs<RelationSourceNode>(node) || nodeIs<LocalTableSourceNode>(node)) &&
|
||||||
node->getStream() == sort_stream &&
|
node->getStream() == sort_stream &&
|
||||||
new_rse && new_rse != rse)
|
new_rse && new_rse != rse)
|
||||||
{
|
{
|
||||||
@ -2090,7 +2089,7 @@ static RecordSource* gen_outer(thread_db* tdbb, OptimizerBlk* opt, RseNode* rse,
|
|||||||
{
|
{
|
||||||
const RecordSourceNode* node = rse->rse_relations[i];
|
const RecordSourceNode* node = rse->rse_relations[i];
|
||||||
|
|
||||||
if (nodeIs<RelationSourceNode>(node))
|
if (nodeIs<RelationSourceNode>(node) || nodeIs<LocalTableSourceNode>(node))
|
||||||
{
|
{
|
||||||
stream_ptr[i]->stream_rsb = NULL;
|
stream_ptr[i]->stream_rsb = NULL;
|
||||||
stream_ptr[i]->stream_num = node->getStream();
|
stream_ptr[i]->stream_num = node->getStream();
|
||||||
|
@ -180,7 +180,8 @@ namespace
|
|||||||
if (relationNode->getKind() != DmlNode::KIND_REC_SOURCE)
|
if (relationNode->getKind() != DmlNode::KIND_REC_SOURCE)
|
||||||
PAR_syntax_error(csb, "TABLE");
|
PAR_syntax_error(csb, "TABLE");
|
||||||
|
|
||||||
RelationSourceNode* relationSource = nodeAs<RelationSourceNode>(
|
//// TODO: LocalTableSourceNode
|
||||||
|
auto relationSource = nodeAs<RelationSourceNode>(
|
||||||
static_cast<RecordSourceNode*>(relationNode));
|
static_cast<RecordSourceNode*>(relationNode));
|
||||||
|
|
||||||
if (!relationSource)
|
if (!relationSource)
|
||||||
@ -1011,6 +1012,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
// in which case the base relation (and alias) must be specified
|
// in which case the base relation (and alias) must be specified
|
||||||
|
|
||||||
USHORT n = (unsigned int) csb->csb_blr_reader.getByte();
|
USHORT n = (unsigned int) csb->csb_blr_reader.getByte();
|
||||||
|
//// TODO: LocalTableSourceNode (blr_local_table_id)
|
||||||
if (n != blr_relation && n != blr_relation2 && n != blr_rid && n != blr_rid2)
|
if (n != blr_relation && n != blr_relation2 && n != blr_rid && n != blr_rid2)
|
||||||
PAR_syntax_error(csb, "TABLE");
|
PAR_syntax_error(csb, "TABLE");
|
||||||
|
|
||||||
@ -1018,6 +1020,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
// this would add a new context; while this is a reference to
|
// this would add a new context; while this is a reference to
|
||||||
// an existing context
|
// an existing context
|
||||||
|
|
||||||
|
//// TODO: LocalTableSourceNode
|
||||||
plan->relationNode = RelationSourceNode::parse(tdbb, csb, n, false);
|
plan->relationNode = RelationSourceNode::parse(tdbb, csb, n, false);
|
||||||
|
|
||||||
jrd_rel* relation = plan->relationNode->relation;
|
jrd_rel* relation = plan->relationNode->relation;
|
||||||
@ -1297,6 +1300,9 @@ RecordSourceNode* PAR_parseRecordSource(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
case blr_rid2:
|
case blr_rid2:
|
||||||
return RelationSourceNode::parse(tdbb, csb, blrOp, true);
|
return RelationSourceNode::parse(tdbb, csb, blrOp, true);
|
||||||
|
|
||||||
|
case blr_local_table_id:
|
||||||
|
return LocalTableSourceNode::parse(tdbb, csb, blrOp, true);
|
||||||
|
|
||||||
case blr_union:
|
case blr_union:
|
||||||
case blr_recurse:
|
case blr_recurse:
|
||||||
return UnionSourceNode::parse(tdbb, csb, blrOp);
|
return UnionSourceNode::parse(tdbb, csb, blrOp);
|
||||||
@ -1622,6 +1628,7 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
case blr_rid:
|
case blr_rid:
|
||||||
case blr_relation2:
|
case blr_relation2:
|
||||||
case blr_rid2:
|
case blr_rid2:
|
||||||
|
case blr_local_table_id:
|
||||||
case blr_union:
|
case blr_union:
|
||||||
case blr_recurse:
|
case blr_recurse:
|
||||||
case blr_window:
|
case blr_window:
|
||||||
|
@ -59,7 +59,6 @@ namespace Jrd
|
|||||||
bool irsb_active;
|
bool irsb_active;
|
||||||
State irsb_state;
|
State irsb_state;
|
||||||
FB_UINT64 irsb_position;
|
FB_UINT64 irsb_position;
|
||||||
RecordBuffer* irsb_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
128
src/jrd/recsrc/LocalTableStream.cpp
Normal file
128
src/jrd/recsrc/LocalTableStream.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* The contents of this file are subject to the Initial
|
||||||
|
* Developer's Public License Version 1.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed AS IS,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing rights
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code was created by Adriano dos Santos Fernandes
|
||||||
|
* for the Firebird Open Source RDBMS project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Adriano dos Santos Fernandes <adrianosf@gmail.com>
|
||||||
|
* and all contributors signed below.
|
||||||
|
*
|
||||||
|
* All Rights Reserved.
|
||||||
|
* Contributor(s): ______________________________________.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "firebird.h"
|
||||||
|
#include "../jrd/align.h"
|
||||||
|
#include "../jrd/jrd.h"
|
||||||
|
#include "../jrd/req.h"
|
||||||
|
#include "../dsql/StmtNodes.h"
|
||||||
|
|
||||||
|
#include "RecordSource.h"
|
||||||
|
|
||||||
|
using namespace Firebird;
|
||||||
|
using namespace Jrd;
|
||||||
|
|
||||||
|
// ------------------------
|
||||||
|
// Data access: local table
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
|
LocalTableStream::LocalTableStream(CompilerScratch* csb, StreamType stream, const DeclareLocalTableNode* table)
|
||||||
|
: RecordStream(csb, stream),
|
||||||
|
m_table(table)
|
||||||
|
{
|
||||||
|
fb_assert(m_table);
|
||||||
|
|
||||||
|
m_impure = csb->allocImpure<Impure>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTableStream::open(thread_db* tdbb) const
|
||||||
|
{
|
||||||
|
const auto request = tdbb->getRequest();
|
||||||
|
const auto impure = request->getImpure<Impure>(m_impure);
|
||||||
|
|
||||||
|
impure->irsb_flags = irsb_open;
|
||||||
|
|
||||||
|
const auto rpb = &request->req_rpb[m_stream];
|
||||||
|
rpb->getWindow(tdbb).win_flags = 0;
|
||||||
|
|
||||||
|
rpb->rpb_number.setValue(BOF_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTableStream::close(thread_db* tdbb) const
|
||||||
|
{
|
||||||
|
const auto request = tdbb->getRequest();
|
||||||
|
|
||||||
|
invalidateRecords(request);
|
||||||
|
|
||||||
|
const auto impure = request->getImpure<Impure>(m_impure);
|
||||||
|
|
||||||
|
if (impure->irsb_flags & irsb_open)
|
||||||
|
impure->irsb_flags &= ~irsb_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalTableStream::getRecord(thread_db* tdbb) const
|
||||||
|
{
|
||||||
|
JRD_reschedule(tdbb);
|
||||||
|
|
||||||
|
const auto request = tdbb->getRequest();
|
||||||
|
const auto rpb = &request->req_rpb[m_stream];
|
||||||
|
const auto impure = request->getImpure<Impure>(m_impure);
|
||||||
|
|
||||||
|
if (!(impure->irsb_flags & irsb_open))
|
||||||
|
{
|
||||||
|
rpb->rpb_number.setValid(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpb->rpb_record)
|
||||||
|
rpb->rpb_record = FB_NEW_POOL(*tdbb->getDefaultPool()) Record(*tdbb->getDefaultPool(), m_format);
|
||||||
|
|
||||||
|
rpb->rpb_number.increment();
|
||||||
|
|
||||||
|
if (!m_table->getImpure(tdbb, request)->recordBuffer->fetch(rpb->rpb_number.getValue(), rpb->rpb_record))
|
||||||
|
{
|
||||||
|
rpb->rpb_number.setValid(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalTableStream::refetchRecord(thread_db* tdbb) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalTableStream::lockRecord(thread_db* tdbb) const
|
||||||
|
{
|
||||||
|
status_exception::raise(Arg::Gds(isc_record_lock_not_supp));
|
||||||
|
return false; // compiler silencer
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTableStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const
|
||||||
|
{
|
||||||
|
//// TODO: Use Local Table name/alias.
|
||||||
|
|
||||||
|
if (detailed)
|
||||||
|
plan += printIndent(++level) + "Local Table Full Scan";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!level)
|
||||||
|
plan += "(";
|
||||||
|
|
||||||
|
plan += "Local_Table";
|
||||||
|
plan += " NATURAL";
|
||||||
|
|
||||||
|
if (!level)
|
||||||
|
plan += ")";
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ namespace Jrd
|
|||||||
class jrd_prc;
|
class jrd_prc;
|
||||||
class AggNode;
|
class AggNode;
|
||||||
class BoolExprNode;
|
class BoolExprNode;
|
||||||
|
class DeclareLocalTableNode;
|
||||||
class Sort;
|
class Sort;
|
||||||
class CompilerScratch;
|
class CompilerScratch;
|
||||||
class RecordBuffer;
|
class RecordBuffer;
|
||||||
@ -1145,6 +1146,24 @@ namespace Jrd
|
|||||||
Firebird::Array<const NestValueArray*> m_keys;
|
Firebird::Array<const NestValueArray*> m_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LocalTableStream : public RecordStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LocalTableStream(CompilerScratch* csb, StreamType stream, const DeclareLocalTableNode* table);
|
||||||
|
|
||||||
|
void open(thread_db* tdbb) const override;
|
||||||
|
void close(thread_db* tdbb) const override;
|
||||||
|
|
||||||
|
bool getRecord(thread_db* tdbb) const override;
|
||||||
|
bool refetchRecord(thread_db* tdbb) const override;
|
||||||
|
bool lockRecord(thread_db* tdbb) const override;
|
||||||
|
|
||||||
|
void print(thread_db* tdbb, Firebird::string& plan, bool detailed, unsigned level) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const DeclareLocalTableNode* m_table;
|
||||||
|
};
|
||||||
|
|
||||||
class Union : public RecordStream
|
class Union : public RecordStream
|
||||||
{
|
{
|
||||||
struct Impure : public RecordSource::Impure
|
struct Impure : public RecordSource::Impure
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||||
--
|
--
|
||||||
('2021-05-11 14:10:00', 'JRD', 0, 957)
|
('2021-08-25 07:16:00', 'JRD', 0, 958)
|
||||||
--('2015-03-17 18:33:00', 'QLI', 1, 533)
|
--('2015-03-17 18:33:00', 'QLI', 1, 533)
|
||||||
('2018-03-17 12:00:00', 'GFIX', 3, 136)
|
('2018-03-17 12:00:00', 'GFIX', 3, 136)
|
||||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||||
|
@ -1064,6 +1064,7 @@ Data source : @4', NULL, NULL)
|
|||||||
('tom_key_length', NULL, 'SysFunction.cpp', NULL, 0, 954, NULL, 'Invalid key length @1, need >@2', NULL, NULL);
|
('tom_key_length', NULL, 'SysFunction.cpp', NULL, 0, 954, NULL, 'Invalid key length @1, need >@2', NULL, NULL);
|
||||||
('inf_invalid_args', NULL, NULL, NULL, 0, 955, NULL, 'Invalid information arguments', NULL, NULL);
|
('inf_invalid_args', NULL, NULL, NULL, 0, 955, NULL, 'Invalid information arguments', NULL, NULL);
|
||||||
('sysf_invalid_null_empty', NULL, 'SysFunction.cpp', NULL, 0, 956, NULL, 'Empty or NULL parameter @1 is not accepted', NULL, NULL);
|
('sysf_invalid_null_empty', NULL, 'SysFunction.cpp', NULL, 0, 956, NULL, 'Empty or NULL parameter @1 is not accepted', NULL, NULL);
|
||||||
|
('bad_loctab_num', NULL, NULL, NULL, 0, 957, NULL, 'Undefined local table number @1', NULL, NULL);
|
||||||
-- GFIX
|
-- GFIX
|
||||||
('gfix_db_name', 'ALICE_gfix', 'alice.c', NULL, 3, 1, NULL, 'data base file name (@1) already given', NULL, NULL);
|
('gfix_db_name', 'ALICE_gfix', 'alice.c', NULL, 3, 1, NULL, 'data base file name (@1) already given', NULL, NULL);
|
||||||
('gfix_invalid_sw', 'ALICE_gfix', 'alice.c', NULL, 3, 2, NULL, 'invalid switch @1', NULL, NULL);
|
('gfix_invalid_sw', 'ALICE_gfix', 'alice.c', NULL, 3, 2, NULL, 'invalid switch @1', NULL, NULL);
|
||||||
|
@ -963,6 +963,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
|||||||
(-901, '22', '023', 0, 954, 'tom_key_length', NULL, NULL)
|
(-901, '22', '023', 0, 954, 'tom_key_length', NULL, NULL)
|
||||||
(-901, 'HY', '000', 0, 955, 'inf_invalid_args', NULL, 'WARNING')
|
(-901, 'HY', '000', 0, 955, 'inf_invalid_args', NULL, 'WARNING')
|
||||||
(-901, '22', '023', 0, 956, 'sysf_invalid_null_empty', NULL, NULL)
|
(-901, '22', '023', 0, 956, 'sysf_invalid_null_empty', NULL, NULL)
|
||||||
|
(-901, 'HY', '000', 0, 957, 'bad_loctab_num', NULL, NULL)
|
||||||
-- GFIX
|
-- GFIX
|
||||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||||
|
@ -263,6 +263,7 @@ const int op_subproc_decl = 27;
|
|||||||
const int op_subfunc_decl = 28;
|
const int op_subfunc_decl = 28;
|
||||||
const int op_window_win = 29;
|
const int op_window_win = 29;
|
||||||
const int op_erase = 30; // special due to optional blr_marks after blr_erase
|
const int op_erase = 30; // special due to optional blr_marks after blr_erase
|
||||||
|
const int op_dcl_local_table = 31;
|
||||||
|
|
||||||
static const UCHAR
|
static const UCHAR
|
||||||
// generic print formats
|
// generic print formats
|
||||||
@ -302,7 +303,7 @@ static const UCHAR
|
|||||||
gen_id[] = { op_byte, op_literal, op_line, op_verb, 0},
|
gen_id[] = { op_byte, op_literal, op_line, op_verb, 0},
|
||||||
gen_id2[] = { op_byte, op_literal, op_line, 0},
|
gen_id2[] = { op_byte, op_literal, op_line, 0},
|
||||||
declare[] = { op_word, op_dtype, op_line, 0},
|
declare[] = { op_word, op_dtype, op_line, 0},
|
||||||
variable[] = { op_word, op_line, 0},
|
one_word[] = { op_word, op_line, 0},
|
||||||
indx[] = { op_line, op_verb, op_indent, op_byte, op_line, op_args, 0},
|
indx[] = { op_line, op_verb, op_indent, op_byte, op_line, op_args, 0},
|
||||||
seek[] = { op_line, op_verb, op_verb, 0},
|
seek[] = { op_line, op_verb, op_verb, 0},
|
||||||
join[] = { op_join, op_line, 0},
|
join[] = { op_join, op_line, 0},
|
||||||
@ -332,6 +333,7 @@ static const UCHAR
|
|||||||
user_savepoint[] = { op_byte, op_byte, op_literal, op_line, 0},
|
user_savepoint[] = { op_byte, op_byte, op_literal, op_line, 0},
|
||||||
exec_into[] = { op_word, op_line, op_indent, op_exec_into, 0},
|
exec_into[] = { op_word, op_line, op_indent, op_exec_into, 0},
|
||||||
dcl_cursor[] = { op_word, op_line, op_verb, op_indent, op_word, op_line, op_args, 0},
|
dcl_cursor[] = { op_word, op_line, op_verb, op_indent, op_word, op_line, op_args, 0},
|
||||||
|
dcl_local_table[] = { op_dcl_local_table, 0 },
|
||||||
cursor_stmt[] = { op_cursor_stmt, 0 },
|
cursor_stmt[] = { op_cursor_stmt, 0 },
|
||||||
strlength[] = { op_byte, op_line, op_verb, 0},
|
strlength[] = { op_byte, op_line, op_verb, 0},
|
||||||
trim[] = { op_byte, op_byte_opt_verb, op_verb, 0},
|
trim[] = { op_byte, op_byte_opt_verb, op_verb, 0},
|
||||||
@ -350,7 +352,8 @@ static const UCHAR
|
|||||||
op_line, op_indent, op_byte, op_literal, op_pad, op_line, 0},
|
op_line, op_indent, op_byte, op_literal, op_pad, op_line, 0},
|
||||||
store3[] = { op_line, op_byte, op_line, op_verb, op_verb, op_verb, 0},
|
store3[] = { op_line, op_byte, op_line, op_verb, op_verb, op_verb, 0},
|
||||||
marks[] = { op_byte, op_literal, op_line, op_verb, 0},
|
marks[] = { op_byte, op_literal, op_line, op_verb, 0},
|
||||||
erase[] = { op_erase, 0};
|
erase[] = { op_erase, 0},
|
||||||
|
local_table[] = { op_word, op_byte, op_literal, op_byte, op_line, 0};
|
||||||
|
|
||||||
|
|
||||||
#include "../jrd/blp.h"
|
#include "../jrd/blp.h"
|
||||||
@ -3779,6 +3782,56 @@ static void blr_print_verb(gds_ctl* control, SSHORT level)
|
|||||||
offset = blr_print_line(control, offset);
|
offset = blr_print_line(control, offset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case op_dcl_local_table:
|
||||||
|
{
|
||||||
|
offset = blr_print_line(control, offset);
|
||||||
|
blr_indent(control, level);
|
||||||
|
blr_print_word(control);
|
||||||
|
offset = blr_print_line(control, offset);
|
||||||
|
|
||||||
|
static const char* subCodes[] =
|
||||||
|
{
|
||||||
|
nullptr,
|
||||||
|
"format"
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((blr_operator = control->ctl_blr_reader.getByte()) != blr_end)
|
||||||
|
{
|
||||||
|
blr_indent(control, level);
|
||||||
|
|
||||||
|
if (blr_operator == 0 || blr_operator >= FB_NELEM(subCodes))
|
||||||
|
blr_error(control, "*** invalid blr_dcl_local_table sub code ***");
|
||||||
|
|
||||||
|
blr_format(control, "blr_dcl_local_table_%s, ", subCodes[blr_operator]);
|
||||||
|
|
||||||
|
switch (blr_operator)
|
||||||
|
{
|
||||||
|
case blr_dcl_local_table_format:
|
||||||
|
n = blr_print_word(control);
|
||||||
|
offset = blr_print_line(control, offset);
|
||||||
|
++level;
|
||||||
|
|
||||||
|
while (--n >= 0)
|
||||||
|
{
|
||||||
|
blr_indent(control, level);
|
||||||
|
blr_print_dtype(control);
|
||||||
|
offset = blr_print_line(control, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
--level;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fb_assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print blr_end
|
||||||
|
control->ctl_blr_reader.seekBackward(1);
|
||||||
|
blr_print_verb(control, level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user