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. |