2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-10-08 10:42:48 +02:00
|
|
|
* MODULE: exe.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Statement execution
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, 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 Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2002-06-30 11:58:20 +02:00
|
|
|
*
|
|
|
|
* 2001.6.21 Claudio Valderrama: Allow inserting strings into blob fields.
|
2010-11-29 15:54:07 +01:00
|
|
|
* 2001.6.28 Claudio Valderrama: Move code to cleanup_rpb() as directed
|
2002-06-30 11:58:20 +02:00
|
|
|
* by Ann Harrison and cleanup of new record in store() routine.
|
|
|
|
* 2001.10.11 Claudio Valderrama: Fix SF Bug #436462: From now, we only
|
|
|
|
* count real store, modify and delete operations either in an external
|
|
|
|
* file or in a table. Counting on a view caused up to three operations
|
|
|
|
* being reported instead of one.
|
|
|
|
* 2001.12.03 Claudio Valderrama: new visit to the same issue: views need
|
|
|
|
* to count virtual operations, not real I/O on the underlying tables.
|
2002-09-28 16:04:35 +02:00
|
|
|
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
|
|
|
|
* exception handling in SPs/triggers,
|
|
|
|
* implemented ROWS_AFFECTED system variable
|
2002-10-29 04:17:45 +01:00
|
|
|
*
|
2008-12-05 02:20:14 +01:00
|
|
|
* 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks
|
2002-10-29 04:17:45 +01:00
|
|
|
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "MPEXL" port
|
|
|
|
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
|
2002-10-29 21:20:44 +01:00
|
|
|
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
|
2002-10-31 06:06:02 +01:00
|
|
|
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
|
2003-11-02 12:55:17 +01:00
|
|
|
* 2003.10.05 Dmitry Yemanov: Added support for explicit cursors in PSQL
|
2007-03-06 03:29:48 +01:00
|
|
|
* Adriano dos Santos Fernandes
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2009-05-29 13:27:41 +02:00
|
|
|
#ifdef TIME_WITH_SYS_TIME
|
2002-09-18 14:50:13 +02:00
|
|
|
# include <sys/time.h>
|
|
|
|
# include <time.h>
|
|
|
|
#else
|
2009-05-29 13:27:41 +02:00
|
|
|
# ifdef HAVE_SYS_TIME_H
|
2002-09-18 14:50:13 +02:00
|
|
|
# include <sys/time.h>
|
|
|
|
# else
|
|
|
|
# include <time.h>
|
|
|
|
# endif
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-10-13 12:39:52 +02:00
|
|
|
#include "../common/common.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ibsetjmp.h"
|
2009-04-29 16:00:32 +02:00
|
|
|
#include "../common/classes/VaryStr.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/req.h"
|
|
|
|
#include "../jrd/val.h"
|
|
|
|
#include "../jrd/exe.h"
|
2008-04-09 22:18:47 +02:00
|
|
|
#include "../jrd/extds/ExtDS.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/tra.h"
|
2003-11-11 13:19:20 +01:00
|
|
|
#include "gen/iberror.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ods.h"
|
|
|
|
#include "../jrd/btr.h"
|
|
|
|
#include "../jrd/rse.h"
|
|
|
|
#include "../jrd/lck.h"
|
|
|
|
#include "../jrd/intl.h"
|
|
|
|
#include "../jrd/sbm.h"
|
|
|
|
#include "../jrd/blb.h"
|
|
|
|
#include "../jrd/blr.h"
|
2010-10-12 13:36:51 +02:00
|
|
|
#include "../dsql/ExprNodes.h"
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
#include "../dsql/StmtNodes.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/blb_proto.h"
|
|
|
|
#include "../jrd/btr_proto.h"
|
|
|
|
#include "../jrd/cmp_proto.h"
|
|
|
|
#include "../jrd/dfw_proto.h"
|
|
|
|
#include "../jrd/dpm_proto.h"
|
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/evl_proto.h"
|
|
|
|
#include "../jrd/exe_proto.h"
|
|
|
|
#include "../jrd/ext_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../yvalve/gds_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/idx_proto.h"
|
2005-05-28 00:45:31 +02:00
|
|
|
#include "../jrd/intl_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd_proto.h"
|
|
|
|
|
|
|
|
#include "../jrd/lck_proto.h"
|
|
|
|
#include "../jrd/met_proto.h"
|
|
|
|
#include "../jrd/mov_proto.h"
|
|
|
|
#include "../jrd/opt_proto.h"
|
|
|
|
#include "../jrd/par_proto.h"
|
|
|
|
#include "../jrd/rlck_proto.h"
|
2004-03-20 16:33:30 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/tra_proto.h"
|
|
|
|
#include "../jrd/vio_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/isc_s_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-04-22 10:45:52 +02:00
|
|
|
#include "../dsql/dsql_proto.h"
|
2003-04-25 16:51:04 +02:00
|
|
|
#include "../jrd/rpb_chain.h"
|
2010-10-12 13:36:51 +02:00
|
|
|
#include "../jrd/RecordSourceNodes.h"
|
2006-07-17 19:44:18 +02:00
|
|
|
#include "../jrd/VirtualTable.h"
|
2009-02-01 23:10:12 +01:00
|
|
|
#include "../jrd/trace/TraceManager.h"
|
|
|
|
#include "../jrd/trace/TraceJrdHelpers.h"
|
2004-03-19 07:14:53 +01:00
|
|
|
|
2008-05-19 15:47:48 +02:00
|
|
|
#include "../dsql/Nodes.h"
|
2009-12-09 19:45:44 +01:00
|
|
|
#include "../jrd/recsrc/RecordSource.h"
|
|
|
|
#include "../jrd/recsrc/Cursor.h"
|
2009-12-21 18:43:01 +01:00
|
|
|
#include "../jrd/Function.h"
|
2008-05-19 15:47:48 +02:00
|
|
|
|
2003-03-01 20:19:23 +01:00
|
|
|
|
2004-03-20 16:33:30 +01:00
|
|
|
using namespace Jrd;
|
2008-08-27 14:20:47 +02:00
|
|
|
using namespace Firebird;
|
2004-03-20 16:33:30 +01:00
|
|
|
|
2005-06-24 14:56:34 +02:00
|
|
|
// AffectedRows class implementation
|
|
|
|
|
|
|
|
AffectedRows::AffectedRows()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AffectedRows::clear()
|
|
|
|
{
|
|
|
|
writeFlag = false;
|
|
|
|
fetchedRows = modifiedRows = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AffectedRows::bumpFetched()
|
|
|
|
{
|
|
|
|
fetchedRows++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AffectedRows::bumpModified(bool increment)
|
|
|
|
{
|
|
|
|
if (increment) {
|
|
|
|
modifiedRows++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
writeFlag = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AffectedRows::isReadOnly() const
|
|
|
|
{
|
|
|
|
return !writeFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AffectedRows::hasCursor() const
|
|
|
|
{
|
|
|
|
return (fetchedRows > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int AffectedRows::getCount() const
|
|
|
|
{
|
|
|
|
return writeFlag ? modifiedRows : fetchedRows;
|
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
// StatusXcp class implementation
|
2003-11-02 12:55:17 +01:00
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
StatusXcp::StatusXcp()
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
void StatusXcp::clear()
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
fb_utils::init_status(status);
|
2003-11-02 12:55:17 +01:00
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
void StatusXcp::init(const ISC_STATUS* vector)
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
|
|
|
memcpy(status, vector, sizeof(ISC_STATUS_ARRAY));
|
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
void StatusXcp::copyTo(ISC_STATUS* vector) const
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
|
|
|
memcpy(vector, status, sizeof(ISC_STATUS_ARRAY));
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
bool StatusXcp::success() const
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
2003-11-02 13:05:38 +01:00
|
|
|
return (status[1] == FB_SUCCESS);
|
2003-11-02 12:55:17 +01:00
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
SLONG StatusXcp::as_gdscode() const
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
|
|
|
return status[1];
|
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
SLONG StatusXcp::as_sqlcode() const
|
2003-11-02 12:55:17 +01:00
|
|
|
{
|
|
|
|
return gds__sqlcode(status);
|
|
|
|
}
|
|
|
|
|
2010-03-21 08:29:58 +01:00
|
|
|
void StatusXcp::as_sqlstate(char* sqlstate) const
|
|
|
|
{
|
|
|
|
fb_sqlstate(sqlstate, status);
|
|
|
|
}
|
|
|
|
|
2011-07-10 03:23:53 +02:00
|
|
|
static void execute_ext_procedure(thread_db* tdbb, jrd_req* request);
|
2008-12-20 09:12:19 +01:00
|
|
|
static void execute_looper(thread_db*, jrd_req*, jrd_tra*, jrd_req::req_s);
|
2009-04-28 15:08:04 +02:00
|
|
|
static void looper_seh(thread_db*, jrd_req*);
|
2004-03-11 06:04:26 +01:00
|
|
|
static void release_blobs(thread_db*, jrd_req*);
|
2004-01-03 11:59:52 +01:00
|
|
|
static void release_proc_save_points(jrd_req*);
|
2004-03-11 06:04:26 +01:00
|
|
|
static void trigger_failure(thread_db*, jrd_req*);
|
2005-01-04 14:09:11 +01:00
|
|
|
static void stuff_stack_trace(const jrd_req*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-11-07 15:30:38 +01:00
|
|
|
const size_t MAX_STACK_TRACE = 2048;
|
2004-08-06 17:26:55 +02:00
|
|
|
|
2009-06-25 17:58:09 +02:00
|
|
|
|
2010-11-21 04:47:29 +01:00
|
|
|
// Perform an assignment.
|
2010-12-04 23:15:03 +01:00
|
|
|
void EXE_assignment(thread_db* tdbb, const AssignmentNode* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
DEV_BLKCHK(node, type_nod);
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_req* request = tdbb->getRequest();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-06-27 04:08:25 +02:00
|
|
|
// Get descriptors of src field/parameter/variable, etc.
|
2007-06-23 20:48:27 +02:00
|
|
|
request->req_flags &= ~req_null;
|
2010-12-04 23:15:03 +01:00
|
|
|
dsc* from_desc = EVL_expr(tdbb, request, node->asgnFrom);
|
2007-06-23 20:48:27 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
EXE_assignment(tdbb, node->asgnTo, from_desc, (request->req_flags & req_null),
|
|
|
|
node->missing, node->missing2);
|
2007-06-23 20:48:27 +02:00
|
|
|
|
|
|
|
request->req_operation = jrd_req::req_return;
|
|
|
|
}
|
|
|
|
|
2010-11-21 04:47:29 +01:00
|
|
|
// Perform an assignment.
|
|
|
|
void EXE_assignment(thread_db* tdbb, const ValueExprNode* source, const ValueExprNode* target)
|
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
jrd_req* request = tdbb->getRequest();
|
2007-06-23 20:48:27 +02:00
|
|
|
|
2010-11-21 04:47:29 +01:00
|
|
|
// Get descriptors of src field/parameter/variable, etc.
|
|
|
|
request->req_flags &= ~req_null;
|
|
|
|
dsc* from_desc = EVL_expr(tdbb, request, source);
|
|
|
|
|
|
|
|
EXE_assignment(tdbb, target, from_desc, (request->req_flags & req_null), NULL, NULL);
|
|
|
|
|
|
|
|
request->req_operation = jrd_req::req_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform an assignment.
|
|
|
|
void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bool from_null,
|
2010-12-04 23:15:03 +01:00
|
|
|
const ValueExprNode* missing_node, const ValueExprNode* missing2_node)
|
2007-06-23 20:48:27 +02:00
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_req* request = tdbb->getRequest();
|
2007-06-23 20:48:27 +02:00
|
|
|
|
|
|
|
// Get descriptors of receiving and sending fields/parameters, variables, etc.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-02 01:46:03 +01:00
|
|
|
dsc* missing = NULL;
|
2010-11-21 04:47:29 +01:00
|
|
|
if (missing_node)
|
2010-12-04 23:15:03 +01:00
|
|
|
missing = EVL_expr(tdbb, request, missing_node);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2007-06-27 04:08:25 +02:00
|
|
|
// Get descriptor of target field/parameter/variable, etc.
|
2001-12-24 03:51:06 +01:00
|
|
|
DSC* to_desc = EVL_assign_to(tdbb, to);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->req_flags &= ~req_null;
|
|
|
|
|
2004-11-25 01:47:20 +01:00
|
|
|
// NS: If we are assigning to NULL, we finished.
|
|
|
|
// This functionality is currently used to allow calling UDF routines
|
|
|
|
// without assigning resulting value anywhere.
|
2007-06-23 20:48:27 +02:00
|
|
|
if (!to_desc)
|
2004-11-25 01:47:20 +01:00
|
|
|
return;
|
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
SSHORT null = from_null ? -1 : 0;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
if (!null && missing && MOV_compare(missing, from_desc) == 0)
|
2001-05-23 15:26:42 +02:00
|
|
|
null = -1;
|
|
|
|
|
2007-02-06 15:25:10 +01:00
|
|
|
USHORT* impure_flags = NULL;
|
2010-11-02 18:05:01 +01:00
|
|
|
const ParameterNode* toParam;
|
|
|
|
const VariableNode* toVar;
|
2007-02-06 15:25:10 +01:00
|
|
|
|
2010-11-02 18:05:01 +01:00
|
|
|
if ((toParam = ExprNode::as<ParameterNode>(to)))
|
2007-01-17 02:19:01 +01:00
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
const MessageNode* message = toParam->message;
|
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
if (toParam->argInfo)
|
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
EVL_validate(tdbb, Item(Item::TYPE_PARAMETER, message->messageNumber, toParam->argNumber),
|
2010-10-12 13:36:51 +02:00
|
|
|
toParam->argInfo, from_desc, null == -1);
|
|
|
|
}
|
2007-01-17 02:19:01 +01:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
impure_flags = request->getImpure<USHORT>(
|
2010-12-04 23:15:03 +01:00
|
|
|
message->impureFlags + (sizeof(USHORT) * toParam->argNumber));
|
2010-10-12 13:36:51 +02:00
|
|
|
}
|
2010-11-02 18:05:01 +01:00
|
|
|
else if ((toVar = ExprNode::as<VariableNode>(to)))
|
2010-10-12 13:36:51 +02:00
|
|
|
{
|
2010-11-02 18:05:01 +01:00
|
|
|
if (toVar->varInfo)
|
2010-10-12 13:36:51 +02:00
|
|
|
{
|
2010-11-02 18:05:01 +01:00
|
|
|
EVL_validate(tdbb, Item(Item::TYPE_VARIABLE, toVar->varId),
|
|
|
|
toVar->varInfo, from_desc, null == -1);
|
2010-10-12 13:36:51 +02:00
|
|
|
}
|
2010-11-02 18:05:01 +01:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
impure_flags = &request->getImpure<impure_value>(
|
2010-12-04 23:15:03 +01:00
|
|
|
toVar->varDecl->impureOffset)->vlu_flags;
|
2007-01-17 02:19:01 +01:00
|
|
|
}
|
|
|
|
|
2007-02-06 15:25:10 +01:00
|
|
|
if (impure_flags != NULL)
|
|
|
|
*impure_flags |= VLU_checked;
|
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
// If the value is non-missing, move/convert it. Otherwise fill the
|
|
|
|
// field with appropriate nulls.
|
2004-01-13 10:52:19 +01:00
|
|
|
dsc temp;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!null)
|
|
|
|
{
|
2007-06-23 20:48:27 +02:00
|
|
|
// if necessary and appropriate, use the indicator variable
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
if (toParam && toParam->argIndicator)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
dsc* indicator = EVL_assign_to(tdbb, toParam->argIndicator);
|
|
|
|
temp.dsc_dtype = dtype_short;
|
|
|
|
temp.dsc_length = sizeof(SSHORT);
|
|
|
|
temp.dsc_scale = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
temp.dsc_sub_type = 0;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
SSHORT len;
|
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
if ((from_desc->dsc_dtype <= dtype_varying) && (to_desc->dsc_dtype <= dtype_varying) &&
|
2001-05-23 15:26:42 +02:00
|
|
|
(TEXT_LEN(from_desc) > TEXT_LEN(to_desc)))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
len = TEXT_LEN(from_desc);
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
2010-10-12 13:36:51 +02:00
|
|
|
else
|
2001-05-23 15:26:42 +02:00
|
|
|
len = 0;
|
|
|
|
|
2003-10-08 10:42:48 +02:00
|
|
|
temp.dsc_address = (UCHAR *) &len;
|
2007-03-02 01:46:03 +01:00
|
|
|
MOV_move(tdbb, &temp, indicator);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 06:24:29 +01:00
|
|
|
if (len)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
temp = *from_desc;
|
|
|
|
temp.dsc_length = TEXT_LEN(to_desc);
|
2010-10-12 13:36:51 +02:00
|
|
|
|
|
|
|
if (temp.dsc_dtype == dtype_cstring)
|
2001-05-23 15:26:42 +02:00
|
|
|
temp.dsc_length += 1;
|
2010-10-12 13:36:51 +02:00
|
|
|
else if (temp.dsc_dtype == dtype_varying)
|
2001-05-23 15:26:42 +02:00
|
|
|
temp.dsc_length += 2;
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
from_desc = &temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-21 10:15:48 +02:00
|
|
|
// Validate range for datetime values
|
|
|
|
|
2008-03-26 11:21:04 +01:00
|
|
|
if (DTYPE_IS_DATE(from_desc->dsc_dtype))
|
|
|
|
{
|
|
|
|
switch (from_desc->dsc_dtype)
|
|
|
|
{
|
2006-07-21 10:15:48 +02:00
|
|
|
case dtype_sql_date:
|
2008-03-26 11:21:04 +01:00
|
|
|
if (!Firebird::TimeStamp::isValidDate(*(GDS_DATE*) from_desc->dsc_address))
|
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_date_range_exceeded));
|
2008-03-26 11:21:04 +01:00
|
|
|
}
|
2006-07-21 10:15:48 +02:00
|
|
|
break;
|
2008-03-26 11:21:04 +01:00
|
|
|
|
2006-07-21 10:15:48 +02:00
|
|
|
case dtype_sql_time:
|
2008-03-26 11:21:04 +01:00
|
|
|
if (!Firebird::TimeStamp::isValidTime(*(GDS_TIME*) from_desc->dsc_address))
|
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_time_range_exceeded));
|
2008-03-26 11:21:04 +01:00
|
|
|
}
|
2006-07-21 10:15:48 +02:00
|
|
|
break;
|
2008-03-26 11:21:04 +01:00
|
|
|
|
2006-07-21 10:15:48 +02:00
|
|
|
case dtype_timestamp:
|
2008-03-26 11:21:04 +01:00
|
|
|
if (!Firebird::TimeStamp::isValidTimeStamp(*(GDS_TIMESTAMP*) from_desc->dsc_address))
|
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_datetime_range_exceeded));
|
2008-03-26 11:21:04 +01:00
|
|
|
}
|
2006-07-21 10:15:48 +02:00
|
|
|
break;
|
2008-03-26 11:21:04 +01:00
|
|
|
|
2006-07-21 10:15:48 +02:00
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
if (DTYPE_IS_BLOB_OR_QUAD(from_desc->dsc_dtype) || DTYPE_IS_BLOB_OR_QUAD(to_desc->dsc_dtype))
|
2006-08-05 21:52:26 +02:00
|
|
|
{
|
2007-03-02 01:46:03 +01:00
|
|
|
// ASF: Don't let MOV_move call BLB_move because MOV
|
|
|
|
// will not pass the destination field to BLB_move.
|
2005-12-05 13:40:22 +01:00
|
|
|
BLB_move(tdbb, from_desc, to_desc, to);
|
2006-08-05 21:52:26 +02:00
|
|
|
}
|
2006-01-15 17:04:39 +01:00
|
|
|
else if (!DSC_EQUIV(from_desc, to_desc, false))
|
2009-03-03 15:57:53 +01:00
|
|
|
{
|
2007-03-02 01:46:03 +01:00
|
|
|
MOV_move(tdbb, from_desc, to_desc);
|
2009-03-03 15:57:53 +01:00
|
|
|
}
|
2006-08-05 21:52:26 +02:00
|
|
|
else if (from_desc->dsc_dtype == dtype_short)
|
|
|
|
{
|
2009-01-14 09:22:32 +01:00
|
|
|
*((SSHORT*) to_desc->dsc_address) = *((SSHORT*) from_desc->dsc_address);
|
2004-01-13 10:52:19 +01:00
|
|
|
}
|
2006-08-05 21:52:26 +02:00
|
|
|
else if (from_desc->dsc_dtype == dtype_long)
|
|
|
|
{
|
2009-01-14 09:22:32 +01:00
|
|
|
*((SLONG*) to_desc->dsc_address) = *((SLONG*) from_desc->dsc_address);
|
2004-01-13 10:52:19 +01:00
|
|
|
}
|
2006-08-05 21:52:26 +02:00
|
|
|
else if (from_desc->dsc_dtype == dtype_int64)
|
|
|
|
{
|
2009-01-14 09:22:32 +01:00
|
|
|
*((SINT64*) to_desc->dsc_address) = *((SINT64*) from_desc->dsc_address);
|
2004-01-13 10:52:19 +01:00
|
|
|
}
|
2006-08-05 21:52:26 +02:00
|
|
|
else
|
2009-03-03 15:57:53 +01:00
|
|
|
{
|
2008-01-16 09:54:50 +01:00
|
|
|
memcpy(to_desc->dsc_address, from_desc->dsc_address, from_desc->dsc_length);
|
2009-03-03 15:57:53 +01:00
|
|
|
}
|
2008-01-16 09:54:50 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
to_desc->dsc_flags &= ~DSC_null;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else
|
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
if (missing2_node && (missing = EVL_expr(tdbb, request, missing2_node)))
|
2009-03-03 15:57:53 +01:00
|
|
|
MOV_move(tdbb, missing, to_desc);
|
|
|
|
else
|
|
|
|
memset(to_desc->dsc_address, 0, to_desc->dsc_length);
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
to_desc->dsc_flags |= DSC_null;
|
|
|
|
}
|
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
// Handle the null flag as appropriate for fields and message arguments.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2011-04-02 06:27:07 +02:00
|
|
|
|
|
|
|
const FieldNode* toField = ExprNode::as<FieldNode>(to);
|
|
|
|
if (toField)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2010-11-14 18:25:48 +01:00
|
|
|
Record* record = request->req_rpb[toField->fieldStream].rpb_record;
|
|
|
|
|
|
|
|
if (null)
|
|
|
|
SET_NULL(record, toField->fieldId);
|
|
|
|
else
|
|
|
|
CLEAR_NULL(record, toField->fieldId);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2010-10-12 13:36:51 +02:00
|
|
|
else if (toParam && toParam->argFlag)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
to_desc = EVL_assign_to(tdbb, toParam->argFlag);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
// If the null flag is a string with an effective length of one,
|
|
|
|
// then -1 will not fit. Therefore, store 1 instead.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
if (null && to_desc->dsc_dtype <= dtype_varying)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2008-12-20 09:12:19 +01:00
|
|
|
USHORT minlen;
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
switch (to_desc->dsc_dtype)
|
|
|
|
{
|
|
|
|
case dtype_text:
|
|
|
|
minlen = 1;
|
|
|
|
break;
|
|
|
|
case dtype_cstring:
|
|
|
|
minlen = 2;
|
|
|
|
break;
|
|
|
|
case dtype_varying:
|
|
|
|
minlen = 3;
|
|
|
|
break;
|
|
|
|
}
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
if (to_desc->dsc_length <= minlen)
|
|
|
|
null = 1;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
temp.dsc_dtype = dtype_short;
|
|
|
|
temp.dsc_length = sizeof(SSHORT);
|
|
|
|
temp.dsc_scale = 0;
|
|
|
|
temp.dsc_sub_type = 0;
|
2009-01-14 10:19:00 +01:00
|
|
|
temp.dsc_address = (UCHAR*) &null;
|
2007-03-02 01:46:03 +01:00
|
|
|
MOV_move(tdbb, &temp, to_desc);
|
2010-10-12 13:36:51 +02:00
|
|
|
|
|
|
|
if (null && toParam->argIndicator)
|
2009-11-23 06:24:29 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
to_desc = EVL_assign_to(tdbb, toParam->argIndicator);
|
2007-03-02 01:46:03 +01:00
|
|
|
MOV_move(tdbb, &temp, to_desc);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, jrd_req::req_ta trigger_action)
|
2006-11-05 19:30:36 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E _ e x e c u t e _ d b _ t r i g g e r s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute database triggers
|
|
|
|
*
|
|
|
|
**************************************/
|
2011-05-09 12:15:19 +02:00
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
|
2011-05-10 03:12:14 +02:00
|
|
|
// Do nothing if user doesn't want database triggers.
|
2011-05-09 12:15:19 +02:00
|
|
|
if (attachment->att_flags & ATT_no_db_triggers)
|
2006-11-05 19:30:36 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
int type = 0;
|
|
|
|
|
|
|
|
switch (trigger_action)
|
|
|
|
{
|
|
|
|
case jrd_req::req_trigger_connect:
|
|
|
|
type = DB_TRIGGER_CONNECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case jrd_req::req_trigger_disconnect:
|
|
|
|
type = DB_TRIGGER_DISCONNECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case jrd_req::req_trigger_trans_start:
|
|
|
|
type = DB_TRIGGER_TRANS_START;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case jrd_req::req_trigger_trans_commit:
|
|
|
|
type = DB_TRIGGER_TRANS_COMMIT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case jrd_req::req_trigger_trans_rollback:
|
|
|
|
type = DB_TRIGGER_TRANS_ROLLBACK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-09 12:15:19 +02:00
|
|
|
if (attachment->att_triggers[type])
|
2006-11-05 19:30:36 +01:00
|
|
|
{
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_tra* old_transaction = tdbb->getTransaction();
|
|
|
|
tdbb->setTransaction(transaction);
|
2006-11-05 19:30:36 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2011-05-09 12:15:19 +02:00
|
|
|
EXE_execute_triggers(tdbb, &attachment->att_triggers[type],
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
NULL, NULL, trigger_action, StmtNode::ALL_TRIGS);
|
2007-12-03 16:46:39 +01:00
|
|
|
tdbb->setTransaction(old_transaction);
|
2006-11-05 19:30:36 +01:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2007-12-03 16:46:39 +01:00
|
|
|
tdbb->setTransaction(old_transaction);
|
2006-11-05 19:30:36 +01:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
2009-10-21 02:42:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Execute DDL triggers.
|
|
|
|
void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTriggers, int action)
|
|
|
|
{
|
2011-05-09 12:15:19 +02:00
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
// Our caller verifies (ATT_no_db_triggers) if DDL triggers should not run.
|
|
|
|
|
2011-05-09 12:15:19 +02:00
|
|
|
if (attachment->att_ddl_triggers)
|
2009-10-21 02:42:38 +02:00
|
|
|
{
|
2009-10-31 02:46:06 +01:00
|
|
|
jrd_tra* const oldTransaction = tdbb->getTransaction();
|
2009-10-21 02:42:38 +02:00
|
|
|
tdbb->setTransaction(transaction);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
trig_vec triggers;
|
|
|
|
trig_vec* triggersPtr = &triggers;
|
2006-11-05 19:30:36 +01:00
|
|
|
|
2011-05-09 12:15:19 +02:00
|
|
|
for (trig_vec::iterator i = attachment->att_ddl_triggers->begin();
|
|
|
|
i != attachment->att_ddl_triggers->end();
|
2009-10-21 02:42:38 +02:00
|
|
|
++i)
|
|
|
|
{
|
|
|
|
if ((i->type & (1LL << action)) &&
|
|
|
|
((preTriggers && (i->type & 0x1) == 0) || (!preTriggers && (i->type & 0x1) == 0x1)))
|
|
|
|
{
|
|
|
|
triggers.add() = *i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
EXE_execute_triggers(tdbb, &triggersPtr, NULL, NULL, jrd_req::req_trigger_ddl,
|
|
|
|
StmtNode::ALL_TRIGS);
|
2009-10-21 02:42:38 +02:00
|
|
|
|
2009-10-31 02:46:06 +01:00
|
|
|
tdbb->setTransaction(oldTransaction);
|
2009-10-21 02:42:38 +02:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2009-10-31 02:46:06 +01:00
|
|
|
tdbb->setTransaction(oldTransaction);
|
2009-10-21 02:42:38 +02:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
2006-11-05 19:30:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-08 13:14:57 +02:00
|
|
|
void EXE_receive(thread_db* tdbb,
|
|
|
|
jrd_req* request,
|
|
|
|
USHORT msg,
|
|
|
|
ULONG length,
|
|
|
|
UCHAR* buffer,
|
|
|
|
bool top_level)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E _ r e c e i v e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Move a message from JRD to the host program. This corresponds to
|
2010-12-04 23:15:03 +01:00
|
|
|
* a JRD BLR/Stmtode* send.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
DEV_BLKCHK(request, type_req);
|
|
|
|
|
2004-10-03 14:10:19 +02:00
|
|
|
if (--tdbb->tdbb_quantum < 0)
|
|
|
|
JRD_reschedule(tdbb, 0, true);
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
jrd_tra* transaction = request->req_transaction;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(request->req_flags & req_active)) {
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (request->req_flags & req_proc_fetch)
|
|
|
|
{
|
|
|
|
/* request->req_proc_sav_point stores all the request savepoints.
|
|
|
|
When going to continue execution put request save point list
|
|
|
|
into transaction->tra_save_point so that it is used in looper.
|
|
|
|
When we come back to EXE_receive() restore
|
|
|
|
transaction->tra_save_point and merge all work done under
|
|
|
|
stored procedure savepoints into the current transaction
|
|
|
|
savepoint, which is the savepoint for fetch. */
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
Savepoint* const save_sav_point = transaction->tra_save_point;
|
2001-05-23 15:26:42 +02:00
|
|
|
transaction->tra_save_point = request->req_proc_sav_point;
|
|
|
|
request->req_proc_sav_point = save_sav_point;
|
|
|
|
|
|
|
|
if (!transaction->tra_save_point) {
|
2002-11-03 18:29:51 +01:00
|
|
|
VIO_start_save_point(tdbb, transaction);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2002-04-03 01:12:03 +02:00
|
|
|
try
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2011-10-16 22:36:07 +02:00
|
|
|
const bool external =
|
|
|
|
(request->getStatement()->procedure && request->getStatement()->procedure->getExternal()) ||
|
|
|
|
(request->getStatement()->function && request->getStatement()->function->fun_external);
|
2009-10-21 02:42:38 +02:00
|
|
|
|
|
|
|
if (external)
|
|
|
|
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
|
|
|
else
|
|
|
|
{
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (StmtNode::is<StallNode>(request->req_message))
|
2009-10-21 02:42:38 +02:00
|
|
|
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
if (!(request->req_flags & req_active) || request->req_operation != jrd_req::req_send)
|
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
const MessageNode* message = StmtNode::as<MessageNode>(request->req_message);
|
|
|
|
const Format* format = message->format;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
if (msg != message->messageNumber)
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
if (length != format->fmt_length)
|
2008-12-20 09:12:19 +01:00
|
|
|
ERR_post(Arg::Gds(isc_port_len) << Arg::Num(length) << Arg::Num(format->fmt_length));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
memcpy(buffer, request->getImpure<UCHAR>(message->impureOffset), length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-24 04:00:22 +01:00
|
|
|
// ASF: temporary blobs returned to the client should not be released
|
|
|
|
// with the request, but in the transaction end.
|
|
|
|
if (top_level)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < format->fmt_count; ++i)
|
|
|
|
{
|
|
|
|
const DSC* desc = &format->fmt_desc[i];
|
|
|
|
|
|
|
|
if (desc->isBlob())
|
|
|
|
{
|
2009-10-21 02:42:38 +02:00
|
|
|
const bid* id = (bid*) (buffer + (ULONG)(IPTR)desc->dsc_address);
|
2007-03-24 04:00:22 +01:00
|
|
|
|
2008-04-05 21:28:52 +02:00
|
|
|
if (transaction->tra_blobs->locate(id->bid_temp_id()))
|
2007-03-24 04:00:22 +01:00
|
|
|
{
|
2008-04-05 21:28:52 +02:00
|
|
|
BlobIndex* current = &transaction->tra_blobs->current();
|
2007-03-24 04:00:22 +01:00
|
|
|
|
|
|
|
if (current->bli_request &&
|
|
|
|
current->bli_request->req_blobs.locate(id->bid_temp_id()))
|
|
|
|
{
|
|
|
|
current->bli_request->req_blobs.fastRemove();
|
|
|
|
current->bli_request = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
if (!external)
|
|
|
|
execute_looper(tdbb, request, transaction, jrd_req::req_proceed);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-03 01:12:03 +02:00
|
|
|
} //try
|
2006-05-19 17:17:02 +02:00
|
|
|
catch (const Firebird::Exception&)
|
2002-04-03 01:12:03 +02:00
|
|
|
{
|
|
|
|
if (request->req_flags & req_proc_fetch)
|
|
|
|
{
|
2004-03-18 06:56:06 +01:00
|
|
|
Savepoint* const save_sav_point = transaction->tra_save_point;
|
2002-04-03 01:12:03 +02:00
|
|
|
transaction->tra_save_point = request->req_proc_sav_point;
|
|
|
|
request->req_proc_sav_point = save_sav_point;
|
|
|
|
release_proc_save_points(request);
|
|
|
|
}
|
2002-04-18 05:54:36 +02:00
|
|
|
throw;
|
2002-04-03 01:12:03 +02:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:24:29 +01:00
|
|
|
if (request->req_flags & req_proc_fetch)
|
|
|
|
{
|
2004-03-18 06:56:06 +01:00
|
|
|
Savepoint* const save_sav_point = transaction->tra_save_point;
|
2001-05-23 15:26:42 +02:00
|
|
|
transaction->tra_save_point = request->req_proc_sav_point;
|
|
|
|
request->req_proc_sav_point = save_sav_point;
|
2008-12-20 09:12:19 +01:00
|
|
|
VIO_merge_proc_sav_points(tdbb, transaction, &request->req_proc_sav_point);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
// Release a request instance.
|
|
|
|
void EXE_release(thread_db* tdbb, jrd_req* request)
|
|
|
|
{
|
|
|
|
DEV_BLKCHK(request, type_req);
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
EXE_unwind(tdbb, request);
|
|
|
|
|
2011-04-01 17:28:07 +02:00
|
|
|
// system requests are released after all attachments gone and with
|
|
|
|
// req_attachment not cleared
|
|
|
|
|
|
|
|
const Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
|
|
|
|
if (request->req_attachment && request->req_attachment == attachment)
|
2010-04-19 00:19:11 +02:00
|
|
|
{
|
|
|
|
size_t pos;
|
|
|
|
if (request->req_attachment->att_requests.find(request, pos))
|
|
|
|
request->req_attachment->att_requests.remove(pos);
|
|
|
|
|
|
|
|
request->req_attachment = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-08 13:14:57 +02:00
|
|
|
void EXE_send(thread_db* tdbb, jrd_req* request, USHORT msg, ULONG length, const UCHAR* buffer)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E _ s e n d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-12-05 02:20:14 +01:00
|
|
|
* Send a message from the host program to the engine.
|
2001-05-23 15:26:42 +02:00
|
|
|
* This corresponds to a blr_receive or blr_select statement.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
DEV_BLKCHK(request, type_req);
|
|
|
|
|
2004-10-03 14:10:19 +02:00
|
|
|
if (--tdbb->tdbb_quantum < 0)
|
|
|
|
JRD_reschedule(tdbb, 0, true);
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(request->req_flags & req_active))
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
const StmtNode* message;
|
|
|
|
const StmtNode* node;
|
2010-08-09 17:48:51 +02:00
|
|
|
|
2009-10-31 07:25:01 +01:00
|
|
|
if (request->req_operation != jrd_req::req_receive)
|
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
|
|
|
node = request->req_message;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
jrd_tra* transaction = request->req_transaction;
|
2010-04-19 00:19:11 +02:00
|
|
|
const JrdStatement* statement = request->getStatement();
|
|
|
|
|
2011-10-16 22:36:07 +02:00
|
|
|
const bool external =
|
|
|
|
(statement->procedure && statement->procedure->getExternal()) ||
|
|
|
|
(statement->function && statement->function->fun_external);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
if (external)
|
2009-01-14 09:22:32 +01:00
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
fb_assert(statement->topNode->kind == DmlNode::KIND_STATEMENT);
|
|
|
|
const CompoundStmtNode* list = StmtNode::as<CompoundStmtNode>(
|
|
|
|
static_cast<const StmtNode*>(statement->topNode));
|
|
|
|
fb_assert(list);
|
|
|
|
|
2011-10-16 22:36:07 +02:00
|
|
|
message = list->statements[e_extrout_input_message]->as<MessageNode>();
|
2010-12-04 23:15:03 +01:00
|
|
|
fb_assert(message);
|
2009-10-21 02:42:38 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
const SelectNode* selectNode;
|
|
|
|
|
|
|
|
if (StmtNode::is<MessageNode>(node))
|
|
|
|
message = node;
|
|
|
|
else if ((selectNode = StmtNode::as<SelectNode>(node)))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
const NestConst<StmtNode>* ptr = selectNode->statements.begin();
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
for (const NestConst<StmtNode>* end = selectNode->statements.end(); ptr != end; ++ptr)
|
2009-01-14 09:22:32 +01:00
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
const ReceiveNode* receiveNode = (*ptr)->as<ReceiveNode>();
|
|
|
|
message = receiveNode->message;
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
if (message->as<MessageNode>()->messageNumber == msg)
|
2009-10-21 02:42:38 +02:00
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
request->req_next = *ptr;
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
break;
|
2009-01-14 09:22:32 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2010-12-04 23:15:03 +01:00
|
|
|
else
|
|
|
|
BUGCHECK(167); // msg 167 invalid SEND request
|
2009-01-14 09:22:32 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
const Format* format = StmtNode::as<MessageNode>(message)->format;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
if (msg != StmtNode::as<MessageNode>(message)->messageNumber)
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (length != format->fmt_length)
|
2008-12-20 09:12:19 +01:00
|
|
|
ERR_post(Arg::Gds(isc_port_len) << Arg::Num(length) << Arg::Num(format->fmt_length));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
memcpy(request->getImpure<UCHAR>(message->impureOffset), buffer, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-28 00:45:31 +02:00
|
|
|
for (USHORT i = 0; i < format->fmt_count; ++i)
|
|
|
|
{
|
|
|
|
const DSC* desc = &format->fmt_desc[i];
|
|
|
|
|
|
|
|
// ASF: I'll not test for dtype_cstring because usage is only internal
|
|
|
|
if (desc->dsc_dtype == dtype_text || desc->dsc_dtype == dtype_varying)
|
|
|
|
{
|
2010-12-04 23:15:03 +01:00
|
|
|
const UCHAR* p = request->getImpure<UCHAR>(message->impureOffset +
|
2010-04-07 15:10:27 +02:00
|
|
|
(ULONG)(IPTR) desc->dsc_address);
|
2005-05-28 00:45:31 +02:00
|
|
|
USHORT len;
|
|
|
|
|
|
|
|
switch (desc->dsc_dtype)
|
|
|
|
{
|
|
|
|
case dtype_text:
|
|
|
|
len = desc->dsc_length;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_varying:
|
|
|
|
len = reinterpret_cast<const vary*>(p)->vary_length;
|
|
|
|
p += sizeof(USHORT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-06-14 05:16:54 +02:00
|
|
|
CharSet* charSet = INTL_charset_lookup(tdbb, DSC_GET_CHARSET(desc));
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2005-06-14 05:16:54 +02:00
|
|
|
if (!charSet->wellFormed(len, p))
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_malformed_string));
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
2007-05-23 04:26:27 +02:00
|
|
|
else if (desc->isBlob())
|
|
|
|
{
|
2007-05-24 02:39:38 +02:00
|
|
|
if (desc->getCharSet() != CS_NONE && desc->getCharSet() != CS_BINARY)
|
2007-05-23 04:26:27 +02:00
|
|
|
{
|
2010-04-05 23:20:08 +02:00
|
|
|
const Jrd::bid* bid = request->getImpure<Jrd::bid>(
|
2010-12-04 23:15:03 +01:00
|
|
|
message->impureOffset + (ULONG)(IPTR) desc->dsc_address);
|
2007-05-23 04:26:27 +02:00
|
|
|
|
|
|
|
if (!bid->isEmpty())
|
|
|
|
{
|
2008-04-09 22:18:47 +02:00
|
|
|
AutoBlb blob(tdbb, BLB_open(tdbb, transaction/*tdbb->getTransaction()*/, bid));
|
2007-05-23 04:26:27 +02:00
|
|
|
BLB_check_well_formed(tdbb, desc, blob.getBlb());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
if (!external)
|
|
|
|
execute_looper(tdbb, request, transaction, jrd_req::req_proceed);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E _ s t a r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Start an execution running.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2010-04-02 23:48:15 +02:00
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
BLKCHK(request, type_req);
|
|
|
|
BLKCHK(transaction, type_tra);
|
|
|
|
|
|
|
|
if (request->req_flags & req_active)
|
2008-08-30 05:14:08 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_sync) << Arg::Gds(isc_reqinuse));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (transaction->tra_flags & TRA_prepared)
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_no_trans));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
JrdStatement* statement = request->getStatement();
|
2010-08-05 17:55:49 +02:00
|
|
|
const jrd_prc* proc = statement->procedure;
|
2009-12-31 12:24:28 +01:00
|
|
|
|
2011-11-10 15:35:40 +01:00
|
|
|
if (proc && !proc->isImplemented())
|
2009-12-31 12:24:28 +01:00
|
|
|
{
|
|
|
|
status_exception::raise(
|
|
|
|
Arg::Gds(isc_proc_pack_not_implemented) <<
|
2010-01-27 05:32:27 +01:00
|
|
|
Arg::Str(proc->getName().identifier) << Arg::Str(proc->getName().package));
|
2009-12-31 12:24:28 +01:00
|
|
|
}
|
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
/* Post resources to transaction block. In particular, the interest locks
|
|
|
|
on relations/indices are copied to the transaction, which is very
|
|
|
|
important for (short-lived) dynamically compiled requests. This will
|
|
|
|
provide transaction stability by preventing a relation from being
|
|
|
|
dropped after it has been referenced from an active transaction. */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
TRA_post_resources(tdbb, transaction, statement->resources);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-01-07 16:15:06 +01:00
|
|
|
Lock* lock = transaction->tra_cancel_lock;
|
|
|
|
if (lock && lock->lck_logical == LCK_none)
|
2008-01-26 13:57:52 +01:00
|
|
|
LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT);
|
2007-01-07 16:15:06 +01:00
|
|
|
|
2004-12-07 02:19:55 +01:00
|
|
|
TRA_attach_request(transaction, request);
|
2010-04-19 00:19:11 +02:00
|
|
|
request->req_flags &= req_in_use;
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_flags |= req_active;
|
|
|
|
request->req_flags &= ~req_reserved;
|
2002-11-21 00:18:16 +01:00
|
|
|
request->req_operation = jrd_req::req_evaluate;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// set up to count records affected by request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->req_records_selected = 0;
|
|
|
|
request->req_records_updated = 0;
|
|
|
|
request->req_records_inserted = 0;
|
|
|
|
request->req_records_deleted = 0;
|
|
|
|
|
2006-01-25 13:11:37 +01:00
|
|
|
request->req_records_affected.clear();
|
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// CVC: set up to count virtual operations on SQL views.
|
2002-06-30 11:58:20 +02:00
|
|
|
|
|
|
|
request->req_view_flags = 0;
|
|
|
|
request->req_top_view_store = NULL;
|
|
|
|
request->req_top_view_modify = NULL;
|
|
|
|
request->req_top_view_erase = NULL;
|
|
|
|
|
2003-02-12 20:12:15 +01:00
|
|
|
// Store request start time for timestamp work
|
2004-10-30 21:41:54 +02:00
|
|
|
request->req_timestamp.validate();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-23 21:17:30 +01:00
|
|
|
// Set all invariants to not computed.
|
2010-10-12 13:36:51 +02:00
|
|
|
const ULONG* const* ptr, * const* end;
|
2010-04-19 00:19:11 +02:00
|
|
|
for (ptr = statement->invariants.begin(), end = statement->invariants.end();
|
|
|
|
ptr < end; ++ptr)
|
2003-02-12 20:12:15 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
impure_value* impure = request->getImpure<impure_value>(**ptr);
|
2003-11-23 21:17:30 +01:00
|
|
|
impure->vlu_flags = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
if (statement->sqlText)
|
2009-02-05 21:41:47 +01:00
|
|
|
tdbb->bumpStats(RuntimeStatistics::STMT_EXECUTES);
|
2006-10-07 12:53:01 +02:00
|
|
|
|
2003-02-12 20:12:15 +01:00
|
|
|
// Start a save point if not in middle of one
|
2010-04-02 23:48:15 +02:00
|
|
|
if (transaction && (transaction != attachment->getSysTransaction())) {
|
2002-11-03 18:29:51 +01:00
|
|
|
VIO_start_save_point(tdbb, transaction);
|
|
|
|
}
|
2003-02-12 20:12:15 +01:00
|
|
|
|
2006-07-04 16:44:43 +02:00
|
|
|
request->req_src_line = 0;
|
|
|
|
request->req_src_column = 0;
|
|
|
|
|
2010-04-04 10:52:10 +02:00
|
|
|
looper_seh(tdbb, request);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:12:15 +01:00
|
|
|
// If any requested modify/delete/insert ops have completed, forget them
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-04-02 23:48:15 +02:00
|
|
|
if (transaction && (transaction != attachment->getSysTransaction()) &&
|
|
|
|
transaction->tra_save_point && !(transaction->tra_save_point->sav_flags & SAV_user) &&
|
2003-02-12 20:12:15 +01:00
|
|
|
!transaction->tra_save_point->sav_verb_count)
|
|
|
|
{
|
|
|
|
// Forget about any undo for this verb
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-03 18:29:51 +01:00
|
|
|
VIO_verb_cleanup(tdbb, transaction);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
void EXE_unwind(thread_db* tdbb, jrd_req* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E _ u n w i n d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2010-04-19 00:19:11 +02:00
|
|
|
* Unwind a request, maybe active, maybe not.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DEV_BLKCHK(request, type_req);
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
if (request->req_flags & req_active)
|
2007-12-04 14:44:56 +01:00
|
|
|
{
|
2010-04-19 00:19:11 +02:00
|
|
|
const JrdStatement* statement = request->getStatement();
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (statement->fors.getCount() || request->req_ext_stmt)
|
2007-12-04 14:44:56 +01:00
|
|
|
{
|
2004-08-30 20:11:08 +02:00
|
|
|
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_req* old_request = tdbb->getRequest();
|
|
|
|
jrd_tra* old_transaction = tdbb->getTransaction();
|
2007-12-04 14:44:56 +01:00
|
|
|
try {
|
|
|
|
tdbb->setRequest(request);
|
|
|
|
tdbb->setTransaction(request->req_transaction);
|
2003-12-31 06:36:12 +01:00
|
|
|
|
2010-08-05 17:55:49 +02:00
|
|
|
for (const RecordSource* const* ptr = statement->fors.begin();
|
2010-04-19 00:19:11 +02:00
|
|
|
ptr != statement->fors.end(); ++ptr)
|
2007-12-04 14:44:56 +01:00
|
|
|
{
|
2009-12-09 19:45:44 +01:00
|
|
|
(*ptr)->close(tdbb);
|
2007-12-04 14:44:56 +01:00
|
|
|
}
|
2006-03-10 18:46:18 +01:00
|
|
|
|
2009-12-09 19:45:44 +01:00
|
|
|
while (request->req_ext_stmt)
|
2008-04-09 22:18:47 +02:00
|
|
|
request->req_ext_stmt->close(tdbb);
|
2007-12-04 14:44:56 +01:00
|
|
|
}
|
2007-12-05 01:03:15 +01:00
|
|
|
catch (const Firebird::Exception&)
|
2006-03-10 18:46:18 +01:00
|
|
|
{
|
2007-12-04 14:44:56 +01:00
|
|
|
tdbb->setRequest(old_request);
|
|
|
|
tdbb->setTransaction(old_transaction);
|
|
|
|
throw;
|
2006-03-10 18:46:18 +01:00
|
|
|
}
|
2007-12-04 14:44:56 +01:00
|
|
|
|
2007-12-03 16:46:39 +01:00
|
|
|
tdbb->setRequest(old_request);
|
|
|
|
tdbb->setTransaction(old_transaction);
|
2006-03-10 18:46:18 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
release_blobs(tdbb, request);
|
|
|
|
}
|
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
delete request->resultSet;
|
|
|
|
request->resultSet = NULL;
|
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
request->req_sorts.unlinkAll();
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->req_proc_sav_point && (request->req_flags & req_proc_fetch))
|
|
|
|
release_proc_save_points(request);
|
|
|
|
|
2004-12-07 02:19:55 +01:00
|
|
|
TRA_detach_request(request);
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_flags &= ~(req_active | req_proc_fetch | req_reserved);
|
|
|
|
request->req_flags |= req_abort | req_stall;
|
2004-10-30 21:41:54 +02:00
|
|
|
request->req_timestamp.invalidate();
|
2009-02-01 23:10:12 +01:00
|
|
|
request->req_proc_inputs = NULL;
|
|
|
|
request->req_proc_caller = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-10 03:23:53 +02:00
|
|
|
// Execute an external procedure.
|
|
|
|
static void execute_ext_procedure(thread_db* tdbb, jrd_req* request)
|
|
|
|
{
|
|
|
|
const JrdStatement* statement = request->getStatement();
|
|
|
|
|
|
|
|
fb_assert(statement->topNode->kind == DmlNode::KIND_STATEMENT);
|
|
|
|
const CompoundStmtNode* extStmts = StmtNode::as<CompoundStmtNode>(
|
|
|
|
static_cast<const StmtNode*>(statement->topNode));
|
|
|
|
fb_assert(extStmts);
|
|
|
|
|
|
|
|
switch (request->req_operation)
|
|
|
|
{
|
|
|
|
case jrd_req::req_evaluate:
|
2011-10-16 22:36:07 +02:00
|
|
|
request->req_message = extStmts->statements[e_extrout_input_message]->as<MessageNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
request->req_flags |= req_stall;
|
|
|
|
request->req_operation = jrd_req::req_receive;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case jrd_req::req_sync:
|
|
|
|
{
|
|
|
|
const MessageNode* outMsgNode =
|
2011-10-16 22:36:07 +02:00
|
|
|
extStmts->statements[e_extrout_output_message]->as<MessageNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
fb_assert(outMsgNode);
|
|
|
|
|
|
|
|
const Format* outFormat = outMsgNode->format;
|
|
|
|
|
|
|
|
if (!request->resultSet)
|
|
|
|
{
|
|
|
|
const MessageNode* inMsgNode =
|
2011-10-16 22:36:07 +02:00
|
|
|
extStmts->statements[e_extrout_input_message]->as<MessageNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
fb_assert(inMsgNode && request->req_message == inMsgNode);
|
|
|
|
|
|
|
|
const CompoundStmtNode* list =
|
2011-10-16 22:36:07 +02:00
|
|
|
extStmts->statements[e_extrout_input_assign]->as<CompoundStmtNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
|
|
|
|
|
|
|
|
const Format* format = inMsgNode->format;
|
|
|
|
|
|
|
|
// Clear the flags from the input message.
|
|
|
|
USHORT* impure_flags = request->getImpure<USHORT>(inMsgNode->impureFlags);
|
|
|
|
memset(impure_flags, 0, sizeof(USHORT) * format->fmt_count);
|
|
|
|
|
|
|
|
// Clear the flags from the output message.
|
|
|
|
impure_flags = request->getImpure<USHORT>(outMsgNode->impureFlags);
|
|
|
|
memset(impure_flags, 0, sizeof(USHORT) * outFormat->fmt_count);
|
|
|
|
|
|
|
|
// Validate/move input parameters.
|
|
|
|
for (size_t i = 0; i < list->statements.getCount(); ++i)
|
|
|
|
{
|
|
|
|
EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
|
|
|
|
list->statements[i].getObject()));
|
|
|
|
}
|
|
|
|
|
|
|
|
const MessageNode* inMsgNode2 =
|
2011-10-16 22:36:07 +02:00
|
|
|
extStmts->statements[e_extrout_input_message2]->as<MessageNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
if (!inMsgNode2)
|
|
|
|
inMsgNode2 = inMsgNode;
|
|
|
|
|
|
|
|
const MessageNode* outMsgNode2 =
|
2011-10-16 22:36:07 +02:00
|
|
|
extStmts->statements[e_extrout_output_message2]->as<MessageNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
if (!outMsgNode2)
|
|
|
|
outMsgNode2 = outMsgNode;
|
|
|
|
|
|
|
|
UCHAR* inMsg = request->getImpure<UCHAR>(inMsgNode2->impureOffset);
|
|
|
|
UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode2->impureOffset);
|
|
|
|
|
2011-10-16 22:36:07 +02:00
|
|
|
// Set all output fields to null.
|
|
|
|
memset(outMsg, 0, outMsgNode2->format->fmt_length);
|
|
|
|
|
|
|
|
if (statement->procedure)
|
|
|
|
request->resultSet = statement->procedure->getExternal()->open(tdbb, inMsg, outMsg);
|
|
|
|
else if (statement->function)
|
|
|
|
statement->function->fun_external->execute(tdbb, inMsg, outMsg);
|
2011-07-10 03:23:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
request->req_message = outMsgNode;
|
2011-10-16 22:36:07 +02:00
|
|
|
|
|
|
|
bool result = statement->procedure ? request->resultSet->fetch(tdbb) : true;
|
2011-07-10 03:23:53 +02:00
|
|
|
UCHAR* outMsg = request->getImpure<UCHAR>(outMsgNode->impureOffset);
|
|
|
|
|
|
|
|
// Set the eof flag.
|
|
|
|
const dsc& eofDesc = outFormat->fmt_desc[outFormat->fmt_count - 1];
|
|
|
|
fb_assert(eofDesc.dsc_dtype == dtype_short);
|
|
|
|
*((SSHORT*)(UCHAR*) (outMsg + (IPTR) eofDesc.dsc_address)) = (SSHORT) result;
|
|
|
|
|
|
|
|
const CompoundStmtNode* list =
|
2011-10-16 22:36:07 +02:00
|
|
|
extStmts->statements[e_extrout_output_assign]->as<CompoundStmtNode>();
|
2011-07-10 03:23:53 +02:00
|
|
|
fb_assert(list && (list->onlyAssignments || list->statements.isEmpty()));
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
// Validate/move output parameters.
|
|
|
|
for (size_t i = 0; i < list->statements.getCount(); ++i)
|
|
|
|
{
|
|
|
|
EXE_assignment(tdbb, static_cast<const AssignmentNode*>(
|
|
|
|
list->statements[i].getObject()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
static void execute_looper(thread_db* tdbb,
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_req* request,
|
2008-12-20 09:12:19 +01:00
|
|
|
jrd_tra* transaction, jrd_req::req_s next_state)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ l o o p e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Wrapper around looper. This will execute
|
|
|
|
* looper with the save point mechanism.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
DEV_BLKCHK(request, type_req);
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2010-04-02 23:48:15 +02:00
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// Start a save point
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!(request->req_flags & req_proc_fetch) && request->req_transaction)
|
2008-03-04 07:02:32 +01:00
|
|
|
{
|
2010-04-02 23:48:15 +02:00
|
|
|
if (transaction && (transaction != attachment->getSysTransaction()))
|
2002-11-03 18:29:51 +01:00
|
|
|
VIO_start_save_point(tdbb, transaction);
|
2008-03-04 07:02:32 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->req_flags &= ~req_stall;
|
|
|
|
request->req_operation = next_state;
|
2002-09-28 16:04:35 +02:00
|
|
|
|
2008-09-01 15:18:02 +02:00
|
|
|
EXE_looper(tdbb, request, request->req_next);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// If any requested modify/delete/insert ops have completed, forget them
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-14 10:19:00 +01:00
|
|
|
if (!(request->req_flags & req_proc_fetch) && request->req_transaction)
|
|
|
|
{
|
2010-04-02 23:48:15 +02:00
|
|
|
if (transaction && (transaction != attachment->getSysTransaction()) &&
|
|
|
|
transaction->tra_save_point && !transaction->tra_save_point->sav_verb_count)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2009-11-22 04:56:20 +01:00
|
|
|
// Forget about any undo for this verb
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
VIO_verb_cleanup(tdbb, transaction);
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
void EXE_execute_triggers(thread_db* tdbb,
|
2004-02-20 07:43:27 +01:00
|
|
|
trig_vec** triggers,
|
2008-03-25 20:41:13 +01:00
|
|
|
record_param* old_rpb,
|
|
|
|
record_param* new_rpb,
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
jrd_req::req_ta trigger_action, StmtNode::WhichTrigger which_trig)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ t r i g g e r s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute group of triggers. Return pointer to failing trigger
|
|
|
|
* if any blow up.
|
|
|
|
*
|
|
|
|
**************************************/
|
2009-10-21 02:42:38 +02:00
|
|
|
if (!*triggers)
|
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2010-03-08 17:16:30 +01:00
|
|
|
jrd_req* const request = tdbb->getRequest();
|
|
|
|
jrd_tra* const transaction = request ? request->req_transaction : tdbb->getTransaction();
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
trig_vec* vector = *triggers;
|
2008-03-28 14:21:59 +01:00
|
|
|
Record* const old_rec = old_rpb ? old_rpb->rpb_record : NULL;
|
|
|
|
Record* const new_rec = new_rpb ? new_rpb->rpb_record : NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-12-05 12:06:46 +01:00
|
|
|
Record* null_rec = NULL;
|
|
|
|
|
2006-11-05 19:30:36 +01:00
|
|
|
if (!old_rec && !new_rec)
|
|
|
|
{
|
|
|
|
// this is a database trigger
|
|
|
|
}
|
|
|
|
else if (!old_rec || !new_rec)
|
|
|
|
{
|
2005-12-05 12:06:46 +01:00
|
|
|
const Record* record = old_rec ? old_rec : new_rec;
|
|
|
|
fb_assert(record && record->rec_format);
|
|
|
|
// copy the record
|
2008-12-20 09:12:19 +01:00
|
|
|
null_rec = FB_NEW_RPT(record->rec_pool, record->rec_length) Record(record->rec_pool);
|
2005-12-05 14:25:03 +01:00
|
|
|
null_rec->rec_length = record->rec_length;
|
|
|
|
null_rec->rec_format = record->rec_format;
|
2005-12-05 12:06:46 +01:00
|
|
|
// zero the record buffer
|
|
|
|
memset(null_rec->rec_data, 0, record->rec_length);
|
|
|
|
// initialize all fields to missing
|
|
|
|
const SSHORT n = (record->rec_format->fmt_count + 7) >> 3;
|
|
|
|
memset(null_rec->rec_data, 0xFF, n);
|
|
|
|
}
|
|
|
|
|
2010-03-08 17:16:30 +01:00
|
|
|
const Firebird::TimeStamp timestamp =
|
|
|
|
request ? request->req_timestamp : Firebird::TimeStamp::getCurrentTimeStamp();
|
|
|
|
|
2001-12-28 07:31:38 +01:00
|
|
|
try
|
|
|
|
{
|
2002-09-19 18:02:58 +02:00
|
|
|
for (trig_vec::iterator ptr = vector->begin(); ptr != vector->end(); ++ptr)
|
2001-12-28 07:31:38 +01:00
|
|
|
{
|
2002-09-19 18:02:58 +02:00
|
|
|
ptr->compile(tdbb);
|
2006-11-05 19:30:36 +01:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
if (ptr->extTrigger)
|
2008-03-25 20:41:13 +01:00
|
|
|
{
|
2009-10-21 02:42:38 +02:00
|
|
|
//// TODO: trace stuff
|
|
|
|
|
|
|
|
ptr->extTrigger->execute(tdbb, (Firebird::ExternalTrigger::Action) trigger_action,
|
|
|
|
old_rpb, new_rpb);
|
2008-03-25 20:41:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-04-19 00:19:11 +02:00
|
|
|
jrd_req* trigger = ptr->statement->findRequest(tdbb);
|
2010-08-05 02:44:58 +02:00
|
|
|
|
2011-02-11 15:26:14 +01:00
|
|
|
if (trigger->req_rpb.getCount() > 0)
|
2009-10-21 02:42:38 +02:00
|
|
|
{
|
2011-02-11 15:26:14 +01:00
|
|
|
trigger->req_rpb[0].rpb_record = old_rec ? old_rec : null_rec;
|
|
|
|
|
|
|
|
if (old_rec && trigger_action != jrd_req::req_trigger_insert)
|
|
|
|
{
|
|
|
|
trigger->req_rpb[0].rpb_number = old_rpb->rpb_number;
|
|
|
|
trigger->req_rpb[0].rpb_number.setValid(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
trigger->req_rpb[0].rpb_number.setValid(false);
|
2009-10-21 02:42:38 +02:00
|
|
|
}
|
2011-02-11 15:26:14 +01:00
|
|
|
|
|
|
|
if (trigger->req_rpb.getCount() > 1)
|
|
|
|
trigger->req_rpb[1].rpb_record = new_rec ? new_rec : null_rec;
|
2008-03-25 20:41:13 +01:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (new_rec && !(which_trig == StmtNode::PRE_TRIG &&
|
|
|
|
trigger_action == jrd_req::req_trigger_insert))
|
2009-10-21 02:42:38 +02:00
|
|
|
{
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (which_trig == StmtNode::PRE_TRIG &&
|
|
|
|
trigger_action == jrd_req::req_trigger_update)
|
|
|
|
{
|
2009-10-21 02:42:38 +02:00
|
|
|
new_rpb->rpb_number = old_rpb->rpb_number;
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
}
|
2008-03-25 20:41:13 +01:00
|
|
|
|
2011-02-11 15:26:14 +01:00
|
|
|
if (trigger->req_rpb.getCount() > 1)
|
|
|
|
{
|
|
|
|
trigger->req_rpb[1].rpb_number = new_rpb->rpb_number;
|
|
|
|
trigger->req_rpb[1].rpb_number.setValid(true);
|
|
|
|
}
|
2009-10-21 02:42:38 +02:00
|
|
|
}
|
2010-08-05 02:44:58 +02:00
|
|
|
else if (trigger->req_rpb.getCount() > 1)
|
2009-10-21 02:42:38 +02:00
|
|
|
trigger->req_rpb[1].rpb_number.setValid(false);
|
2009-02-02 04:35:52 +01:00
|
|
|
|
2010-03-08 17:16:30 +01:00
|
|
|
trigger->req_timestamp = timestamp;
|
2009-10-21 02:42:38 +02:00
|
|
|
trigger->req_trigger_action = trigger_action;
|
2009-02-01 23:10:12 +01:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
TraceTrigExecute trace(tdbb, trigger, which_trig);
|
2009-02-01 23:10:12 +01:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
EXE_start(tdbb, trigger, transaction);
|
2009-02-01 23:10:12 +01:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
trigger->req_attachment = NULL;
|
|
|
|
trigger->req_flags &= ~req_in_use;
|
|
|
|
trigger->req_timestamp.invalidate();
|
|
|
|
|
|
|
|
const bool ok = (trigger->req_operation != jrd_req::req_unwind);
|
|
|
|
trace.finish(ok ? res_successful : res_failed);
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
trigger_failure(tdbb, trigger);
|
|
|
|
break;
|
|
|
|
}
|
2001-12-28 07:31:38 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2005-12-05 12:06:46 +01:00
|
|
|
delete null_rec;
|
2001-12-28 07:31:38 +01:00
|
|
|
if (vector != *triggers) {
|
2002-09-19 18:02:58 +02:00
|
|
|
MET_release_triggers(tdbb, &vector);
|
2001-12-28 07:31:38 +01:00
|
|
|
}
|
|
|
|
}
|
2009-10-22 01:48:07 +02:00
|
|
|
catch (const Firebird::Exception&)
|
2001-12-28 07:31:38 +01:00
|
|
|
{
|
2005-12-05 12:06:46 +01:00
|
|
|
delete null_rec;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (vector != *triggers) {
|
2002-09-19 18:02:58 +02:00
|
|
|
MET_release_triggers(tdbb, &vector);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2009-10-21 02:42:38 +02:00
|
|
|
|
|
|
|
throw;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-06 17:26:55 +02:00
|
|
|
static void stuff_stack_trace(const jrd_req* request)
|
|
|
|
{
|
|
|
|
Firebird::string sTrace;
|
|
|
|
bool isEmpty = true;
|
|
|
|
|
2004-10-04 10:15:00 +02:00
|
|
|
for (const jrd_req* req = request; req; req = req->req_caller)
|
2004-08-06 17:26:55 +02:00
|
|
|
{
|
2010-04-19 00:19:11 +02:00
|
|
|
const JrdStatement* statement = req->getStatement();
|
2004-08-06 17:26:55 +02:00
|
|
|
Firebird::string name;
|
2006-01-03 12:28:24 +01:00
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
if (statement->triggerName.length())
|
2009-11-23 06:24:29 +01:00
|
|
|
{
|
2004-08-06 17:26:55 +02:00
|
|
|
name = "At trigger '";
|
2010-04-19 00:19:11 +02:00
|
|
|
name += statement->triggerName.c_str();
|
2004-08-06 17:26:55 +02:00
|
|
|
}
|
2010-04-19 00:19:11 +02:00
|
|
|
else if (statement->procedure)
|
2009-11-23 06:24:29 +01:00
|
|
|
{
|
2011-10-03 00:11:41 +02:00
|
|
|
name = statement->parentStatement ? "At sub procedure '" : "At procedure '";
|
2010-04-19 00:19:11 +02:00
|
|
|
name += statement->procedure->getName().toString().c_str();
|
2004-08-06 17:26:55 +02:00
|
|
|
}
|
2010-04-19 00:19:11 +02:00
|
|
|
else if (statement->function)
|
2009-12-21 18:43:01 +01:00
|
|
|
{
|
2011-10-03 00:11:41 +02:00
|
|
|
name = statement->parentStatement ? "At sub function '" : "At function '";
|
2010-04-19 00:19:11 +02:00
|
|
|
name += statement->function->getName().toString().c_str();
|
2009-12-21 18:43:01 +01:00
|
|
|
}
|
2004-08-06 17:26:55 +02:00
|
|
|
|
|
|
|
if (! name.isEmpty())
|
|
|
|
{
|
|
|
|
name.trim();
|
|
|
|
|
2006-07-05 10:18:48 +02:00
|
|
|
if (sTrace.length() + name.length() + 2 > MAX_STACK_TRACE)
|
2004-08-06 17:26:55 +02:00
|
|
|
break;
|
|
|
|
|
2009-11-23 06:24:29 +01:00
|
|
|
if (isEmpty)
|
|
|
|
{
|
2004-08-06 17:26:55 +02:00
|
|
|
isEmpty = false;
|
|
|
|
sTrace += name + "'";
|
|
|
|
}
|
2006-07-04 16:44:43 +02:00
|
|
|
else {
|
2004-08-06 17:26:55 +02:00
|
|
|
sTrace += "\n" + name + "'";
|
2006-07-04 16:44:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (req->req_src_line)
|
|
|
|
{
|
|
|
|
Firebird::string src_info;
|
|
|
|
src_info.printf(" line: %u, col: %u", req->req_src_line, req->req_src_column);
|
2006-07-05 10:18:48 +02:00
|
|
|
|
|
|
|
if (sTrace.length() + src_info.length() > MAX_STACK_TRACE)
|
|
|
|
break;
|
2006-07-06 04:54:59 +02:00
|
|
|
|
|
|
|
sTrace += src_info;
|
2006-07-04 16:44:43 +02:00
|
|
|
}
|
2004-08-06 17:26:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isEmpty)
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post_nothrow(Arg::Gds(isc_stack_trace) << Arg::Str(sTrace));
|
2004-08-06 17:26:55 +02:00
|
|
|
}
|
|
|
|
|
2004-08-21 11:29:46 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* node, bool stmtExpr)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-09-01 15:18:02 +02:00
|
|
|
* E X E _ l o o p e r
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Cycle thru request execution tree. Return next node for
|
|
|
|
* execution on stall or request complete.
|
|
|
|
*
|
|
|
|
**************************************/
|
2011-02-09 11:59:24 +01:00
|
|
|
if (!request->req_transaction)
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_req_no_trans));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
2010-04-02 23:48:15 +02:00
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
|
|
|
jrd_tra* sysTransaction = attachment->getSysTransaction();
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2010-12-04 23:15:03 +01:00
|
|
|
|
|
|
|
if (!node || node->kind != DmlNode::KIND_STATEMENT)
|
|
|
|
BUGCHECK(147);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-28 07:31:38 +01:00
|
|
|
// Save the old pool and request to restore on exit
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
StmtNode::ExeState exeState(tdbb);
|
2004-08-30 20:11:08 +02:00
|
|
|
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
|
2001-12-28 07:31:38 +01:00
|
|
|
|
2007-12-03 16:46:39 +01:00
|
|
|
tdbb->setRequest(request);
|
2011-02-09 11:59:24 +01:00
|
|
|
tdbb->setTransaction(request->req_transaction);
|
2008-09-01 15:18:02 +02:00
|
|
|
|
2010-11-14 18:25:48 +01:00
|
|
|
if (!stmtExpr)
|
2008-09-01 15:18:02 +02:00
|
|
|
{
|
|
|
|
fb_assert(request->req_caller == NULL);
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
request->req_caller = exeState.oldRequest;
|
2008-09-01 15:18:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
request->req_operation = jrd_req::req_evaluate;
|
2001-12-28 07:31:38 +01:00
|
|
|
|
2011-02-09 11:59:24 +01:00
|
|
|
const SLONG save_point_number = (request->req_transaction->tra_save_point) ?
|
|
|
|
request->req_transaction->tra_save_point->sav_number : 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-12-04 22:36:29 +01:00
|
|
|
tdbb->tdbb_flags &= ~(TDBB_stack_trace_done | TDBB_sys_error);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-29 12:41:29 +01:00
|
|
|
// Execute stuff until we drop
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
const JrdStatement* statement = request->getStatement();
|
|
|
|
|
2011-10-16 22:36:07 +02:00
|
|
|
bool runExternal = (statement->procedure && statement->procedure->getExternal()) ||
|
|
|
|
(statement->function && statement->function->fun_external);
|
2009-10-21 02:42:38 +02:00
|
|
|
|
2010-11-14 18:25:48 +01:00
|
|
|
while (runExternal ||
|
|
|
|
(node && !(request->req_flags & req_stall) &&
|
|
|
|
(!stmtExpr || request->req_operation == jrd_req::req_evaluate)))
|
2001-12-29 12:41:29 +01:00
|
|
|
{
|
2002-04-03 01:12:03 +02:00
|
|
|
try {
|
2011-10-16 22:36:07 +02:00
|
|
|
if ((statement->procedure && statement->procedure->getExternal()) ||
|
|
|
|
(statement->function && statement->function->fun_external))
|
2009-10-21 02:42:38 +02:00
|
|
|
{
|
|
|
|
if (runExternal)
|
|
|
|
runExternal = false;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
2011-07-10 03:23:53 +02:00
|
|
|
execute_ext_procedure(tdbb, request);
|
2009-10-21 02:42:38 +02:00
|
|
|
goto end;
|
|
|
|
}
|
2002-04-03 01:12:03 +02:00
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
if (request->req_operation == jrd_req::req_evaluate && (--tdbb->tdbb_quantum < 0))
|
2003-12-22 11:00:59 +01:00
|
|
|
JRD_reschedule(tdbb, 0, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-05 01:55:54 +01:00
|
|
|
if (request->req_operation == jrd_req::req_evaluate && node->hasLineColumn)
|
|
|
|
{
|
|
|
|
request->req_src_line = node->line;
|
|
|
|
request->req_src_column = node->column;
|
|
|
|
}
|
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
node = node->execute(tdbb, request, &exeState);
|
2011-02-09 22:26:18 +01:00
|
|
|
|
|
|
|
if (exeState.exit)
|
|
|
|
return node;
|
2002-04-03 01:12:03 +02:00
|
|
|
} // try
|
2009-01-14 10:19:00 +01:00
|
|
|
catch (const Firebird::Exception& ex)
|
|
|
|
{
|
2005-01-04 14:09:11 +01:00
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
|
2005-01-04 14:09:11 +01:00
|
|
|
|
2008-11-06 17:04:20 +01:00
|
|
|
request->adjustCallerStats();
|
|
|
|
|
2011-02-09 11:59:24 +01:00
|
|
|
// Ensure the transaction hasn't disappeared in the meantime
|
|
|
|
fb_assert(request->req_transaction);
|
|
|
|
|
2005-01-04 14:09:11 +01:00
|
|
|
// Skip this handling for errors coming from the nested looper calls,
|
|
|
|
// as they're already handled properly. The only need is to undo
|
|
|
|
// our own savepoints.
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (exeState.catchDisabled)
|
2009-01-14 10:19:00 +01:00
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
if (request->req_transaction != sysTransaction)
|
2009-11-23 06:24:29 +01:00
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
for (const Savepoint* save_point = request->req_transaction->tra_save_point;
|
2005-01-04 14:09:11 +01:00
|
|
|
((save_point) && (save_point_number <= save_point->sav_number));
|
2011-02-09 11:59:24 +01:00
|
|
|
save_point = request->req_transaction->tra_save_point)
|
2005-01-04 14:09:11 +01:00
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
++request->req_transaction->tra_save_point->sav_verb_count;
|
|
|
|
EXE_verb_cleanup(tdbb, request->req_transaction);
|
2005-01-04 14:09:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_punt();
|
2002-04-03 01:12:03 +02:00
|
|
|
}
|
|
|
|
|
2005-01-04 14:09:11 +01:00
|
|
|
// If the database is already bug-checked, then get out
|
2002-04-03 01:12:03 +02:00
|
|
|
if (dbb->dbb_flags & DBB_bugcheck) {
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
|
2002-04-03 01:12:03 +02:00
|
|
|
}
|
|
|
|
|
2005-01-04 14:09:11 +01:00
|
|
|
// Since an error happened, the current savepoint needs to be undone
|
2011-02-09 11:59:24 +01:00
|
|
|
if (request->req_transaction != sysTransaction &&
|
|
|
|
request->req_transaction->tra_save_point)
|
2005-07-25 07:13:01 +02:00
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
++request->req_transaction->tra_save_point->sav_verb_count;
|
|
|
|
EXE_verb_cleanup(tdbb, request->req_transaction);
|
2002-04-03 01:12:03 +02:00
|
|
|
}
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
exeState.errorPending = true;
|
|
|
|
exeState.catchDisabled = true;
|
|
|
|
request->req_operation = jrd_req::req_unwind;
|
|
|
|
request->req_label = 0;
|
|
|
|
|
|
|
|
if (!(tdbb->tdbb_flags & TDBB_stack_trace_done) && !(tdbb->tdbb_flags & TDBB_sys_error))
|
2009-11-23 06:24:29 +01:00
|
|
|
{
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
stuff_stack_trace(request);
|
|
|
|
tdbb->tdbb_flags |= TDBB_stack_trace_done;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
} // while()
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
request->adjustCallerStats();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
fb_assert(request->req_auto_trans.getCount() == 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
// If there is no node, assume we have finished processing the
|
|
|
|
// request unless we are in the middle of processing an
|
|
|
|
// asynchronous message
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (!stmtExpr && !node)
|
2008-11-30 03:23:01 +01:00
|
|
|
{
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
// Close active cursors
|
|
|
|
for (const Cursor* const* ptr = request->req_cursors.begin();
|
|
|
|
ptr < request->req_cursors.end(); ++ptr)
|
|
|
|
{
|
|
|
|
if (*ptr)
|
|
|
|
(*ptr)->close(tdbb);
|
|
|
|
}
|
|
|
|
|
|
|
|
request->req_flags &= ~(req_active | req_reserved);
|
|
|
|
request->req_timestamp.invalidate();
|
|
|
|
release_blobs(tdbb, request);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
end:
|
|
|
|
request->req_next = node;
|
2011-02-09 11:59:24 +01:00
|
|
|
tdbb->setTransaction(exeState.oldTransaction);
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
tdbb->setRequest(exeState.oldRequest);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (!stmtExpr)
|
2009-01-14 10:19:00 +01:00
|
|
|
{
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
fb_assert(request->req_caller == exeState.oldRequest);
|
|
|
|
request->req_caller = NULL;
|
|
|
|
}
|
|
|
|
|
2011-02-09 11:59:24 +01:00
|
|
|
// Ensure the transaction hasn't disappeared in the meantime
|
|
|
|
fb_assert(request->req_transaction);
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
// In the case of a pending error condition (one which did not
|
|
|
|
// result in a exception to the top of looper), we need to
|
|
|
|
// delete the last savepoint
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (exeState.errorPending)
|
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
if (request->req_transaction != sysTransaction)
|
2009-01-14 10:19:00 +01:00
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
for (const Savepoint* save_point = request->req_transaction->tra_save_point;
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
((save_point) && (save_point_number <= save_point->sav_number));
|
2011-02-09 11:59:24 +01:00
|
|
|
save_point = request->req_transaction->tra_save_point)
|
2009-01-14 10:19:00 +01:00
|
|
|
{
|
2011-02-09 11:59:24 +01:00
|
|
|
++request->req_transaction->tra_save_point->sav_verb_count;
|
|
|
|
EXE_verb_cleanup(tdbb, request->req_transaction);
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_punt();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
// if the request was aborted, assume that we have already
|
|
|
|
// longjmp'ed to the top of looper, and therefore that the
|
|
|
|
// last savepoint has already been deleted
|
2008-08-05 17:16:58 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
if (request->req_flags & req_abort) {
|
|
|
|
ERR_post(Arg::Gds(isc_req_sync));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
return node;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
// Start looper under Windows SEH (Structured Exception Handling) control
|
|
|
|
static void looper_seh(thread_db* tdbb, jrd_req* request)
|
|
|
|
{
|
|
|
|
#ifdef WIN_NT
|
|
|
|
START_CHECK_FOR_EXCEPTIONS(NULL);
|
|
|
|
#endif
|
|
|
|
// TODO:
|
|
|
|
// 1. Try to fix the problem with MSVC C++ runtime library, making
|
|
|
|
// even C++ exceptions that are implemented in terms of Win32 SEH
|
|
|
|
// getting catched by the SEH handler below.
|
|
|
|
// 2. Check if it really is correct that only Win32 catches CPU
|
|
|
|
// exceptions (such as SEH) here. Shouldn't any platform capable
|
|
|
|
// of handling signals use this stuff?
|
|
|
|
// (see jrd/ibsetjmp.h for implementation of these macros)
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-04 23:15:03 +01:00
|
|
|
EXE_looper(tdbb, request, static_cast<const StmtNode*>(request->getStatement()->topNode));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactored the support for blr_handler, blr_loop, blr_exec_sql, blr_exec_into, blr_exec_stmt,
blr_start_savepoint, blr_end_savepoint, blr_store, blr_store2, blr_erase, blr_modify,
blr_modify2, blr_exec_proc, blr_exec_proc2, blr_exec_pid, blr_dcl_cursor, blr_cursor_stmt,
blr_set_generator, blr_receive, blr_stall, blr_select, blr_block, blr_error_handler,
blr_label, blr_leave, blr_continue and the source info node.
2010-11-29 03:17:04 +01:00
|
|
|
#ifdef WIN_NT
|
|
|
|
END_CHECK_FOR_EXCEPTIONS(NULL);
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static void release_blobs(thread_db* tdbb, jrd_req* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e l e a s e _ b l o b s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release temporary blobs assigned by this request.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
DEV_BLKCHK(request, type_req);
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
jrd_tra* transaction = request->req_transaction;
|
2009-01-14 10:19:00 +01:00
|
|
|
if (transaction)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
DEV_BLKCHK(transaction, type_tra);
|
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// Release blobs bound to this request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-04-05 21:28:52 +02:00
|
|
|
if (request->req_blobs.getFirst())
|
|
|
|
{
|
2008-12-05 02:20:14 +01:00
|
|
|
while (true)
|
2006-04-06 10:18:53 +02:00
|
|
|
{
|
|
|
|
const ULONG blob_temp_id = request->req_blobs.current();
|
2008-04-05 21:28:52 +02:00
|
|
|
if (transaction->tra_blobs->locate(blob_temp_id))
|
2008-01-16 09:54:50 +01:00
|
|
|
{
|
2008-04-05 21:28:52 +02:00
|
|
|
BlobIndex *current = &transaction->tra_blobs->current();
|
2007-03-28 04:16:52 +02:00
|
|
|
if (current->bli_materialized)
|
|
|
|
{
|
|
|
|
request->req_blobs.fastRemove();
|
|
|
|
current->bli_request = NULL;
|
|
|
|
}
|
|
|
|
else
|
2007-03-22 02:42:33 +01:00
|
|
|
{
|
2008-12-05 02:20:14 +01:00
|
|
|
// Blob was created by request, is accounted for internal needs,
|
2006-04-06 10:18:53 +02:00
|
|
|
// but is not materialized. Get rid of it.
|
|
|
|
BLB_cancel(tdbb, current->bli_blob_object);
|
2008-12-05 02:20:14 +01:00
|
|
|
// Since the routine above modifies req_blobs
|
2006-04-06 10:18:53 +02:00
|
|
|
// we need to reestablish accessor position
|
|
|
|
}
|
2007-03-28 04:16:52 +02:00
|
|
|
|
|
|
|
if (request->req_blobs.locate(Firebird::locGreat, blob_temp_id))
|
|
|
|
continue;
|
2008-01-16 09:54:50 +01:00
|
|
|
|
|
|
|
break;
|
2004-06-22 22:13:10 +02:00
|
|
|
}
|
2008-01-16 09:54:50 +01:00
|
|
|
|
|
|
|
// Blob accounting inconsistent, only detected in DEV_BUILD.
|
|
|
|
fb_assert(false);
|
|
|
|
|
2006-04-06 10:18:53 +02:00
|
|
|
if (!request->req_blobs.getNext())
|
|
|
|
break;
|
2004-06-22 22:13:10 +02:00
|
|
|
}
|
2008-04-05 21:28:52 +02:00
|
|
|
}
|
2004-06-22 22:13:10 +02:00
|
|
|
|
|
|
|
request->req_blobs.clear();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// Release arrays assigned by this request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-14 10:19:00 +01:00
|
|
|
for (ArrayField** array = &transaction->tra_arrays; *array;)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
DEV_BLKCHK(*array, type_arr);
|
|
|
|
if ((*array)->arr_request == request)
|
|
|
|
BLB_release_array(*array);
|
|
|
|
else
|
|
|
|
array = &(*array)->arr_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
static void release_proc_save_points(jrd_req* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e l e a s e _ p r o c _ s a v e _ p o i n t s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release temporary blobs assigned by this request.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-03-18 06:56:06 +01:00
|
|
|
Savepoint* sav_point = request->req_proc_sav_point;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 06:24:29 +01:00
|
|
|
if (request->req_transaction)
|
|
|
|
{
|
|
|
|
while (sav_point)
|
|
|
|
{
|
2004-03-18 06:56:06 +01:00
|
|
|
Savepoint* const temp_sav_point = sav_point->sav_next;
|
2003-12-13 11:42:10 +01:00
|
|
|
delete sav_point;
|
|
|
|
sav_point = temp_sav_point;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
request->req_proc_sav_point = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-11 06:04:26 +01:00
|
|
|
static void trigger_failure(thread_db* tdbb, jrd_req* trigger)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t r i g g e r _ f a i l u r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Trigger failed, report error.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
EXE_unwind(tdbb, trigger);
|
2001-12-29 12:41:29 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
trigger->req_attachment = NULL;
|
|
|
|
trigger->req_flags &= ~req_in_use;
|
2004-10-30 21:41:54 +02:00
|
|
|
trigger->req_timestamp.invalidate();
|
2001-12-29 12:41:29 +01:00
|
|
|
|
|
|
|
if (trigger->req_flags & req_leave)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
trigger->req_flags &= ~req_leave;
|
2008-09-03 13:23:00 +02:00
|
|
|
string msg;
|
2010-04-19 00:19:11 +02:00
|
|
|
MET_trigger_msg(tdbb, msg, trigger->getStatement()->triggerName, trigger->req_label);
|
2008-09-03 13:23:00 +02:00
|
|
|
if (msg.hasData())
|
2001-12-29 12:41:29 +01:00
|
|
|
{
|
2010-04-19 00:19:11 +02:00
|
|
|
if (trigger->getStatement()->flags & JrdStatement::FLAG_SYS_TRIGGER)
|
2001-12-29 12:41:29 +01:00
|
|
|
{
|
2003-04-10 08:49:16 +02:00
|
|
|
ISC_STATUS code = PAR_symbol_to_gdscode(msg);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (code)
|
2001-12-29 12:41:29 +01:00
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_integ_fail) << Arg::Num(trigger->req_label) <<
|
|
|
|
Arg::Gds(code));
|
2001-12-29 12:41:29 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_integ_fail) << Arg::Num(trigger->req_label) <<
|
|
|
|
Arg::Gds(isc_random) << Arg::Str(msg));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
2001-12-29 12:41:29 +01:00
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_integ_fail) << Arg::Num(trigger->req_label));
|
2001-12-29 12:41:29 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
2001-12-29 12:41:29 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERR_punt();
|
2001-12-29 12:41:29 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-24 19:45:33 +02:00
|
|
|
void EXE_verb_cleanup(thread_db* tdbb, jrd_tra* transaction)
|
2005-01-04 14:09:11 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2009-10-24 19:45:33 +02:00
|
|
|
* E X E _ v e r b _ c l e a n u p
|
2005-01-04 14:09:11 +01:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* If an error happens during the backout of a savepoint, then the transaction
|
|
|
|
* must be marked 'dead' because that is the only way to clean up after a
|
|
|
|
* failed backout. The easiest way to do this is to kill the application
|
|
|
|
* by calling bugcheck.
|
|
|
|
*
|
|
|
|
**************************************/
|
2009-10-24 19:45:33 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
VIO_verb_cleanup(tdbb, transaction);
|
|
|
|
}
|
|
|
|
catch (const Firebird::Exception&)
|
|
|
|
{
|
|
|
|
if (tdbb->getDatabase()->dbb_flags & DBB_bugcheck)
|
2005-01-04 14:09:11 +01:00
|
|
|
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
|
2009-10-24 19:45:33 +02:00
|
|
|
BUGCHECK(290); // msg 290 error during savepoint backout
|
2005-01-04 14:09:11 +01:00
|
|
|
}
|
|
|
|
}
|