2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Command Oriented Query Language
|
2003-09-25 13:49:12 +02:00
|
|
|
* MODULE: exe.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Execution phase
|
|
|
|
*
|
|
|
|
* 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2004-04-29 00:36:29 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <setjmp.h>
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../qli/dtr.h"
|
|
|
|
#include "../qli/exe.h"
|
|
|
|
#include "../qli/all_proto.h"
|
|
|
|
#include "../qli/err_proto.h"
|
|
|
|
#include "../qli/eval_proto.h"
|
|
|
|
#include "../qli/exe_proto.h"
|
2004-02-02 12:02:12 +01:00
|
|
|
#include "../qli/report.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../qli/forma_proto.h"
|
|
|
|
#include "../qli/mov_proto.h"
|
|
|
|
#include "../qli/repor_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/utl_proto.h"
|
2007-04-06 12:10:10 +02:00
|
|
|
#include "../common/classes/UserBlob.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
using MsgFormat::SafeArg;
|
|
|
|
|
2002-01-04 12:34:22 +01:00
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2002-09-11 13:30:50 +02:00
|
|
|
#ifdef HAVE_VFORK_H
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <vfork.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 06:05:02 +02:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
|
|
|
|
2004-05-16 03:42:11 +02:00
|
|
|
const char* FOPEN_WRITE_TYPE = "w";
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static DSC *assignment(qli_nod*, DSC *, qli_nod*, qli_nod*, qli_par*);
|
|
|
|
static void commit_retaining(qli_nod*);
|
|
|
|
static bool copy_blob(qli_nod*, qli_par*);
|
|
|
|
static void db_error(qli_req*, ISC_STATUS *);
|
|
|
|
static void execute_abort(qli_nod*);
|
|
|
|
static void execute_assignment(qli_nod*);
|
|
|
|
static void execute_for(qli_nod*);
|
|
|
|
static void execute_modify(qli_nod*);
|
|
|
|
static void execute_output(qli_nod*);
|
|
|
|
static void execute_print(qli_nod*);
|
|
|
|
static void execute_repeat(qli_nod*);
|
|
|
|
static void execute_store(qli_nod*);
|
|
|
|
static void map_data(qli_msg*);
|
|
|
|
static void print_counts(qli_req*);
|
|
|
|
static void set_null(qli_msg*);
|
|
|
|
static void transaction_state(qli_nod*, DBB);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// definitions for SET COUNT
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-16 03:42:11 +02:00
|
|
|
const int COUNT_ITEMS = 4;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-15 21:15:58 +01:00
|
|
|
static const SCHAR count_info[] =
|
|
|
|
{
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_info_req_select_count,
|
|
|
|
isc_info_req_insert_count,
|
|
|
|
isc_info_req_update_count,
|
|
|
|
isc_info_req_delete_count
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void EXEC_abort(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ a b o r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* An asynchrous abort has been requested. Request that all
|
|
|
|
* requests be unwound and set flag.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_req* request = QLI_requests; request; request = request->req_next)
|
2008-01-15 21:15:58 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->req_handle)
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_unwind_request(status_vector, &request->req_handle, 0);
|
2008-01-15 21:15:58 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
QLI_abort = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
void EXEC_execute( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ e x e c u t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (QLI_abort)
|
|
|
|
EXEC_poll_abort();
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
if (node) {
|
2008-01-15 21:15:58 +01:00
|
|
|
switch (node->nod_type)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_abort:
|
|
|
|
execute_abort(node);
|
|
|
|
|
|
|
|
case nod_assign:
|
|
|
|
execute_assignment(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_commit_retaining:
|
|
|
|
commit_retaining(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_erase:
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
|
|
|
qli_msg* message = (qli_msg*) node->nod_arg[e_era_message];
|
|
|
|
if (message)
|
|
|
|
EXEC_send(message);
|
|
|
|
}
|
2008-01-15 21:15:58 +01:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_for:
|
|
|
|
execute_for(node);
|
|
|
|
return;
|
2008-01-15 21:15:58 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_list:
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
|
|
|
qli_nod** ptr = node->nod_arg;
|
|
|
|
for (USHORT i = 0; i < node->nod_count; i++)
|
|
|
|
EXEC_execute(*ptr++);
|
|
|
|
}
|
2008-01-15 21:15:58 +01:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_modify:
|
|
|
|
execute_modify(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_output:
|
|
|
|
execute_output(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_print:
|
|
|
|
execute_print(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_repeat:
|
|
|
|
execute_repeat(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_store:
|
|
|
|
execute_store(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_if:
|
|
|
|
if (EVAL_boolean(node->nod_arg[e_if_boolean])) {
|
|
|
|
EXEC_execute(node->nod_arg[e_if_true]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (node->nod_arg[e_if_false]) {
|
|
|
|
EXEC_execute(node->nod_arg[e_if_false]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_report_loop:
|
|
|
|
RPT_report(node);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
2004-05-16 03:42:11 +02:00
|
|
|
ERRQ_bugcheck(33); // Msg33 EXEC_execute: not implemented
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE EXEC_open_blob( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ o p e n _ b l o b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Given a blob field node, open and return the blob.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
dsc* desc = EVAL_value(node);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!desc)
|
2004-05-03 01:06:37 +02:00
|
|
|
return 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Starting from the print item, work our way back to the database block
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (node->nod_type == nod_reference)
|
|
|
|
node = node->nod_arg[0];
|
|
|
|
|
|
|
|
if (node->nod_type != nod_field)
|
2004-05-16 03:42:11 +02:00
|
|
|
ERRQ_bugcheck(34); // Msg34 print_blob: expected field node
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_ctx* context = (qli_ctx*) node->nod_arg[e_fld_context];
|
|
|
|
qli_req* request = context->ctx_request;
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB dbb = request->req_database;
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE blob = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Format blob parameter block
|
|
|
|
UCHAR bpb[20];
|
|
|
|
UCHAR* p = bpb;
|
2003-11-08 17:40:17 +01:00
|
|
|
*p++ = isc_bpb_version1;
|
|
|
|
*p++ = isc_bpb_source_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 2;
|
|
|
|
*p++ = desc->dsc_sub_type;
|
|
|
|
*p++ = desc->dsc_sub_type >> 8;
|
2003-11-08 17:40:17 +01:00
|
|
|
*p++ = isc_bpb_target_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 1;
|
|
|
|
*p++ = 1;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
const USHORT bpb_length = p - bpb;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_open_blob2(status_vector, &dbb->dbb_handle, &dbb->dbb_transaction,
|
2003-11-11 13:19:20 +01:00
|
|
|
&blob, (ISC_QUAD*) desc->dsc_address, bpb_length,
|
2003-11-10 10:16:38 +01:00
|
|
|
bpb))
|
2003-10-29 11:53:47 +01:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
ERRQ_database_error(dbb, status_vector);
|
2003-10-29 11:53:47 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return blob;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-15 21:15:58 +01:00
|
|
|
FILE* EXEC_open_output(qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ o p e n _ o u t p u t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Open output stream to re-direct output.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
// Evaluate filename and copy to a null terminated string
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
dsc* desc = EVAL_value(node->nod_arg[e_out_file]);
|
2004-02-20 07:43:27 +01:00
|
|
|
const TEXT* p = NULL;
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT temp[64];
|
2003-09-29 14:43:14 +02:00
|
|
|
SSHORT l = MOVQ_get_string(desc, &p, (vary*) temp, sizeof(temp));
|
2008-01-15 21:15:58 +01:00
|
|
|
if (l >= MAXPATHLEN)
|
|
|
|
l = MAXPATHLEN - 1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-15 21:15:58 +01:00
|
|
|
TEXT filename[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (l)
|
2008-01-15 21:15:58 +01:00
|
|
|
memcpy(filename, p, l);
|
|
|
|
|
|
|
|
filename[l] = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// If output is to a file, just do it
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!node->nod_arg[e_out_pipe]) {
|
2004-04-29 00:36:29 +02:00
|
|
|
FILE* out_file = fopen(filename, FOPEN_WRITE_TYPE);
|
2003-09-25 13:49:12 +02:00
|
|
|
if (out_file)
|
2008-01-15 21:15:58 +01:00
|
|
|
return out_file;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_print_error(42, filename);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg42 Can't open output file %s
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// Output is to a file. Setup file and fork process
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-08 01:58:10 +01:00
|
|
|
#ifdef WIN_NT
|
2004-04-29 00:36:29 +02:00
|
|
|
FILE* out_file = _popen(filename, "w");
|
2003-09-25 13:49:12 +02:00
|
|
|
if (out_file)
|
2008-01-15 21:15:58 +01:00
|
|
|
return out_file;
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
2003-09-25 13:49:12 +02:00
|
|
|
TEXT* argv[20];
|
|
|
|
TEXT** arg = argv;
|
2004-11-10 05:26:45 +01:00
|
|
|
TEXT** const end = argv + FB_NELEM(argv) - 1; // The last element should be NULL
|
2004-02-21 10:24:14 +01:00
|
|
|
TEXT* pp = filename;
|
2004-11-10 05:26:45 +01:00
|
|
|
while (*pp && arg < end) {
|
2004-02-21 10:24:14 +01:00
|
|
|
*arg++ = pp;
|
|
|
|
while (*pp && *pp != ' ')
|
|
|
|
pp++;
|
|
|
|
if (!*pp)
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2004-02-21 10:24:14 +01:00
|
|
|
*pp++ = 0;
|
|
|
|
while (*pp == ' ')
|
|
|
|
pp++;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
*arg = NULL;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
int pair[2];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (pipe(pair) < 0)
|
2003-09-25 13:49:12 +02:00
|
|
|
IBERROR(36); // Msg36 couldn't create pipe
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!vfork()) {
|
|
|
|
close(pair[1]);
|
|
|
|
close(0);
|
|
|
|
dup(pair[0]);
|
|
|
|
close(pair[0]);
|
|
|
|
execvp(argv[0], argv);
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_msg_put(43, filename); // Msg43 Couldn't run %s
|
2001-05-23 15:26:42 +02:00
|
|
|
_exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(pair[0]);
|
|
|
|
|
2004-04-29 00:36:29 +02:00
|
|
|
FILE* out_file = fdopen(pair[1], "w");
|
2003-09-26 11:26:38 +02:00
|
|
|
if (out_file)
|
2008-01-15 21:15:58 +01:00
|
|
|
return out_file;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2004-04-29 00:36:29 +02:00
|
|
|
IBERROR(37); // Msg37 fdopen failed
|
2003-02-07 10:40:54 +01:00
|
|
|
return NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EXEC_poll_abort(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ p o l l _ a b o r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Poll for abort flag (actually, most routines will check the
|
|
|
|
* flag before calling to save time).
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (!QLI_abort)
|
|
|
|
return;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
IBERROR(38); // Msg38 execution terminated by signal
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
DSC *EXEC_receive(qli_msg* message, qli_par* parameter)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ r e c e i v e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Receive a message from a running request.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_req* request = message->msg_request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_receive(status_vector, &request->req_handle, message->msg_number,
|
2003-09-25 13:49:12 +02:00
|
|
|
message->msg_length, message->msg_buffer, 0))
|
2008-01-15 21:15:58 +01:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
db_error(request, status_vector);
|
2008-01-15 21:15:58 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!parameter)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return EVAL_parameter(parameter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
void EXEC_send( qli_msg* message)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ s e n d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Send a message to a running request. First, however, map
|
|
|
|
* any data to the message.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_req* request = message->msg_request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
map_data(message);
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_send(status_vector, &request->req_handle, message->msg_number,
|
2003-08-30 04:12:44 +02:00
|
|
|
message->msg_length, message->msg_buffer, 0))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
db_error(request, status_vector);
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
void EXEC_start_request( qli_req* request, qli_msg* message)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ s t a r t _ r e q u e s t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Start a request running. If there is a message to be sent, do
|
|
|
|
* a start and send.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-15 21:15:58 +01:00
|
|
|
if (message)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
map_data(message);
|
2003-11-08 17:40:17 +01:00
|
|
|
if (!isc_start_and_send(status_vector, &request->req_handle,
|
2003-08-30 04:12:44 +02:00
|
|
|
&request->req_database-> dbb_transaction,
|
2001-05-23 15:26:42 +02:00
|
|
|
message->msg_number, message->msg_length,
|
2003-09-25 13:49:12 +02:00
|
|
|
message->msg_buffer, 0))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
return;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-01-15 21:15:58 +01:00
|
|
|
else
|
|
|
|
{
|
2003-11-08 17:40:17 +01:00
|
|
|
if (!isc_start_request(status_vector, &request->req_handle,
|
2003-09-25 13:49:12 +02:00
|
|
|
&request->req_database-> dbb_transaction, 0))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
return;
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
db_error(request, status_vector);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
void EXEC_top( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E X E C _ t o p
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a node type.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
EXEC_execute(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static DSC *assignment( qli_nod* from_node,
|
2001-12-24 03:51:06 +01:00
|
|
|
DSC* to_desc,
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod* validation,
|
|
|
|
qli_nod* initial,
|
|
|
|
qli_par* parameter)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a s s i g n m e n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Evaluate an expression and perform an assignment. If something
|
|
|
|
* goes wrong and there was a prompt, try again.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-07-30 01:43:24 +02:00
|
|
|
jmp_buf old_env;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-10-10 21:32:04 +02:00
|
|
|
memcpy(old_env, QLI_env, sizeof(QLI_env));
|
2001-05-23 15:26:42 +02:00
|
|
|
QLI_reprompt = FALSE;
|
|
|
|
QLI_prompt_count = 0;
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
USHORT trash;
|
|
|
|
USHORT* missing_flag = &trash;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* message = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (parameter) {
|
|
|
|
message = parameter->par_message;
|
|
|
|
missing_flag =
|
|
|
|
(USHORT *) (message->msg_buffer + parameter->par_offset);
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
memcpy(QLI_env, old_env, sizeof(QLI_env));
|
|
|
|
dsc* from_desc = EVAL_value(from_node);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
if (from_desc->dsc_missing & DSC_initial) {
|
|
|
|
from_desc = EVAL_value(initial);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If there is a value present, do any assignment; otherwise null fill */
|
|
|
|
|
2008-01-15 21:15:58 +01:00
|
|
|
if (*missing_flag = to_desc->dsc_missing = from_desc->dsc_missing)
|
|
|
|
{
|
|
|
|
if (from_desc->dsc_length)
|
|
|
|
memset(from_desc->dsc_address, 0, from_desc->dsc_length);
|
2006-05-19 17:17:02 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
MOVQ_move(from_desc, to_desc);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
if (validation && EVAL_boolean(validation) <= 0) {
|
|
|
|
IBERROR(39); // Msg39 field validation error
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
QLI_reprompt = FALSE;
|
|
|
|
memcpy(QLI_env, old_env, sizeof(QLI_env));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
return from_desc;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
}
|
|
|
|
catch (const Firebird::Exception&) {
|
2001-12-24 03:51:06 +01:00
|
|
|
if (QLI_abort || !QLI_prompt_count) {
|
2002-10-10 21:32:04 +02:00
|
|
|
memcpy(QLI_env, old_env, sizeof(QLI_env));
|
2001-12-24 03:51:06 +01:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
QLI_reprompt = TRUE;
|
|
|
|
QLI_prompt_count = 0;
|
2003-02-07 10:40:54 +01:00
|
|
|
return NULL;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void commit_retaining( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o m m i t _ r e t a i n i n g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute commit retaining statement for
|
2003-09-25 13:49:12 +02:00
|
|
|
* one or more named databases or all databases.
|
2001-05-23 15:26:42 +02:00
|
|
|
* If there's more than one, prepare it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/* If there aren't any open databases then obviously
|
|
|
|
there isn't anything to commit. */
|
|
|
|
|
|
|
|
if (node->nod_count == 0 && !QLI_databases)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (node->nod_type == nod_commit_retaining &&
|
|
|
|
((node->nod_count > 1) ||
|
2003-09-25 13:49:12 +02:00
|
|
|
(node->nod_count == 0 && QLI_databases->dbb_next)))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_type = nod_prepare;
|
|
|
|
commit_retaining(node);
|
|
|
|
node->nod_type = nod_commit_retaining;
|
|
|
|
}
|
|
|
|
else if (node->nod_count == 1) {
|
2004-03-07 08:58:55 +01:00
|
|
|
DBB database = (DBB) node->nod_arg[0];
|
2001-05-23 15:26:42 +02:00
|
|
|
database->dbb_flags |= DBB_prepared;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
QLI_databases->dbb_flags |= DBB_prepared;
|
|
|
|
|
|
|
|
|
|
|
|
if (node->nod_count == 0) {
|
2004-03-07 08:58:55 +01:00
|
|
|
for (DBB database = QLI_databases; database;
|
|
|
|
database = database->dbb_next)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((node->nod_type == nod_commit_retaining)
|
|
|
|
&& !(database->dbb_flags & DBB_prepared))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_msg_put(465, database->dbb_symbol->sym_string);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (node->nod_type == nod_prepare)
|
|
|
|
database->dbb_flags |= DBB_prepared;
|
|
|
|
if (database->dbb_transaction)
|
|
|
|
transaction_state(node, database);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod** ptr = node->nod_arg;
|
|
|
|
for (const qli_nod* const* const end = ptr + node->nod_count; ptr < end; ptr++)
|
|
|
|
{
|
2004-03-07 08:58:55 +01:00
|
|
|
DBB database = (DBB) *ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((node->nod_type == nod_commit_retaining) &&
|
|
|
|
!(database->dbb_flags & DBB_prepared))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_msg_put(465, database->dbb_symbol->sym_string);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (node->nod_type == nod_prepare)
|
|
|
|
database->dbb_flags |= DBB_prepared;
|
|
|
|
if (database->dbb_transaction)
|
|
|
|
transaction_state(node, database);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static bool copy_blob( qli_nod* value, qli_par* parameter)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o p y _ b l o b
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Copy a blob from one database to another. If the blob can be
|
2004-03-07 08:58:55 +01:00
|
|
|
* successfully assigned, return false and let somebody else just
|
2001-05-23 15:26:42 +02:00
|
|
|
* copy the blob ids.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-11 04:17:05 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* If assignment isn't from a field, there isn't a blob copy, so
|
|
|
|
do a dumb assignment. */
|
|
|
|
|
|
|
|
if (value->nod_type != nod_field)
|
2003-09-25 13:49:12 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Find the sending and receiving requests. If they are the same
|
|
|
|
and no filtering is necessary, a simple assignment will suffice. */
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_ctx* context = (qli_ctx*) value->nod_arg[e_fld_context];
|
|
|
|
qli_req* from_request = context->ctx_request;
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB from_dbb = from_request->req_database;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* message = parameter->par_message;
|
|
|
|
qli_req* to_request = message->msg_request;
|
2003-09-25 13:49:12 +02:00
|
|
|
DBB to_dbb = to_request->req_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
dsc* from_desc = EVAL_value(value);
|
|
|
|
dsc* to_desc = EVAL_parameter(parameter);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (to_dbb == from_dbb &&
|
|
|
|
(!to_desc->dsc_sub_type ||
|
2003-09-25 13:49:12 +02:00
|
|
|
from_desc->dsc_sub_type == to_desc->dsc_sub_type))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
// We've got a blob copy on our hands.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!from_desc) {
|
|
|
|
*to_desc->dsc_address = 0;
|
2003-09-25 13:49:12 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
// Format blob parameter block for the existing blob
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR bpb[20];
|
|
|
|
UCHAR* p = bpb;
|
2003-11-08 17:40:17 +01:00
|
|
|
*p++ = isc_bpb_version1;
|
|
|
|
*p++ = isc_bpb_source_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 2;
|
|
|
|
*p++ = from_desc->dsc_sub_type;
|
|
|
|
*p++ = from_desc->dsc_sub_type >> 8;
|
2003-11-08 17:40:17 +01:00
|
|
|
*p++ = isc_bpb_target_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 2;
|
|
|
|
*p++ = to_desc->dsc_sub_type;
|
|
|
|
*p++ = to_desc->dsc_sub_type >> 8;
|
2003-09-25 13:49:12 +02:00
|
|
|
const USHORT bpb_length = p - bpb;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2007-04-06 12:10:10 +02:00
|
|
|
UserBlob to_blob(status_vector);
|
|
|
|
UserBlob from_blob(status_vector);
|
|
|
|
|
|
|
|
if (!to_blob.create(to_dbb->dbb_handle, to_dbb->dbb_transaction,
|
|
|
|
*(ISC_QUAD*) to_desc->dsc_address))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(to_dbb, status_vector);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!from_blob.open(from_dbb->dbb_handle, from_dbb->dbb_transaction,
|
|
|
|
*(ISC_QUAD*) from_desc->dsc_address, bpb_length,
|
2003-11-10 10:16:38 +01:00
|
|
|
bpb))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
ERRQ_database_error(from_dbb, status_vector);
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
SLONG size, segment_count, max_segment;
|
2007-04-10 12:04:00 +02:00
|
|
|
if (!getBlobSize(from_blob, &size, &segment_count, &max_segment))
|
2007-04-06 12:10:10 +02:00
|
|
|
ERRQ_database_error(from_dbb, status_vector);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR fixed_buffer[4096];
|
|
|
|
UCHAR* buffer;
|
|
|
|
USHORT buffer_length;
|
2003-08-19 13:16:10 +02:00
|
|
|
if (max_segment < (SLONG) sizeof(fixed_buffer)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer_length = sizeof(fixed_buffer);
|
|
|
|
buffer = fixed_buffer;
|
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
else
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer_length = max_segment;
|
2001-07-12 07:46:06 +02:00
|
|
|
buffer = (UCHAR*) gds__alloc(buffer_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
2003-09-25 13:49:12 +02:00
|
|
|
// We don't care about QLI specific memory leaks for V4.0
|
|
|
|
gds_alloc_flag_unfreed((void *) buffer); // QLI: don't care
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
size_t length;
|
|
|
|
while (from_blob.getSegment(buffer_length, buffer, length) && !from_blob.getCode())
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!to_blob.putSegment(length, buffer))
|
2003-10-29 11:53:47 +01:00
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
ERRQ_database_error(to_dbb, status_vector);
|
2003-10-29 11:53:47 +01:00
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (buffer != fixed_buffer)
|
|
|
|
gds__free(buffer);
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!from_blob.close())
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(from_dbb, status_vector);
|
|
|
|
|
2007-04-06 12:10:10 +02:00
|
|
|
if (!to_blob.close())
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(to_dbb, status_vector);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void db_error( qli_req* request, ISC_STATUS * status_vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ e r r o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* A database error has occurred. Unless it was the result of
|
|
|
|
* an unwind, generate an error.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
EXEC_poll_abort();
|
|
|
|
ERRQ_database_error(request->req_database, status_vector);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_abort( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ a b o r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Abort a statement.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (node->nod_count) {
|
2004-02-20 07:43:27 +01:00
|
|
|
const TEXT* ptr = NULL;
|
|
|
|
UCHAR temp[80];
|
2004-03-07 08:58:55 +01:00
|
|
|
const USHORT l =
|
2004-02-20 07:43:27 +01:00
|
|
|
MOVQ_get_string(EVAL_value(node->nod_arg[0]), &ptr,
|
2003-09-29 14:43:14 +02:00
|
|
|
(vary*) temp, sizeof(temp));
|
2003-09-25 13:49:12 +02:00
|
|
|
|
|
|
|
UCHAR msg[128];
|
2004-02-20 07:43:27 +01:00
|
|
|
MOVQ_terminate(ptr, (SCHAR*) msg, l, sizeof(msg));
|
2007-03-28 06:20:36 +02:00
|
|
|
ERRQ_error(40, SafeArg() << msg);
|
2003-09-25 13:49:12 +02:00
|
|
|
// Msg40 Request terminated by statement: %s
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
IBERROR(41); // Msg41 Request terminated by statement
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_assignment( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ a s s i g n m e n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (node->nod_flags & NOD_remote)
|
|
|
|
return;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod* to = node->nod_arg[e_asn_to];
|
|
|
|
qli_nod* from = node->nod_arg[e_asn_from];
|
|
|
|
qli_nod* initial = node->nod_arg[e_asn_initial];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_par* parameter;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (to->nod_type == nod_field) {
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod* reference = to->nod_arg[e_fld_reference];
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter = reference->nod_import;
|
|
|
|
if (to->nod_desc.dsc_dtype == dtype_blob &&
|
|
|
|
from->nod_desc.dsc_dtype == dtype_blob &&
|
2003-09-25 13:49:12 +02:00
|
|
|
copy_blob(from, parameter))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
parameter = node->nod_import;
|
|
|
|
|
|
|
|
if (parameter)
|
|
|
|
parameter = parameter->par_missing;
|
|
|
|
|
|
|
|
assignment(from, EVAL_value(to),
|
|
|
|
node->nod_arg[e_asn_valid], initial, parameter);
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// propagate the missing flag in variable assignments
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (to->nod_type == nod_variable) {
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_fld* field = (qli_fld*) to->nod_arg[e_fld_field];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (to->nod_desc.dsc_missing & DSC_missing)
|
|
|
|
field->fld_flags |= FLD_missing;
|
|
|
|
else
|
|
|
|
field->fld_flags &= ~FLD_missing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_for( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ f o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a FOR loop. This may require that a request get
|
|
|
|
* started, a message sent, and a message received for each
|
|
|
|
* record. At the other end of the spectrum, there may be
|
|
|
|
* absolutely nothing to do.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/* If there is a request associated with the node, start it and possibly
|
|
|
|
send a message along with it. */
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_req* request = (qli_req*) node->nod_arg[e_for_request];
|
2003-09-25 13:49:12 +02:00
|
|
|
if (request)
|
2004-02-02 12:02:12 +01:00
|
|
|
EXEC_start_request(request, (qli_msg*) node->nod_arg[e_for_send]);
|
2003-09-25 13:49:12 +02:00
|
|
|
else {
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* amessage = (qli_msg*) node->nod_arg[e_for_send];
|
2003-09-25 13:49:12 +02:00
|
|
|
if (amessage)
|
|
|
|
EXEC_send(amessage);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If there isn't a receive message, the body of the loop has been
|
2004-02-02 12:02:12 +01:00
|
|
|
optimized out of existence. So skip it. */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* message = (qli_msg*) node->nod_arg[e_for_receive];
|
2003-09-25 13:49:12 +02:00
|
|
|
if (!message)
|
2001-05-23 15:26:42 +02:00
|
|
|
goto count;
|
|
|
|
|
|
|
|
/* Receive messages in a loop until the end of file field comes up
|
|
|
|
true. */
|
|
|
|
|
2003-09-10 19:52:12 +02:00
|
|
|
while (true) {
|
2004-02-02 12:02:12 +01:00
|
|
|
dsc* desc = EXEC_receive(message, (qli_par*) node->nod_arg[e_for_eof]);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*(USHORT *) desc->dsc_address)
|
|
|
|
break;
|
|
|
|
EXEC_execute(node->nod_arg[e_for_statement]);
|
|
|
|
if (request && request->req_continue)
|
|
|
|
EXEC_send(request->req_continue);
|
|
|
|
}
|
|
|
|
|
|
|
|
count:
|
|
|
|
if (QLI_count)
|
|
|
|
print_counts(request);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_modify( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ m o d i f y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a modify statement. This probably involves sending a
|
|
|
|
* message to the running request and executing a sub-statement.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (node->nod_flags & NOD_remote)
|
|
|
|
return;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* message = (qli_msg*) node->nod_arg[e_mod_send];
|
2003-09-25 13:49:12 +02:00
|
|
|
if (message)
|
2001-05-23 15:26:42 +02:00
|
|
|
set_null(message);
|
|
|
|
|
|
|
|
EXEC_execute(node->nod_arg[e_mod_statement]);
|
|
|
|
|
|
|
|
if (message)
|
|
|
|
EXEC_send(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_output( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ o u t p u t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Open output stream to re-direct output.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_prt* print = (qli_prt*) node->nod_arg[e_out_print];
|
2001-05-23 15:26:42 +02:00
|
|
|
print->prt_file = EXEC_open_output(node);
|
|
|
|
|
2006-05-20 05:31:05 +02:00
|
|
|
// Set up error handling
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
jmp_buf old_env;
|
|
|
|
jmp_buf env;
|
2002-10-10 21:32:04 +02:00
|
|
|
memcpy(old_env, QLI_env, sizeof(QLI_env));
|
|
|
|
memcpy(QLI_env, env, sizeof(QLI_env));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-20 05:31:05 +02:00
|
|
|
// Finally, execute the query
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
EXEC_execute(node->nod_arg[e_out_statement]);
|
|
|
|
memcpy(QLI_env, old_env, sizeof(QLI_env));
|
2008-01-15 21:15:58 +01:00
|
|
|
fclose(print->prt_file);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
}
|
|
|
|
catch (const Firebird::Exception&) {
|
2001-12-24 03:51:06 +01:00
|
|
|
if (print->prt_file) {
|
2008-01-15 21:15:58 +01:00
|
|
|
fclose(print->prt_file);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2002-10-10 21:32:04 +02:00
|
|
|
memcpy(QLI_env, old_env, sizeof(QLI_env));
|
2001-12-24 03:51:06 +01:00
|
|
|
throw;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_print( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ p r i n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a print statement. Since the loop has been factored
|
|
|
|
* out, this should be easy.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (node->nod_arg[e_prt_header]) {
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_put((TEXT*) node->nod_arg[e_prt_header], (qli_prt*) node->nod_arg[e_prt_output]);
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_arg[e_prt_header] = NULL;
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
FMT_print(node->nod_arg[e_prt_list], (qli_prt*) node->nod_arg[e_prt_output]);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_repeat( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-09-25 13:49:12 +02:00
|
|
|
* e x e c u t e _ r e p e a t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a REPEAT statement. In short, loop.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-09-25 13:49:12 +02:00
|
|
|
SLONG count = MOVQ_get_long(EVAL_value(node->nod_arg[e_rpt_value]), 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
while (--count >= 0)
|
|
|
|
EXEC_execute(node->nod_arg[e_rpt_statement]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void execute_store( qli_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e x e c u t e _ s t o r e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Execute a STORE statement. This may involve starting
|
|
|
|
* a request, sending a message, and executing a sub-statement.
|
|
|
|
* On the other hand, it may be a mody no-op if the statement
|
|
|
|
* is part of another request and doesn't need any data from
|
|
|
|
* here.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_msg* message = (qli_msg*) node->nod_arg[e_sto_send];
|
2003-09-25 13:49:12 +02:00
|
|
|
if (message)
|
2001-05-23 15:26:42 +02:00
|
|
|
set_null(message);
|
|
|
|
|
|
|
|
if (!(node->nod_flags & NOD_remote))
|
|
|
|
EXEC_execute(node->nod_arg[e_sto_statement]);
|
|
|
|
|
|
|
|
/* If there is a request associated with the node, start it and possibly
|
|
|
|
send a message along with it. */
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_req* request = (qli_req*) node->nod_arg[e_sto_request];
|
2003-09-25 13:49:12 +02:00
|
|
|
if (request)
|
2004-02-02 12:02:12 +01:00
|
|
|
EXEC_start_request(request, (qli_msg*) node->nod_arg[e_sto_send]);
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (message)
|
|
|
|
EXEC_send(message);
|
|
|
|
|
|
|
|
if (QLI_count)
|
|
|
|
print_counts(request);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void map_data( qli_msg* message)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a p _ d a t a
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Map data to a message in preparation for sending.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_par* parameter = message->msg_parameters; parameter;
|
2003-09-25 13:49:12 +02:00
|
|
|
parameter = parameter->par_next)
|
|
|
|
{
|
|
|
|
dsc* desc = ¶meter->par_desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_address = message->msg_buffer + parameter->par_offset;
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_par* missing_parameter = parameter->par_missing;
|
2003-09-25 13:49:12 +02:00
|
|
|
if (missing_parameter) {
|
|
|
|
USHORT* missing_flag = (USHORT*) (message->msg_buffer +
|
2001-05-23 15:26:42 +02:00
|
|
|
missing_parameter->par_offset);
|
2003-08-30 04:12:44 +02:00
|
|
|
*missing_flag = (desc->dsc_missing & DSC_missing) ? DSC_missing : 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod* from = parameter->par_value;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (desc->dsc_dtype == dtype_blob && copy_blob(from, parameter))
|
|
|
|
continue;
|
|
|
|
assignment(from, desc, 0, 0, parameter->par_missing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void print_counts( qli_req* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p r i n t _ c o u n t s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-09-25 13:49:12 +02:00
|
|
|
* Print out the count of records affected
|
2001-05-23 15:26:42 +02:00
|
|
|
* by the last statement.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-01-17 08:52:14 +01:00
|
|
|
UCHAR count_buffer[COUNT_ITEMS * 7 + 1];
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_request_info(status_vector, &request->req_handle, 0,
|
2003-08-30 04:12:44 +02:00
|
|
|
sizeof(count_info), count_info,
|
2006-01-17 08:52:14 +01:00
|
|
|
sizeof(count_buffer), (SCHAR*) count_buffer))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2003-08-30 04:12:44 +02:00
|
|
|
return;
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
// print out the counts of any records affected
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
int length = 0;
|
2006-01-17 08:52:14 +01:00
|
|
|
for (UCHAR* c = count_buffer; *c != isc_info_end; c += length) {
|
2008-01-15 21:15:58 +01:00
|
|
|
const UCHAR item = *c++;
|
2006-01-17 08:52:14 +01:00
|
|
|
length = gds__vax_integer(c, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
c += 2;
|
2006-01-17 08:52:14 +01:00
|
|
|
const ULONG number = gds__vax_integer(c, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (number)
|
|
|
|
switch (item) {
|
2003-11-08 17:40:17 +01:00
|
|
|
case isc_info_req_select_count:
|
2006-01-17 08:52:14 +01:00
|
|
|
printf("\nrecords selected: %"ULONGFORMAT"\n", number);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
case isc_info_req_insert_count:
|
2006-01-17 08:52:14 +01:00
|
|
|
printf("records inserted: %"ULONGFORMAT"\n", number);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
case isc_info_req_update_count:
|
2006-01-17 08:52:14 +01:00
|
|
|
printf("records updated: %"ULONGFORMAT"\n", number);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 17:40:17 +01:00
|
|
|
case isc_info_req_delete_count:
|
2006-01-17 08:52:14 +01:00
|
|
|
printf("records deleted: %"ULONGFORMAT"\n", number);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void set_null( qli_msg* message)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t _ n u l l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Set all parameters of an outgoing
|
|
|
|
* message to null - this allows conditional
|
|
|
|
* assignments to work in store and modify
|
|
|
|
* statements.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-02 12:02:12 +01:00
|
|
|
for (qli_par* parameter = message->msg_parameters; parameter;
|
2003-09-25 13:49:12 +02:00
|
|
|
parameter = parameter->par_next)
|
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
qli_nod* from = parameter->par_value;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (from->nod_type == nod_field) {
|
2003-09-25 13:49:12 +02:00
|
|
|
dsc* desc = EVAL_value(from);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_missing |= DSC_missing;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
from->nod_desc.dsc_missing |= DSC_missing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static void transaction_state( qli_nod* node, DBB database)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t r a n s a c t i o n _ s t a t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-09-25 13:49:12 +02:00
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
* set the state of the working transaction
|
|
|
|
* in a particular database to prepared or
|
|
|
|
* committed.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (database->dbb_transaction) {
|
|
|
|
if (node->nod_type == nod_commit_retaining) {
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_commit_retaining(status, &database->dbb_transaction))
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(database, status);
|
|
|
|
}
|
|
|
|
else if (node->nod_type == nod_prepare) {
|
2003-11-08 17:40:17 +01:00
|
|
|
if (isc_prepare_transaction(status, &database->dbb_transaction))
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRQ_database_error(database, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-09-25 13:49:12 +02:00
|
|
|
|
|
|
|
|