|
From: <asf...@us...> - 2014-05-19 19:06:51
|
Revision: 59606
http://sourceforge.net/p/firebird/code/59606
Author: asfernandes
Date: 2014-05-19 19:06:47 +0000 (Mon, 19 May 2014)
Log Message:
-----------
Feature CORE-4403 - Allow referencing cursors as record variables in PSQL.
Improvement CORE-4434 - Extend the use of colon prefix for read/assignment OLD/NEW fields and assignment to variables.
Modified Paths:
--------------
firebird/trunk/lang_helpers/gds_codes.ftn
firebird/trunk/lang_helpers/gds_codes.pas
firebird/trunk/src/dsql/BlrDebugWriter.cpp
firebird/trunk/src/dsql/BlrDebugWriter.h
firebird/trunk/src/dsql/DdlNodes.epp
firebird/trunk/src/dsql/ExprNodes.cpp
firebird/trunk/src/dsql/ExprNodes.h
firebird/trunk/src/dsql/Nodes.h
firebird/trunk/src/dsql/StmtNodes.cpp
firebird/trunk/src/dsql/dsql.h
firebird/trunk/src/dsql/parse.y
firebird/trunk/src/dsql/pass1.cpp
firebird/trunk/src/dsql/pass1_proto.h
firebird/trunk/src/include/consts_pub.h
firebird/trunk/src/include/gen/codetext.h
firebird/trunk/src/include/gen/iberror.h
firebird/trunk/src/include/gen/msgs.h
firebird/trunk/src/include/gen/sql_code.h
firebird/trunk/src/include/gen/sql_state.h
firebird/trunk/src/jrd/DebugInterface.cpp
firebird/trunk/src/jrd/DebugInterface.h
firebird/trunk/src/jrd/RecordSourceNodes.cpp
firebird/trunk/src/jrd/exe.h
firebird/trunk/src/jrd/filters.cpp
firebird/trunk/src/jrd/recsrc/Cursor.h
firebird/trunk/src/jrd/vio.cpp
firebird/trunk/src/msgs/facilities2.sql
firebird/trunk/src/msgs/messages2.sql
firebird/trunk/src/msgs/system_errors2.sql
Modified: firebird/trunk/lang_helpers/gds_codes.ftn
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.ftn 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/lang_helpers/gds_codes.ftn 2014-05-19 19:06:47 UTC (rev 59606)
@@ -1594,6 +1594,8 @@
PARAMETER (GDS__miss_trusted_role = 335545090)
INTEGER*4 GDS__set_invalid_role
PARAMETER (GDS__set_invalid_role = 335545091)
+ INTEGER*4 GDS__cursor_not_positioned
+ PARAMETER (GDS__cursor_not_positioned = 335545092)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw
Modified: firebird/trunk/lang_helpers/gds_codes.pas
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.pas 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/lang_helpers/gds_codes.pas 2014-05-19 19:06:47 UTC (rev 59606)
@@ -804,6 +804,7 @@
gds_map_notable = 335545089;
gds_miss_trusted_role = 335545090;
gds_set_invalid_role = 335545091;
+ gds_cursor_not_positioned = 335545092;
gds_gfix_db_name = 335740929;
gds_gfix_invalid_sw = 335740930;
gds_gfix_incmp_sw = 335740932;
Modified: firebird/trunk/src/dsql/BlrDebugWriter.cpp
===================================================================
--- firebird/trunk/src/dsql/BlrDebugWriter.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/BlrDebugWriter.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -106,6 +106,19 @@
debugData.add(reinterpret_cast<const UCHAR*>(name), len);
}
+void BlrDebugWriter::putDebugCursor(USHORT number, const MetaName& name)
+{
+ debugData.add(fb_dbg_map_curname);
+
+ debugData.add(number);
+ debugData.add(number >> 8);
+
+ USHORT len = MIN(name.length(), MAX_UCHAR);
+ debugData.add(len);
+
+ debugData.add(reinterpret_cast<const UCHAR*>(name.c_str()), len);
+}
+
void BlrDebugWriter::putDebugSubFunction(DeclareSubFuncNode* subFuncNode)
{
debugData.add(fb_dbg_subfunc);
Modified: firebird/trunk/src/dsql/BlrDebugWriter.h
===================================================================
--- firebird/trunk/src/dsql/BlrDebugWriter.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/BlrDebugWriter.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -47,6 +47,7 @@
void putDebugSrcInfo(ULONG, ULONG);
void putDebugVariable(USHORT, const Firebird::MetaName&);
void putDebugArgument(UCHAR, USHORT, const TEXT*);
+ void putDebugCursor(USHORT, const Firebird::MetaName&);
void putDebugSubFunction(DeclareSubFuncNode* subFuncNode);
void putDebugSubProcedure(DeclareSubProcNode* subProcNode);
Modified: firebird/trunk/src/dsql/DdlNodes.epp
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.epp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/DdlNodes.epp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -3173,7 +3173,7 @@
{
relationNode->alias = OLD_CONTEXT_NAME;
dsql_ctx* oldContext = PASS1_make_context(dsqlScratch, relationNode);
- oldContext->ctx_flags |= CTX_system;
+ oldContext->ctx_flags |= CTX_system | CTX_cursor;
}
else
dsqlScratch->contextNumber++;
@@ -3182,7 +3182,7 @@
{
relationNode->alias = NEW_CONTEXT_NAME;
dsql_ctx* newContext = PASS1_make_context(dsqlScratch, relationNode);
- newContext->ctx_flags |= CTX_system;
+ newContext->ctx_flags |= CTX_system | CTX_cursor;
}
else
dsqlScratch->contextNumber++;
Modified: firebird/trunk/src/dsql/ExprNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/ExprNodes.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/ExprNodes.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -33,6 +33,7 @@
#include "../jrd/SysFunction.h"
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/Optimizer.h"
+#include "../jrd/recsrc/Cursor.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/cvt_proto.h"
@@ -3990,6 +3991,8 @@
*i = copier.remap[*i];
}
+ fb_assert(!cursorNumber.specified);
+
return node;
}
@@ -4032,11 +4035,33 @@
getDesc(tdbb, csb, &desc);
impureOffset = CMP_impure(csb, sizeof(impure_value));
+ // As all streams belongs to the same cursor, we use only the first.
+ cursorNumber = csb->csb_rpt[internalStreamList[0]].csb_cursor_number;
+
return this;
}
dsc* DerivedExprNode::execute(thread_db* tdbb, jrd_req* request) const
{
+ if (cursorNumber.specified)
+ {
+ const Cursor* const cursor = request->req_cursors[cursorNumber.value];
+ const Cursor::Impure* const cursorImpure = request->getImpure<Cursor::Impure>(cursor->m_impure);
+
+ if (!cursorImpure->irsb_active)
+ {
+ // error: invalid cursor state
+ status_exception::raise(Arg::Gds(isc_cursor_not_open));
+ }
+
+ if (cursorImpure->irsb_state != Cursor::POSITIONED)
+ {
+ status_exception::raise(
+ Arg::Gds(isc_cursor_not_positioned) <<
+ Arg::Str(cursor->name));
+ }
+ }
+
dsc* value = NULL;
for (const StreamType* i = internalStreamList.begin(); i != internalStreamList.end(); ++i)
@@ -4492,7 +4517,8 @@
fieldStream(0),
format(NULL),
fieldId(0),
- byId(false)
+ byId(false),
+ dsqlCursorField(false)
{
}
@@ -4506,7 +4532,8 @@
fieldStream(stream),
format(NULL),
fieldId(id),
- byId(aById)
+ byId(aById),
+ dsqlCursorField(false)
{
}
@@ -4685,26 +4712,16 @@
return this;
}
- if (dsqlScratch->isPsql())
+ if (dsqlScratch->isPsql() && !dsqlQualifier.hasData())
{
- if (dsqlQualifier.hasData())
- {
- if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_TRIGGER) // triggers only
- return internalDsqlPass(dsqlScratch, NULL);
-
- PASS1_field_unknown(NULL, NULL, this);
- }
-
-
VariableNode* node = FB_NEW(getPool()) VariableNode(getPool());
node->line = line;
node->column = column;
node->dsqlName = dsqlName;
-
return node->dsqlPass(dsqlScratch);
}
-
- return internalDsqlPass(dsqlScratch, NULL);
+ else
+ return internalDsqlPass(dsqlScratch, NULL);
}
// Resolve a field name to an available context.
@@ -4781,13 +4798,14 @@
for (DsqlContextStack::iterator stack(*dsqlScratch->context); stack.hasData(); ++stack)
{
- // resolveContext() checks the type of the
- // given context, so the cast to dsql_ctx* is safe.
-
dsql_ctx* context = stack.object();
- if (context->ctx_scope_level != currentScopeLevel - 1)
+ if (context->ctx_scope_level != currentScopeLevel - 1 ||
+ ((context->ctx_flags & CTX_cursor) && dsqlQualifier.isEmpty()) ||
+ (!(context->ctx_flags & CTX_cursor) && dsqlCursorField))
+ {
continue;
+ }
dsql_fld* field = resolveContext(dsqlScratch, dsqlQualifier, context, resolveByAlias);
@@ -5322,6 +5340,7 @@
stream = copier.remap[stream];
}
+ fb_assert(!cursorNumber.specified);
return PAR_gen_field(tdbb, stream, fldId, byId);
}
@@ -5540,6 +5559,7 @@
format = CMP_format(tdbb, csb, fieldStream);
impureOffset = CMP_impure(csb, sizeof(impure_value_ex));
+ cursorNumber = csb->csb_rpt[fieldStream].csb_cursor_number;
return this;
}
@@ -5548,6 +5568,25 @@
{
impure_value* const impure = request->getImpure<impure_value>(impureOffset);
+ if (cursorNumber.specified)
+ {
+ const Cursor* const cursor = request->req_cursors[cursorNumber.value];
+ const Cursor::Impure* const cursorImpure = request->getImpure<Cursor::Impure>(cursor->m_impure);
+
+ if (!cursorImpure->irsb_active)
+ {
+ // error: invalid cursor state
+ status_exception::raise(Arg::Gds(isc_cursor_not_open));
+ }
+
+ if (cursorImpure->irsb_state != Cursor::POSITIONED)
+ {
+ status_exception::raise(
+ Arg::Gds(isc_cursor_not_positioned) <<
+ Arg::Str(cursor->name));
+ }
+ }
+
record_param& rpb = request->req_rpb[fieldStream];
Record* record = rpb.rpb_record;
jrd_rel* relation = rpb.rpb_relation;
Modified: firebird/trunk/src/dsql/ExprNodes.h
===================================================================
--- firebird/trunk/src/dsql/ExprNodes.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/ExprNodes.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -519,6 +519,7 @@
public:
NestConst<ValueExprNode> arg;
Firebird::Array<StreamType> internalStreamList;
+ Nullable<USHORT> cursorNumber;
};
@@ -647,6 +648,8 @@
const Format* format;
const USHORT fieldId;
const bool byId;
+ bool dsqlCursorField;
+ Nullable<USHORT> cursorNumber;
};
Modified: firebird/trunk/src/dsql/Nodes.h
===================================================================
--- firebird/trunk/src/dsql/Nodes.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/Nodes.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -970,6 +970,7 @@
static const unsigned DFLAG_DERIVED = 0x08;
static const unsigned DFLAG_DT_IGNORE_COLUMN_CHECK = 0x10;
static const unsigned DFLAG_DT_CTE_USED = 0x20;
+ static const unsigned DFLAG_CURSOR = 0x40;
RecordSourceNode(Type aType, MemoryPool& pool)
: ExprNode(aType, pool, KIND_REC_SOURCE),
Modified: firebird/trunk/src/dsql/StmtNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/StmtNodes.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/StmtNodes.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -277,6 +277,13 @@
node->asgnFrom = doDsqlPass(dsqlScratch, asgnFrom);
node->asgnTo = doDsqlPass(dsqlScratch, asgnTo);
+ DerivedFieldNode* fieldNode = node->asgnTo->as<DerivedFieldNode>();
+ if (fieldNode && fieldNode->context &&
+ (fieldNode->context->ctx_flags & (CTX_system | CTX_cursor)) == CTX_cursor)
+ {
+ ERR_post(Arg::Gds(isc_read_only_field));
+ }
+
// Try to force asgnFrom to be same type as asgnTo eg: ? = FIELD case
PASS1_set_parameter_type(dsqlScratch, node->asgnFrom, node->asgnTo, false);
@@ -343,41 +350,44 @@
doPass1(tdbb, csb, missing.getAddress());
// ASF: No idea why we do not call pass1 for missing2.
- // Perform any post-processing here.
+ return this;
+}
- sub = asgnTo;
+AssignmentNode* AssignmentNode::pass2(thread_db* tdbb, CompilerScratch* csb)
+{
+ ExprNode::doPass2(tdbb, csb, asgnFrom.getAddress());
+ ExprNode::doPass2(tdbb, csb, asgnTo.getAddress());
+ ExprNode::doPass2(tdbb, csb, missing.getAddress());
+ ExprNode::doPass2(tdbb, csb, missing2.getAddress());
- if ((fieldNode = sub->as<FieldNode>()))
+ FieldNode* fieldNode;
+
+ if ((fieldNode = asgnTo->as<FieldNode>()))
{
- stream = fieldNode->fieldStream;
- tail = &csb->csb_rpt[stream];
+ CompilerScratch::csb_repeat* tail = &csb->csb_rpt[fieldNode->fieldStream];
// Assignments to the OLD context are prohibited for all trigger types.
- if ((tail->csb_flags & csb_trigger) && stream == OLD_CONTEXT_VALUE)
+ if ((tail->csb_flags & csb_trigger) && fieldNode->fieldStream == OLD_CONTEXT_VALUE)
ERR_post(Arg::Gds(isc_read_only_field));
// Assignments to the NEW context are prohibited for post-action triggers.
- if ((tail->csb_flags & csb_trigger) && stream == NEW_CONTEXT_VALUE &&
+ if ((tail->csb_flags & csb_trigger) && fieldNode->fieldStream == NEW_CONTEXT_VALUE &&
(csb->csb_g_flags & csb_post_trigger))
{
ERR_post(Arg::Gds(isc_read_only_field));
}
+
+ // Assignment to cursor fields are always prohibited.
+ // But we cannot detect FOR cursors here. They are treated in dsqlPass.
+ if (fieldNode->cursorNumber.specified)
+ ERR_post(Arg::Gds(isc_read_only_field));
}
- else if (!(sub->is<ParameterNode>() || sub->is<VariableNode>() || sub->is<NullNode>()))
+ else if (!(asgnTo->is<ParameterNode>() || asgnTo->is<VariableNode>() || asgnTo->is<NullNode>()))
ERR_post(Arg::Gds(isc_read_only_field));
return this;
}
-AssignmentNode* AssignmentNode::pass2(thread_db* tdbb, CompilerScratch* csb)
-{
- ExprNode::doPass2(tdbb, csb, asgnFrom.getAddress());
- ExprNode::doPass2(tdbb, csb, asgnTo.getAddress());
- ExprNode::doPass2(tdbb, csb, missing.getAddress());
- ExprNode::doPass2(tdbb, csb, missing2.getAddress());
- return this;
-}
-
const StmtNode* AssignmentNode::execute(thread_db* tdbb, jrd_req* request, ExeState* /*exeState*/) const
{
if (request->req_operation == jrd_req::req_evaluate)
@@ -1010,6 +1020,8 @@
// Assignment.
+ dsqlScratch->appendUChar(blr_begin);
+
if (dsqlIntoStmt)
{
ValueListNode* list = cursor->rse->dsqlSelectList;
@@ -1020,8 +1032,6 @@
Arg::Gds(isc_dsql_count_mismatch));
}
- dsqlScratch->appendUChar(blr_begin);
-
NestConst<ValueExprNode>* ptr = list->items.begin();
NestConst<ValueExprNode>* end = list->items.end();
NestConst<ValueExprNode>* ptr_to = dsqlIntoStmt->items.begin();
@@ -1032,9 +1042,9 @@
GEN_expr(dsqlScratch, *ptr++);
GEN_expr(dsqlScratch, *ptr_to++);
}
+ }
- dsqlScratch->appendUChar(blr_end);
- }
+ dsqlScratch->appendUChar(blr_end);
}
CursorStmtNode* CursorStmtNode::pass1(thread_db* tdbb, CompilerScratch* csb)
@@ -1177,18 +1187,19 @@
// Make sure the cursor doesn't exist.
PASS1_cursor_name(dsqlScratch, dsqlName, CUR_TYPE_ALL, false);
- // Temporarily hide unnecessary contexts and process our RSE.
- DsqlContextStack* const baseContext = dsqlScratch->context;
- DsqlContextStack temp;
- dsqlScratch->context = &temp;
- rse = PASS1_rse(dsqlScratch, dsqlSelect->dsqlExpr, dsqlSelect->dsqlWithLock);
- dsqlScratch->context->clear();
- dsqlScratch->context = baseContext;
+ SelectExprNode* dt = FB_NEW(getPool()) SelectExprNode(getPool());
+ dt->dsqlFlags = RecordSourceNode::DFLAG_DERIVED | RecordSourceNode::DFLAG_CURSOR;
+ dt->querySpec = dsqlSelect->dsqlExpr;
+ dt->alias = dsqlName.c_str();
+ rse = PASS1_derived_table(dsqlScratch, dt, NULL, dsqlSelect->dsqlWithLock);
+
// Assign number and store in the dsqlScratch stack.
cursorNumber = dsqlScratch->cursorNumber++;
dsqlScratch->cursors.push(this);
+ dsqlScratch->putDebugCursor(cursorNumber, dsqlName);
+
return this;
}
@@ -1239,12 +1250,19 @@
cursor = FB_NEW(*tdbb->getDefaultPool()) Cursor(csb, rsb, rse->rse_invariants,
(rse->flags & RseNode::FLAG_SCROLLABLE));
+ csb->csb_dbg_info->curIndexToName.get(cursorNumber, cursor->name);
if (cursorNumber >= csb->csb_cursors.getCount())
csb->csb_cursors.grow(cursorNumber + 1);
csb->csb_cursors[cursorNumber] = cursor;
+ StreamList cursorStreams;
+ cursor->getAccessPath()->findUsedStreams(cursorStreams);
+
+ for (StreamList::const_iterator i = cursorStreams.begin(); i != cursorStreams.end(); ++i)
+ csb->csb_rpt[*i].csb_cursor_number = cursorNumber;
+
return this;
}
@@ -4315,16 +4333,30 @@
ForNode* node = FB_NEW(getPool()) ForNode(getPool());
node->dsqlCursor = dsqlCursor;
- node->dsqlSelect = dsqlSelect->dsqlPass(dsqlScratch);
+ const DsqlContextStack::iterator base(*dsqlScratch->context);
+
if (dsqlCursor)
{
fb_assert(dsqlCursor->dsqlCursorType != DeclareCursorNode::CUR_TYPE_NONE);
PASS1_cursor_name(dsqlScratch, dsqlCursor->dsqlName, DeclareCursorNode::CUR_TYPE_ALL, false);
- dsqlCursor->rse = node->dsqlSelect->dsqlRse;
+
+ SelectExprNode* dt = FB_NEW(getPool()) SelectExprNode(getPool());
+ dt->dsqlFlags = RecordSourceNode::DFLAG_DERIVED | RecordSourceNode::DFLAG_CURSOR;
+ dt->querySpec = dsqlSelect->dsqlExpr;
+ dt->alias = dsqlCursor->dsqlName.c_str();
+
+ node->rse = PASS1_derived_table(dsqlScratch, dt, NULL, dsqlSelect->dsqlWithLock);
+
+ dsqlCursor->rse = node->rse;
dsqlCursor->cursorNumber = dsqlScratch->cursorNumber++;
dsqlScratch->cursors.push(dsqlCursor);
+
+ // ASF: We cannot write this cursor name in debug info, as dsqlScratch->cursorNumber is
+ // decremented below. But for now we don't need it.
}
+ else
+ node->rse = dsqlSelect->dsqlPass(dsqlScratch)->dsqlRse;
node->dsqlInto = dsqlPassArray(dsqlScratch, dsqlInto);
@@ -4339,6 +4371,8 @@
dsqlScratch->labels.pop();
}
+ dsqlScratch->context->clear(base);
+
if (dsqlCursor)
{
dsqlScratch->cursorNumber--;
@@ -4370,12 +4404,12 @@
if (!statement || dsqlForceSingular)
dsqlScratch->appendUChar(blr_singular);
- GEN_rse(dsqlScratch, dsqlSelect->dsqlRse);
+ GEN_rse(dsqlScratch, rse);
dsqlScratch->appendUChar(blr_begin);
// Build body of FOR loop
- ValueListNode* list = dsqlSelect->dsqlRse->dsqlSelectList;
+ ValueListNode* list = rse->dsqlSelectList;
if (dsqlInto)
{
@@ -4425,6 +4459,9 @@
cursor = FB_NEW(*tdbb->getDefaultPool()) Cursor(csb, rsb, rse->rse_invariants,
(rse->flags & RseNode::FLAG_SCROLLABLE));
+ // ASF: We cannot define the name of the cursor here, but this is not a problem,
+ // as implicit cursors are always positioned in a valid record, and the name is
+ // only used to raise isc_cursor_not_positioned.
impureOffset = CMP_impure(csb, sizeof(SLONG));
@@ -4870,7 +4907,7 @@
forNode->dsqlForceSingular = true;
// Get the already processed relations.
- RseNode* processedRse = forNode->dsqlSelect->dsqlRse->dsqlStreams->items[0]->as<RseNode>();
+ RseNode* processedRse = forNode->rse->dsqlStreams->items[0]->as<RseNode>();
source = processedRse->dsqlStreams->items[0];
target = processedRse->dsqlStreams->items[1]->as<RelationSourceNode>();
Modified: firebird/trunk/src/dsql/dsql.h
===================================================================
--- firebird/trunk/src/dsql/dsql.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/dsql.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -778,6 +778,7 @@
const USHORT CTX_recursive = 0x10; // Context has secondary number (ctx_recursive) generated for recursive UNION
const USHORT CTX_view_with_check_store = 0x20; // Context of WITH CHECK OPTION view's store trigger
const USHORT CTX_view_with_check_modify = 0x40; // Context of WITH CHECK OPTION view's modify trigger
+const USHORT CTX_cursor = 0x80; // Context is a cursor
//! Aggregate/union map block to map virtual fields to their base
//! TMN: NOTE! This datatype should definitely be renamed!
Modified: firebird/trunk/src/dsql/parse.y
===================================================================
--- firebird/trunk/src/dsql/parse.y 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/parse.y 2014-05-19 19:06:47 UTC (rev 59606)
@@ -690,6 +690,7 @@
Jrd::MergeNode::NotMatched* mergeNotMatchedClause;
Jrd::MergeNode::Matched* mergeMatchedClause;
Jrd::SelectNode* selectNode;
+ Jrd::ForNode* forNode;
Jrd::SetTransactionNode* setTransactionNode;
Jrd::SetTransactionNode::RestrictionOption* setTransactionRestrictionClause;
Jrd::DeclareSubProcNode* declareSubProcNode;
@@ -2687,7 +2688,7 @@
%type <stmtNode> simple_proc_statement
simple_proc_statement
- : assignment
+ : assignment_statement
| insert { $$ = $1; }
| merge { $$ = $1; }
| update
@@ -2709,12 +2710,18 @@
| RETURN value { $$ = newNode<ReturnNode>($2); }
;
+%type <stmtNode> assignment_statement
+assignment_statement
+ : assignment
+ | ':' assignment { $$ = $2; }
+ ;
+
%type <stmtNode> complex_proc_statement
complex_proc_statement
: in_autonomous_transaction
| if_then_else
| while
- | for_select
+ | for_select { $$ = $1; }
| for_exec_into { $$ = $1; }
;
@@ -2743,20 +2750,48 @@
: EXCEPTION { $$ = newNode<ExceptionNode>(); }
;
-%type <stmtNode> for_select
+%type <forNode> for_select
for_select
- : label_def_opt FOR select INTO variable_list cursor_def DO proc_block
+ : label_def_opt FOR select
+ {
+ ForNode* node = newNode<ForNode>();
+ node->dsqlLabelName = $1;
+ node->dsqlSelect = $3;
+ $$ = node;
+ }
+ for_select_into_cursor($4) DO proc_block
+ {
+ ForNode* node = $4;
+ node->statement = $7;
+ $$ = node;
+ }
+ ;
+
+%type for_select_into_cursor(<forNode>)
+for_select_into_cursor($forNode)
+ : into_variable_list cursor_def_opt
{
- ForNode* node = newNode<ForNode>();
- node->dsqlLabelName = $1;
- node->dsqlSelect = $3;
- node->dsqlInto = $5;
- node->dsqlCursor = $6;
- node->statement = $8;
- $$ = node;
+ $forNode->dsqlInto = $1;
+ $forNode->dsqlCursor = $2;
}
+ | into_variable_list_opt cursor_def
+ {
+ $forNode->dsqlInto = $1;
+ $forNode->dsqlCursor = $2;
+ }
;
+%type <valueListNode> into_variable_list_opt
+into_variable_list_opt
+ : /* nothing */ { $$ = NULL; }
+ | into_variable_list
+ ;
+
+%type <valueListNode> into_variable_list
+into_variable_list
+ : INTO variable_list { $$ = $2; }
+ ;
+
%type <execStatementNode> exec_sql
exec_sql
: EXECUTE STATEMENT
@@ -2982,11 +3017,15 @@
| symbol_label_name
;
+%type <declCursorNode> cursor_def_opt
+cursor_def_opt
+ : /* nothing */ { $$ = NULL; }
+ | cursor_def
+ ;
+
%type <declCursorNode> cursor_def
cursor_def
- : // nothing
- { $$ = NULL; }
- | AS CURSOR symbol_cursor_name
+ : AS CURSOR symbol_cursor_name
{ $$ = newNode<DeclareCursorNode>(*$3, DeclareCursorNode::CUR_TYPE_FOR); }
;
@@ -3072,15 +3111,15 @@
fetch_cursor
: FETCH
{ $<cursorStmtNode>$ = newNode<CursorStmtNode>(blr_cursor_fetch_scroll); }
- fetch_scroll($<cursorStmtNode>2) FROM symbol_cursor_name INTO variable_list
+ fetch_scroll($<cursorStmtNode>2) FROM symbol_cursor_name into_variable_list_opt
{
CursorStmtNode* cursorStmt = $<cursorStmtNode>2;
cursorStmt->dsqlName = *$5;
- cursorStmt->dsqlIntoStmt = $7;
+ cursorStmt->dsqlIntoStmt = $6;
$$ = cursorStmt;
}
- | FETCH symbol_cursor_name INTO variable_list
- { $$ = newNode<CursorStmtNode>(blr_cursor_fetch, *$2, $4); }
+ | FETCH symbol_cursor_name into_variable_list_opt
+ { $$ = newNode<CursorStmtNode>(blr_cursor_fetch, *$2, $3); }
;
%type fetch_scroll(<cursorStmtNode>)
@@ -5624,6 +5663,14 @@
fieldNode->dsqlName = *$3;
$$ = fieldNode;
}
+ | ':' symbol_table_alias_name '.' symbol_column_name
+ {
+ FieldNode* fieldNode = newNode<FieldNode>();
+ fieldNode->dsqlQualifier = *$2;
+ fieldNode->dsqlName = *$4;
+ fieldNode->dsqlCursorField = true;
+ $$ = fieldNode;
+ }
;
%type <fieldNode> simple_column_name
Modified: firebird/trunk/src/dsql/pass1.cpp
===================================================================
--- firebird/trunk/src/dsql/pass1.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/pass1.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -427,7 +427,12 @@
context->ctx_procedure = procedure;
if (selNode)
+ {
context->ctx_context = USHORT(MAX_UCHAR) + 1 + dsqlScratch->derivedContextNumber++;
+
+ if (selNode->dsqlFlags & RecordSourceNode::DFLAG_CURSOR)
+ context->ctx_flags |= CTX_cursor;
+ }
else
context->ctx_context = dsqlScratch->contextNumber++;
@@ -951,7 +956,7 @@
// Process derived table which is part of a from clause.
RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* input,
- const char* cte_alias)
+ const char* cte_alias, bool updateLock)
{
DEV_BLKCHK(dsqlScratch, dsql_type_req);
@@ -1051,7 +1056,7 @@
rse = pass1_union(dsqlScratch, unionExpr, NULL, NULL, false, 0);
}
else
- rse = PASS1_rse(dsqlScratch, input, false);
+ rse = PASS1_rse(dsqlScratch, input, updateLock);
// Finish off by cleaning up contexts and put them into derivedContext
// so create view (ddl) can deal with it.
@@ -1213,7 +1218,7 @@
const string* const* saveCteAlias = dsqlScratch->currCteAlias;
dsqlScratch->resetCTEAlias(alias);
- rse = PASS1_rse(dsqlScratch, input, false);
+ rse = PASS1_rse(dsqlScratch, input, updateLock);
if (saveCteAlias)
dsqlScratch->resetCTEAlias(**saveCteAlias);
Modified: firebird/trunk/src/dsql/pass1_proto.h
===================================================================
--- firebird/trunk/src/dsql/pass1_proto.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/dsql/pass1_proto.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -41,7 +41,7 @@
void PASS1_check_unique_fields_names(Jrd::StrArray& names, const Jrd::CompoundStmtNode* fields);
Jrd::BoolExprNode* PASS1_compose(Jrd::BoolExprNode*, Jrd::BoolExprNode*, UCHAR);
Jrd::DeclareCursorNode* PASS1_cursor_name(Jrd::DsqlCompilerScratch*, const Firebird::MetaName&, USHORT, bool);
-Jrd::RseNode* PASS1_derived_table(Jrd::DsqlCompilerScratch*, Jrd::SelectExprNode*, const char*);
+Jrd::RseNode* PASS1_derived_table(Jrd::DsqlCompilerScratch*, Jrd::SelectExprNode*, const char*, bool);
void PASS1_expand_select_node(Jrd::DsqlCompilerScratch*, Jrd::ExprNode*, Jrd::ValueListNode*, bool);
void PASS1_field_unknown(const TEXT*, const TEXT*, const Jrd::ExprNode*);
void PASS1_limit(Jrd::DsqlCompilerScratch*, NestConst<Jrd::ValueExprNode>,
Modified: firebird/trunk/src/include/consts_pub.h
===================================================================
--- firebird/trunk/src/include/consts_pub.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/include/consts_pub.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -673,6 +673,7 @@
#define fb_dbg_map_argument 4
#define fb_dbg_subproc 5
#define fb_dbg_subfunc 6
+#define fb_dbg_map_curname 7
// sub code for fb_dbg_map_argument
#define fb_dbg_arg_input 0
Modified: firebird/trunk/src/include/gen/codetext.h
===================================================================
--- firebird/trunk/src/include/gen/codetext.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/include/gen/codetext.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -793,6 +793,7 @@
{"map_notable", 335545089},
{"miss_trusted_role", 335545090},
{"set_invalid_role", 335545091},
+ {"cursor_not_positioned", 335545092},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},
Modified: firebird/trunk/src/include/gen/iberror.h
===================================================================
--- firebird/trunk/src/include/gen/iberror.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/include/gen/iberror.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -827,6 +827,7 @@
const ISC_STATUS isc_map_notable = 335545089L;
const ISC_STATUS isc_miss_trusted_role = 335545090L;
const ISC_STATUS isc_set_invalid_role = 335545091L;
+const ISC_STATUS isc_cursor_not_positioned = 335545092L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@@ -1284,7 +1285,7 @@
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
-const ISC_STATUS isc_err_max = 1228;
+const ISC_STATUS isc_err_max = 1229;
#else /* c definitions */
@@ -2081,6 +2082,7 @@
#define isc_map_notable 335545089L
#define isc_miss_trusted_role 335545090L
#define isc_set_invalid_role 335545091L
+#define isc_cursor_not_positioned 335545092L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@@ -2538,7 +2540,7 @@
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
-#define isc_err_max 1228
+#define isc_err_max 1229
#endif
Modified: firebird/trunk/src/include/gen/msgs.h
===================================================================
--- firebird/trunk/src/include/gen/msgs.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/include/gen/msgs.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -796,6 +796,7 @@
{335545089, "Global mapping is not available when table RDB$MAP is not present in database @1"}, /* map_notable */
{335545090, "Your attachment has no trusted role"}, /* miss_trusted_role */
{335545091, "Role @1 is invalid or unavailable"}, /* set_invalid_role */
+ {335545092, "Cursor @1 is not positioned in a valid record"}, /* cursor_not_positioned */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
Modified: firebird/trunk/src/include/gen/sql_code.h
===================================================================
--- firebird/trunk/src/include/gen/sql_code.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/include/gen/sql_code.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -792,6 +792,7 @@
{335545089, -901}, /* 769 map_notable */
{335545090, -901}, /* 770 miss_trusted_role */
{335545091, -901}, /* 771 set_invalid_role */
+ {335545092, -596}, /* 772 cursor_not_positioned */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */
Modified: firebird/trunk/src/include/gen/sql_state.h
===================================================================
--- firebird/trunk/src/include/gen/sql_state.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/include/gen/sql_state.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -792,6 +792,7 @@
{335545089, "0A000"}, // 769 map_notable
{335545090, "0P000"}, // 770 miss_trusted_role
{335545091, "0P000"}, // 771 set_invalid_role
+ {335545092, "HY109"}, // 772 cursor_not_positioned
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw
Modified: firebird/trunk/src/jrd/DebugInterface.cpp
===================================================================
--- firebird/trunk/src/jrd/DebugInterface.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/DebugInterface.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -111,6 +111,7 @@
break;
case fb_dbg_map_varname:
+ case fb_dbg_map_curname:
{
if (data + 3 > end)
{
@@ -118,11 +119,11 @@
break;
}
- // variable number
+ // variable/cursor number
USHORT index = *data++;
index |= *data++ << 8;
- // variable name string length
+ // variable/cursor name string length
USHORT length = *data++;
if (data + length > end)
@@ -131,9 +132,12 @@
break;
}
- dbgInfo.varIndexToName.put(index, MetaName((const TEXT*) data, length));
+ if (code == fb_dbg_map_varname)
+ dbgInfo.varIndexToName.put(index, MetaName((const TEXT*) data, length));
+ else
+ dbgInfo.curIndexToName.put(index, MetaName((const TEXT*) data, length));
- // variable name string
+ // variable/cursor name string
data += length;
}
break;
Modified: firebird/trunk/src/jrd/DebugInterface.h
===================================================================
--- firebird/trunk/src/jrd/DebugInterface.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/DebugInterface.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -91,6 +91,7 @@
blrToSrc(p),
varIndexToName(p),
argInfoToName(p),
+ curIndexToName(p),
subFuncs(p),
subProcs(p)
{
@@ -106,6 +107,7 @@
blrToSrc.clear();
varIndexToName.clear();
argInfoToName.clear();
+ curIndexToName.clear();
{ // scope
GenericMap<Pair<Left<MetaName, DbgInfo*> > >::Accessor accessor(&subFuncs);
@@ -129,6 +131,7 @@
MapBlrToSrc blrToSrc; // mapping between blr offsets and source text position
MapVarIndexToName varIndexToName; // mapping between variable index and name
MapArgumentInfoToName argInfoToName; // mapping between argument info (type, index) and name
+ MapVarIndexToName curIndexToName; // mapping between cursor index and name
GenericMap<Pair<Left<MetaName, DbgInfo*> > > subFuncs; // sub functions
GenericMap<Pair<Left<MetaName, DbgInfo*> > > subProcs; // sub procedures
};
Modified: firebird/trunk/src/jrd/RecordSourceNodes.cpp
===================================================================
--- firebird/trunk/src/jrd/RecordSourceNodes.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/RecordSourceNodes.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -3077,7 +3077,7 @@
RseNode* SelectExprNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
fb_assert(dsqlFlags & DFLAG_DERIVED);
- return PASS1_derived_table(dsqlScratch, this, NULL);
+ return PASS1_derived_table(dsqlScratch, this, NULL, false);
}
@@ -3148,7 +3148,7 @@
dsqlScratch->currCtes.push(cte);
RseNode* derivedNode = PASS1_derived_table(dsqlScratch,
- cte, (isRecursive ? relAlias.c_str() : NULL));
+ cte, (isRecursive ? relAlias.c_str() : NULL), false);
if (!isRecursive)
cte->alias = saveCteName;
Modified: firebird/trunk/src/jrd/exe.h
===================================================================
--- firebird/trunk/src/jrd/exe.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/exe.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -533,6 +533,7 @@
void activate();
void deactivate();
+ Nullable<USHORT> csb_cursor_number; // Cursor number for this stream
StreamType csb_stream; // Map user context to internal stream
StreamType csb_view_stream; // stream number for view relation, below
USHORT csb_flags;
Modified: firebird/trunk/src/jrd/filters.cpp
===================================================================
--- firebird/trunk/src/jrd/filters.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/filters.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -1377,6 +1377,24 @@
string_put(control, "");
}
+ MapVarIndexToName::ConstAccessor cursors(&dbgInfo.curIndexToName);
+ if (cursors.getFirst())
+ {
+ string_put(control, "Cursors:");
+ str.printf("%10s %-32s", "Number", "Name");
+ string_put(control, str.c_str());
+ str.replace(str.begin(), str.end(), str.length(), '-');
+ string_put(control, str.c_str());
+
+ do
+ {
+ str.printf("%10d %-32s", cursors.current()->first, cursors.current()->second.c_str());
+ string_put(control, str.c_str());
+ } while (cursors.getNext());
+
+ string_put(control, "");
+ }
+
string_put(control, "BLR to Source mapping:");
str.printf("%10s %10s %10s", "BLR offset", "Line", "Column");
string_put(control, str.c_str());
Modified: firebird/trunk/src/jrd/recsrc/Cursor.h
===================================================================
--- firebird/trunk/src/jrd/recsrc/Cursor.h 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/recsrc/Cursor.h 2014-05-19 19:06:47 UTC (rev 59606)
@@ -35,6 +35,7 @@
class Cursor
{
+ public:
enum State { BOS, POSITIONED, EOS };
struct Impure
@@ -78,7 +79,11 @@
return true;
}
+ public:
ULONG m_impure;
+ Firebird::MetaName name; // optional name for explicit PSQL cursors
+
+ private:
const RecordSource* const m_top;
const VarInvariantArray* const m_invariants;
const bool m_scrollable;
Modified: firebird/trunk/src/jrd/vio.cpp
===================================================================
--- firebird/trunk/src/jrd/vio.cpp 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/jrd/vio.cpp 2014-05-19 19:06:47 UTC (rev 59606)
@@ -1947,7 +1947,7 @@
// Allocate a garbage collect record block if all are active.
record_param rpb;
- rpb.rpb_record = 0;
+ rpb.rpb_record = NULL;
Record* record = VIO_record(tdbb, &rpb, MET_current(tdbb, relation), dbb->dbb_permanent);
record->rec_flags |= REC_gc_active;
Modified: firebird/trunk/src/msgs/facilities2.sql
===================================================================
--- firebird/trunk/src/msgs/facilities2.sql 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/msgs/facilities2.sql 2014-05-19 19:06:47 UTC (rev 59606)
@@ -1,7 +1,7 @@
/* 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 (?, ?, ?, ?);
--
-('2014-04-30 18:55:42', 'JRD', 0, 772)
+('2014-05-14 23:48:00', 'JRD', 0, 773)
('2012-01-23 20:10:30', 'QLI', 1, 532)
('2013-11-13 15:59:10', 'GFIX', 3, 122)
('1996-11-07 13:39:40', 'GPRE', 4, 1)
Modified: firebird/trunk/src/msgs/messages2.sql
===================================================================
--- firebird/trunk/src/msgs/messages2.sql 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/msgs/messages2.sql 2014-05-19 19:06:47 UTC (rev 59606)
@@ -879,6 +879,7 @@
('map_notable', 'MappingList::getList', 'Mapping.cpp', NULL, 0, 769, NULL, 'Global mapping is not available when table RDB$MAP is not present in database @1', NULL, NULL);
('miss_trusted_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 770, NULL, 'Your attachment has no trusted role', NULL, NULL);
('set_invalid_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 771, NULL, 'Role @1 is invalid or unavailable', NULL, NULL);
+('cursor_not_positioned', NULL, NULL, NULL, 0, 772, NULL, 'Cursor @1 is not positioned in a valid record', NULL, NULL);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
Modified: firebird/trunk/src/msgs/system_errors2.sql
===================================================================
--- firebird/trunk/src/msgs/system_errors2.sql 2014-05-19 14:54:20 UTC (rev 59605)
+++ firebird/trunk/src/msgs/system_errors2.sql 2014-05-19 19:06:47 UTC (rev 59606)
@@ -778,6 +778,7 @@
(-901, '0A', '000', 0, 769, 'map_notable', NULL, NULL);
(-901, '0P', '000', 0, 770, 'miss_trusted_role', NULL, NULL);
(-901, '0P', '000', 0, 771, 'set_invalid_role', NULL, NULL);
+(-596, 'HY', '109', 0, 772, 'cursor_not_positioned', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|