2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: Dynamic SQL runtime support
|
2003-10-05 08:33:56 +02:00
|
|
|
* MODULE: dsql.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Local processing for External entry points.
|
|
|
|
*
|
|
|
|
* 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-10 19:35:13 +02:00
|
|
|
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
|
|
|
|
* conditionals, as the engine now fully supports
|
|
|
|
* readonly databases.
|
2001-12-24 03:51:06 +01:00
|
|
|
* December 2001 Mike Nordell: Major overhaul to (try to) make it C++
|
2002-06-29 08:56:51 +02:00
|
|
|
* 2001.6.3 Claudio Valderrama: fixed a bad behaved loop in get_plan_info()
|
|
|
|
* and get_rsb_item() that caused a crash when plan info was requested.
|
|
|
|
* 2001.6.9 Claudio Valderrama: Added nod_del_view, nod_current_role and nod_breakleave.
|
2002-10-29 21:20:44 +01:00
|
|
|
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
|
2002-06-29 08:56:51 +02:00
|
|
|
*
|
2002-10-30 07:40:58 +01:00
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
|
|
*
|
2004-01-16 11:43:21 +01:00
|
|
|
* 2004.01.16 Vlad Horsun: added support for EXECUTE BLOCK statement
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
/**************************************************************
|
|
|
|
V4 Multi-threading changes.
|
|
|
|
|
|
|
|
-- direct calls to gds__ () & isc_ () entrypoints
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
gds__ () or isc_ () call.
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
-- calls through embedded GDML.
|
|
|
|
|
|
|
|
the following protocol will be used. Care should be taken if
|
|
|
|
nested FOR loops are added.
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT(); // last statement before FOR loop
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR ...............
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER(); // First statement in FOR loop
|
2001-05-23 15:26:42 +02:00
|
|
|
.....some C code....
|
|
|
|
.....some C code....
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT(); // last statement in FOR loop
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER(); // First statement after FOR loop
|
2001-05-23 15:26:42 +02:00
|
|
|
***************************************************************/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2002-12-16 16:38:26 +01:00
|
|
|
#include "fb_exception.h"
|
2004-04-29 00:00:03 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "../dsql/dsql.h"
|
2003-11-08 00:27:24 +01:00
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/thd.h"
|
|
|
|
#include "../jrd/align.h"
|
|
|
|
#include "../jrd/intl.h"
|
|
|
|
#include "../jrd/iberr.h"
|
2004-05-01 00:47:16 +02:00
|
|
|
//#include "../dsql/sqlda.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../dsql/alld_proto.h"
|
|
|
|
#include "../dsql/ddl_proto.h"
|
|
|
|
#include "../dsql/dsql_proto.h"
|
|
|
|
#include "../dsql/errd_proto.h"
|
|
|
|
#include "../dsql/gen_proto.h"
|
|
|
|
#include "../dsql/hsh_proto.h"
|
|
|
|
#include "../dsql/make_proto.h"
|
|
|
|
#include "../dsql/movd_proto.h"
|
|
|
|
#include "../dsql/parse_proto.h"
|
|
|
|
#include "../dsql/pass1_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/sch_proto.h"
|
2004-05-18 00:30:09 +02:00
|
|
|
#include "../jrd/thread_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/why_proto.h"
|
2002-12-16 16:38:26 +01:00
|
|
|
#include "../jrd/y_handle.h"
|
2003-09-28 23:36:05 +02:00
|
|
|
#include "../common/config/config.h"
|
2002-06-23 21:51:37 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_CTYPE_H
|
|
|
|
#include <ctype.h>
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef VMS
|
|
|
|
#include <descrip.h>
|
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
static void cleanup(void*);
|
2004-05-03 01:06:37 +02:00
|
|
|
static void cleanup_database(FB_API_HANDLE*, void*);
|
|
|
|
static void cleanup_transaction(FB_API_HANDLE, void*);
|
2003-11-01 11:26:43 +01:00
|
|
|
static void close_cursor(dsql_req*);
|
2002-12-16 16:38:26 +01:00
|
|
|
static USHORT convert(SLONG, UCHAR*);
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS error();
|
2003-11-01 11:26:43 +01:00
|
|
|
static void execute_blob(dsql_req*, USHORT, const UCHAR*, USHORT, UCHAR*,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT, UCHAR*, USHORT, UCHAR*);
|
2004-05-03 01:06:37 +02:00
|
|
|
static ISC_STATUS execute_request(dsql_req*, FB_API_HANDLE*, USHORT, const UCHAR*,
|
2003-10-16 10:51:06 +02:00
|
|
|
USHORT, UCHAR*, USHORT, UCHAR*, USHORT, UCHAR*, bool);
|
2003-11-01 11:26:43 +01:00
|
|
|
static SSHORT filter_sub_type(dsql_req*, const dsql_nod*);
|
|
|
|
static bool get_indices(SSHORT*, const SCHAR**, SSHORT*, SCHAR**);
|
|
|
|
static USHORT get_plan_info(dsql_req*, SSHORT, SCHAR**);
|
|
|
|
static USHORT get_request_info(dsql_req*, SSHORT, SCHAR*);
|
|
|
|
static bool get_rsb_item(SSHORT*, const SCHAR**, SSHORT*, SCHAR**, USHORT*,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT*);
|
2004-05-03 01:06:37 +02:00
|
|
|
static dsql_dbb* init(FB_API_HANDLE*);
|
2003-11-01 11:26:43 +01:00
|
|
|
static void map_in_out(dsql_req*, dsql_msg*, USHORT, const UCHAR*, USHORT, UCHAR*);
|
2003-10-16 10:51:06 +02:00
|
|
|
static USHORT name_length(const TEXT*);
|
2004-02-02 12:02:12 +01:00
|
|
|
static USHORT parse_blr(USHORT, const UCHAR*, const USHORT, dsql_par*);
|
2003-11-28 07:48:34 +01:00
|
|
|
static dsql_req* prepare(dsql_req*, USHORT, const TEXT*, USHORT, USHORT);
|
2001-12-24 03:51:06 +01:00
|
|
|
static void punt(void);
|
2003-10-16 10:51:06 +02:00
|
|
|
static UCHAR* put_item(UCHAR, USHORT, const UCHAR*, UCHAR*, const UCHAR* const);
|
2003-11-01 11:26:43 +01:00
|
|
|
static void release_request(dsql_req*, bool);
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS return_success(void);
|
2003-11-01 11:26:43 +01:00
|
|
|
static UCHAR* var_info(dsql_msg*, const UCHAR*, const UCHAR* const, UCHAR*,
|
|
|
|
const UCHAR* const, USHORT);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
extern dsql_nod* DSQL_parse;
|
2003-09-28 23:36:05 +02:00
|
|
|
|
|
|
|
#ifdef DSQL_DEBUG
|
2003-10-03 04:00:40 +02:00
|
|
|
unsigned DSQL_debug;
|
2003-09-28 02:36:28 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
static bool init_flag = false;
|
2004-02-02 12:02:12 +01:00
|
|
|
static dsql_dbb* databases;
|
|
|
|
static dsql_opn* open_cursors;
|
2003-10-29 11:53:47 +01:00
|
|
|
|
2003-02-13 10:33:26 +01:00
|
|
|
static const SCHAR db_hdr_info_items[] = {
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_info_db_sql_dialect,
|
2003-11-08 00:27:24 +01:00
|
|
|
isc_info_ods_version,
|
|
|
|
isc_info_base_level,
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_info_db_read_only,
|
|
|
|
frb_info_att_charset,
|
2003-11-08 00:27:24 +01:00
|
|
|
isc_info_end
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
2003-11-01 11:26:43 +01:00
|
|
|
|
2003-02-13 10:33:26 +01:00
|
|
|
static const SCHAR explain_info[] = {
|
2003-11-08 00:27:24 +01:00
|
|
|
isc_info_access_path
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
2003-11-01 11:26:43 +01:00
|
|
|
|
2003-02-13 10:33:26 +01:00
|
|
|
static const SCHAR record_info[] = {
|
2003-11-08 00:27:24 +01:00
|
|
|
isc_info_req_update_count, isc_info_req_delete_count,
|
|
|
|
isc_info_req_select_count, isc_info_req_insert_count
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
2003-11-01 11:26:43 +01:00
|
|
|
|
2003-02-13 10:33:26 +01:00
|
|
|
static const UCHAR sql_records_info[] = {
|
2003-11-08 00:27:24 +01:00
|
|
|
isc_info_sql_records
|
2001-05-23 15:26:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef ANY_THREADING
|
|
|
|
static MUTX_T databases_mutex;
|
|
|
|
static MUTX_T cursors_mutex;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2003-09-28 23:36:05 +02:00
|
|
|
#ifdef DSQL_DEBUG
|
2004-06-14 01:47:02 +02:00
|
|
|
IMPLEMENT_TRACE_ROUTINE(dsql_trace, "DSQL")
|
2003-09-28 23:36:05 +02:00
|
|
|
#endif
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
// declarations of the C++ implementations of the C API functions
|
|
|
|
// with the matching name.
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_ALLOCATE_CPP( ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* db_handle,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_EXECUTE_CPP( ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2002-12-16 16:38:26 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT in_blr_length,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* in_blr,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT in_msg_type,
|
|
|
|
USHORT in_msg_length,
|
|
|
|
UCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
UCHAR* out_blr,
|
|
|
|
USHORT out_msg_type,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
UCHAR* out_msg);
|
|
|
|
|
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_FETCH_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT blr_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* blr,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR* dsql_msg_buf
|
2001-12-24 03:51:06 +01:00
|
|
|
#ifdef SCROLLABLE_CURSORS
|
2004-07-02 09:26:18 +02:00
|
|
|
, USHORT direction, SLONG offset);
|
2001-12-24 03:51:06 +01:00
|
|
|
#else
|
|
|
|
);
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_FREE_CPP(ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT option);
|
|
|
|
|
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_INSERT_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT blr_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const UCHAR* blr,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* dsql_msg_buf);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_PREPARE_CPP(ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2002-12-16 16:38:26 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* string,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT dialect,
|
|
|
|
USHORT item_length,
|
2003-02-13 10:33:26 +01:00
|
|
|
const UCHAR* items,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT buffer_length,
|
|
|
|
UCHAR* buffer);
|
|
|
|
|
|
|
|
static
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_SQL_INFO_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT item_length,
|
2003-02-13 10:33:26 +01:00
|
|
|
const UCHAR* items,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT info_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
UCHAR* info);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_SET_CURSOR_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* input_cursor,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT type);
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
// Begin : C API -> C++ wrapper functions
|
2003-09-28 02:36:28 +02:00
|
|
|
// Note that we don't wrap dsql8_execute_immediate since it
|
2001-12-24 03:51:06 +01:00
|
|
|
// contains no req in its parameter list.
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_allocate_statement(
|
|
|
|
ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* db_handle,
|
2003-10-03 04:00:40 +02:00
|
|
|
dsql_req** req_handle)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2002-12-16 16:38:26 +01:00
|
|
|
return GDS_DSQL_ALLOCATE_CPP(user_status, db_handle, req_handle);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_execute(
|
|
|
|
ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2003-10-03 04:00:40 +02:00
|
|
|
dsql_req** req_handle,
|
|
|
|
USHORT in_blr_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const SCHAR* in_blr,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT in_msg_type,
|
|
|
|
USHORT in_msg_length,
|
|
|
|
SCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
SCHAR* out_blr,
|
|
|
|
USHORT out_msg_type,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
SCHAR* out_msg)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
return GDS_DSQL_EXECUTE_CPP(user_status,
|
|
|
|
trans_handle,
|
2002-12-16 16:38:26 +01:00
|
|
|
req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
in_blr_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(in_blr),
|
2001-12-24 03:51:06 +01:00
|
|
|
in_msg_type,
|
|
|
|
in_msg_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
reinterpret_cast<UCHAR*>(in_msg),
|
2001-12-24 03:51:06 +01:00
|
|
|
out_blr_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
reinterpret_cast<UCHAR*>(out_blr),
|
2001-12-24 03:51:06 +01:00
|
|
|
out_msg_type,
|
|
|
|
out_msg_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
reinterpret_cast<UCHAR*>(out_msg));
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_fetch(
|
|
|
|
ISC_STATUS* user_status,
|
2003-02-12 20:28:13 +01:00
|
|
|
dsql_req** req_handle,
|
|
|
|
USHORT blr_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const SCHAR* blr,
|
2003-02-12 20:28:13 +01:00
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
SCHAR* dsql_msg_buf
|
2001-12-24 03:51:06 +01:00
|
|
|
#ifdef SCROLLABLE_CURSORS
|
2003-10-03 04:00:40 +02:00
|
|
|
, USHORT direction, SLONG offset
|
2001-12-24 03:51:06 +01:00
|
|
|
#endif
|
2003-10-03 04:00:40 +02:00
|
|
|
)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
return GDS_DSQL_FETCH_CPP( user_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
blr_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(blr),
|
2001-12-24 03:51:06 +01:00
|
|
|
msg_type,
|
|
|
|
msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
reinterpret_cast<UCHAR*>(dsql_msg_buf)
|
2001-12-24 03:51:06 +01:00
|
|
|
#ifdef SCROLLABLE_CURSORS
|
|
|
|
, direction, offset
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_free_statement(
|
|
|
|
ISC_STATUS* user_status,
|
2003-02-12 20:28:13 +01:00
|
|
|
dsql_req** req_handle,
|
|
|
|
USHORT option)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2003-02-12 20:28:13 +01:00
|
|
|
return GDS_DSQL_FREE_CPP(user_status, req_handle, option);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_insert(
|
|
|
|
ISC_STATUS* user_status,
|
2003-10-01 12:58:07 +02:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT blr_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const SCHAR* blr,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const SCHAR* dsql_msg_buf)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
return GDS_DSQL_INSERT_CPP( user_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
blr_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(blr),
|
2001-12-24 03:51:06 +01:00
|
|
|
msg_type,
|
|
|
|
msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(dsql_msg_buf));
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_prepare(
|
|
|
|
ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2003-10-03 04:00:40 +02:00
|
|
|
dsql_req** req_handle,
|
|
|
|
USHORT length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* string,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT dialect,
|
|
|
|
USHORT item_length,
|
|
|
|
const SCHAR* items,
|
|
|
|
USHORT buffer_length,
|
|
|
|
SCHAR* buffer)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
return GDS_DSQL_PREPARE_CPP(user_status,
|
|
|
|
trans_handle,
|
2002-12-16 16:38:26 +01:00
|
|
|
req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
length,
|
|
|
|
string,
|
|
|
|
dialect,
|
|
|
|
item_length,
|
2003-02-13 10:33:26 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(items),
|
2001-12-24 03:51:06 +01:00
|
|
|
buffer_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
reinterpret_cast<UCHAR*>(buffer));
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
//////////////////////////////////////////////////////////////////
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_sql_info(
|
|
|
|
ISC_STATUS* user_status,
|
|
|
|
dsql_req** req_handle,
|
|
|
|
USHORT item_length,
|
|
|
|
const SCHAR* items,
|
|
|
|
USHORT info_length,
|
|
|
|
SCHAR* info)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
return GDS_DSQL_SQL_INFO_CPP( user_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
item_length,
|
2003-02-12 20:28:13 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(items),
|
2001-12-24 03:51:06 +01:00
|
|
|
info_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
reinterpret_cast<UCHAR*>(info));
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_set_cursor(
|
|
|
|
ISC_STATUS* user_status,
|
|
|
|
dsql_req** req_handle,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* input_cursor,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT type)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
return GDS_DSQL_SET_CURSOR_CPP(user_status,
|
2003-02-12 20:28:13 +01:00
|
|
|
req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
input_cursor,
|
|
|
|
type);
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
// End : C API -> C++ wrapper functions
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_allocate_statement
|
|
|
|
|
|
|
|
@brief Allocate a statement handle.
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param db_handle
|
|
|
|
@param req_handle
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS
|
|
|
|
GDS_DSQL_ALLOCATE_CPP( ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* db_handle,
|
2003-02-12 20:28:13 +01:00
|
|
|
dsql_req** req_handle)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
init(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// If we haven't been initialized yet, do it now
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* database = init(db_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(DsqlMemoryPool::createPool());
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// allocate the request block
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
dsql_req* request = FB_NEW(*tdsql->getDefaultPool()) dsql_req(*tdsql->getDefaultPool());
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_dbb = database;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
*req_handle = request;
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_execute
|
|
|
|
|
|
|
|
@brief Execute a non-SELECT dynamic SQL statement.
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param trans_handle
|
|
|
|
@param req_handle
|
|
|
|
@param in_blr_length
|
|
|
|
@param in_blr
|
|
|
|
@param in_msg_type
|
|
|
|
@param in_msg_length
|
|
|
|
@param in_msg
|
|
|
|
@param out_blr_length
|
|
|
|
@param out_blr
|
|
|
|
@param out_msg_type
|
|
|
|
@param out_msg_length
|
|
|
|
@param out_msg
|
|
|
|
|
|
|
|
**/
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS GDS_DSQL_EXECUTE_CPP(
|
|
|
|
ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2003-10-03 04:00:40 +02:00
|
|
|
dsql_req** req_handle,
|
|
|
|
USHORT in_blr_length,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* in_blr,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT in_msg_type,
|
|
|
|
USHORT in_msg_length,
|
|
|
|
UCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
UCHAR* out_blr,
|
|
|
|
USHORT out_msg_type,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
UCHAR* out_msg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS sing_status;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
init(0);
|
|
|
|
sing_status = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request = *req_handle;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(&request->req_pool);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if ((SSHORT) in_msg_type == -1) {
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_type = REQ_EMBED_SELECT;
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Only allow NULL trans_handle if we're starting a transaction
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
if (*trans_handle == 0 && request->req_type != REQ_START_TRANS)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 901,
|
|
|
|
isc_arg_gds, isc_bad_trans_handle, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If the request is a SELECT or blob statement then this is an open.
|
|
|
|
Make sure the cursor is not already open. */
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_type == REQ_SELECT ||
|
2004-01-16 11:43:21 +01:00
|
|
|
request->req_type == REQ_EXEC_BLOCK ||
|
|
|
|
request->req_type == REQ_SELECT_BLOCK ||
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_type == REQ_SELECT_UPD ||
|
|
|
|
request->req_type == REQ_EMBED_SELECT ||
|
|
|
|
request->req_type == REQ_GET_SEGMENT ||
|
|
|
|
request->req_type == REQ_PUT_SEGMENT)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
|
|
|
if (request->req_flags & REQ_cursor_open)
|
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 502,
|
|
|
|
isc_arg_gds, isc_dsql_cursor_open_err, 0);
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// A select with a non zero output length is a singleton select
|
2003-11-01 11:26:43 +01:00
|
|
|
bool singleton;
|
2003-02-12 20:28:13 +01:00
|
|
|
if (request->req_type == REQ_SELECT && out_msg_length != 0) {
|
2003-09-04 23:26:15 +02:00
|
|
|
singleton = true;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-09-04 23:26:15 +02:00
|
|
|
singleton = false;
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_type != REQ_EMBED_SELECT)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-09-04 23:26:15 +02:00
|
|
|
sing_status = execute_request(request, trans_handle, in_blr_length,
|
|
|
|
in_blr, in_msg_length, in_msg,
|
|
|
|
out_blr_length, out_blr,
|
|
|
|
out_msg_length, out_msg, singleton);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If the output message length is zero on a REQ_SELECT then we must
|
|
|
|
* be doing an OPEN cursor operation.
|
2001-07-10 19:35:13 +02:00
|
|
|
* If we do have an output message length, then we're doing
|
2001-05-23 15:26:42 +02:00
|
|
|
* a singleton SELECT. In that event, we don't add the cursor
|
|
|
|
* to the list of open cursors (it's not really open).
|
|
|
|
*/
|
2002-04-04 07:35:21 +02:00
|
|
|
if ((request->req_type == REQ_SELECT && out_msg_length == 0) ||
|
2004-01-16 11:43:21 +01:00
|
|
|
(request->req_type == REQ_SELECT_BLOCK) ||
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_type == REQ_SELECT_UPD ||
|
|
|
|
request->req_type == REQ_EMBED_SELECT ||
|
|
|
|
request->req_type == REQ_GET_SEGMENT ||
|
2003-02-12 20:28:13 +01:00
|
|
|
request->req_type == REQ_PUT_SEGMENT)
|
|
|
|
{
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_flags |= REQ_cursor_open |
|
|
|
|
((request->
|
|
|
|
req_type == REQ_EMBED_SELECT) ? REQ_embedded_sql_cursor : 0);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_opn* open_cursor = FB_NEW(*DSQL_permanent_pool) dsql_opn;
|
2003-11-01 11:26:43 +01:00
|
|
|
request->req_open_cursor = open_cursor;
|
2002-04-04 07:35:21 +02:00
|
|
|
open_cursor->opn_request = request;
|
2002-12-16 16:38:26 +01:00
|
|
|
open_cursor->opn_transaction = *trans_handle;
|
2002-04-04 07:35:21 +02:00
|
|
|
THD_MUTEX_LOCK(&cursors_mutex);
|
|
|
|
open_cursor->opn_next = open_cursors;
|
|
|
|
open_cursors = open_cursor;
|
|
|
|
THD_MUTEX_UNLOCK(&cursors_mutex);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-11-01 11:26:43 +01:00
|
|
|
ISC_STATUS_ARRAY local_status;
|
2002-04-04 07:35:21 +02:00
|
|
|
gds__transaction_cleanup(local_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
trans_handle,
|
2004-01-21 08:18:30 +01:00
|
|
|
cleanup_transaction, NULL);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!sing_status) {
|
|
|
|
return return_success();
|
|
|
|
}
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch (const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2001-12-24 03:51:06 +01:00
|
|
|
return sing_status;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS dsql8_execute_immediate_common(ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* db_handle,
|
|
|
|
FB_API_HANDLE* trans_handle,
|
2002-04-04 15:53:20 +02:00
|
|
|
USHORT length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* string,
|
2002-04-04 15:53:20 +02:00
|
|
|
USHORT dialect,
|
|
|
|
USHORT in_blr_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const UCHAR* in_blr,
|
2002-04-04 15:53:20 +02:00
|
|
|
USHORT in_msg_type,
|
|
|
|
USHORT in_msg_length,
|
|
|
|
UCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
UCHAR* out_blr,
|
|
|
|
USHORT out_msg_type,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
UCHAR* out_msg,
|
|
|
|
long possible_requests)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2002-04-04 15:53:20 +02:00
|
|
|
* d s q l _ e x e c u t e _ i m m e d i a t e _ c o m m o n
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2002-04-04 15:53:20 +02:00
|
|
|
* Common part of prepare and execute a statement.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS status;
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* database = init(db_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(DsqlMemoryPool::createPool());
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// allocate the request block, then prepare the request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
dsql_req* request = FB_NEW(*tdsql->getDefaultPool())
|
|
|
|
dsql_req(*tdsql->getDefaultPool());
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_dbb = database;
|
2002-12-16 16:38:26 +01:00
|
|
|
request->req_trans = *trans_handle;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try {
|
|
|
|
|
|
|
|
if (!length) {
|
|
|
|
length = strlen(string);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Figure out which parser version to use
|
2003-09-28 02:36:28 +02:00
|
|
|
/* Since the API to dsql8_execute_immediate is public and can not be changed, there needs to
|
2001-05-23 15:26:42 +02:00
|
|
|
* be a way to send the parser version to DSQL so that the parser can compare the keyword
|
|
|
|
* version to the parser version. To accomplish this, the parser version is combined with
|
|
|
|
* the client dialect and sent across that way. In dsql8_execute_immediate, the parser version
|
|
|
|
* and client dialect are separated and passed on to their final desintations. The information
|
|
|
|
* is combined as follows:
|
|
|
|
* Dialect * 10 + parser_version
|
|
|
|
*
|
|
|
|
* and is extracted in dsql8_execute_immediate as follows:
|
|
|
|
* parser_version = ((dialect *10)+parser_version)%10
|
|
|
|
* client_dialect = ((dialect *10)+parser_version)/10
|
|
|
|
*
|
|
|
|
* For example, parser_version = 1 and client dialect = 1
|
|
|
|
*
|
|
|
|
* combined = (1 * 10) + 1 == 11
|
|
|
|
*
|
|
|
|
* parser = (combined) %10 == 1
|
|
|
|
* dialect = (combined) / 19 == 1
|
|
|
|
*
|
2001-07-10 19:35:13 +02:00
|
|
|
* If the parser version is not part of the dialect, then assume that the
|
2001-05-23 15:26:42 +02:00
|
|
|
* connection being made is a local classic connection.
|
|
|
|
*/
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
USHORT parser_version;
|
2002-04-04 07:35:21 +02:00
|
|
|
if ((dialect / 10) == 0)
|
|
|
|
parser_version = 2;
|
|
|
|
else {
|
|
|
|
parser_version = dialect % 10;
|
|
|
|
dialect /= 10;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_client_dialect = dialect;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
request = prepare(request, length, string, dialect, parser_version);
|
2002-04-04 15:53:20 +02:00
|
|
|
|
|
|
|
if (!((1 << request->req_type) & possible_requests))
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-06-16 17:43:00 +02:00
|
|
|
const int max_diag_len = 50;
|
2003-11-28 07:48:34 +01:00
|
|
|
char err_str[max_diag_len + 1];
|
|
|
|
strncpy(err_str, string, max_diag_len);
|
|
|
|
err_str[max_diag_len] = 0;
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -902,
|
|
|
|
isc_arg_gds, isc_exec_sql_invalid_req,
|
2003-11-28 07:48:34 +01:00
|
|
|
isc_arg_string, err_str, isc_arg_end);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2002-04-04 15:53:20 +02:00
|
|
|
|
2003-09-04 23:26:15 +02:00
|
|
|
execute_request(request, trans_handle, in_blr_length, in_blr,
|
|
|
|
in_msg_length, in_msg, out_blr_length, out_blr,
|
|
|
|
out_msg_length, out_msg, false);
|
|
|
|
|
|
|
|
release_request(request, true);
|
2002-04-04 07:35:21 +02:00
|
|
|
} // try
|
2004-03-01 04:35:23 +01:00
|
|
|
catch (const std::exception& ex) {
|
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2002-04-04 07:35:21 +02:00
|
|
|
status = error();
|
2003-09-04 23:26:15 +02:00
|
|
|
release_request(request, true);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2002-04-04 07:35:21 +02:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-10-03 04:00:40 +02:00
|
|
|
ISC_STATUS dsql8_execute_immediate(
|
|
|
|
ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* db_handle,
|
|
|
|
FB_API_HANDLE* trans_handle,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* string,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT dialect,
|
|
|
|
USHORT in_blr_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const SCHAR* in_blr,
|
2003-10-03 04:00:40 +02:00
|
|
|
USHORT in_msg_type,
|
|
|
|
USHORT in_msg_length,
|
|
|
|
SCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
SCHAR* out_blr,
|
|
|
|
USHORT out_msg_type,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
SCHAR* out_msg)
|
2002-04-04 15:53:20 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d s q l _ e x e c u t e _ i m m e d i a t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Prepare and execute a statement.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
return dsql8_execute_immediate_common(user_status, db_handle, trans_handle, length,
|
2002-12-16 16:38:26 +01:00
|
|
|
string, dialect, in_blr_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
reinterpret_cast<const UCHAR*>(in_blr),
|
2002-12-16 16:38:26 +01:00
|
|
|
in_msg_type, in_msg_length,
|
|
|
|
reinterpret_cast<UCHAR*>(in_msg),
|
|
|
|
out_blr_length,
|
|
|
|
reinterpret_cast<UCHAR*>(out_blr),
|
|
|
|
out_msg_type, out_msg_length,
|
|
|
|
reinterpret_cast<UCHAR*>(out_msg),
|
|
|
|
~0);
|
2002-04-04 15:53:20 +02:00
|
|
|
}
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
check_for_create_database
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
@brief When executing dynamic sql_operator in context of existing connection and
|
2003-02-15 04:01:51 +01:00
|
|
|
existing transaction, it is not clear - what should do "Create Database"
|
|
|
|
operator with existing db_handle and tra_handle. Therefore we don't exec it.
|
|
|
|
|
|
|
|
|
|
|
|
@param sql
|
|
|
|
@param crdb
|
|
|
|
|
|
|
|
**/
|
2004-03-20 15:57:40 +01:00
|
|
|
static bool check_for_create_database(const Firebird::string& sql,
|
2003-11-01 11:26:43 +01:00
|
|
|
const TEXT* crdb)
|
2002-04-04 15:53:20 +02:00
|
|
|
{
|
2004-03-31 19:27:08 +02:00
|
|
|
for (Firebird::string::size_type i = 0; i < sql.length(); i++) {
|
2004-03-20 15:57:40 +01:00
|
|
|
switch (sql[i]) {
|
2002-04-04 15:53:20 +02:00
|
|
|
case '\t':
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
case ' ':
|
|
|
|
continue;
|
|
|
|
}
|
2004-03-20 15:57:40 +01:00
|
|
|
if (tolower(sql[i]) != *crdb++)
|
2002-04-04 15:53:20 +02:00
|
|
|
break;
|
|
|
|
if (! *crdb)
|
2003-11-01 11:26:43 +01:00
|
|
|
return true;
|
2002-04-04 15:53:20 +02:00
|
|
|
}
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
return false;
|
2002-04-04 15:53:20 +02:00
|
|
|
}
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
callback_execute_immediate
|
|
|
|
|
|
|
|
@brief Execute sql_operator in context of jrd_transaction_handle
|
|
|
|
|
|
|
|
|
|
|
|
@param status
|
|
|
|
@param jrd_attachment_handle
|
|
|
|
@param jrd_transaction_handle
|
|
|
|
@param sql_operator
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS callback_execute_immediate( ISC_STATUS* status,
|
2004-03-20 15:57:40 +01:00
|
|
|
Jrd::Attachment* jrd_attachment_handle,
|
|
|
|
Jrd::jrd_tra* jrd_transaction_handle,
|
|
|
|
const Firebird::string& sql_operator)
|
2002-04-04 15:53:20 +02:00
|
|
|
{
|
2003-11-28 07:48:34 +01:00
|
|
|
// Other requests appear to be incorrect in this context
|
2002-04-04 15:53:20 +02:00
|
|
|
long requests = (1 << REQ_INSERT) | (1 << REQ_DELETE) | (1 << REQ_UPDATE)
|
2003-01-14 14:47:30 +01:00
|
|
|
| (1 << REQ_DDL) | (1 << REQ_SET_GENERATOR) | (1 << REQ_EXEC_PROCEDURE);
|
2002-04-04 15:53:20 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
if (check_for_create_database(sql_operator, "createdatabase") ||
|
|
|
|
check_for_create_database(sql_operator, "createschema"))
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
|
|
|
requests = 0;
|
|
|
|
}
|
2002-04-04 15:53:20 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// 1. Locate why_db_handle, corresponding to jrd_database_handle
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2002-04-04 15:53:20 +02:00
|
|
|
THD_MUTEX_LOCK (&databases_mutex);
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* database;
|
2002-04-04 15:53:20 +02:00
|
|
|
for (database = databases; database; database = database->dbb_next)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2004-05-03 01:06:37 +02:00
|
|
|
if (WHY_translate_handle(database->dbb_database_handle)->handle.h_dbb == jrd_attachment_handle)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2002-04-04 15:53:20 +02:00
|
|
|
break;
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
|
|
|
}
|
2002-04-04 15:53:20 +02:00
|
|
|
if (! database) {
|
2003-11-08 00:27:24 +01:00
|
|
|
status[0] = isc_arg_gds;
|
|
|
|
status[1] = isc_bad_db_handle;
|
|
|
|
status[2] = isc_arg_end;
|
2002-04-04 15:53:20 +02:00
|
|
|
THD_MUTEX_UNLOCK(&databases_mutex);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2002-04-04 15:53:20 +02:00
|
|
|
return status[1];
|
|
|
|
}
|
2004-05-03 01:06:37 +02:00
|
|
|
WHY_DBB why_db_handle = WHY_translate_handle(database->dbb_database_handle);
|
2002-04-04 15:53:20 +02:00
|
|
|
|
|
|
|
/* 2. Create why_trans_handle - it's new, but points to the same jrd
|
|
|
|
transaction as original before callback. */
|
2004-05-03 01:06:37 +02:00
|
|
|
WHY_TRA why_trans_handle = WHY_alloc_handle(why_db_handle->implementation, HANDLE_transaction);
|
2004-05-05 06:20:39 +02:00
|
|
|
if (!why_trans_handle) {
|
|
|
|
status[0] = isc_arg_gds;
|
|
|
|
status[1] = isc_virmemexh;
|
|
|
|
status[2] = isc_arg_end;
|
|
|
|
THD_MUTEX_UNLOCK(&databases_mutex);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2004-05-05 06:20:39 +02:00
|
|
|
return status[1];
|
|
|
|
}
|
2002-12-16 16:38:26 +01:00
|
|
|
why_trans_handle->handle.h_tra = jrd_transaction_handle;
|
2002-04-04 15:53:20 +02:00
|
|
|
why_trans_handle->parent = why_db_handle;
|
|
|
|
THD_MUTEX_UNLOCK (&databases_mutex);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2002-04-04 15:53:20 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// 3. Call execute... function
|
2004-04-10 02:25:22 +02:00
|
|
|
const ISC_STATUS rc = dsql8_execute_immediate_common(status,
|
2004-05-03 01:06:37 +02:00
|
|
|
&database->dbb_database_handle, &why_trans_handle->public_handle,
|
2004-03-20 15:57:40 +01:00
|
|
|
sql_operator.length(), sql_operator.c_str(),
|
|
|
|
database->dbb_db_SQL_dialect,
|
|
|
|
0, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL, requests);
|
2004-03-31 19:27:08 +02:00
|
|
|
WHY_cleanup_transaction(why_trans_handle);
|
2004-05-03 01:06:37 +02:00
|
|
|
WHY_free_handle(why_trans_handle->public_handle);
|
2004-03-31 19:27:08 +02:00
|
|
|
return rc;
|
2002-04-04 15:53:20 +02:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-04-10 08:32:58 +02:00
|
|
|
WHY_DBB GetWhyAttachment (ISC_STATUS* status,
|
2004-03-20 15:57:40 +01:00
|
|
|
Jrd::Attachment* jrd_attachment_handle)
|
2003-03-01 20:19:23 +01:00
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-03-01 20:19:23 +01:00
|
|
|
THD_MUTEX_LOCK (&databases_mutex);
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* database;
|
2004-05-03 01:06:37 +02:00
|
|
|
WHY_DBB db_handle;
|
2003-03-01 20:19:23 +01:00
|
|
|
for (database = databases; database; database = database->dbb_next)
|
|
|
|
{
|
2004-05-03 01:06:37 +02:00
|
|
|
db_handle = WHY_translate_handle(database->dbb_database_handle);
|
|
|
|
if (db_handle->handle.h_dbb == jrd_attachment_handle)
|
2003-03-01 20:19:23 +01:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! database) {
|
2003-11-08 00:27:24 +01:00
|
|
|
status[0] = isc_arg_gds;
|
|
|
|
status[1] = isc_bad_db_handle;
|
|
|
|
status[2] = isc_arg_end;
|
2003-03-01 20:19:23 +01:00
|
|
|
}
|
|
|
|
THD_MUTEX_UNLOCK (&databases_mutex);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2004-05-03 01:06:37 +02:00
|
|
|
return database ? db_handle : 0;
|
2003-03-01 20:19:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_fetch
|
|
|
|
|
|
|
|
@brief Fetch next record from a dynamic SQL cursor
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param req_handle
|
|
|
|
@param blr_length
|
|
|
|
@param blr
|
|
|
|
@param msg_type
|
|
|
|
@param msg_length
|
|
|
|
@param dsql_msg
|
|
|
|
@param direction
|
|
|
|
@param offset
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_FETCH_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT blr_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* blr,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR* dsql_msg_buf
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SCROLLABLE_CURSORS
|
2001-12-24 03:51:06 +01:00
|
|
|
, USHORT direction, SLONG offset
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2001-12-24 03:51:06 +01:00
|
|
|
)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_msg* message;
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* parameter;
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS s;
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
init(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request = *req_handle;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(&request->req_pool);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// if the cursor isn't open, we've got a problem
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_type == REQ_SELECT ||
|
|
|
|
request->req_type == REQ_SELECT_UPD ||
|
2004-01-16 11:43:21 +01:00
|
|
|
request->req_type == REQ_SELECT_BLOCK ||
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_type == REQ_EMBED_SELECT ||
|
|
|
|
request->req_type == REQ_GET_SEGMENT)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
|
|
|
if (!(request->req_flags & REQ_cursor_open))
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 504,
|
|
|
|
isc_arg_gds, isc_dsql_cursor_err, 0);
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef SCROLLABLE_CURSORS
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* check whether we need to send an asynchronous scrolling message
|
|
|
|
to the engine; the engine will automatically advance one record
|
|
|
|
in the same direction as before, so optimize out messages of that
|
2001-05-23 15:26:42 +02:00
|
|
|
type */
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_type == REQ_SELECT &&
|
2003-02-12 20:28:13 +01:00
|
|
|
request->req_dbb->dbb_base_level >= 5)
|
|
|
|
{
|
|
|
|
switch (direction)
|
|
|
|
{
|
2002-04-04 07:35:21 +02:00
|
|
|
case isc_fetch_next:
|
|
|
|
if (!(request->req_flags & REQ_backwards))
|
|
|
|
offset = 0;
|
|
|
|
else {
|
|
|
|
direction = blr_forward;
|
|
|
|
offset = 1;
|
|
|
|
request->req_flags &= ~REQ_backwards;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_fetch_prior:
|
|
|
|
if (request->req_flags & REQ_backwards)
|
|
|
|
offset = 0;
|
|
|
|
else {
|
|
|
|
direction = blr_backward;
|
|
|
|
offset = 1;
|
|
|
|
request->req_flags |= REQ_backwards;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_fetch_first:
|
|
|
|
direction = blr_bof_forward;
|
2001-05-23 15:26:42 +02:00
|
|
|
offset = 1;
|
|
|
|
request->req_flags &= ~REQ_backwards;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
case isc_fetch_last:
|
|
|
|
direction = blr_eof_backward;
|
2001-05-23 15:26:42 +02:00
|
|
|
offset = 1;
|
|
|
|
request->req_flags |= REQ_backwards;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_fetch_absolute:
|
|
|
|
direction = blr_bof_forward;
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_flags &= ~REQ_backwards;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
case isc_fetch_relative:
|
|
|
|
if (offset < 0) {
|
|
|
|
direction = blr_backward;
|
|
|
|
offset = -offset;
|
|
|
|
request->req_flags |= REQ_backwards;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
direction = blr_forward;
|
|
|
|
request->req_flags &= ~REQ_backwards;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (offset)
|
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* offset_parameter;
|
2002-04-04 07:35:21 +02:00
|
|
|
DSC desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
message = (dsql_msg*) request->req_async;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
desc.dsc_dtype = dtype_short;
|
|
|
|
desc.dsc_scale = 0;
|
|
|
|
desc.dsc_length = sizeof(USHORT);
|
|
|
|
desc.dsc_flags = 0;
|
2004-01-21 08:18:30 +01:00
|
|
|
desc.dsc_address = (UCHAR*) & direction;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
offset_parameter = message->msg_parameters;
|
|
|
|
parameter = offset_parameter->par_next;
|
|
|
|
MOVD_move(&desc, ¶meter->par_desc);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
desc.dsc_dtype = dtype_long;
|
|
|
|
desc.dsc_scale = 0;
|
|
|
|
desc.dsc_length = sizeof(SLONG);
|
|
|
|
desc.dsc_flags = 0;
|
2004-01-21 08:18:30 +01:00
|
|
|
desc.dsc_address = (UCHAR*) & offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
MOVD_move(&desc, &offset_parameter->par_desc);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-08-30 03:54:25 +02:00
|
|
|
s = isc_receive2(tdsql->tsql_status, &request->req_handle,
|
|
|
|
message->msg_number, message->msg_length,
|
|
|
|
message->msg_buffer, 0, direction, offset);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (s) {
|
2002-04-04 07:35:21 +02:00
|
|
|
punt();
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
message = (dsql_msg*) request->req_receive;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Insure that the blr for the message is parsed, regardless of
|
|
|
|
whether anything is found by the call to receive. */
|
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (blr_length) {
|
2002-04-04 07:35:21 +02:00
|
|
|
parse_blr(blr_length, blr, msg_length, message->msg_parameters);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (request->req_type == REQ_GET_SEGMENT)
|
|
|
|
{
|
|
|
|
// For get segment, use the user buffer and indicator directly.
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
parameter = request->req_blob->blb_segment;
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* null = parameter->par_null;
|
2003-02-12 20:28:13 +01:00
|
|
|
USHORT* ret_length =
|
2004-01-21 08:18:30 +01:00
|
|
|
(USHORT *) (dsql_msg_buf + (IPTR) null->par_user_desc.dsc_address);
|
|
|
|
UCHAR* buffer = dsql_msg_buf + (IPTR) parameter->par_user_desc.dsc_address;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-08-30 03:54:25 +02:00
|
|
|
s = isc_get_segment(tdsql->tsql_status, &request->req_handle,
|
|
|
|
ret_length, parameter->par_user_desc.dsc_length,
|
|
|
|
reinterpret_cast<char*>(buffer));
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!s) {
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2002-04-04 07:35:21 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (s == isc_segment) {
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2002-04-04 07:35:21 +02:00
|
|
|
return 101;
|
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (s == isc_segstr_eof) {
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2002-04-04 07:35:21 +02:00
|
|
|
return 100;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
punt();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-08-30 03:54:25 +02:00
|
|
|
s = isc_receive(tdsql->tsql_status, &request->req_handle,
|
|
|
|
message->msg_number, message->msg_length,
|
|
|
|
message->msg_buffer, 0);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (s) {
|
2002-04-04 07:35:21 +02:00
|
|
|
punt();
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
const dsql_par* eof = request->req_eof;
|
2003-02-12 20:28:13 +01:00
|
|
|
if (eof)
|
|
|
|
{
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!*((USHORT *) eof->par_desc.dsc_address)) {
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2002-04-04 07:35:21 +02:00
|
|
|
return 100;
|
|
|
|
}
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
map_in_out(NULL, message, 0, blr, msg_length, dsql_msg_buf);
|
2002-04-04 07:35:21 +02:00
|
|
|
} // try
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_free_statement
|
|
|
|
|
|
|
|
@brief Release request for a dsql statement
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param req_handle
|
|
|
|
@param option
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_FREE_CPP(ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT option)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request;
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
init(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
request = *req_handle;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(&request->req_pool);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (option & DSQL_drop) {
|
2003-11-28 07:48:34 +01:00
|
|
|
// Release everything associate with the request.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-04 23:26:15 +02:00
|
|
|
release_request(request, true);
|
2002-04-04 07:35:21 +02:00
|
|
|
*req_handle = NULL;
|
|
|
|
}
|
|
|
|
else if (option & DSQL_close) {
|
2003-11-28 07:48:34 +01:00
|
|
|
// Just close the cursor associated with the request.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!(request->req_flags & REQ_cursor_open))
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 501,
|
|
|
|
isc_arg_gds, isc_dsql_cursor_close_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
close_cursor(request);
|
|
|
|
}
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_insert
|
|
|
|
|
|
|
|
@brief Insert next record into a dynamic SQL cursor
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param req_handle
|
|
|
|
@param blr_length
|
|
|
|
@param blr
|
|
|
|
@param msg_type
|
|
|
|
@param msg_length
|
|
|
|
@param dsql_msg
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_INSERT_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT blr_length,
|
2003-10-29 11:53:47 +01:00
|
|
|
const UCHAR* blr,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT msg_type,
|
|
|
|
USHORT msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* dsql_msg_buf)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
init(0);
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
dsql_req* request = *req_handle;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(&request->req_pool);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// if the cursor isn't open, we've got a problem
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_type == REQ_PUT_SEGMENT)
|
|
|
|
if (!(request->req_flags & REQ_cursor_open))
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 504,
|
|
|
|
isc_arg_gds, isc_dsql_cursor_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
dsql_msg* message = (dsql_msg*) request->req_receive;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Insure that the blr for the message is parsed, regardless of
|
|
|
|
whether anything is found by the call to receive. */
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (blr_length)
|
|
|
|
parse_blr(blr_length, blr, msg_length, message->msg_parameters);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_type == REQ_PUT_SEGMENT) {
|
2003-11-28 07:48:34 +01:00
|
|
|
// For put segment, use the user buffer and indicator directly.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* parameter = request->req_blob->blb_segment;
|
2003-10-29 11:53:47 +01:00
|
|
|
const SCHAR* buffer =
|
|
|
|
reinterpret_cast<const SCHAR*>(
|
2004-01-21 08:18:30 +01:00
|
|
|
dsql_msg_buf + (IPTR) parameter->par_user_desc.dsc_address);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-11-28 07:48:34 +01:00
|
|
|
const ISC_STATUS s =
|
|
|
|
isc_put_segment(tdsql->tsql_status, &request->req_handle,
|
2003-08-30 03:54:25 +02:00
|
|
|
parameter->par_user_desc.dsc_length, buffer);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2002-04-04 07:35:21 +02:00
|
|
|
if (s)
|
|
|
|
punt();
|
|
|
|
}
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_prepare
|
|
|
|
|
|
|
|
@brief Prepare a statement for execution.
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param trans_handle
|
|
|
|
@param req_handle
|
|
|
|
@param length
|
|
|
|
@param string
|
|
|
|
@param dialect
|
|
|
|
@param item_length
|
|
|
|
@param items
|
|
|
|
@param buffer_length
|
|
|
|
@param buffer
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_PREPARE_CPP(ISC_STATUS* user_status,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2002-12-16 16:38:26 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* string,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT dialect,
|
|
|
|
USHORT item_length,
|
2003-02-13 10:33:26 +01:00
|
|
|
const UCHAR* items,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT buffer_length,
|
|
|
|
UCHAR* buffer)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS status;
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
init(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* old_request = *req_handle;
|
|
|
|
if (!old_request) {
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -901,
|
|
|
|
isc_arg_gds, isc_bad_req_handle,
|
2003-11-01 11:26:43 +01:00
|
|
|
0);
|
|
|
|
}
|
2002-06-29 08:56:51 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* database;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (old_request) { // this test is irrelevant, see ERRD_post call above
|
|
|
|
database = old_request->req_dbb;
|
|
|
|
if (!database) {
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -901,
|
|
|
|
isc_arg_gds, isc_bad_req_handle,
|
2003-11-01 11:26:43 +01:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// check to see if old request has an open cursor
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (old_request && (old_request->req_flags & REQ_cursor_open)) {
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 519,
|
|
|
|
isc_arg_gds, isc_dsql_open_cursor_request, 0);
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Allocate a new request block and then prepare the request. We want to
|
|
|
|
keep the old request around, as is, until we know that we are able
|
|
|
|
to prepare the new one. */
|
|
|
|
/* It would be really *nice* to know *why* we want to
|
|
|
|
keep the old request around -- 1994-October-27 David Schnepper */
|
2002-06-29 08:56:51 +02:00
|
|
|
/* Because that's the client's allocated statement handle and we
|
|
|
|
don't want to trash the context in it -- 2001-Oct-27 Ann Harrison */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(DsqlMemoryPool::createPool());
|
|
|
|
dsql_req* request = FB_NEW(*tdsql->getDefaultPool())
|
|
|
|
dsql_req(*tdsql->getDefaultPool());
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_dbb = database;
|
2002-12-16 16:38:26 +01:00
|
|
|
request->req_trans = *trans_handle;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try {
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-11 01:00:51 +01:00
|
|
|
if (!string) {
|
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
|
|
|
|
isc_arg_gds, isc_command_end_err, 0); // Unexpected end of command
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!length) {
|
2002-04-04 07:35:21 +02:00
|
|
|
length = strlen(string);
|
2003-12-11 01:00:51 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Figure out which parser version to use
|
2003-09-28 02:36:28 +02:00
|
|
|
/* Since the API to dsql8_prepare is public and can not be changed, there needs to
|
2001-05-23 15:26:42 +02:00
|
|
|
* be a way to send the parser version to DSQL so that the parser can compare the keyword
|
|
|
|
* version to the parser version. To accomplish this, the parser version is combined with
|
|
|
|
* the client dialect and sent across that way. In dsql8_prepare_statement, the parser version
|
|
|
|
* and client dialect are separated and passed on to their final desintations. The information
|
|
|
|
* is combined as follows:
|
|
|
|
* Dialect * 10 + parser_version
|
|
|
|
*
|
|
|
|
* and is extracted in dsql8_prepare_statement as follows:
|
|
|
|
* parser_version = ((dialect *10)+parser_version)%10
|
|
|
|
* client_dialect = ((dialect *10)+parser_version)/10
|
|
|
|
*
|
|
|
|
* For example, parser_version = 1 and client dialect = 1
|
|
|
|
*
|
|
|
|
* combined = (1 * 10) + 1 == 11
|
|
|
|
*
|
|
|
|
* parser = (combined) %10 == 1
|
|
|
|
* dialect = (combined) / 19 == 1
|
|
|
|
*
|
2001-07-10 19:35:13 +02:00
|
|
|
* If the parser version is not part of the dialect, then assume that the
|
2001-05-23 15:26:42 +02:00
|
|
|
* connection being made is a local classic connection.
|
|
|
|
*/
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
USHORT parser_version;
|
2002-04-04 07:35:21 +02:00
|
|
|
if ((dialect / 10) == 0)
|
|
|
|
parser_version = 2;
|
|
|
|
else {
|
|
|
|
parser_version = dialect % 10;
|
|
|
|
dialect /= 10;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_client_dialect = dialect;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
request = prepare(request, length, string, dialect, parser_version);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Can not prepare a CREATE DATABASE/SCHEMA statement
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if ((request->req_type == REQ_DDL) &&
|
|
|
|
(request->req_ddl_node->nod_type == nod_def_database))
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 530,
|
|
|
|
isc_arg_gds, isc_dsql_crdb_prepare_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
request->req_flags |= REQ_prepared;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Now that we know that the new request exists, zap the old one.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(&old_request->req_pool);
|
2003-09-04 23:26:15 +02:00
|
|
|
release_request(old_request, true);
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* The request was sucessfully prepared, and the old request was
|
|
|
|
* successfully zapped, so set the client's handle to the new request */
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
*req_handle = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-12-16 16:38:26 +01:00
|
|
|
return GDS_DSQL_SQL_INFO_CPP(user_status,
|
2001-12-24 03:51:06 +01:00
|
|
|
req_handle,
|
|
|
|
item_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
items,
|
2001-12-24 03:51:06 +01:00
|
|
|
buffer_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
buffer);
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
} // try
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex) {
|
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2002-04-04 07:35:21 +02:00
|
|
|
status = error();
|
2003-09-04 23:26:15 +02:00
|
|
|
release_request(request, true);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2002-04-04 07:35:21 +02:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_set_cursor_name
|
|
|
|
|
|
|
|
@brief Set a cursor name for a dynamic request
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param req_handle
|
|
|
|
@param input_cursor
|
|
|
|
@param type
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_SET_CURSOR_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* input_cursor,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
init(0);
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request = *req_handle;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(&request->req_pool);
|
2003-11-01 11:26:43 +01:00
|
|
|
|
|
|
|
TEXT cursor[132];
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (input_cursor[0] == '\"')
|
|
|
|
{
|
|
|
|
// Quoted cursor names eh? Strip'em.
|
|
|
|
// Note that "" will be replaced with ".
|
|
|
|
//
|
|
|
|
int index;
|
|
|
|
for (index = 0; *input_cursor; input_cursor++) {
|
|
|
|
if (*input_cursor == '\"') {
|
|
|
|
input_cursor++;
|
|
|
|
}
|
|
|
|
cursor[index++] = *input_cursor;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
cursor[index] = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
else // not quoted name
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2004-03-12 08:00:52 +01:00
|
|
|
size_t i;
|
2003-11-28 07:48:34 +01:00
|
|
|
for (i = 0; i < sizeof(cursor) - 1 // PJPG 20001013
|
|
|
|
&& input_cursor[i] // PJPG 20001013
|
|
|
|
&& input_cursor[i] != ' '; ++i) // PJPG 20001013
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
|
|
|
cursor[i] = UPPER7(input_cursor[i]);
|
|
|
|
}
|
|
|
|
cursor[i] = '\0';
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2003-11-01 11:26:43 +01:00
|
|
|
const USHORT length = name_length(cursor);
|
2002-04-04 07:35:21 +02:00
|
|
|
|
|
|
|
if (length == 0) {
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 502,
|
|
|
|
isc_arg_gds, isc_dsql_decl_err, 0);
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// If there already is a different cursor by the same name, bitch
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
const dsql_sym* symbol =
|
|
|
|
HSHD_lookup(request->req_dbb, cursor, length, SYM_cursor, 0);
|
|
|
|
if (symbol) {
|
2002-04-04 07:35:21 +02:00
|
|
|
if (request->req_cursor == symbol) {
|
|
|
|
return return_success();
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 502,
|
|
|
|
isc_arg_gds, isc_dsql_decl_err, 0);
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* If there already is a cursor and its name isn't the same, ditto.
|
2001-05-23 15:26:42 +02:00
|
|
|
We already know there is no cursor by this name in the hash table */
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!request->req_cursor) {
|
|
|
|
request->req_cursor = MAKE_symbol(request->req_dbb, cursor,
|
2001-05-23 15:26:42 +02:00
|
|
|
length, SYM_cursor, request);
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(request->req_cursor != symbol);
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 502,
|
|
|
|
isc_arg_gds, isc_dsql_decl_err, 0);
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
dsql_sql_info
|
|
|
|
|
|
|
|
@brief Provide information on dsql statement
|
|
|
|
|
|
|
|
|
|
|
|
@param user_status
|
|
|
|
@param req_handle
|
|
|
|
@param item_length
|
|
|
|
@param items
|
|
|
|
@param info_length
|
|
|
|
@param info
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS GDS_DSQL_SQL_INFO_CPP( ISC_STATUS* user_status,
|
2002-11-21 00:18:16 +01:00
|
|
|
dsql_req** req_handle,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT item_length,
|
2003-02-13 10:33:26 +01:00
|
|
|
const UCHAR* items,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT info_length,
|
2002-12-16 16:38:26 +01:00
|
|
|
UCHAR* info)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR buffer[256], *buffer_ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT length, number, first_index;
|
2003-10-01 12:58:07 +02:00
|
|
|
tsql thd_context;
|
|
|
|
tsql* tdsql;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_set_thread_data(tdsql, &thd_context);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
tdsql->tsql_status = user_status;
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
init(0);
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-13 04:32:30 +02:00
|
|
|
// Pre-initialize buffer. This is necessary because we don't want to transfer rubbish over the wire
|
|
|
|
memset(info, 0, info_length);
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request = *req_handle;
|
2002-04-04 07:35:21 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* const end_items = items + item_length;
|
|
|
|
const UCHAR* const end_info = info + info_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
// CVC: Is it the idea that this pointer remains with its previous value
|
|
|
|
// in the loop or should it be made NULL in each iteration?
|
|
|
|
dsql_msg** message = NULL;
|
2002-04-04 07:35:21 +02:00
|
|
|
first_index = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
while (items < end_items && *items != isc_info_end)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
UCHAR item = *items++; // cannot be const
|
2003-11-08 00:27:24 +01:00
|
|
|
if (item == isc_info_sql_select || item == isc_info_sql_bind)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
message = (item == isc_info_sql_select) ?
|
2002-04-04 07:35:21 +02:00
|
|
|
&request->req_receive : &request->req_send;
|
|
|
|
if (info + 1 >= end_info) {
|
2003-11-08 00:27:24 +01:00
|
|
|
*info = isc_info_truncated;
|
2002-04-04 07:35:21 +02:00
|
|
|
return return_success();
|
|
|
|
}
|
|
|
|
*info++ = item;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (item == isc_info_sql_stmt_type)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
|
|
|
switch (request->req_type) {
|
|
|
|
case REQ_SELECT:
|
|
|
|
case REQ_EMBED_SELECT:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_select;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_SELECT_UPD:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_select_for_upd;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_DDL:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_ddl;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_GET_SEGMENT:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_get_segment;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_PUT_SEGMENT:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_put_segment;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_COMMIT:
|
|
|
|
case REQ_COMMIT_RETAIN:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_commit;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_ROLLBACK:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_rollback;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_START_TRANS:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_start_trans;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_INSERT:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_insert;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_UPDATE:
|
|
|
|
case REQ_UPDATE_CURSOR:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_update;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_DELETE:
|
|
|
|
case REQ_DELETE_CURSOR:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_delete;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_EXEC_PROCEDURE:
|
2003-11-08 00:27:24 +01:00
|
|
|
number = isc_info_sql_stmt_exec_procedure;
|
2002-04-04 07:35:21 +02:00
|
|
|
break;
|
|
|
|
case REQ_SET_GENERATOR:
|
|
|
|
number = isc_info_sql_stmt_set_generator;
|
|
|
|
break;
|
2002-10-29 21:20:44 +01:00
|
|
|
case REQ_SAVEPOINT:
|
|
|
|
number = isc_info_sql_stmt_savepoint;
|
|
|
|
break;
|
2004-01-16 11:43:21 +01:00
|
|
|
case REQ_EXEC_BLOCK:
|
|
|
|
number = isc_info_sql_stmt_exec_procedure;
|
|
|
|
break;
|
|
|
|
case REQ_SELECT_BLOCK:
|
|
|
|
number = isc_info_sql_stmt_select;
|
|
|
|
break;
|
2002-04-04 07:35:21 +02:00
|
|
|
default:
|
|
|
|
number = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
length = convert((SLONG) number, buffer);
|
|
|
|
info = put_item(item, length, buffer, info, end_info);
|
|
|
|
if (!info) {
|
|
|
|
return return_success();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (item == isc_info_sql_sqlda_start) {
|
2002-04-04 07:35:21 +02:00
|
|
|
length = *items++;
|
2003-11-16 02:44:51 +01:00
|
|
|
first_index =
|
2004-02-02 12:02:12 +01:00
|
|
|
static_cast<USHORT>(gds__vax_integer(items, length));
|
2002-04-04 07:35:21 +02:00
|
|
|
items += length;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
else if (item == isc_info_sql_batch_fetch) {
|
|
|
|
if (request->req_flags & REQ_no_batch)
|
2003-09-04 23:26:15 +02:00
|
|
|
number = 0;
|
2002-04-04 07:35:21 +02:00
|
|
|
else
|
2003-09-04 23:26:15 +02:00
|
|
|
number = 1;
|
2002-04-04 07:35:21 +02:00
|
|
|
length = convert((SLONG) number, buffer);
|
|
|
|
if (!(info = put_item(item, length, buffer, info, end_info))) {
|
|
|
|
return return_success();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (item == isc_info_sql_records) {
|
2003-09-04 23:26:15 +02:00
|
|
|
length = get_request_info(request, (SSHORT) sizeof(buffer),
|
|
|
|
reinterpret_cast<SCHAR*>(buffer));
|
|
|
|
if (length && !(info = put_item(item, length, buffer, info,
|
|
|
|
end_info)))
|
|
|
|
{
|
2002-04-04 07:35:21 +02:00
|
|
|
return return_success();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (item == isc_info_sql_get_plan) {
|
2001-07-10 19:35:13 +02:00
|
|
|
/* be careful, get_plan_info() will reallocate the buffer to a
|
2001-05-23 15:26:42 +02:00
|
|
|
larger size if it is not big enough */
|
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
buffer_ptr = buffer;
|
|
|
|
length =
|
2002-12-16 16:38:26 +01:00
|
|
|
get_plan_info(request, (SSHORT) sizeof(buffer), reinterpret_cast<SCHAR**>(&buffer_ptr));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-12-29 23:26:35 +01:00
|
|
|
if (length) {
|
|
|
|
info = put_item(item, length, buffer_ptr, info, end_info);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-12-29 23:26:35 +01:00
|
|
|
if (length > sizeof(buffer)) {
|
2002-04-04 07:35:21 +02:00
|
|
|
gds__free(buffer_ptr);
|
2002-12-29 23:26:35 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-12-29 23:26:35 +01:00
|
|
|
if (!info) {
|
2002-04-04 07:35:21 +02:00
|
|
|
return return_success();
|
2002-12-29 23:26:35 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
else if (!message ||
|
2003-11-08 00:27:24 +01:00
|
|
|
(item != isc_info_sql_num_variables
|
|
|
|
&& item != isc_info_sql_describe_vars))
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
|
|
|
buffer[0] = item;
|
2003-11-08 00:27:24 +01:00
|
|
|
item = isc_info_error;
|
|
|
|
length = 1 + convert((SLONG) isc_infunk, buffer + 1);
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!(info = put_item(item, length, buffer, info, end_info))) {
|
|
|
|
return return_success();
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2002-04-04 07:35:21 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
number = (*message) ? (*message)->msg_index : 0;
|
|
|
|
length = convert((SLONG) number, buffer);
|
|
|
|
if (!(info = put_item(item, length, buffer, info, end_info))) {
|
|
|
|
return return_success();
|
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
if (item == isc_info_sql_num_variables) {
|
2002-04-04 07:35:21 +02:00
|
|
|
continue;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* end_describe = items;
|
2002-04-04 07:35:21 +02:00
|
|
|
while (end_describe < end_items &&
|
2003-11-08 00:27:24 +01:00
|
|
|
*end_describe != isc_info_end &&
|
|
|
|
*end_describe != isc_info_sql_describe_end)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
|
|
|
end_describe++;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
info = var_info(*message,
|
2001-12-24 03:51:06 +01:00
|
|
|
items,
|
|
|
|
end_describe,
|
|
|
|
info,
|
|
|
|
end_info,
|
|
|
|
first_index);
|
2002-04-04 07:35:21 +02:00
|
|
|
if (!info) {
|
|
|
|
return return_success();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-04-04 07:35:21 +02:00
|
|
|
items = end_describe;
|
2003-11-08 00:27:24 +01:00
|
|
|
if (*items == isc_info_sql_describe_end) {
|
2002-04-04 07:35:21 +02:00
|
|
|
items++;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
*info++ = isc_info_end;
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
catch(const std::exception& ex)
|
2002-04-04 07:35:21 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(tdsql->tsql_status, ex);
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2003-11-10 10:16:38 +01:00
|
|
|
return tdsql->tsql_status[1];
|
2002-04-04 07:35:21 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
return return_success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-28 23:36:05 +02:00
|
|
|
#ifdef DSQL_DEBUG
|
|
|
|
|
2003-09-29 12:48:48 +02:00
|
|
|
static void trace_line(const char* message, ...) {
|
|
|
|
char buffer[1024];
|
|
|
|
va_list params;
|
|
|
|
va_start(params, message);
|
2004-03-09 01:17:07 +01:00
|
|
|
VSNPRINTF(buffer, sizeof(buffer), message, params);
|
2003-09-29 12:48:48 +02:00
|
|
|
va_end(params);
|
2003-10-29 11:53:47 +01:00
|
|
|
buffer[sizeof(buffer) - 1] = 0;
|
2003-09-29 12:48:48 +02:00
|
|
|
gds__trace_raw(buffer);
|
2003-09-28 23:36:05 +02:00
|
|
|
}
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
DSQL_pretty
|
|
|
|
|
|
|
|
@brief Pretty print a node tree.
|
|
|
|
|
|
|
|
|
|
|
|
@param node
|
|
|
|
@param column
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
void DSQL_pretty(const dsql_nod* node, int column)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-10 10:16:38 +01:00
|
|
|
const dsql_str* string;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
TEXT buffer[1024];
|
|
|
|
|
|
|
|
TEXT s[64];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
TEXT* p = buffer;
|
2004-05-14 21:20:01 +02:00
|
|
|
p += sprintf(p, "%p ", (void*) node);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (column) {
|
|
|
|
USHORT l = column * 3;
|
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = ' ';
|
2001-12-24 03:51:06 +01:00
|
|
|
} while (--l);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
if (!node) {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s *** null ***\n", buffer);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
switch (MemoryPool::blk_type(node)) {
|
|
|
|
case (TEXT) dsql_type_str:
|
2003-11-10 10:16:38 +01:00
|
|
|
trace_line("%sSTRING: \"%s\"\n", buffer, ((dsql_str*) node)->str_data);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
case (TEXT) dsql_type_fld:
|
2003-11-10 10:16:38 +01:00
|
|
|
trace_line("%sFIELD: %s\n", buffer, ((dsql_fld*) node)->fld_name);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
case (TEXT) dsql_type_sym:
|
2003-11-01 11:26:43 +01:00
|
|
|
trace_line("%sSYMBOL: %s\n", buffer, ((dsql_sym*) node)->sym_string);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
case (TEXT) dsql_type_nod:
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%sUNKNOWN BLOCK TYPE\n", buffer);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
const TEXT* verb;
|
|
|
|
const dsql_nod* const* ptr = node->nod_arg;
|
|
|
|
const dsql_nod* const* const end = ptr + node->nod_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (node->nod_type) {
|
|
|
|
case nod_abort:
|
|
|
|
verb = "abort";
|
|
|
|
break;
|
|
|
|
case nod_agg_average:
|
|
|
|
verb = "agg_average";
|
|
|
|
break;
|
|
|
|
case nod_agg_count:
|
|
|
|
verb = "agg_count";
|
|
|
|
break;
|
|
|
|
/* count2
|
|
|
|
case nod_agg_distinct: verb = "agg_distinct"; break;
|
|
|
|
*/
|
|
|
|
case nod_agg_max:
|
|
|
|
verb = "agg_max";
|
|
|
|
break;
|
|
|
|
case nod_agg_min:
|
|
|
|
verb = "agg_min";
|
|
|
|
break;
|
|
|
|
case nod_agg_total:
|
|
|
|
verb = "agg_total";
|
|
|
|
break;
|
|
|
|
case nod_add:
|
|
|
|
verb = "add";
|
|
|
|
break;
|
|
|
|
case nod_alias:
|
|
|
|
verb = "alias";
|
|
|
|
break;
|
|
|
|
case nod_ansi_all:
|
|
|
|
case nod_all:
|
|
|
|
verb = "all";
|
|
|
|
break;
|
|
|
|
case nod_and:
|
|
|
|
verb = "and";
|
|
|
|
break;
|
|
|
|
case nod_ansi_any:
|
|
|
|
case nod_any:
|
|
|
|
verb = "any";
|
|
|
|
break;
|
|
|
|
case nod_array:
|
|
|
|
verb = "array element";
|
|
|
|
break;
|
|
|
|
case nod_assign:
|
|
|
|
verb = "assign";
|
|
|
|
break;
|
|
|
|
case nod_average:
|
|
|
|
verb = "average";
|
|
|
|
break;
|
|
|
|
case nod_between:
|
|
|
|
verb = "between";
|
|
|
|
break;
|
|
|
|
case nod_cast:
|
|
|
|
verb = "cast";
|
|
|
|
break;
|
|
|
|
case nod_collate:
|
|
|
|
verb = "collate";
|
|
|
|
break;
|
|
|
|
case nod_concatenate:
|
|
|
|
verb = "concatenate";
|
|
|
|
break;
|
|
|
|
case nod_containing:
|
|
|
|
verb = "containing";
|
|
|
|
break;
|
|
|
|
case nod_count:
|
|
|
|
verb = "count";
|
|
|
|
break;
|
|
|
|
case nod_current_date:
|
|
|
|
verb = "current_date";
|
|
|
|
break;
|
|
|
|
case nod_current_time:
|
|
|
|
verb = "current_time";
|
|
|
|
break;
|
|
|
|
case nod_current_timestamp:
|
|
|
|
verb = "current_timestamp";
|
|
|
|
break;
|
|
|
|
case nod_cursor:
|
|
|
|
verb = "cursor";
|
|
|
|
break;
|
|
|
|
case nod_dbkey:
|
|
|
|
verb = "dbkey";
|
|
|
|
break;
|
|
|
|
case nod_rec_version:
|
|
|
|
verb = "record_version";
|
|
|
|
break;
|
|
|
|
case nod_def_database:
|
|
|
|
verb = "define database";
|
|
|
|
break;
|
|
|
|
case nod_def_field:
|
|
|
|
verb = "define field";
|
|
|
|
break;
|
|
|
|
case nod_def_generator:
|
|
|
|
verb = "define generator";
|
|
|
|
break;
|
|
|
|
case nod_def_filter:
|
|
|
|
verb = "define filter";
|
|
|
|
break;
|
|
|
|
case nod_def_index:
|
|
|
|
verb = "define index";
|
|
|
|
break;
|
|
|
|
case nod_def_relation:
|
|
|
|
verb = "define relation";
|
|
|
|
break;
|
2003-11-28 07:48:34 +01:00
|
|
|
// CVC: New node redef_relation.
|
2002-06-29 08:56:51 +02:00
|
|
|
case nod_redef_relation:
|
|
|
|
verb = "redefine relation";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_def_view:
|
|
|
|
verb = "define view";
|
|
|
|
break;
|
2002-09-01 17:44:45 +02:00
|
|
|
case nod_redef_view:
|
|
|
|
verb = "redefine view";
|
|
|
|
break;
|
2002-08-27 09:48:34 +02:00
|
|
|
case nod_mod_view:
|
|
|
|
verb = "modify view";
|
|
|
|
break;
|
|
|
|
case nod_replace_view:
|
|
|
|
verb = "replace view";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_delete:
|
|
|
|
verb = "delete";
|
|
|
|
break;
|
|
|
|
case nod_del_field:
|
|
|
|
verb = "delete field";
|
|
|
|
break;
|
|
|
|
case nod_del_filter:
|
|
|
|
verb = "delete filter";
|
|
|
|
break;
|
|
|
|
case nod_del_generator:
|
|
|
|
verb = "delete generator";
|
|
|
|
break;
|
|
|
|
case nod_del_index:
|
|
|
|
verb = "delete index";
|
|
|
|
break;
|
|
|
|
case nod_del_relation:
|
|
|
|
verb = "delete relation";
|
|
|
|
break;
|
2003-11-28 07:48:34 +01:00
|
|
|
// CVC: New node del_view.
|
2002-06-29 08:56:51 +02:00
|
|
|
case nod_del_view:
|
|
|
|
verb = "delete view";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_def_procedure:
|
|
|
|
verb = "define procedure";
|
|
|
|
break;
|
2002-08-27 09:48:34 +02:00
|
|
|
case nod_mod_procedure:
|
|
|
|
verb = "modify procedure";
|
|
|
|
break;
|
|
|
|
case nod_replace_procedure:
|
|
|
|
verb = "replace procedure";
|
|
|
|
break;
|
2003-11-28 07:48:34 +01:00
|
|
|
// CVC: New node redef_procedure.
|
2002-06-29 08:56:51 +02:00
|
|
|
case nod_redef_procedure:
|
|
|
|
verb = "redefine procedure";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_del_procedure:
|
2003-01-25 02:50:32 +01:00
|
|
|
verb = "delete procedure";
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
case nod_def_trigger:
|
|
|
|
verb = "define trigger";
|
|
|
|
break;
|
|
|
|
case nod_mod_trigger:
|
|
|
|
verb = "modify trigger";
|
|
|
|
break;
|
2002-08-27 09:48:34 +02:00
|
|
|
case nod_replace_trigger:
|
|
|
|
verb = "replace trigger";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_del_trigger:
|
|
|
|
verb = "delete trigger";
|
|
|
|
break;
|
|
|
|
case nod_divide:
|
|
|
|
verb = "divide";
|
|
|
|
break;
|
|
|
|
case nod_eql_all:
|
|
|
|
case nod_eql_any:
|
|
|
|
case nod_eql:
|
|
|
|
verb = "eql";
|
|
|
|
break;
|
|
|
|
case nod_erase:
|
|
|
|
verb = "erase";
|
|
|
|
break;
|
|
|
|
case nod_execute:
|
|
|
|
verb = "execute";
|
|
|
|
break;
|
|
|
|
case nod_exec_procedure:
|
|
|
|
verb = "execute procedure";
|
|
|
|
break;
|
2004-01-16 11:43:21 +01:00
|
|
|
case nod_exec_block:
|
|
|
|
verb = "execute block";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_exists:
|
|
|
|
verb = "exists";
|
|
|
|
break;
|
|
|
|
case nod_extract:
|
|
|
|
verb = "extract";
|
|
|
|
break;
|
|
|
|
case nod_flag:
|
|
|
|
verb = "flag";
|
|
|
|
break;
|
|
|
|
case nod_foreign:
|
|
|
|
verb = "foreign key";
|
|
|
|
break;
|
|
|
|
case nod_gen_id:
|
|
|
|
verb = "gen_id";
|
|
|
|
break;
|
|
|
|
case nod_geq_all:
|
|
|
|
case nod_geq_any:
|
|
|
|
case nod_geq:
|
|
|
|
verb = "geq";
|
|
|
|
break;
|
|
|
|
case nod_get_segment:
|
|
|
|
verb = "get segment";
|
|
|
|
break;
|
|
|
|
case nod_grant:
|
|
|
|
verb = "grant";
|
|
|
|
break;
|
|
|
|
case nod_gtr_all:
|
|
|
|
case nod_gtr_any:
|
|
|
|
case nod_gtr:
|
|
|
|
verb = "gtr";
|
|
|
|
break;
|
|
|
|
case nod_insert:
|
|
|
|
verb = "insert";
|
|
|
|
break;
|
2002-06-14 14:07:20 +02:00
|
|
|
case nod_internal_info:
|
|
|
|
verb = "internal info";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_join:
|
|
|
|
verb = "join";
|
|
|
|
break;
|
|
|
|
case nod_join_full:
|
|
|
|
verb = "join_full";
|
|
|
|
break;
|
|
|
|
case nod_join_left:
|
|
|
|
verb = "join_left";
|
|
|
|
break;
|
|
|
|
case nod_join_right:
|
|
|
|
verb = "join_right";
|
|
|
|
break;
|
|
|
|
case nod_leq_all:
|
|
|
|
case nod_leq_any:
|
|
|
|
case nod_leq:
|
|
|
|
verb = "leq";
|
|
|
|
break;
|
|
|
|
case nod_like:
|
|
|
|
verb = "like";
|
|
|
|
break;
|
|
|
|
case nod_list:
|
|
|
|
verb = "list";
|
|
|
|
break;
|
|
|
|
case nod_lss_all:
|
|
|
|
case nod_lss_any:
|
|
|
|
case nod_lss:
|
|
|
|
verb = "lss";
|
|
|
|
break;
|
|
|
|
case nod_max:
|
|
|
|
verb = "max";
|
|
|
|
break;
|
|
|
|
case nod_min:
|
|
|
|
verb = "min";
|
|
|
|
break;
|
|
|
|
case nod_missing:
|
|
|
|
verb = "missing";
|
|
|
|
break;
|
|
|
|
case nod_modify:
|
|
|
|
verb = "modify";
|
|
|
|
break;
|
|
|
|
case nod_mod_database:
|
|
|
|
verb = "modify database";
|
|
|
|
break;
|
|
|
|
case nod_mod_field:
|
|
|
|
verb = "modify field";
|
|
|
|
break;
|
|
|
|
case nod_mod_relation:
|
|
|
|
verb = "modify relation";
|
|
|
|
break;
|
|
|
|
case nod_multiply:
|
|
|
|
verb = "multiply";
|
|
|
|
break;
|
|
|
|
case nod_negate:
|
|
|
|
verb = "negate";
|
|
|
|
break;
|
|
|
|
case nod_neq_all:
|
|
|
|
case nod_neq_any:
|
|
|
|
case nod_neq:
|
|
|
|
verb = "neq";
|
|
|
|
break;
|
|
|
|
case nod_not:
|
|
|
|
verb = "not";
|
|
|
|
break;
|
|
|
|
case nod_null:
|
|
|
|
verb = "null";
|
|
|
|
break;
|
|
|
|
case nod_or:
|
|
|
|
verb = "or";
|
|
|
|
break;
|
|
|
|
case nod_order:
|
|
|
|
verb = "order";
|
|
|
|
break;
|
|
|
|
case nod_primary:
|
|
|
|
verb = "primary key";
|
|
|
|
break;
|
|
|
|
case nod_procedure_name:
|
|
|
|
verb = "procedure name";
|
|
|
|
break;
|
|
|
|
case nod_put_segment:
|
|
|
|
verb = "put segment";
|
|
|
|
break;
|
|
|
|
case nod_relation_name:
|
|
|
|
verb = "relation name";
|
|
|
|
break;
|
|
|
|
case nod_rel_proc_name:
|
|
|
|
verb = "rel/proc name";
|
|
|
|
break;
|
|
|
|
case nod_return:
|
|
|
|
verb = "return";
|
|
|
|
break;
|
|
|
|
case nod_revoke:
|
|
|
|
verb = "revoke";
|
|
|
|
break;
|
|
|
|
case nod_rse:
|
|
|
|
verb = "rse";
|
|
|
|
break;
|
|
|
|
case nod_select:
|
|
|
|
verb = "select";
|
|
|
|
break;
|
|
|
|
case nod_select_expr:
|
|
|
|
verb = "select expr";
|
|
|
|
break;
|
|
|
|
case nod_starting:
|
|
|
|
verb = "starting";
|
|
|
|
break;
|
|
|
|
case nod_store:
|
|
|
|
verb = "store";
|
|
|
|
break;
|
|
|
|
case nod_substr:
|
|
|
|
verb = "substr";
|
|
|
|
break;
|
|
|
|
case nod_subtract:
|
|
|
|
verb = "subtract";
|
|
|
|
break;
|
|
|
|
case nod_total:
|
|
|
|
verb = "total";
|
|
|
|
break;
|
|
|
|
case nod_update:
|
|
|
|
verb = "update";
|
|
|
|
break;
|
|
|
|
case nod_union:
|
|
|
|
verb = "union";
|
|
|
|
break;
|
|
|
|
case nod_unique:
|
|
|
|
verb = "unique";
|
|
|
|
break;
|
|
|
|
case nod_upcase:
|
|
|
|
verb = "upcase";
|
|
|
|
break;
|
|
|
|
case nod_singular:
|
|
|
|
verb = "singular";
|
|
|
|
break;
|
|
|
|
case nod_user_name:
|
|
|
|
verb = "user_name";
|
|
|
|
break;
|
2003-11-28 07:48:34 +01:00
|
|
|
// CVC: New node current_role.
|
2002-06-29 08:56:51 +02:00
|
|
|
case nod_current_role:
|
|
|
|
verb = "current_role";
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_via:
|
|
|
|
verb = "via";
|
|
|
|
break;
|
|
|
|
|
2002-08-03 17:27:20 +02:00
|
|
|
case nod_coalesce:
|
|
|
|
verb = "coalesce";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_simple_case:
|
|
|
|
verb = "simple_case";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_searched_case:
|
|
|
|
verb = "searched_case";
|
|
|
|
break;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_add2:
|
|
|
|
verb = "add2";
|
|
|
|
break;
|
|
|
|
case nod_agg_total2:
|
|
|
|
verb = "agg_total2";
|
|
|
|
break;
|
|
|
|
case nod_divide2:
|
|
|
|
verb = "divide2";
|
|
|
|
break;
|
|
|
|
case nod_gen_id2:
|
|
|
|
verb = "gen_id2";
|
|
|
|
break;
|
|
|
|
case nod_multiply2:
|
|
|
|
verb = "multiply2";
|
|
|
|
break;
|
|
|
|
case nod_subtract2:
|
|
|
|
verb = "subtract2";
|
|
|
|
break;
|
2003-11-07 15:10:16 +01:00
|
|
|
case nod_limit:
|
|
|
|
verb = "limit";
|
|
|
|
break;
|
|
|
|
case nod_rows:
|
|
|
|
verb = "rows";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
/* IOL: missing node types */
|
|
|
|
case nod_on_error:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "on error";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_block:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "block";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_default:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "default";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_plan_expr:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "plan";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_index:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "index";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_index_order:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "order";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_plan_item:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "item";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_natural:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "natural";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
|
|
|
case nod_join_inner:
|
2003-11-01 11:26:43 +01:00
|
|
|
verb = "join_inner";
|
2003-01-25 02:50:32 +01:00
|
|
|
break;
|
2003-11-28 07:48:34 +01:00
|
|
|
// SKIDDER: some more missing node types
|
2003-09-28 23:36:05 +02:00
|
|
|
case nod_commit:
|
|
|
|
verb = "commit";
|
|
|
|
break;
|
|
|
|
case nod_rollback:
|
|
|
|
verb = "rollback";
|
|
|
|
break;
|
|
|
|
case nod_trans:
|
|
|
|
verb = "trans";
|
|
|
|
break;
|
|
|
|
case nod_def_default:
|
|
|
|
verb = "def_default";
|
|
|
|
break;
|
|
|
|
case nod_del_default:
|
|
|
|
verb = "del_default";
|
|
|
|
break;
|
|
|
|
case nod_def_domain:
|
|
|
|
verb = "def_domain";
|
|
|
|
break;
|
|
|
|
case nod_mod_domain:
|
|
|
|
verb = "mod_domain";
|
|
|
|
break;
|
|
|
|
case nod_del_domain:
|
|
|
|
verb = "del_domain";
|
|
|
|
break;
|
|
|
|
case nod_def_constraint:
|
|
|
|
verb = "def_constraint";
|
|
|
|
break;
|
|
|
|
case nod_def_trigger_msg:
|
|
|
|
verb = "def_trigger_msg";
|
|
|
|
break;
|
|
|
|
case nod_mod_trigger_msg:
|
|
|
|
verb = "mod_trigger_msg";
|
|
|
|
break;
|
|
|
|
case nod_del_trigger_msg:
|
|
|
|
verb = "del_trigger_msg";
|
|
|
|
break;
|
|
|
|
case nod_def_exception:
|
|
|
|
verb = "def_exception";
|
|
|
|
break;
|
|
|
|
case nod_mod_exception:
|
|
|
|
verb = "mod_exception";
|
|
|
|
break;
|
|
|
|
case nod_del_exception:
|
|
|
|
verb = "del_exception";
|
|
|
|
break;
|
|
|
|
case nod_def_shadow:
|
|
|
|
verb = "def_shadow";
|
|
|
|
break;
|
|
|
|
case nod_del_shadow:
|
|
|
|
verb = "del_shadow";
|
|
|
|
break;
|
|
|
|
case nod_def_udf:
|
|
|
|
verb = "def_udf";
|
|
|
|
break;
|
|
|
|
case nod_del_udf:
|
|
|
|
verb = "del_udf";
|
|
|
|
break;
|
|
|
|
case nod_rel_constraint:
|
|
|
|
verb = "rel_constraint";
|
|
|
|
break;
|
|
|
|
case nod_delete_rel_constraint:
|
|
|
|
verb = "delete_rel_constraint";
|
|
|
|
break;
|
|
|
|
case nod_references:
|
|
|
|
verb = "references";
|
|
|
|
break;
|
|
|
|
case nod_proc_obj:
|
|
|
|
verb = "proc_obj";
|
|
|
|
break;
|
|
|
|
case nod_trig_obj:
|
|
|
|
verb = "trig_obj";
|
|
|
|
break;
|
|
|
|
case nod_view_obj:
|
|
|
|
verb = "view_obj";
|
|
|
|
break;
|
|
|
|
case nod_exit:
|
|
|
|
verb = "exit";
|
|
|
|
break;
|
|
|
|
case nod_if:
|
|
|
|
verb = "if";
|
|
|
|
break;
|
|
|
|
case nod_erase_current:
|
|
|
|
verb = "erase_current";
|
|
|
|
break;
|
|
|
|
case nod_modify_current:
|
|
|
|
verb = "modify_current";
|
|
|
|
break;
|
|
|
|
case nod_post:
|
|
|
|
verb = "post";
|
|
|
|
break;
|
|
|
|
case nod_sqlcode:
|
|
|
|
verb = "sqlcode";
|
|
|
|
break;
|
|
|
|
case nod_gdscode:
|
|
|
|
verb = "gdscode";
|
|
|
|
break;
|
|
|
|
case nod_exception:
|
|
|
|
verb = "exception";
|
|
|
|
break;
|
|
|
|
case nod_exception_stmt:
|
|
|
|
verb = "exception_stmt";
|
|
|
|
break;
|
|
|
|
case nod_start_savepoint:
|
|
|
|
verb = "start_savepoint";
|
|
|
|
break;
|
|
|
|
case nod_end_savepoint:
|
|
|
|
verb = "end_savepoint";
|
|
|
|
break;
|
|
|
|
case nod_dom_value:
|
|
|
|
verb = "dom_value";
|
|
|
|
break;
|
|
|
|
case nod_user_group:
|
|
|
|
verb = "user_group";
|
|
|
|
break;
|
|
|
|
case nod_from:
|
|
|
|
verb = "from";
|
|
|
|
break;
|
|
|
|
case nod_agg_average2:
|
|
|
|
verb = "agg_average2";
|
|
|
|
break;
|
|
|
|
case nod_access:
|
|
|
|
verb = "access";
|
|
|
|
break;
|
|
|
|
case nod_wait:
|
|
|
|
verb = "wait";
|
|
|
|
break;
|
|
|
|
case nod_isolation:
|
|
|
|
verb = "isolation";
|
|
|
|
break;
|
|
|
|
case nod_version:
|
|
|
|
verb = "version";
|
|
|
|
break;
|
|
|
|
case nod_table_lock:
|
|
|
|
verb = "table_lock";
|
|
|
|
break;
|
|
|
|
case nod_lock_mode:
|
|
|
|
verb = "lock_mode";
|
|
|
|
break;
|
|
|
|
case nod_reserve:
|
|
|
|
verb = "reserve";
|
|
|
|
break;
|
|
|
|
case nod_commit_retain:
|
|
|
|
verb = "commit_retain";
|
|
|
|
break;
|
|
|
|
case nod_page_size:
|
|
|
|
verb = "page_size";
|
|
|
|
break;
|
|
|
|
case nod_file_length:
|
|
|
|
verb = "file_length";
|
|
|
|
break;
|
|
|
|
case nod_file_desc:
|
|
|
|
verb = "file_desc";
|
|
|
|
break;
|
|
|
|
case nod_log_file_desc:
|
|
|
|
verb = "log_file_desc";
|
|
|
|
break;
|
|
|
|
case nod_cache_file_desc:
|
|
|
|
verb = "cache_file_desc";
|
|
|
|
break;
|
|
|
|
case nod_group_commit_wait:
|
|
|
|
verb = "group_commit_wait";
|
|
|
|
break;
|
|
|
|
case nod_check_point_len:
|
|
|
|
verb = "check_point_len";
|
|
|
|
break;
|
|
|
|
case nod_num_log_buffers:
|
|
|
|
verb = "num_log_buffers";
|
|
|
|
break;
|
|
|
|
case nod_log_buffer_size:
|
|
|
|
verb = "log_buffer_size";
|
|
|
|
break;
|
|
|
|
case nod_drop_log:
|
|
|
|
verb = "drop_log";
|
|
|
|
break;
|
|
|
|
case nod_drop_cache:
|
|
|
|
verb = "drop_cache";
|
|
|
|
break;
|
|
|
|
case nod_dfl_charset:
|
|
|
|
verb = "dfl_charset";
|
|
|
|
break;
|
|
|
|
case nod_password:
|
|
|
|
verb = "password";
|
|
|
|
break;
|
|
|
|
case nod_lc_ctype:
|
|
|
|
verb = "lc_ctype";
|
|
|
|
break;
|
|
|
|
case nod_udf_return_value:
|
|
|
|
verb = "udf_return_value";
|
|
|
|
break;
|
|
|
|
case nod_def_computed:
|
|
|
|
verb = "def_computed";
|
|
|
|
break;
|
|
|
|
case nod_merge:
|
|
|
|
verb = "merge";
|
|
|
|
break;
|
|
|
|
case nod_set_generator:
|
|
|
|
verb = "set_generator";
|
|
|
|
break;
|
|
|
|
case nod_set_generator2:
|
|
|
|
verb = "set_generator2";
|
|
|
|
break;
|
|
|
|
case nod_mod_index:
|
|
|
|
verb = "mod_index";
|
|
|
|
break;
|
|
|
|
case nod_idx_active:
|
|
|
|
verb = "idx_active";
|
|
|
|
break;
|
|
|
|
case nod_idx_inactive:
|
|
|
|
verb = "idx_inactive";
|
|
|
|
break;
|
|
|
|
case nod_restrict:
|
|
|
|
verb = "restrict";
|
|
|
|
break;
|
|
|
|
case nod_cascade:
|
|
|
|
verb = "cascade";
|
|
|
|
break;
|
|
|
|
case nod_set_statistics:
|
|
|
|
verb = "set_statistics";
|
|
|
|
break;
|
|
|
|
case nod_ref_upd_del:
|
|
|
|
verb = "ref_upd_del";
|
|
|
|
break;
|
|
|
|
case nod_ref_trig_action:
|
|
|
|
verb = "ref_trig_action";
|
|
|
|
break;
|
|
|
|
case nod_def_role:
|
|
|
|
verb = "def_role";
|
|
|
|
break;
|
|
|
|
case nod_role_name:
|
|
|
|
verb = "role_name";
|
|
|
|
break;
|
|
|
|
case nod_grant_admin:
|
|
|
|
verb = "grant_admin";
|
|
|
|
break;
|
|
|
|
case nod_del_role:
|
|
|
|
verb = "del_role";
|
|
|
|
break;
|
|
|
|
case nod_mod_domain_type:
|
|
|
|
verb = "mod_domain_type";
|
|
|
|
break;
|
|
|
|
case nod_mod_field_name:
|
|
|
|
verb = "mod_field_name";
|
|
|
|
break;
|
|
|
|
case nod_mod_field_type:
|
|
|
|
verb = "mod_field_type";
|
|
|
|
break;
|
|
|
|
case nod_mod_field_pos:
|
|
|
|
verb = "mod_field_pos";
|
|
|
|
break;
|
|
|
|
case nod_udf_param:
|
|
|
|
verb = "udf_param";
|
|
|
|
break;
|
|
|
|
case nod_exec_sql:
|
|
|
|
verb = "exec_sql";
|
|
|
|
break;
|
|
|
|
case nod_for_update:
|
|
|
|
verb = "for_update";
|
|
|
|
break;
|
|
|
|
case nod_user_savepoint:
|
|
|
|
verb = "user_savepoint";
|
|
|
|
break;
|
|
|
|
case nod_release_savepoint:
|
|
|
|
verb = "release_savepoint";
|
|
|
|
break;
|
|
|
|
case nod_undo_savepoint:
|
|
|
|
verb = "undo_savepoint";
|
|
|
|
break;
|
|
|
|
case nod_difference_file:
|
|
|
|
verb = "difference_file";
|
|
|
|
break;
|
|
|
|
case nod_drop_difference:
|
|
|
|
verb = "drop_difference";
|
|
|
|
break;
|
|
|
|
case nod_begin_backup:
|
|
|
|
verb = "begin_backup";
|
|
|
|
break;
|
|
|
|
case nod_end_backup:
|
|
|
|
verb = "end_backup";
|
|
|
|
break;
|
|
|
|
case nod_derived_table:
|
|
|
|
verb = "derived_table";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_exec_into:
|
|
|
|
verb = "exec_into";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_breakleave:
|
|
|
|
verb = "breakleave";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_for_select:
|
|
|
|
verb = "for_select";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_while:
|
|
|
|
verb = "while";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_label:
|
|
|
|
verb = "label";
|
2003-11-10 10:16:38 +01:00
|
|
|
DSQL_pretty(node->nod_arg[e_label_name], column + 1);
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s number %d\n", buffer,
|
|
|
|
(int)(IPTR)node->nod_arg[e_label_number]);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_derived_field:
|
|
|
|
verb = "derived_field";
|
|
|
|
trace_line("%s%s\n", buffer, verb);
|
2003-11-10 10:16:38 +01:00
|
|
|
DSQL_pretty(node->nod_arg[e_derived_field_value], column + 1);
|
|
|
|
DSQL_pretty(node->nod_arg[e_derived_field_name], column + 1);
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s scope %d\n", buffer,
|
|
|
|
(USHORT)(U_IPTR)node->nod_arg[e_derived_field_scope]);
|
|
|
|
return;
|
2003-01-25 02:50:32 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_aggregate:
|
2003-11-10 10:16:38 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
verb = "aggregate";
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s%s\n", buffer, verb);
|
2003-11-10 10:16:38 +01:00
|
|
|
const dsql_ctx* context = (dsql_ctx*) node->nod_arg[e_agg_context];
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s context %d\n", buffer, context->ctx_context);
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_map* map = context->ctx_map;
|
|
|
|
if (map != NULL)
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s map\n", buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
while (map) {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s position %d\n", buffer, map->map_position);
|
2001-05-23 15:26:42 +02:00
|
|
|
DSQL_pretty(map->map_node, column + 2);
|
|
|
|
map = map->map_next;
|
|
|
|
}
|
|
|
|
DSQL_pretty(node->nod_arg[e_agg_group], column + 1);
|
|
|
|
DSQL_pretty(node->nod_arg[e_agg_rse], column + 1);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2003-11-10 10:16:38 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_constant:
|
|
|
|
verb = "constant";
|
|
|
|
if (node->nod_desc.dsc_address) {
|
|
|
|
if (node->nod_desc.dsc_dtype == dtype_text)
|
|
|
|
sprintf(s, "constant \"%s\"", node->nod_desc.dsc_address);
|
|
|
|
else
|
2003-04-03 03:51:03 +02:00
|
|
|
sprintf(s, "constant %ld",
|
2001-05-23 15:26:42 +02:00
|
|
|
*(SLONG *) (node->nod_desc.dsc_address));
|
|
|
|
verb = s;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nod_field:
|
2003-11-10 10:16:38 +01:00
|
|
|
{
|
|
|
|
const dsql_ctx* context = (dsql_ctx*) node->nod_arg[e_fld_context];
|
|
|
|
const dsql_rel* relation = context->ctx_relation;
|
|
|
|
const dsql_prc* procedure = context->ctx_procedure;
|
|
|
|
const dsql_fld* field = (dsql_fld*) node->nod_arg[e_fld_field];
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%sfield %s.%s, context %d\n", buffer,
|
2002-11-09 09:05:26 +01:00
|
|
|
(relation != NULL ?
|
|
|
|
relation->rel_name :
|
|
|
|
(procedure != NULL ?
|
|
|
|
procedure->prc_name :
|
|
|
|
"unknown_db_object")),
|
|
|
|
field->fld_name, context->ctx_context);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2003-11-10 10:16:38 +01:00
|
|
|
}
|
2002-11-09 09:05:26 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_field_name:
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%sfield name: \"", buffer);
|
2003-11-10 10:16:38 +01:00
|
|
|
string = (dsql_str*) node->nod_arg[e_fln_context];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (string)
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s.", string->str_data);
|
2003-11-10 10:16:38 +01:00
|
|
|
string = (dsql_str*) node->nod_arg[e_fln_name];
|
2002-07-06 07:32:02 +02:00
|
|
|
if (string != 0) {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s\"\n", string->str_data);
|
2002-07-06 07:32:02 +02:00
|
|
|
}
|
|
|
|
else {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s\"\n", "*");
|
2002-07-06 07:32:02 +02:00
|
|
|
}
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_map:
|
2003-11-10 10:16:38 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
verb = "map";
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s%s\n", buffer, verb);
|
2003-11-10 10:16:38 +01:00
|
|
|
const dsql_ctx* context = (dsql_ctx*) node->nod_arg[e_map_context];
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s context %d\n", buffer, context->ctx_context);
|
2003-11-10 10:16:38 +01:00
|
|
|
for (const dsql_map* map = (dsql_map*) node->nod_arg[e_map_map]; map;
|
|
|
|
map = map->map_next)
|
|
|
|
{
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s position %d\n", buffer, map->map_position);
|
2001-05-23 15:26:42 +02:00
|
|
|
DSQL_pretty(map->map_node, column + 1);
|
|
|
|
}
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2003-11-10 10:16:38 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_relation:
|
2003-11-10 10:16:38 +01:00
|
|
|
{
|
|
|
|
const dsql_ctx* context = (dsql_ctx*) node->nod_arg[e_rel_context];
|
|
|
|
const dsql_rel* relation = context->ctx_relation;
|
|
|
|
const dsql_prc* procedure = context->ctx_procedure;
|
2004-01-28 08:50:41 +01:00
|
|
|
if ( relation != NULL ) {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%srelation %s, context %d\n",
|
2002-11-09 09:05:26 +01:00
|
|
|
buffer, relation->rel_name, context->ctx_context);
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
|
|
|
else if ( procedure != NULL ) {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%sprocedure %s, context %d\n",
|
2002-11-09 09:05:26 +01:00
|
|
|
buffer, procedure->prc_name, context->ctx_context);
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%sUNKNOWN DB OBJECT, context %d\n",
|
2003-11-01 11:26:43 +01:00
|
|
|
buffer, context->ctx_context);
|
2002-11-09 09:05:26 +01:00
|
|
|
}
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2003-11-10 10:16:38 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_variable:
|
2003-11-10 10:16:38 +01:00
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
const dsql_var* variable = (dsql_var*) node->nod_arg[e_var_variable];
|
2002-07-06 07:32:02 +02:00
|
|
|
// Adding variable->var_variable_number to display, obviously something
|
|
|
|
// is missing from the printf, and Im assuming this was it.
|
|
|
|
// (anyway can't be worse than it was MOD 05-July-2002.
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%svariable %s %d\n", buffer, variable->var_name, variable->var_variable_number);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2003-11-10 10:16:38 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_var_name:
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%svariable name: \"", buffer);
|
2003-11-10 10:16:38 +01:00
|
|
|
string = (dsql_str*) node->nod_arg[e_vrn_name];
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s\"\n", string->str_data);
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-01-25 02:50:32 +01:00
|
|
|
case nod_parameter:
|
2003-11-01 11:26:43 +01:00
|
|
|
if (node->nod_column) {
|
|
|
|
trace_line("%sparameter: %d\n", buffer,
|
2004-01-21 08:18:30 +01:00
|
|
|
(USHORT)(IPTR)node->nod_arg[e_par_parameter]);
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
|
|
|
else {
|
2004-02-02 12:02:12 +01:00
|
|
|
const dsql_par* param = (dsql_par*) node->nod_arg[e_par_parameter];
|
2003-11-01 11:26:43 +01:00
|
|
|
trace_line("%sparameter: %d\n", buffer, param->par_index);
|
2003-01-25 02:50:32 +01:00
|
|
|
}
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2003-01-25 02:50:32 +01:00
|
|
|
|
|
|
|
|
2002-06-29 08:56:51 +02:00
|
|
|
case nod_udf:
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line ("%sfunction: \"", buffer);
|
2002-06-29 08:56:51 +02:00
|
|
|
/* nmcc: how are we supposed to tell which type of nod_udf this is ?? */
|
|
|
|
/* CVC: The answer is that nod_arg[0] can be either the udf name or the
|
|
|
|
pointer to udf struct returned by METD_get_function, so we should resort
|
|
|
|
to the block type. The replacement happens in pass1_udf(). */
|
2003-11-10 10:16:38 +01:00
|
|
|
// switch (node->nod_arg[e_udf_name]->nod_header.blk_type) {
|
|
|
|
switch (MemoryPool::blk_type(node->nod_arg[e_udf_name])) {
|
2002-07-05 17:00:26 +02:00
|
|
|
case dsql_type_udf:
|
2003-11-10 10:16:38 +01:00
|
|
|
trace_line ("%s\"\n", ((dsql_udf*) node->nod_arg[e_udf_name])->udf_name);
|
2002-06-29 08:56:51 +02:00
|
|
|
break;
|
2002-07-05 17:00:26 +02:00
|
|
|
case dsql_type_str:
|
2003-11-10 10:16:38 +01:00
|
|
|
string = (dsql_str*) node->nod_arg[e_udf_name];
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line ("%s\"\n", string->str_data);
|
2002-06-29 08:56:51 +02:00
|
|
|
break;
|
|
|
|
default:
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line ("%s\"\n", "<ERROR>");
|
2002-06-29 08:56:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (node->nod_count == 2) {
|
|
|
|
DSQL_pretty (*ptr, column + 1);
|
|
|
|
}
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2002-06-29 08:56:51 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
default:
|
|
|
|
sprintf(s, "unknown type %d", node->nod_type);
|
|
|
|
verb = s;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (node->nod_desc.dsc_dtype) {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s%s (%d,%d,%p)\n",
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer, verb,
|
|
|
|
node->nod_desc.dsc_dtype,
|
|
|
|
node->nod_desc.dsc_length, node->nod_desc.dsc_address);
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-09-28 23:36:05 +02:00
|
|
|
trace_line("%s%s\n", buffer, verb);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
++column;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
while (ptr < end) {
|
2001-05-23 15:26:42 +02:00
|
|
|
DSQL_pretty(*ptr++, column);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-28 02:36:28 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
cleanup
|
|
|
|
|
|
|
|
@brief exit handler for local dsql image
|
|
|
|
|
|
|
|
|
|
|
|
@param arg
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static void cleanup( void *arg)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (init_flag) {
|
2003-02-12 20:28:13 +01:00
|
|
|
init_flag = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
databases = 0;
|
|
|
|
open_cursors = 0;
|
|
|
|
HSHD_fini();
|
|
|
|
ALLD_fini();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
cleanup_database
|
|
|
|
|
|
|
|
@brief Clean up DSQL globals.
|
|
|
|
|
2003-11-09 16:38:03 +01:00
|
|
|
N.B., the cleanup handlers (registered with isc_database_cleanup)
|
2003-02-15 04:01:51 +01:00
|
|
|
are called outside of the ISC thread mechanism...
|
|
|
|
|
|
|
|
These do not make use of the context at this time.
|
|
|
|
|
|
|
|
|
|
|
|
@param db_handle
|
|
|
|
@param flag
|
|
|
|
|
|
|
|
**/
|
2004-05-03 01:06:37 +02:00
|
|
|
static void cleanup_database(FB_API_HANDLE* db_handle, void* flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2002-12-16 16:38:26 +01:00
|
|
|
if (flag)
|
|
|
|
Firebird::fatal_exception::raise("Illegal call to cleanup_database");
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!db_handle || !databases)
|
|
|
|
return;
|
|
|
|
|
2002-12-16 16:38:26 +01:00
|
|
|
/* if (flag)
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();*/
|
2002-12-16 16:38:26 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
THD_MUTEX_LOCK(&databases_mutex);
|
2002-11-12 17:04:01 +01:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* dbb;
|
|
|
|
for (dsql_dbb** dbb_ptr = &databases; dbb = *dbb_ptr; dbb_ptr = &dbb->dbb_next)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (dbb->dbb_database_handle == *db_handle) {
|
|
|
|
*dbb_ptr = dbb->dbb_next;
|
|
|
|
dbb->dbb_next = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2002-12-16 16:38:26 +01:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
if (dbb) {
|
|
|
|
if (flag) {
|
2002-11-12 17:04:01 +01:00
|
|
|
for (int i = 0; i < irq_MAX; i++)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (dbb->dbb_requests[i])
|
|
|
|
isc_release_request(user_status,
|
2003-08-30 03:54:25 +02:00
|
|
|
reinterpret_cast <void**>(&dbb->dbb_requests[i]));
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
HSHD_finish(dbb);
|
2001-12-24 03:51:06 +01:00
|
|
|
delete dbb->dbb_pool;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2002-11-12 17:04:01 +01:00
|
|
|
else if (flag)
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2002-12-16 16:38:26 +01:00
|
|
|
*/
|
|
|
|
if (dbb) {
|
|
|
|
HSHD_finish(dbb);
|
2003-01-16 18:47:10 +01:00
|
|
|
DsqlMemoryPool::deletePool(dbb->dbb_pool);
|
2002-12-16 16:38:26 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!databases) {
|
2002-12-16 16:38:26 +01:00
|
|
|
cleanup(0);
|
|
|
|
gds__unregister_cleanup(cleanup, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
THD_MUTEX_UNLOCK(&databases_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
cleanup_transaction
|
|
|
|
|
|
|
|
@brief Clean up after a transaction. This means
|
|
|
|
closing all open cursors.
|
|
|
|
|
|
|
|
|
|
|
|
@param tra_handle
|
|
|
|
@param arg
|
|
|
|
|
|
|
|
**/
|
2004-05-03 01:06:37 +02:00
|
|
|
static void cleanup_transaction (FB_API_HANDLE tra_handle, void* arg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY local_status;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// find this transaction/request pair in the list of pairs
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
THD_MUTEX_LOCK(&cursors_mutex);
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_opn** open_cursor_ptr = &open_cursors;
|
|
|
|
dsql_opn* open_cursor;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (open_cursor = *open_cursor_ptr)
|
2004-01-28 08:50:41 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (open_cursor->opn_transaction == tra_handle) {
|
|
|
|
/* Found it, close the cursor but don't remove it from the list.
|
|
|
|
The close routine will have done that. */
|
|
|
|
|
|
|
|
THD_MUTEX_UNLOCK(&cursors_mutex);
|
2001-07-10 19:35:13 +02:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
* we are expected to be within the subsystem when we do this
|
2001-07-10 19:35:13 +02:00
|
|
|
* cleanup, for now do a thread_enter/thread_exit here.
|
2003-09-28 02:36:28 +02:00
|
|
|
* Note that the function dsql8_free_statement() calls the local function.
|
2001-07-10 19:35:13 +02:00
|
|
|
* Over the long run, it might be better to move the subsystem_exit()
|
2001-05-23 15:26:42 +02:00
|
|
|
* call in why.c below the cleanup handlers. smistry 9-27-98
|
|
|
|
*/
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER(); //ttt
|
2001-12-24 03:51:06 +01:00
|
|
|
GDS_DSQL_FREE_CPP( local_status,
|
|
|
|
&open_cursor->opn_request,
|
|
|
|
DSQL_close);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
THD_MUTEX_LOCK(&cursors_mutex);
|
|
|
|
open_cursor_ptr = &open_cursors;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
open_cursor_ptr = &open_cursor->opn_next;
|
2004-01-28 08:50:41 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
THD_MUTEX_UNLOCK(&cursors_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
close_cursor
|
|
|
|
|
|
|
|
@brief Close an open cursor.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static void close_cursor( dsql_req* request)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_handle) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT(); //ttt
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->req_type == REQ_GET_SEGMENT ||
|
|
|
|
request->req_type == REQ_PUT_SEGMENT)
|
2003-08-30 03:54:25 +02:00
|
|
|
isc_close_blob(status_vector, &request->req_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-08-30 03:54:25 +02:00
|
|
|
isc_unwind_request(status_vector, &request->req_handle, 0);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
request->req_flags &= ~(REQ_cursor_open | REQ_embedded_sql_cursor);
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Remove the open cursor from the list
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
THD_MUTEX_LOCK(&cursors_mutex);
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_opn** open_cursor_ptr = &open_cursors;
|
|
|
|
dsql_opn* open_cursor;
|
2001-05-23 15:26:42 +02:00
|
|
|
for (; open_cursor = *open_cursor_ptr;
|
2003-09-13 14:16:48 +02:00
|
|
|
open_cursor_ptr = &open_cursor->opn_next)
|
|
|
|
{
|
|
|
|
if (open_cursor == request->req_open_cursor) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*open_cursor_ptr = open_cursor->opn_next;
|
|
|
|
break;
|
|
|
|
}
|
2003-09-13 14:16:48 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
THD_MUTEX_UNLOCK(&cursors_mutex);
|
|
|
|
|
|
|
|
if (open_cursor) {
|
2001-12-24 03:51:06 +01:00
|
|
|
delete open_cursor;
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_open_cursor = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
convert
|
|
|
|
|
|
|
|
@brief Convert a number to VAX form -- least significant bytes first.
|
|
|
|
Return the length.
|
|
|
|
|
|
|
|
|
|
|
|
@param number
|
|
|
|
@param buffer
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
|
|
|
|
// CVC: This routine should disappear in favor of a centralized function.
|
|
|
|
static USHORT convert( SLONG number, UCHAR* buffer)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
const UCHAR* p;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-09-17 07:58:40 +02:00
|
|
|
#ifndef WORDS_BIGENDIAN
|
2003-11-01 11:26:43 +01:00
|
|
|
const SLONG n = number;
|
2002-12-16 16:38:26 +01:00
|
|
|
p = (UCHAR *) & n;
|
2001-05-23 15:26:42 +02:00
|
|
|
*buffer++ = *p++;
|
|
|
|
*buffer++ = *p++;
|
|
|
|
*buffer++ = *p++;
|
|
|
|
*buffer++ = *p++;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2002-12-16 16:38:26 +01:00
|
|
|
p = (UCHAR *) (&number + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
*buffer++ = *--p;
|
|
|
|
*buffer++ = *--p;
|
|
|
|
*buffer++ = *--p;
|
|
|
|
*buffer++ = *--p;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
error
|
|
|
|
|
|
|
|
@brief An error returned has been trapped.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS error()
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return tdsql->tsql_status[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
execute_blob
|
|
|
|
|
|
|
|
@brief Open or create a blob.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param in_blr_length
|
|
|
|
@param in_blr
|
|
|
|
@param in_msg_length
|
|
|
|
@param in_msg
|
|
|
|
@param out_blr_length
|
|
|
|
@param out_blr
|
|
|
|
@param out_msg_length
|
|
|
|
@param out_msg
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static void execute_blob( dsql_req* request,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT in_blr_length,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* in_blr,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT in_msg_length,
|
|
|
|
UCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
UCHAR* out_blr,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
UCHAR* out_msg)
|
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR bpb[24];
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS s;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_blb* blob = request->req_blob;
|
2001-05-23 15:26:42 +02:00
|
|
|
map_in_out(request, blob->blb_open_in_msg, in_blr_length, in_blr,
|
|
|
|
in_msg_length, in_msg);
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR* p = bpb;
|
2003-11-08 00:27:24 +01:00
|
|
|
*p++ = isc_bpb_version1;
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT filter = filter_sub_type(request, blob->blb_to);
|
|
|
|
if (filter) {
|
2003-11-08 00:27:24 +01:00
|
|
|
*p++ = isc_bpb_target_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 2;
|
|
|
|
*p++ = static_cast<UCHAR>(filter);
|
|
|
|
*p++ = filter >> 8;
|
|
|
|
}
|
2003-11-01 11:26:43 +01:00
|
|
|
filter = filter_sub_type(request, blob->blb_from);
|
|
|
|
if (filter) {
|
2003-11-08 00:27:24 +01:00
|
|
|
*p++ = isc_bpb_source_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 2;
|
|
|
|
*p++ = static_cast<UCHAR>(filter);
|
|
|
|
*p++ = filter >> 8;
|
|
|
|
}
|
2003-11-01 11:26:43 +01:00
|
|
|
USHORT bpb_length = p - bpb;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (bpb_length == 1) {
|
2001-05-23 15:26:42 +02:00
|
|
|
bpb_length = 0;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* parameter = blob->blb_blob_id;
|
|
|
|
const dsql_par* null = parameter->par_null;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (request->req_type == REQ_GET_SEGMENT)
|
|
|
|
{
|
2003-11-11 13:19:20 +01:00
|
|
|
ISC_QUAD* blob_id = (ISC_QUAD*) parameter->par_desc.dsc_address;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (null && *((SSHORT *) null->par_desc.dsc_address) < 0) {
|
2003-11-11 13:19:20 +01:00
|
|
|
memset(blob_id, 0, sizeof(ISC_QUAD));
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_open_blob2(tdsql->tsql_status,
|
2003-08-30 03:54:25 +02:00
|
|
|
&request->req_dbb->dbb_database_handle,
|
|
|
|
&request->req_trans, &request->req_handle,
|
|
|
|
blob_id, bpb_length,
|
2003-11-10 10:16:38 +01:00
|
|
|
bpb);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-12-24 03:51:06 +01:00
|
|
|
if (s) {
|
2001-05-23 15:26:42 +02:00
|
|
|
punt();
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else
|
|
|
|
{
|
2004-05-03 01:06:37 +02:00
|
|
|
request->req_handle = 0;
|
2003-11-11 13:19:20 +01:00
|
|
|
ISC_QUAD* blob_id = (ISC_QUAD*) parameter->par_desc.dsc_address;
|
|
|
|
memset(blob_id, 0, sizeof(ISC_QUAD));
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_create_blob2(tdsql->tsql_status,
|
2003-08-30 03:54:25 +02:00
|
|
|
&request->req_dbb->dbb_database_handle,
|
|
|
|
&request->req_trans, &request->req_handle,
|
2003-10-29 11:53:47 +01:00
|
|
|
blob_id, bpb_length,
|
|
|
|
reinterpret_cast<const char*>(bpb));
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-12-24 03:51:06 +01:00
|
|
|
if (s) {
|
2001-05-23 15:26:42 +02:00
|
|
|
punt();
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
map_in_out(NULL, blob->blb_open_out_msg, out_blr_length, out_blr,
|
|
|
|
out_msg_length, out_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
execute_request
|
|
|
|
|
|
|
|
@brief Execute a dynamic SQL statement.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param trans_handle
|
|
|
|
@param in_blr_length
|
|
|
|
@param in_blr
|
|
|
|
@param in_msg_length
|
|
|
|
@param in_msg
|
|
|
|
@param out_blr_length
|
|
|
|
@param out_blr
|
|
|
|
@param out_msg_length
|
|
|
|
@param out_msg
|
|
|
|
@param singleton
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static ISC_STATUS execute_request(dsql_req* request,
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE* trans_handle,
|
2003-09-04 23:26:15 +02:00
|
|
|
USHORT in_blr_length,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* in_blr,
|
2003-09-04 23:26:15 +02:00
|
|
|
USHORT in_msg_length,
|
|
|
|
UCHAR* in_msg,
|
|
|
|
USHORT out_blr_length,
|
|
|
|
UCHAR* out_blr,
|
|
|
|
USHORT out_msg_length,
|
|
|
|
UCHAR* out_msg,
|
|
|
|
bool singleton)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_msg* message;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT use_msg_length;
|
|
|
|
UCHAR *use_msg;
|
2002-12-16 16:38:26 +01:00
|
|
|
UCHAR buffer[20];
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS s;
|
|
|
|
ISC_STATUS_ARRAY local_status;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-12-16 16:38:26 +01:00
|
|
|
request->req_trans = *trans_handle;
|
2003-11-01 11:26:43 +01:00
|
|
|
ISC_STATUS return_status = FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (request->req_type) {
|
|
|
|
case REQ_START_TRANS:
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_start_transaction( tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_trans,
|
2001-05-23 15:26:42 +02:00
|
|
|
1,
|
|
|
|
&request->req_dbb->dbb_database_handle,
|
2004-04-18 16:22:27 +02:00
|
|
|
request->req_blr_data.getCount(),
|
|
|
|
request->req_blr_data.begin());
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (s)
|
|
|
|
punt();
|
|
|
|
*trans_handle = request->req_trans;
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_COMMIT:
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_commit_transaction(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_trans);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (s)
|
|
|
|
punt();
|
2004-05-03 01:06:37 +02:00
|
|
|
*trans_handle = 0;
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_COMMIT_RETAIN:
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_commit_retaining(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_trans);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (s)
|
|
|
|
punt();
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_ROLLBACK:
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_rollback_transaction(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_trans);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (s)
|
|
|
|
punt();
|
2004-05-03 01:06:37 +02:00
|
|
|
*trans_handle = 0;
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_DDL:
|
|
|
|
DDL_execute(request);
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_GET_SEGMENT:
|
|
|
|
execute_blob( request,
|
|
|
|
in_blr_length,
|
|
|
|
in_blr,
|
|
|
|
in_msg_length,
|
|
|
|
in_msg,
|
|
|
|
out_blr_length,
|
|
|
|
out_blr,
|
|
|
|
out_msg_length,
|
|
|
|
out_msg);
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_PUT_SEGMENT:
|
|
|
|
execute_blob( request,
|
|
|
|
in_blr_length,
|
|
|
|
in_blr,
|
|
|
|
in_msg_length,
|
|
|
|
in_msg,
|
|
|
|
out_blr_length,
|
|
|
|
out_blr,
|
|
|
|
out_msg_length,
|
|
|
|
out_msg);
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_EXEC_PROCEDURE:
|
2003-11-01 11:26:43 +01:00
|
|
|
if (message = (dsql_msg*) request->req_send) {
|
2001-05-23 15:26:42 +02:00
|
|
|
map_in_out(request, message, in_blr_length, in_blr,
|
|
|
|
in_msg_length, in_msg);
|
|
|
|
in_msg_length = message->msg_length;
|
|
|
|
in_msg = message->msg_buffer;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
in_msg_length = 0;
|
|
|
|
in_msg = NULL;
|
|
|
|
}
|
2003-11-01 11:26:43 +01:00
|
|
|
if (out_msg_length && (message = (dsql_msg*) request->req_receive)) {
|
2001-12-24 03:51:06 +01:00
|
|
|
if (out_blr_length) {
|
2001-05-23 15:26:42 +02:00
|
|
|
parse_blr(out_blr_length, out_blr, out_msg_length,
|
|
|
|
message->msg_parameters);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
use_msg_length = message->msg_length;
|
|
|
|
use_msg = message->msg_buffer;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
use_msg_length = 0;
|
|
|
|
use_msg = NULL;
|
|
|
|
}
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_transact_request(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_dbb->dbb_database_handle,
|
|
|
|
&request->req_trans,
|
2004-04-18 16:22:27 +02:00
|
|
|
(USHORT) (request->req_blr_data.getCount()),
|
2004-05-09 07:48:33 +02:00
|
|
|
(const char*)(request->req_blr_data.begin()),
|
2001-05-23 15:26:42 +02:00
|
|
|
in_msg_length,
|
2003-02-12 20:28:13 +01:00
|
|
|
reinterpret_cast<char*>(in_msg),
|
2001-05-23 15:26:42 +02:00
|
|
|
use_msg_length,
|
2003-02-12 20:28:13 +01:00
|
|
|
reinterpret_cast<char*>(use_msg));
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (s)
|
|
|
|
punt();
|
|
|
|
if (out_msg_length && message)
|
|
|
|
map_in_out(NULL, message, 0, out_blr, out_msg_length, out_msg);
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
default:
|
2003-11-28 07:48:34 +01:00
|
|
|
// Catch invalid request types
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(false);
|
2003-11-28 07:48:34 +01:00
|
|
|
// Fall into ...
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case REQ_SELECT:
|
|
|
|
case REQ_SELECT_UPD:
|
|
|
|
case REQ_INSERT:
|
|
|
|
case REQ_DELETE:
|
|
|
|
case REQ_UPDATE:
|
|
|
|
case REQ_UPDATE_CURSOR:
|
|
|
|
case REQ_DELETE_CURSOR:
|
|
|
|
case REQ_EMBED_SELECT:
|
|
|
|
case REQ_SET_GENERATOR:
|
2002-10-29 21:20:44 +01:00
|
|
|
case REQ_SAVEPOINT:
|
2004-01-16 11:43:21 +01:00
|
|
|
case REQ_EXEC_BLOCK:
|
|
|
|
case REQ_SELECT_BLOCK:
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// If there is no data required, just start the request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
message = (dsql_msg*) request->req_send;
|
2001-05-24 16:54:26 +02:00
|
|
|
if (!message)
|
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_start_request(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle,
|
|
|
|
&request->req_trans,
|
2001-05-24 16:54:26 +02:00
|
|
|
0);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (s)
|
|
|
|
punt();
|
|
|
|
}
|
2001-05-24 16:54:26 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
map_in_out( request,
|
|
|
|
message,
|
|
|
|
in_blr_length,
|
|
|
|
in_blr,
|
|
|
|
in_msg_length,
|
|
|
|
in_msg);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_start_and_send(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle,
|
|
|
|
&request->req_trans,
|
2001-05-24 16:54:26 +02:00
|
|
|
message->msg_number,
|
|
|
|
message->msg_length,
|
|
|
|
message->msg_buffer,
|
|
|
|
0);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (s)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
punt();
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-01-16 11:43:21 +01:00
|
|
|
// REQ_EXEC_BLOCK has no outputs so there are no out_msg
|
|
|
|
// supplied from client side, but REQ_EXEC_BLOCK requires
|
|
|
|
// 2-byte message for EOS synchronization
|
|
|
|
bool isBlock = (request->req_type == REQ_EXEC_BLOCK);
|
|
|
|
|
|
|
|
if (out_msg_length && (message = request->req_receive) || isBlock) {
|
|
|
|
char temp_buffer[DOUBLE_ALIGN*2];
|
|
|
|
dsql_msg temp_msg;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Insure that the blr for the message is parsed, regardless of
|
|
|
|
whether anything is found by the call to receive. */
|
|
|
|
|
2004-01-16 11:43:21 +01:00
|
|
|
if (out_msg_length && out_blr_length) {
|
2001-05-23 15:26:42 +02:00
|
|
|
parse_blr(out_blr_length, out_blr, out_msg_length,
|
|
|
|
message->msg_parameters);
|
2004-01-16 11:43:21 +01:00
|
|
|
}
|
|
|
|
else if (!out_msg_length && isBlock) {
|
|
|
|
message = &temp_msg;
|
|
|
|
|
|
|
|
message->msg_number = 1;
|
|
|
|
message->msg_length = 2;
|
|
|
|
message->msg_buffer = (UCHAR*)FB_ALIGN((U_IPTR) temp_buffer, DOUBLE_ALIGN);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_receive(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle,
|
2001-05-23 15:26:42 +02:00
|
|
|
message->msg_number,
|
2001-05-24 16:54:26 +02:00
|
|
|
message->msg_length,
|
|
|
|
message->msg_buffer,
|
|
|
|
0);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-12-24 03:51:06 +01:00
|
|
|
if (s) {
|
2001-05-23 15:26:42 +02:00
|
|
|
punt();
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-16 11:43:21 +01:00
|
|
|
if (out_msg_length)
|
|
|
|
map_in_out(NULL, message, 0, out_blr, out_msg_length, out_msg);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// if this is a singleton select, make sure there's in fact one record
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
if (singleton)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT counter;
|
|
|
|
|
|
|
|
/* Create a temp message buffer and try two more receives.
|
|
|
|
If both succeed then the first is the next record and the
|
|
|
|
second is either another record or the end of record message.
|
|
|
|
In either case, there's more than one record. */
|
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
UCHAR* message_buffer =
|
2003-01-16 18:47:10 +01:00
|
|
|
(UCHAR*)gds__alloc((ULONG) message->msg_length);
|
2001-05-24 16:54:26 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
s = 0;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-24 16:54:26 +02:00
|
|
|
for (counter = 0; counter < 2 && !s; counter++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_receive(local_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle,
|
2001-05-24 16:54:26 +02:00
|
|
|
message->msg_number,
|
|
|
|
message->msg_length,
|
|
|
|
message_buffer,
|
|
|
|
0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2003-01-16 18:47:10 +01:00
|
|
|
gds__free(message_buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* two successful receives means more than one record
|
|
|
|
a req_sync error on the first pass above means no records
|
|
|
|
a non-req_sync error on any of the passes above is an error */
|
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
if (!s)
|
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
tdsql->tsql_status[0] = isc_arg_gds;
|
|
|
|
tdsql->tsql_status[1] = isc_sing_select_err;
|
|
|
|
tdsql->tsql_status[2] = isc_arg_end;
|
|
|
|
return_status = isc_sing_select_err;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (s == isc_req_sync && counter == 1)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
tdsql->tsql_status[0] = isc_arg_gds;
|
|
|
|
tdsql->tsql_status[1] = isc_stream_eof;
|
|
|
|
tdsql->tsql_status[2] = isc_arg_end;
|
|
|
|
return_status = isc_stream_eof;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (s != isc_req_sync)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
punt();
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
if (!(request->req_dbb->dbb_flags & DBB_v3))
|
|
|
|
{
|
|
|
|
if (request->req_type == REQ_UPDATE_CURSOR)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
GDS_DSQL_SQL_INFO_CPP( local_status,
|
|
|
|
&request,
|
|
|
|
sizeof(sql_records_info),
|
2002-12-16 16:38:26 +01:00
|
|
|
sql_records_info,
|
2001-12-24 03:51:06 +01:00
|
|
|
sizeof(buffer),
|
|
|
|
buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!request->req_updates)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 913,
|
|
|
|
isc_arg_gds, isc_deadlock, isc_arg_gds,
|
|
|
|
isc_update_conflict, 0);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-05-24 16:54:26 +02:00
|
|
|
else if (request->req_type == REQ_DELETE_CURSOR)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
GDS_DSQL_SQL_INFO_CPP( local_status,
|
|
|
|
&request,
|
|
|
|
sizeof(sql_records_info),
|
2002-12-16 16:38:26 +01:00
|
|
|
sql_records_info,
|
2001-12-24 03:51:06 +01:00
|
|
|
sizeof(buffer),
|
|
|
|
buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!request->req_deletes)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 913,
|
|
|
|
isc_arg_gds, isc_deadlock, isc_arg_gds,
|
|
|
|
isc_update_conflict, 0);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return return_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
filter_sub_type
|
|
|
|
|
|
|
|
@brief Determine the sub_type to use in filtering
|
|
|
|
a blob.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param node
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static SSHORT filter_sub_type( dsql_req* request, const dsql_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (node->nod_type == nod_constant)
|
2004-01-21 08:18:30 +01:00
|
|
|
return (SSHORT)(IPTR) node->nod_arg[0];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
const dsql_par* parameter = (dsql_par*) node->nod_arg[e_par_parameter];
|
|
|
|
const dsql_par* null = parameter->par_null;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (null)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*((SSHORT *) null->par_desc.dsc_address))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return *((SSHORT *) parameter->par_desc.dsc_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
get_indices
|
|
|
|
|
|
|
|
@brief Retrieve the indices from the index tree in
|
2003-11-01 11:26:43 +01:00
|
|
|
the request info buffer (explain_ptr), and print them out
|
|
|
|
in the plan buffer. Return true on success and false on failure.
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
@param explain_length_ptr
|
|
|
|
@param explain_ptr
|
|
|
|
@param plan_length_ptr
|
|
|
|
@param plan_ptr
|
|
|
|
|
|
|
|
**/
|
2003-09-04 23:26:15 +02:00
|
|
|
static bool get_indices(
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT* explain_length_ptr,
|
|
|
|
const SCHAR** explain_ptr,
|
|
|
|
SSHORT* plan_length_ptr, SCHAR** plan_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
USHORT length;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT explain_length = *explain_length_ptr;
|
|
|
|
const SCHAR* explain = *explain_ptr;
|
|
|
|
SSHORT plan_length = *plan_length_ptr;
|
|
|
|
SCHAR* plan = *plan_ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* go through the index tree information, just
|
|
|
|
extracting the indices used */
|
|
|
|
|
|
|
|
explain_length--;
|
|
|
|
switch (*explain++) {
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_and:
|
|
|
|
case isc_info_rsb_or:
|
2003-09-05 13:28:23 +02:00
|
|
|
if (!get_indices(&explain_length, &explain, &plan_length, &plan))
|
|
|
|
return false;
|
|
|
|
if (!get_indices(&explain_length, &explain, &plan_length, &plan))
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_dbkey:
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_index:
|
2001-05-23 15:26:42 +02:00
|
|
|
explain_length--;
|
|
|
|
length = *explain++;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// if this isn't the first index, put out a comma
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (plan[-1] != '(' && plan[-1] != ' ') {
|
2003-09-10 15:24:49 +02:00
|
|
|
plan_length -= 2;
|
|
|
|
if (plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = ',';
|
2003-09-10 15:24:49 +02:00
|
|
|
*plan++ = ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// now put out the index name
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if ((plan_length -= length) < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
explain_length -= length;
|
|
|
|
while (length--)
|
|
|
|
*plan++ = *explain++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*explain_length_ptr = explain_length;
|
|
|
|
*explain_ptr = explain;
|
|
|
|
*plan_length_ptr = plan_length;
|
|
|
|
*plan_ptr = plan;
|
|
|
|
|
2003-09-05 13:28:23 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
get_plan_info
|
|
|
|
|
|
|
|
@brief Get the access plan for the request and turn
|
|
|
|
it into a textual representation suitable for
|
|
|
|
human reading.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param buffer_length
|
|
|
|
@param buffer
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static USHORT get_plan_info(
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request,
|
|
|
|
SSHORT buffer_length, SCHAR** out_buffer)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
SCHAR explain_buffer[256];
|
|
|
|
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS s;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
memset(explain_buffer, 0, sizeof(explain_buffer));
|
2003-11-01 11:26:43 +01:00
|
|
|
SCHAR* explain_ptr = explain_buffer;
|
|
|
|
SCHAR* buffer_ptr = *out_buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// get the access path info for the underlying request from the engine
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_request_info(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle,
|
2001-05-23 15:26:42 +02:00
|
|
|
0,
|
|
|
|
sizeof(explain_info),
|
2003-10-29 11:53:47 +01:00
|
|
|
explain_info,
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(explain_buffer), explain_buffer);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (s)
|
|
|
|
return 0;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
if (*explain_buffer == isc_info_truncated) {
|
2001-05-23 15:26:42 +02:00
|
|
|
explain_ptr = (SCHAR *) gds__alloc(BUFFER_XLARGE);
|
2003-11-01 11:26:43 +01:00
|
|
|
// CVC: Added test for memory exhaustion here.
|
|
|
|
// Should we throw an exception or simply return 0 to the caller?
|
|
|
|
if (!explain_ptr) {
|
|
|
|
return 0;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_request_info(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle, 0,
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(explain_info),
|
2003-10-29 11:53:47 +01:00
|
|
|
explain_info,
|
2001-05-23 15:26:42 +02:00
|
|
|
BUFFER_XLARGE, explain_ptr);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
if (s) {
|
|
|
|
// CVC: Before returning, deallocate the buffer!
|
|
|
|
gds__free(explain_ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SCHAR* plan;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
const SCHAR* explain = explain_ptr;
|
2003-11-08 00:27:24 +01:00
|
|
|
if (*explain++ != isc_info_access_path)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
|
|
|
// CVC: deallocate memory!
|
|
|
|
if (explain_ptr != explain_buffer) {
|
|
|
|
gds__free(explain_ptr);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT explain_length = (UCHAR) *explain++;
|
2001-05-23 15:26:42 +02:00
|
|
|
explain_length += (UCHAR) (*explain++) << 8;
|
|
|
|
|
|
|
|
plan = buffer_ptr;
|
|
|
|
|
2002-06-29 08:56:51 +02:00
|
|
|
/* CVC: What if we need to do 2nd pass? Those variables were only initialized
|
|
|
|
at the begining of the function hence they had trash the second time. */
|
|
|
|
USHORT join_count = 0, level = 0;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// keep going until we reach the end of the explain info
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
while (explain_length > 0 && buffer_length > 0) {
|
2003-09-08 13:29:36 +02:00
|
|
|
if (!get_rsb_item(&explain_length, &explain, &buffer_length, &plan,
|
2003-11-01 11:26:43 +01:00
|
|
|
&join_count, &level))
|
|
|
|
{
|
2003-11-28 07:48:34 +01:00
|
|
|
// assume we have run out of room in the buffer, try again with a larger one
|
2004-03-09 01:17:07 +01:00
|
|
|
char* temp = reinterpret_cast<char*>(gds__alloc(BUFFER_XLARGE));
|
|
|
|
if (!temp) {
|
|
|
|
// NOMEM. Do not attempt one more try
|
|
|
|
i++;
|
|
|
|
continue;
|
2004-03-11 06:04:26 +01:00
|
|
|
}
|
|
|
|
else {
|
2004-03-09 01:17:07 +01:00
|
|
|
buffer_ptr = temp;
|
|
|
|
buffer_length = BUFFER_XLARGE;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
if (buffer_ptr == *out_buffer)
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
if (explain_ptr != explain_buffer) {
|
2001-05-23 15:26:42 +02:00
|
|
|
gds__free(explain_ptr);
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
*out_buffer = buffer_ptr;
|
|
|
|
return plan - *out_buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
get_request_info
|
|
|
|
|
|
|
|
@brief Get the records updated/deleted for record
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param buffer_length
|
|
|
|
@param buffer
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static USHORT get_request_info(
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* request,
|
2003-10-29 11:53:47 +01:00
|
|
|
SSHORT buffer_length, SCHAR* buffer)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS s;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// get the info for the request from the engine
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
s = isc_request_info(tdsql->tsql_status,
|
2002-12-16 16:38:26 +01:00
|
|
|
&request->req_handle,
|
2001-05-23 15:26:42 +02:00
|
|
|
0,
|
|
|
|
sizeof(record_info),
|
2003-10-29 11:53:47 +01:00
|
|
|
record_info,
|
2001-05-23 15:26:42 +02:00
|
|
|
buffer_length, buffer);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (s)
|
|
|
|
return 0;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SCHAR* data = buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
request->req_updates = request->req_deletes = 0;
|
|
|
|
request->req_selects = request->req_inserts = 0;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR p;
|
2003-11-08 00:27:24 +01:00
|
|
|
while ((p = *data++) != isc_info_end) {
|
2003-11-01 11:26:43 +01:00
|
|
|
const USHORT data_length =
|
2003-11-16 02:44:51 +01:00
|
|
|
static_cast < USHORT >
|
|
|
|
(gds__vax_integer(reinterpret_cast<UCHAR*>(data), 2));
|
2001-05-23 15:26:42 +02:00
|
|
|
data += 2;
|
|
|
|
|
|
|
|
switch (p) {
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_req_update_count:
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_updates =
|
2003-11-16 02:44:51 +01:00
|
|
|
gds__vax_integer(reinterpret_cast<UCHAR*>(data),
|
|
|
|
data_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_req_delete_count:
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_deletes =
|
2003-11-16 02:44:51 +01:00
|
|
|
gds__vax_integer(reinterpret_cast<UCHAR*>(data),
|
|
|
|
data_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_req_select_count:
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_selects =
|
2003-11-16 02:44:51 +01:00
|
|
|
gds__vax_integer(reinterpret_cast<UCHAR*>(data),
|
|
|
|
data_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_req_insert_count:
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_inserts =
|
2003-11-16 02:44:51 +01:00
|
|
|
gds__vax_integer(reinterpret_cast<UCHAR*>(data),
|
|
|
|
data_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
data += data_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data - buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
get_rsb_item
|
|
|
|
|
|
|
|
@brief Use recursion to print out a reverse-polish
|
2003-09-05 13:28:23 +02:00
|
|
|
access plan of joins and join types. Return true on success
|
|
|
|
and false on failure
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
@param explain_length_ptr
|
|
|
|
@param explain_ptr
|
|
|
|
@param plan_length_ptr
|
|
|
|
@param plan_ptr
|
|
|
|
@param parent_join_count
|
|
|
|
@param level_ptr
|
|
|
|
|
|
|
|
**/
|
2003-09-04 23:26:15 +02:00
|
|
|
static bool get_rsb_item(SSHORT* explain_length_ptr,
|
2003-11-01 11:26:43 +01:00
|
|
|
const SCHAR** explain_ptr,
|
2001-12-24 03:51:06 +01:00
|
|
|
SSHORT* plan_length_ptr,
|
|
|
|
SCHAR** plan_ptr,
|
|
|
|
USHORT* parent_join_count,
|
|
|
|
USHORT* level_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
const SCHAR* p;
|
|
|
|
SSHORT rsb_type, length;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT join_count, union_count, union_level, union_join_count, save_level;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT explain_length = *explain_length_ptr;
|
|
|
|
const SCHAR* explain = *explain_ptr;
|
|
|
|
SSHORT plan_length = *plan_length_ptr;
|
|
|
|
SCHAR* plan = *plan_ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
explain_length--;
|
|
|
|
switch (*explain++) {
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_begin:
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!*level_ptr) {
|
2003-11-28 07:48:34 +01:00
|
|
|
// put out the PLAN prefix
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
p = "\nPLAN ";
|
|
|
|
if ((plan_length -= strlen(p)) < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (*p)
|
|
|
|
*plan++ = *p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*level_ptr)++;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_end:
|
2002-06-29 08:56:51 +02:00
|
|
|
if (*level_ptr) {
|
|
|
|
(*level_ptr)--;
|
|
|
|
}
|
|
|
|
/* else --*parent_join_count; ??? */
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_relation:
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* for the single relation case, initiate
|
2001-05-23 15:26:42 +02:00
|
|
|
the relation with a parenthesis */
|
|
|
|
|
|
|
|
if (!*parent_join_count) {
|
|
|
|
if (--plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = '(';
|
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// if this isn't the first relation, put out a comma
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (plan[-1] != '(') {
|
2003-09-10 15:24:49 +02:00
|
|
|
plan_length -= 2;
|
|
|
|
if (plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = ',';
|
2003-09-10 15:24:49 +02:00
|
|
|
*plan++ = ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// put out the relation name
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
explain_length--;
|
|
|
|
explain_length -= (length = (UCHAR) * explain++);
|
|
|
|
if ((plan_length -= length) < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (length--)
|
|
|
|
*plan++ = *explain++;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_type:
|
2001-05-23 15:26:42 +02:00
|
|
|
explain_length--;
|
|
|
|
switch (rsb_type = *explain++) {
|
|
|
|
/* for stream types which have multiple substreams, print out
|
|
|
|
the stream type and recursively print out the substreams so
|
|
|
|
we will know where to put the parentheses */
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_union:
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// put out all the substreams of the join
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
explain_length--;
|
|
|
|
union_count = (USHORT) * explain++ - 1;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// finish the first union member
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
union_level = *level_ptr;
|
|
|
|
union_join_count = 0;
|
2003-09-04 23:26:15 +02:00
|
|
|
while (true) {
|
2003-09-08 13:29:36 +02:00
|
|
|
if (!get_rsb_item(&explain_length, &explain, &plan_length, &plan,
|
|
|
|
&union_join_count, &union_level))
|
2003-09-04 23:26:15 +02:00
|
|
|
{
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2003-09-04 23:26:15 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (union_level == *level_ptr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for the rest of the members, start the level at 0 so each
|
|
|
|
gets its own "PLAN ... " line */
|
|
|
|
|
|
|
|
while (union_count) {
|
|
|
|
union_join_count = 0;
|
|
|
|
union_level = 0;
|
2003-09-04 23:26:15 +02:00
|
|
|
while (true) {
|
2003-09-08 13:29:36 +02:00
|
|
|
if (!get_rsb_item(&explain_length, &explain, &plan_length,
|
|
|
|
&plan, &union_join_count, &union_level))
|
2003-09-04 23:26:15 +02:00
|
|
|
{
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2003-09-04 23:26:15 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!union_level)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
union_count--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_cross:
|
|
|
|
case isc_info_rsb_left_cross:
|
|
|
|
case isc_info_rsb_merge:
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* if this join is itself part of a join list,
|
2001-05-23 15:26:42 +02:00
|
|
|
but not the first item, then put out a comma */
|
|
|
|
|
|
|
|
if (*parent_join_count && plan[-1] != '(') {
|
2003-09-10 15:24:49 +02:00
|
|
|
plan_length -= 2;
|
|
|
|
if (plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = ',';
|
2003-09-10 15:24:49 +02:00
|
|
|
*plan++ = ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// put out the join type
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
if (rsb_type == isc_info_rsb_cross ||
|
|
|
|
rsb_type == isc_info_rsb_left_cross) {
|
2002-06-29 08:56:51 +02:00
|
|
|
p = "JOIN (";
|
|
|
|
}
|
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
p = "MERGE (";
|
2002-06-29 08:56:51 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if ((plan_length -= strlen(p)) < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (*p)
|
|
|
|
*plan++ = *p++;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// put out all the substreams of the join
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
explain_length--;
|
|
|
|
join_count = (USHORT) * explain++;
|
2002-06-29 08:56:51 +02:00
|
|
|
while (join_count) {
|
2003-09-08 13:29:36 +02:00
|
|
|
if (!get_rsb_item(&explain_length, &explain, &plan_length,
|
|
|
|
&plan, &join_count, level_ptr))
|
2003-09-04 23:26:15 +02:00
|
|
|
{
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2003-09-04 23:26:15 +02:00
|
|
|
}
|
2003-11-28 07:48:34 +01:00
|
|
|
// CVC: Here's the additional stop condition.
|
2003-09-04 23:26:15 +02:00
|
|
|
if (!*level_ptr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-06-29 08:56:51 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// put out the final parenthesis for the join
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (--plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
*plan++ = ')';
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// this qualifies as a stream, so decrement the join count
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (*parent_join_count)
|
|
|
|
-- * parent_join_count;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_indexed:
|
|
|
|
case isc_info_rsb_navigate:
|
|
|
|
case isc_info_rsb_sequential:
|
|
|
|
case isc_info_rsb_ext_sequential:
|
|
|
|
case isc_info_rsb_ext_indexed:
|
|
|
|
if (rsb_type == isc_info_rsb_indexed ||
|
|
|
|
rsb_type == isc_info_rsb_ext_indexed)
|
2003-09-04 23:26:15 +02:00
|
|
|
{
|
|
|
|
p = " INDEX (";
|
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
else if (rsb_type == isc_info_rsb_navigate)
|
2001-05-23 15:26:42 +02:00
|
|
|
p = " ORDER ";
|
|
|
|
else
|
|
|
|
p = " NATURAL";
|
|
|
|
|
|
|
|
if ((plan_length -= strlen(p)) < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (*p)
|
|
|
|
*plan++ = *p++;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// print out additional index information
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
if (rsb_type == isc_info_rsb_indexed ||
|
|
|
|
rsb_type == isc_info_rsb_navigate ||
|
|
|
|
rsb_type == isc_info_rsb_ext_indexed) {
|
2003-09-05 13:28:23 +02:00
|
|
|
if (!get_indices(&explain_length, &explain, &plan_length, &plan))
|
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
if (rsb_type == isc_info_rsb_navigate &&
|
|
|
|
*explain == isc_info_rsb_indexed)
|
2003-09-10 15:24:49 +02:00
|
|
|
{
|
|
|
|
if (!get_rsb_item(&explain_length, &explain, &plan_length,
|
2004-08-20 04:08:39 +02:00
|
|
|
&plan, parent_join_count, level_ptr))
|
2003-09-10 15:24:49 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
if (rsb_type == isc_info_rsb_indexed ||
|
|
|
|
rsb_type == isc_info_rsb_ext_indexed) {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (--plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = ')';
|
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// detect the end of a single relation and put out a final parenthesis
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!*parent_join_count)
|
|
|
|
if (--plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
*plan++ = ')';
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// this also qualifies as a stream, so decrement the join count
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (*parent_join_count)
|
|
|
|
-- * parent_join_count;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_rsb_sort:
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* if this sort is on behalf of a union, don't bother to
|
|
|
|
print out the sort, because unions handle the sort on all
|
|
|
|
substreams at once, and a plan maps to each substream
|
2001-05-23 15:26:42 +02:00
|
|
|
in the union, so the sort doesn't really apply to a particular plan */
|
|
|
|
|
|
|
|
if (explain_length > 2 &&
|
2003-11-08 00:27:24 +01:00
|
|
|
(explain[0] == isc_info_rsb_begin) &&
|
|
|
|
(explain[1] == isc_info_rsb_type) &&
|
|
|
|
(explain[2] == isc_info_rsb_union))
|
2003-09-04 23:26:15 +02:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// if this isn't the first item in the list, put out a comma
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (*parent_join_count && plan[-1] != '(') {
|
2003-09-10 15:24:49 +02:00
|
|
|
plan_length -= 2;
|
|
|
|
if (plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = ',';
|
2003-09-10 15:24:49 +02:00
|
|
|
*plan++ = ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
p = "SORT (";
|
|
|
|
|
|
|
|
if ((plan_length -= strlen(p)) < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (*p)
|
|
|
|
*plan++ = *p++;
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* the rsb_sort should always be followed by a begin...end block,
|
2001-05-23 15:26:42 +02:00
|
|
|
allowing us to include everything inside the sort in parentheses */
|
|
|
|
|
|
|
|
save_level = *level_ptr;
|
|
|
|
while (explain_length > 0 && plan_length > 0) {
|
2003-09-08 13:29:36 +02:00
|
|
|
if (!get_rsb_item(&explain_length, &explain, &plan_length,
|
|
|
|
&plan, parent_join_count, level_ptr))
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*level_ptr == save_level)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (--plan_length < 0)
|
2003-09-05 13:28:23 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*plan++ = ')';
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*explain_length_ptr = explain_length;
|
|
|
|
*explain_ptr = explain;
|
|
|
|
*plan_length_ptr = plan_length;
|
|
|
|
*plan_ptr = plan;
|
|
|
|
|
2003-09-05 13:28:23 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
init
|
|
|
|
|
|
|
|
@brief Initialize dynamic SQL. This is called only once.
|
|
|
|
|
|
|
|
|
|
|
|
@param db_handle
|
|
|
|
|
|
|
|
**/
|
2004-05-03 01:06:37 +02:00
|
|
|
static dsql_dbb* init(FB_API_HANDLE* db_handle)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2001-05-23 15:26:42 +02:00
|
|
|
THD_MUTEX_LOCK(&databases_mutex);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (!init_flag)
|
|
|
|
{
|
|
|
|
init_flag = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
ALLD_init();
|
|
|
|
HSHD_init();
|
|
|
|
|
2003-09-28 23:36:05 +02:00
|
|
|
#ifdef DSQL_DEBUG
|
|
|
|
DSQL_debug = Config::getTraceDSQL();
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
LEX_dsql_init();
|
|
|
|
|
|
|
|
gds__register_cleanup(cleanup, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!db_handle) {
|
|
|
|
THD_MUTEX_UNLOCK(&databases_mutex);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// Look for database block. If we don't find one, allocate one.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_dbb* database;
|
2001-05-23 15:26:42 +02:00
|
|
|
for (database = databases; database; database = database->dbb_next)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (database->dbb_database_handle == *db_handle) {
|
|
|
|
THD_MUTEX_UNLOCK(&databases_mutex);
|
|
|
|
return database;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
DsqlMemoryPool* pool = DsqlMemoryPool::createPool();
|
2004-02-02 12:02:12 +01:00
|
|
|
database = FB_NEW(*pool) dsql_dbb;
|
2001-05-23 15:26:42 +02:00
|
|
|
database->dbb_pool = pool;
|
|
|
|
database->dbb_next = databases;
|
|
|
|
databases = database;
|
|
|
|
database->dbb_database_handle = *db_handle;
|
|
|
|
THD_MUTEX_UNLOCK(&databases_mutex);
|
|
|
|
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY user_status;
|
2003-02-12 20:28:13 +01:00
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-11-09 16:38:03 +01:00
|
|
|
isc_database_cleanup(user_status, db_handle, cleanup_database, NULL);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Determine if the database is V3 or V4
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
SCHAR buffer[128];
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
database->dbb_flags |= DBB_v3;
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-04-10 08:32:58 +02:00
|
|
|
const ISC_STATUS s =
|
2003-02-12 20:28:13 +01:00
|
|
|
isc_database_info(user_status, db_handle,
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(db_hdr_info_items),
|
2003-10-29 11:53:47 +01:00
|
|
|
db_hdr_info_items,
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(buffer), buffer);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (s) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return database;
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* assume that server can not report current character set,
|
|
|
|
and if not then emulate pre-patch actions. */
|
|
|
|
database->dbb_att_charset = 127;
|
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
SCHAR* data = buffer;
|
|
|
|
UCHAR p;
|
2003-11-08 00:27:24 +01:00
|
|
|
while ((p = *data++) != isc_info_end)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-16 02:44:51 +01:00
|
|
|
SSHORT l =
|
|
|
|
static_cast<SSHORT>(
|
|
|
|
gds__vax_integer(reinterpret_cast<UCHAR*>(data), 2));
|
2001-05-23 15:26:42 +02:00
|
|
|
data += 2;
|
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
switch (p)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case isc_info_db_sql_dialect:
|
|
|
|
database->dbb_db_SQL_dialect = (USHORT) data[0];
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_ods_version:
|
2003-11-16 02:44:51 +01:00
|
|
|
if (gds__vax_integer(reinterpret_cast<UCHAR*>(data), l) > 7)
|
2001-05-23 15:26:42 +02:00
|
|
|
database->dbb_flags &= ~DBB_v3;
|
|
|
|
break;
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* This flag indicates the version level of the engine
|
|
|
|
itself, so we can tell what capabilities the engine
|
2001-05-23 15:26:42 +02:00
|
|
|
code itself (as opposed to the on-disk structure).
|
2001-07-10 19:35:13 +02:00
|
|
|
Apparently the base level up to now indicated the major
|
|
|
|
version number, but for 4.1 the base level is being
|
|
|
|
incremented, so the base level indicates an engine version
|
2001-05-23 15:26:42 +02:00
|
|
|
as follows:
|
|
|
|
1 == v1.x
|
|
|
|
2 == v2.x
|
|
|
|
3 == v3.x
|
|
|
|
4 == v4.0 only
|
|
|
|
5 == v4.1
|
2001-07-10 19:35:13 +02:00
|
|
|
Note: this info item is so old it apparently uses an
|
2001-05-23 15:26:42 +02:00
|
|
|
archaic format, not a standard vax integer format.
|
|
|
|
*/
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_base_level:
|
2001-05-23 15:26:42 +02:00
|
|
|
database->dbb_base_level = (USHORT) data[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isc_info_db_read_only:
|
|
|
|
if ((USHORT) data[0])
|
|
|
|
database->dbb_flags |= DBB_read_only;
|
|
|
|
else
|
|
|
|
database->dbb_flags &= ~DBB_read_only;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case frb_info_att_charset:
|
|
|
|
database->dbb_att_charset =
|
2003-02-12 20:28:13 +01:00
|
|
|
static_cast<short>(
|
2003-11-16 02:44:51 +01:00
|
|
|
gds__vax_integer(reinterpret_cast<UCHAR*>(data), 2));
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
data += l;
|
|
|
|
}
|
|
|
|
|
|
|
|
return database;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
map_in_out
|
|
|
|
|
|
|
|
@brief Map data from external world into message or
|
|
|
|
from message to external world.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param message
|
|
|
|
@param blr_length
|
|
|
|
@param blr
|
|
|
|
@param msg_length
|
|
|
|
@param dsql_msg
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static void map_in_out( dsql_req* request,
|
|
|
|
dsql_msg* message,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT blr_length,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* blr,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT msg_length,
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR* dsql_msg_buf)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* parameter;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
USHORT count = parse_blr(blr_length, blr, msg_length, message->msg_parameters);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* When mapping data from the external world, request will be non-NULL.
|
|
|
|
When mapping data from an internal message, request will be NULL. */
|
|
|
|
|
|
|
|
for (parameter = message->msg_parameters; parameter;
|
2003-02-12 20:28:13 +01:00
|
|
|
parameter = parameter->par_next)
|
|
|
|
{
|
|
|
|
if (parameter->par_index)
|
|
|
|
{
|
2003-11-28 07:48:34 +01:00
|
|
|
// Make sure the message given to us is long enough
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
DSC desc = parameter->par_user_desc;
|
2004-01-21 08:18:30 +01:00
|
|
|
USHORT length = (IPTR) desc.dsc_address + desc.dsc_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (length > msg_length)
|
|
|
|
break;
|
2002-06-28 15:49:47 +02:00
|
|
|
if (!desc.dsc_dtype)
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT* flag = NULL;
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* null = parameter->par_null;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (null != NULL)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2004-01-21 08:18:30 +01:00
|
|
|
const USHORT null_offset = (IPTR) null->par_user_desc.dsc_address;
|
2001-05-23 15:26:42 +02:00
|
|
|
length = null_offset + sizeof(SSHORT);
|
|
|
|
if (length > msg_length)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!request) {
|
2003-11-01 11:26:43 +01:00
|
|
|
flag = (SSHORT *) (dsql_msg_buf + null_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
*flag = *((SSHORT *) null->par_desc.dsc_address);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
flag = (SSHORT *) null->par_desc.dsc_address;
|
2003-11-01 11:26:43 +01:00
|
|
|
*flag = *((SSHORT *) (dsql_msg_buf + null_offset));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-21 08:18:30 +01:00
|
|
|
desc.dsc_address = dsql_msg_buf + (IPTR) desc.dsc_address;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!request)
|
|
|
|
MOVD_move(¶meter->par_desc, &desc);
|
|
|
|
else if (!flag || *flag >= 0)
|
|
|
|
MOVD_move(&desc, ¶meter->par_desc);
|
|
|
|
|
|
|
|
count--;
|
|
|
|
}
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* If we got here because the loop was exited early or if part of the
|
|
|
|
message given to us hasn't been used, complain. */
|
|
|
|
|
|
|
|
if (parameter || count)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* dbkey;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request &&
|
|
|
|
((dbkey = request->req_parent_dbkey) != NULL) &&
|
2003-02-12 20:28:13 +01:00
|
|
|
((parameter = request->req_dbkey) != NULL))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
MOVD_move(&dbkey->par_desc, ¶meter->par_desc);
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* null = parameter->par_null;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (null != NULL)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT* flag = (SSHORT *) null->par_desc.dsc_address;
|
2001-05-23 15:26:42 +02:00
|
|
|
*flag = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* rec_version;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request &&
|
|
|
|
((rec_version = request->req_parent_rec_version) != NULL) &&
|
2003-02-12 20:28:13 +01:00
|
|
|
((parameter = request->req_rec_version) != NULL))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
MOVD_move(&rec_version->par_desc, ¶meter->par_desc);
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* null = parameter->par_null;
|
2003-11-01 11:26:43 +01:00
|
|
|
if (null != NULL)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
SSHORT* flag = (SSHORT *) null->par_desc.dsc_address;
|
2001-05-23 15:26:42 +02:00
|
|
|
*flag = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
name_length
|
|
|
|
|
|
|
|
@brief Compute length of user supplied name.
|
|
|
|
|
|
|
|
|
|
|
|
@param name
|
|
|
|
|
|
|
|
**/
|
2003-10-16 10:51:06 +02:00
|
|
|
static USHORT name_length( const TEXT* name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-09-28 02:36:28 +02:00
|
|
|
const char BLANK = '\040';
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-16 10:51:06 +02:00
|
|
|
const TEXT* q = name - 1;
|
|
|
|
for (const TEXT* p = name; *p; p++) {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*p != BLANK)
|
|
|
|
q = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (USHORT) ((q + 1) - name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
parse_blr
|
|
|
|
|
|
|
|
@brief Parse the message of a blr request.
|
|
|
|
|
|
|
|
|
|
|
|
@param blr_length
|
|
|
|
@param blr
|
|
|
|
@param msg_length
|
|
|
|
@param parameters
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static USHORT parse_blr(
|
|
|
|
USHORT blr_length,
|
2004-02-02 12:02:12 +01:00
|
|
|
const UCHAR* blr, const USHORT msg_length, dsql_par* parameters)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/* If there's no blr length, then the format of the current message buffer
|
|
|
|
is identical to the format of the previous one. */
|
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (!blr_length)
|
|
|
|
{
|
2003-10-16 10:51:06 +02:00
|
|
|
USHORT par_count = 0;
|
2004-02-02 12:02:12 +01:00
|
|
|
for (const dsql_par* parameter = parameters; parameter;
|
2003-02-12 20:28:13 +01:00
|
|
|
parameter = parameter->par_next)
|
|
|
|
{
|
|
|
|
if (parameter->par_index) {
|
2003-10-16 10:51:06 +02:00
|
|
|
++par_count;
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
|
|
|
}
|
2003-10-16 10:51:06 +02:00
|
|
|
return par_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*blr != blr_version4 && *blr != blr_version5)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2003-11-28 07:48:34 +01:00
|
|
|
blr++; // skip the blr_version
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*blr++ != blr_begin || *blr++ != blr_message)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
++blr; // skip the message number
|
2003-10-16 10:51:06 +02:00
|
|
|
USHORT count = *blr++;
|
2001-05-23 15:26:42 +02:00
|
|
|
count += (*blr++) << 8;
|
|
|
|
count /= 2;
|
|
|
|
|
2003-10-16 10:51:06 +02:00
|
|
|
USHORT offset = 0;
|
|
|
|
for (USHORT index = 1; index <= count; index++)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-10-16 10:51:06 +02:00
|
|
|
dsc desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_scale = 0;
|
|
|
|
desc.dsc_sub_type = 0;
|
|
|
|
desc.dsc_flags = 0;
|
2003-10-16 10:51:06 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
switch (*blr++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case blr_text:
|
|
|
|
desc.dsc_dtype = dtype_text;
|
|
|
|
desc.dsc_sub_type = ttype_dynamic;
|
|
|
|
desc.dsc_length = *blr++;
|
|
|
|
desc.dsc_length += (*blr++) << 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_varying:
|
|
|
|
desc.dsc_dtype = dtype_varying;
|
|
|
|
desc.dsc_sub_type = ttype_dynamic;
|
|
|
|
desc.dsc_length = *blr++ + sizeof(USHORT);
|
|
|
|
desc.dsc_length += (*blr++) << 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_text2:
|
|
|
|
desc.dsc_dtype = dtype_text;
|
|
|
|
desc.dsc_sub_type = *blr++;
|
|
|
|
desc.dsc_sub_type += (*blr++) << 8;
|
|
|
|
desc.dsc_length = *blr++;
|
|
|
|
desc.dsc_length += (*blr++) << 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_varying2:
|
|
|
|
desc.dsc_dtype = dtype_varying;
|
|
|
|
desc.dsc_sub_type = *blr++;
|
|
|
|
desc.dsc_sub_type += (*blr++) << 8;
|
|
|
|
desc.dsc_length = *blr++ + sizeof(USHORT);
|
|
|
|
desc.dsc_length += (*blr++) << 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_short:
|
|
|
|
desc.dsc_dtype = dtype_short;
|
|
|
|
desc.dsc_length = sizeof(SSHORT);
|
|
|
|
desc.dsc_scale = *blr++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_long:
|
|
|
|
desc.dsc_dtype = dtype_long;
|
|
|
|
desc.dsc_length = sizeof(SLONG);
|
|
|
|
desc.dsc_scale = *blr++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_int64:
|
|
|
|
desc.dsc_dtype = dtype_int64;
|
|
|
|
desc.dsc_length = sizeof(SINT64);
|
|
|
|
desc.dsc_scale = *blr++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_quad:
|
|
|
|
desc.dsc_dtype = dtype_quad;
|
|
|
|
desc.dsc_length = sizeof(SLONG) * 2;
|
|
|
|
desc.dsc_scale = *blr++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_float:
|
|
|
|
desc.dsc_dtype = dtype_real;
|
|
|
|
desc.dsc_length = sizeof(float);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_double:
|
|
|
|
#ifndef VMS
|
|
|
|
case blr_d_float:
|
|
|
|
#endif
|
|
|
|
desc.dsc_dtype = dtype_double;
|
|
|
|
desc.dsc_length = sizeof(double);
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef VMS
|
|
|
|
case blr_d_float:
|
|
|
|
desc.dsc_dtype = dtype_d_float;
|
|
|
|
desc.dsc_length = sizeof(double);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case blr_timestamp:
|
|
|
|
desc.dsc_dtype = dtype_timestamp;
|
|
|
|
desc.dsc_length = sizeof(SLONG) * 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_sql_date:
|
|
|
|
desc.dsc_dtype = dtype_sql_date;
|
|
|
|
desc.dsc_length = sizeof(SLONG);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_sql_time:
|
|
|
|
desc.dsc_dtype = dtype_sql_time;
|
|
|
|
desc.dsc_length = sizeof(SLONG);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-10-16 10:51:06 +02:00
|
|
|
USHORT align = type_alignments[desc.dsc_dtype];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (align)
|
|
|
|
offset = FB_ALIGN(offset, align);
|
2004-01-21 08:18:30 +01:00
|
|
|
desc.dsc_address = (UCHAR*)(IPTR) offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
offset += desc.dsc_length;
|
|
|
|
|
|
|
|
if (*blr++ != blr_short || *blr++ != 0)
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
align = type_alignments[dtype_short];
|
|
|
|
if (align)
|
|
|
|
offset = FB_ALIGN(offset, align);
|
2003-10-16 10:51:06 +02:00
|
|
|
USHORT null_offset = offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
offset += sizeof(SSHORT);
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
for (dsql_par* parameter = parameters; parameter; parameter = parameter->par_next)
|
2003-09-13 14:16:48 +02:00
|
|
|
{
|
|
|
|
if (parameter->par_index == index) {
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter->par_user_desc = desc;
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_par* null = parameter->par_null;
|
2003-10-16 10:51:06 +02:00
|
|
|
if (null) {
|
2001-05-23 15:26:42 +02:00
|
|
|
null->par_user_desc.dsc_dtype = dtype_short;
|
|
|
|
null->par_user_desc.dsc_scale = 0;
|
|
|
|
null->par_user_desc.dsc_length = sizeof(SSHORT);
|
2004-01-21 08:18:30 +01:00
|
|
|
null->par_user_desc.dsc_address = (UCHAR*)(IPTR) null_offset;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2003-09-13 14:16:48 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*blr++ != (UCHAR) blr_end || offset != msg_length)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_sqlda_err, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
prepare
|
|
|
|
|
|
|
|
@brief Prepare a statement for execution. Return SQL status
|
2003-11-01 11:26:43 +01:00
|
|
|
code. Note: caller is responsible for pool handling.
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param string_length
|
|
|
|
@param string
|
|
|
|
@param client_dialect
|
|
|
|
@param parser_version
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static dsql_req* prepare(
|
|
|
|
dsql_req* request,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT string_length,
|
2003-11-28 07:48:34 +01:00
|
|
|
const TEXT* string,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT client_dialect, USHORT parser_version)
|
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY local_status;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-04-10 08:32:58 +02:00
|
|
|
MOVE_CLEAR(local_status, sizeof(ISC_STATUS) * ISC_STATUS_LENGTH);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (client_dialect > SQL_DIALECT_CURRENT)
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 901,
|
|
|
|
isc_arg_gds, isc_wish_list, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!string_length)
|
|
|
|
string_length = strlen(string);
|
|
|
|
|
|
|
|
/* Get rid of the trailing ";" if there is one. */
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
for (const TEXT* p = string + string_length; p-- > string;)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*p != ' ') {
|
|
|
|
if (*p == ';')
|
|
|
|
string_length = p - string;
|
|
|
|
break;
|
|
|
|
}
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Allocate a storage pool and get ready to parse
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
LEX_string(string, string_length, request->req_dbb->dbb_att_charset);
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Parse the SQL statement. If it croaks, return
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
bool stmt_ambiguous = false;
|
2003-02-12 20:28:13 +01:00
|
|
|
if (dsql_yyparse(client_dialect,
|
|
|
|
request->req_dbb->dbb_db_SQL_dialect,
|
|
|
|
parser_version,
|
|
|
|
&stmt_ambiguous))
|
|
|
|
{
|
2003-11-28 07:48:34 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
|
|
|
|
isc_arg_gds, isc_command_end_err, // Unexpected end of command
|
2001-05-23 15:26:42 +02:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// allocate the send and receive messages
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
request->req_send = FB_NEW(*tdsql->getDefaultPool()) dsql_msg;
|
|
|
|
dsql_msg* message = FB_NEW(*tdsql->getDefaultPool()) dsql_msg;
|
2003-11-28 07:48:34 +01:00
|
|
|
request->req_receive = message;
|
2001-05-23 15:26:42 +02:00
|
|
|
message->msg_number = 1;
|
|
|
|
|
|
|
|
#ifdef SCROLLABLE_CURSORS
|
|
|
|
if (request->req_dbb->dbb_base_level >= 5) {
|
2001-07-10 19:35:13 +02:00
|
|
|
/* allocate a message in which to send scrolling information
|
2001-05-23 15:26:42 +02:00
|
|
|
outside of the normal send/receive protocol */
|
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
request->req_async = message = FB_NEW(*tdsql->getDefaultPool()) dsql_msg;
|
2001-05-23 15:26:42 +02:00
|
|
|
message->msg_number = 2;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
request->req_type = REQ_SELECT;
|
|
|
|
request->req_flags &= ~(REQ_cursor_open | REQ_embedded_sql_cursor);
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
* No work is done during pass1 for set transaction - like
|
|
|
|
* checking for valid table names. This is because that will
|
|
|
|
* require a valid transaction handle.
|
|
|
|
* Error will be caught at execute time.
|
|
|
|
*/
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
dsql_nod* node = PASS1_statement(request, DSQL_parse, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!node)
|
|
|
|
return request;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// stop here for requests not requiring code generation
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_type == REQ_DDL && stmt_ambiguous &&
|
|
|
|
request->req_dbb->dbb_db_SQL_dialect != client_dialect)
|
2003-02-12 20:28:13 +01:00
|
|
|
{
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 817,
|
|
|
|
isc_arg_gds, isc_ddl_not_allowed_by_db_sql_dial,
|
|
|
|
isc_arg_number,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SLONG) request->req_dbb->dbb_db_SQL_dialect, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_type == REQ_COMMIT ||
|
|
|
|
request->req_type == REQ_COMMIT_RETAIN ||
|
2003-02-12 20:28:13 +01:00
|
|
|
request->req_type == REQ_ROLLBACK)
|
|
|
|
{
|
|
|
|
return request;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Work on blob segment requests
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_type == REQ_GET_SEGMENT ||
|
2003-02-12 20:28:13 +01:00
|
|
|
request->req_type == REQ_PUT_SEGMENT)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
GEN_port(request, request->req_blob->blb_open_in_msg);
|
|
|
|
GEN_port(request, request->req_blob->blb_open_out_msg);
|
|
|
|
GEN_port(request, request->req_blob->blb_segment_msg);
|
|
|
|
return request;
|
|
|
|
}
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Generate BLR, DDL or TPB for request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-04-18 16:22:27 +02:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
|
|
|
|
|
|
|
//What's a reason not to bloat request_pool?
|
|
|
|
//It was made to keep data local for that request...
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (request->req_type == REQ_START_TRANS ||
|
|
|
|
request->req_type == REQ_DDL ||
|
2003-02-12 20:28:13 +01:00
|
|
|
request->req_type == REQ_EXEC_PROCEDURE)
|
|
|
|
{
|
2003-11-28 07:48:34 +01:00
|
|
|
// Allocate persistent blr string from request's pool.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-16 14:28:43 +02:00
|
|
|
request->req_blr_string = FB_NEW_RPT(*tdsql->getDefaultPool(), 980) dsql_str;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Allocate transient blr string from permanent pool so
|
|
|
|
as not to unnecessarily bloat the request's pool. */
|
|
|
|
|
2003-11-10 10:16:38 +01:00
|
|
|
request->req_blr_string = FB_NEW_RPT(*DSQL_permanent_pool, 980) dsql_str;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
request->req_blr_string->str_length = 980;
|
2003-02-12 20:28:13 +01:00
|
|
|
request->req_blr = reinterpret_cast<BLOB_PTR*>(request->req_blr_string->str_data);
|
2001-05-23 15:26:42 +02:00
|
|
|
request->req_blr_yellow =
|
|
|
|
request->req_blr + request->req_blr_string->str_length;
|
2004-04-18 16:22:27 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* Start transactions takes parameters via a parameter block.
|
2001-05-23 15:26:42 +02:00
|
|
|
The request blr string is used for that. */
|
|
|
|
|
|
|
|
if (request->req_type == REQ_START_TRANS) {
|
|
|
|
GEN_start_transaction(request, node);
|
|
|
|
return request;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (client_dialect > SQL_DIALECT_V5)
|
|
|
|
request->req_flags |= REQ_blr_version5;
|
|
|
|
else
|
|
|
|
request->req_flags |= REQ_blr_version4;
|
|
|
|
GEN_request(request, node);
|
2004-04-18 16:22:27 +02:00
|
|
|
const USHORT length = request->req_blr_data.getCount();
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// stop here for ddl requests
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_type == REQ_DDL)
|
|
|
|
return request;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// have the access method compile the request
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-28 23:36:05 +02:00
|
|
|
#ifdef DSQL_DEBUG
|
2003-02-15 03:05:10 +01:00
|
|
|
if (DSQL_debug & 64) {
|
2003-09-28 23:36:05 +02:00
|
|
|
dsql_trace("Resulting BLR code for DSQL:");
|
2004-04-18 16:22:27 +02:00
|
|
|
gds__print_blr(request->req_blr_data.begin(),
|
2003-09-28 23:36:05 +02:00
|
|
|
gds__trace_printer, 0, 0);
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// stop here for execute procedure requests
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
if (request->req_type == REQ_EXEC_PROCEDURE) {
|
2001-05-23 15:26:42 +02:00
|
|
|
return request;
|
2003-02-12 20:28:13 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// check for warnings
|
2001-05-23 15:26:42 +02:00
|
|
|
if (tdsql->tsql_status[2] == isc_arg_warning) {
|
2003-11-28 07:48:34 +01:00
|
|
|
// save a status vector
|
2001-05-23 15:26:42 +02:00
|
|
|
MOVE_FASTER(tdsql->tsql_status, local_status,
|
2003-04-10 08:32:58 +02:00
|
|
|
sizeof(ISC_STATUS) * ISC_STATUS_LENGTH);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-11-28 07:48:34 +01:00
|
|
|
const ISC_STATUS status = isc_compile_request(tdsql->tsql_status,
|
2003-08-30 03:54:25 +02:00
|
|
|
&request->req_dbb->dbb_database_handle,
|
|
|
|
&request->req_handle, length,
|
2004-04-18 16:22:27 +02:00
|
|
|
(const char*)(request->req_blr_data.begin()));
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
// restore warnings (if there are any)
|
2003-02-12 20:28:13 +01:00
|
|
|
if (local_status[2] == isc_arg_warning)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
int indx, len, warning;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// find end of a status vector
|
2001-05-23 15:26:42 +02:00
|
|
|
PARSE_STATUS(tdsql->tsql_status, indx, warning);
|
|
|
|
if (indx)
|
|
|
|
--indx;
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// calculate length of saved warnings
|
2001-05-23 15:26:42 +02:00
|
|
|
PARSE_STATUS(local_status, len, warning);
|
|
|
|
len -= 2;
|
|
|
|
|
|
|
|
if ((len + indx - 1) < ISC_STATUS_LENGTH)
|
|
|
|
MOVE_FASTER(&local_status[2], &tdsql->tsql_status[indx],
|
2003-04-10 08:32:58 +02:00
|
|
|
sizeof(ISC_STATUS) * len);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-04-21 16:23:46 +02:00
|
|
|
// free blr memory
|
|
|
|
request->req_blr_data.free();
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (status)
|
|
|
|
punt();
|
|
|
|
|
|
|
|
return request;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
punt
|
|
|
|
|
|
|
|
@brief Report a signification error.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static void punt(void)
|
|
|
|
{
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::status_exception::raise(tdsql->tsql_status);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
put_item
|
|
|
|
|
|
|
|
@brief Put information item in output buffer if there is room, and
|
|
|
|
return an updated pointer. If there isn't room for the item,
|
|
|
|
indicate truncation and return NULL.
|
|
|
|
|
|
|
|
|
|
|
|
@param item
|
|
|
|
@param length
|
|
|
|
@param string
|
|
|
|
@param ptr
|
|
|
|
@param end
|
|
|
|
|
|
|
|
**/
|
2002-12-16 16:38:26 +01:00
|
|
|
static UCHAR* put_item( UCHAR item,
|
2001-12-24 03:51:06 +01:00
|
|
|
USHORT length,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* string,
|
2002-12-16 16:38:26 +01:00
|
|
|
UCHAR* ptr,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* const end)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
if (ptr + length + 3 >= end) {
|
2003-11-08 00:27:24 +01:00
|
|
|
*ptr = isc_info_truncated;
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ptr++ = item;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
*ptr++ = (UCHAR)length;
|
|
|
|
*ptr++ = length >> 8;
|
|
|
|
|
|
|
|
if (length) {
|
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*ptr++ = *string++;
|
2001-12-24 03:51:06 +01:00
|
|
|
} while (--length);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
release_request
|
|
|
|
|
|
|
|
@brief Release a dynamic request.
|
|
|
|
|
|
|
|
|
|
|
|
@param request
|
|
|
|
@param top_level
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
static void release_request(dsql_req* request, bool top_level)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// If request is parent, orphan the children and
|
|
|
|
// release a portion of their requests
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
for (dsql_req* child = request->req_offspring; child; child = child->req_sibling) {
|
2001-05-23 15:26:42 +02:00
|
|
|
child->req_flags |= REQ_orphan;
|
|
|
|
child->req_parent = NULL;
|
2004-08-16 14:28:43 +02:00
|
|
|
DsqlMemoryPool *save_default = tdsql->getDefaultPool();
|
|
|
|
tdsql->setDefaultPool(&child->req_pool);
|
2003-09-04 23:26:15 +02:00
|
|
|
release_request(child, false);
|
2004-08-16 14:28:43 +02:00
|
|
|
tdsql->setDefaultPool(save_default);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// For top level requests that are linked to a parent, unlink it
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (top_level && request->req_parent)
|
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_req* parent = request->req_parent;
|
|
|
|
for (dsql_req** ptr = &parent->req_offspring;
|
2001-12-24 03:51:06 +01:00
|
|
|
*ptr;
|
|
|
|
ptr = &(*ptr)->req_sibling)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*ptr == request) {
|
|
|
|
*ptr = request->req_sibling;
|
|
|
|
break;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// If the request had an open cursor, close it
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (request->req_open_cursor) {
|
2001-05-23 15:26:42 +02:00
|
|
|
close_cursor(request);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// If request is named, clear it from the hash table
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_name) {
|
|
|
|
HSHD_remove(request->req_name);
|
|
|
|
request->req_name = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (request->req_cursor) {
|
|
|
|
HSHD_remove(request->req_cursor);
|
|
|
|
request->req_cursor = NULL;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
// If a request has been compiled, release it now
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (request->req_handle) {
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_EXIT();
|
2003-08-30 03:54:25 +02:00
|
|
|
isc_release_request(status_vector, &request->req_handle);
|
2004-05-15 02:58:46 +02:00
|
|
|
THREAD_ENTER();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-04-21 16:23:46 +02:00
|
|
|
// free blr memory
|
|
|
|
request->req_blr_data.free();
|
|
|
|
|
2003-11-28 07:48:34 +01:00
|
|
|
// Only release the entire request for top level requests
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (top_level)
|
2004-04-18 16:22:27 +02:00
|
|
|
DsqlMemoryPool::deletePool(&request->req_pool);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
return_success
|
|
|
|
|
|
|
|
@brief Set up status vector to reflect successful execution.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS return_success(void)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
tsql* tdsql = DSQL_get_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-16 10:51:06 +02:00
|
|
|
ISC_STATUS* p = tdsql->tsql_status;
|
2003-11-08 00:27:24 +01:00
|
|
|
*p++ = isc_arg_gds;
|
2002-11-14 09:33:08 +01:00
|
|
|
*p++ = FB_SUCCESS;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
// do not overwrite warnings
|
|
|
|
if (*p != isc_arg_warning) {
|
2003-11-08 00:27:24 +01:00
|
|
|
*p = isc_arg_end;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-22 16:23:10 +02:00
|
|
|
DSQL_restore_thread_data();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
var_info
|
|
|
|
|
|
|
|
@brief Provide information on an internal message.
|
|
|
|
|
|
|
|
|
|
|
|
@param message
|
|
|
|
@param items
|
|
|
|
@param end_describe
|
|
|
|
@param info
|
|
|
|
@param end
|
|
|
|
@param first_index
|
|
|
|
|
|
|
|
**/
|
2003-10-16 10:51:06 +02:00
|
|
|
static UCHAR* var_info(
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_msg* message,
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* items,
|
|
|
|
const UCHAR* const end_describe,
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR* info,
|
|
|
|
const UCHAR* const end,
|
|
|
|
USHORT first_index)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
UCHAR buf[128];
|
2001-05-23 15:26:42 +02:00
|
|
|
SLONG sql_type, sql_sub_type, sql_scale, sql_len;
|
|
|
|
|
|
|
|
if (!message || !message->msg_index)
|
|
|
|
return info;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
for (const dsql_par* param = message->msg_par_ordered; param;
|
2003-11-01 11:26:43 +01:00
|
|
|
param = param->par_ordered)
|
|
|
|
{
|
2003-10-16 10:51:06 +02:00
|
|
|
if (param->par_index && param->par_index >= first_index) {
|
|
|
|
sql_len = param->par_desc.dsc_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
sql_sub_type = 0;
|
|
|
|
sql_scale = 0;
|
2003-10-16 10:51:06 +02:00
|
|
|
switch (param->par_desc.dsc_dtype) {
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_real:
|
|
|
|
sql_type = SQL_FLOAT;
|
|
|
|
break;
|
|
|
|
case dtype_array:
|
|
|
|
sql_type = SQL_ARRAY;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_timestamp:
|
|
|
|
sql_type = SQL_TIMESTAMP;
|
|
|
|
break;
|
|
|
|
case dtype_sql_date:
|
|
|
|
sql_type = SQL_TYPE_DATE;
|
|
|
|
break;
|
|
|
|
case dtype_sql_time:
|
|
|
|
sql_type = SQL_TYPE_TIME;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_double:
|
|
|
|
sql_type = SQL_DOUBLE;
|
2003-10-16 10:51:06 +02:00
|
|
|
sql_scale = param->par_desc.dsc_scale;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_text:
|
|
|
|
sql_type = SQL_TEXT;
|
2003-10-16 10:51:06 +02:00
|
|
|
sql_sub_type = param->par_desc.dsc_sub_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_blob:
|
|
|
|
sql_type = SQL_BLOB;
|
2003-10-16 10:51:06 +02:00
|
|
|
sql_sub_type = param->par_desc.dsc_sub_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_varying:
|
|
|
|
sql_type = SQL_VARYING;
|
|
|
|
sql_len -= sizeof(USHORT);
|
2003-10-16 10:51:06 +02:00
|
|
|
sql_sub_type = param->par_desc.dsc_sub_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_short:
|
|
|
|
case dtype_long:
|
|
|
|
case dtype_int64:
|
2003-10-16 10:51:06 +02:00
|
|
|
if (param->par_desc.dsc_dtype == dtype_short)
|
2001-05-23 15:26:42 +02:00
|
|
|
sql_type = SQL_SHORT;
|
2003-10-16 10:51:06 +02:00
|
|
|
else if (param->par_desc.dsc_dtype == dtype_long)
|
2001-05-23 15:26:42 +02:00
|
|
|
sql_type = SQL_LONG;
|
|
|
|
else
|
|
|
|
sql_type = SQL_INT64;
|
2003-10-16 10:51:06 +02:00
|
|
|
sql_scale = param->par_desc.dsc_scale;
|
|
|
|
if (param->par_desc.dsc_sub_type)
|
|
|
|
sql_sub_type = param->par_desc.dsc_sub_type;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_quad:
|
|
|
|
sql_type = SQL_QUAD;
|
2003-10-16 10:51:06 +02:00
|
|
|
sql_scale = param->par_desc.dsc_scale;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-11-08 00:27:24 +01:00
|
|
|
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
|
|
|
|
isc_arg_gds, isc_dsql_datatype_err, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-10-16 10:51:06 +02:00
|
|
|
if (sql_type && (param->par_desc.dsc_flags & DSC_nullable))
|
2001-05-23 15:26:42 +02:00
|
|
|
sql_type++;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
for (const UCHAR* describe = items; describe < end_describe;) {
|
|
|
|
USHORT length;
|
|
|
|
const TEXT* name;
|
|
|
|
const UCHAR* buffer = buf;
|
|
|
|
UCHAR item = *describe++;
|
|
|
|
switch (item) {
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_sqlda_seq:
|
2003-11-01 11:26:43 +01:00
|
|
|
length = convert((SLONG) param->par_index, buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_message_seq:
|
2001-05-23 15:26:42 +02:00
|
|
|
length = 0;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_type:
|
2003-11-01 11:26:43 +01:00
|
|
|
length = convert((SLONG) sql_type, buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_sub_type:
|
2003-11-01 11:26:43 +01:00
|
|
|
length = convert((SLONG) sql_sub_type, buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_scale:
|
2003-11-01 11:26:43 +01:00
|
|
|
length = convert((SLONG) sql_scale, buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_length:
|
2003-11-01 11:26:43 +01:00
|
|
|
length = convert((SLONG) sql_len, buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_null_ind:
|
2003-11-01 11:26:43 +01:00
|
|
|
length = convert((SLONG) (sql_type & 1), buf);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_field:
|
2003-11-01 11:26:43 +01:00
|
|
|
if (name = param->par_name) {
|
|
|
|
length = strlen(name);
|
|
|
|
buffer = reinterpret_cast<const UCHAR*>(name);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_relation:
|
2003-11-01 11:26:43 +01:00
|
|
|
if (name = param->par_rel_name) {
|
|
|
|
length = strlen(name);
|
|
|
|
buffer = reinterpret_cast<const UCHAR*>(name);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_owner:
|
2003-11-01 11:26:43 +01:00
|
|
|
if (name = param->par_owner_name) {
|
|
|
|
length = strlen(name);
|
|
|
|
buffer = reinterpret_cast<const UCHAR*>(name);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:27:24 +01:00
|
|
|
case isc_info_sql_alias:
|
2003-11-01 11:26:43 +01:00
|
|
|
if (name = param->par_alias) {
|
|
|
|
length = strlen(name);
|
|
|
|
buffer = reinterpret_cast<const UCHAR*>(name);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-11-01 11:26:43 +01:00
|
|
|
buf[0] = item;
|
2003-11-08 00:27:24 +01:00
|
|
|
item = isc_info_error;
|
|
|
|
length = 1 + convert((SLONG) isc_infunk, buf + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(info = put_item(item, length, buffer, info, end)))
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info + 1 >= end) {
|
2003-11-08 00:27:24 +01:00
|
|
|
*info = isc_info_truncated;
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2003-11-08 00:27:24 +01:00
|
|
|
*info++ = isc_info_sql_describe_end;
|
2003-11-01 11:26:43 +01:00
|
|
|
} // if()
|
|
|
|
} // for()
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|