📄 dsql.c
字号:
/* * PROGRAM: Dynamic SQL runtime support * MODULE: dsql.c * 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.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. * * 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE" * conditionals, as the engine now fully supports * readonly databases. *//*$Id: dsql.c,v 1.1 2001/10/13 10:21:52 dimitr Exp $*//**************************************************************V4 Multi-threading changes.-- direct calls to gds__ () & isc_ () entrypoints THREAD_EXIT; gds__ () or isc_ () call. THREAD_ENTER;-- calls through embedded GDML.the following protocol will be used. Care should be taken ifnested FOR loops are added. THREAD_EXIT; // last statment before FOR loop FOR ............... THREAD_ENTER; // First statment in FOR loop .....some C code.... .....some C code.... THREAD_EXIT; // last statment in FOR loop END_FOR; THREAD_ENTER; // First statment after FOR loop***************************************************************/#define DSQL_MAIN#include "../jrd/ib_stdio.h"#include <stdlib.h>#include <string.h>#include "../dsql/dsql.h"#include "../dsql/node.h"#include "../dsql/sym.h"#include "../jrd/gds.h"#include "../jrd/thd.h"#include "../jrd/align.h"#include "../jrd/intl.h"#include "../jrd/iberr.h"#include "../dsql/sqlda.h"#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"#include "../jrd/thd_proto.h"#include "../jrd/why_proto.h"ASSERT_FILENAME#ifdef VMS#include <descrip.h>#endif#ifdef NETWARE_386#define PRINTF ConsolePrintf#endif#ifndef PRINTF#define PRINTF ib_printf#endif#define ERROR_INIT(env) {\ tdsql->tsql_status = user_status;\ tdsql->tsql_setjmp = (UCHAR*) env;\ tdsql->tsql_default = NULL;\ if (SETJMP (env))\ {\ RESTORE_THREAD_DATA;\ return tdsql->tsql_status [1];\ };\ }#define RETURN_SUCCESS return return_success()#define SET_THREAD_DATA {\ tdsql = &thd_context;\ THD_put_specific ((THDD) tdsql);\ tdsql->tsql_thd_data.thdd_type = THDD_TYPE_TSQL;\ }#define RESTORE_THREAD_DATA THD_restore_specific()#ifdef STACK_REDUCTION#define FREE_MEM_RETURN {\ if (buffer)\ {\ gds__free ((SLONG *)buffer);\ buffer = (TEXT*) NULL;\ }\ return;\ }#else#define FREE_MEM_RETURN return#endifSTATUS DLL_EXPORT callback_execute_immediate (STATUS *, int *, int *, UCHAR *, int);static void cleanup (void *);static void cleanup_database (SLONG **, SLONG);static void cleanup_transaction (SLONG *, SLONG);static void close_cursor (REQ);static USHORT convert (SLONG, SCHAR *);static STATUS error (void);static void execute_blob (REQ, int **, USHORT, UCHAR *, USHORT, UCHAR *, USHORT, UCHAR *, USHORT, UCHAR *);static STATUS execute_request (REQ, int **, USHORT, UCHAR *, USHORT, UCHAR *, USHORT, UCHAR *, USHORT, UCHAR *, USHORT);static SSHORT filter_sub_type (REQ, NOD);static BOOLEAN get_indices (SSHORT *, SCHAR **, SSHORT *, SCHAR **);static USHORT get_plan_info (REQ, SSHORT, SCHAR **);static USHORT get_request_info (REQ, SSHORT, SCHAR *);static BOOLEAN get_rsb_item (SSHORT *, SCHAR **, SSHORT *, SCHAR **, USHORT *, USHORT *);static DBB init (SLONG **);static void map_in_out (REQ, MSG, USHORT, UCHAR *, USHORT, UCHAR *);static USHORT name_length (TEXT *);static USHORT parse_blr (USHORT, UCHAR *, USHORT, PAR);static REQ prepare (REQ, USHORT, TEXT *, USHORT, USHORT);static void punt (void);static SCHAR *put_item (SCHAR, USHORT, SCHAR *, SCHAR *, SCHAR *);static void release_request (REQ, USHORT);static STATUS return_success (void);static SCHAR *var_info (MSG, SCHAR *, SCHAR *, SCHAR *, SCHAR *, USHORT);extern NOD DSQL_parse;static USHORT init_flag;static DBB databases;static OPN open_cursors;static CONST SCHAR db_hdr_info_items [] = { isc_info_db_sql_dialect, gds__info_ods_version, gds__info_base_level, isc_info_db_read_only, frb_info_att_charset, gds__info_end };static CONST SCHAR explain_info [] = { gds__info_access_path };static CONST SCHAR record_info [] = { gds__info_req_update_count, gds__info_req_delete_count, gds__info_req_select_count, gds__info_req_insert_count };static CONST SCHAR sql_records_info [] = { gds__info_sql_records };#ifdef ANY_THREADINGstatic MUTX_T databases_mutex;static MUTX_T cursors_mutex;static USHORT mutex_inited = 0;#endif/* STUFF_INFO used in place of STUFF to avoid confusion with BLR STUFF macro defined in dsql.h */#define STUFF_INFO_WORD(p,value) {*p++ = value; *p++ = value >> 8;}#define STUFF_INFO(p,value) *p++ = value;#define GDS_DSQL_ALLOCATE dsql8_allocate_statement#define GDS_DSQL_EXECUTE dsql8_execute#define GDS_DSQL_EXECUTE_IMMED dsql8_execute_immediate#define GDS_DSQL_FETCH dsql8_fetch#define GDS_DSQL_FREE dsql8_free_statement#define GDS_DSQL_INSERT dsql8_insert#define GDS_DSQL_PREPARE dsql8_prepare#define GDS_DSQL_SET_CURSOR dsql8_set_cursor#define GDS_DSQL_SQL_INFO dsql8_sql_infoSTATUS DLL_EXPORT callback_execute_immediate ( STATUS *status, int *jrd_attachment_handle, int *jrd_transaction_handle, UCHAR *sql_operator, int len){/************************************** * * Functional description * Execute sql_operator in context of jrd_transaction_handle * **************************************/STATUS s;typedef struct hndl { UCHAR type; UCHAR flags; USHORT implementation; int *handle; struct hndl *parent; struct hndl *next; struct hndl *requests; struct hndl *statements; struct hndl *blobs; struct hndl **user_handle; struct clean *cleanup; TEXT *db_path;} *WHY; /* exact copy of `struct hndl' from why.c */WHY why_db_handle = NULL;WHY why_trans_handle = NULL;DBB database;/* 1. Locate why_db_handle, corresponding to jrd_database_handle */THD_MUTEX_LOCK (&databases_mutex);for (database = databases; database; database = database->dbb_next) if (((WHY)(database->dbb_database_handle))->handle == jrd_attachment_handle) break;if (! database) { status[0] = gds_arg_gds; status[1] = gds__bad_db_handle; status[2] = gds_arg_end; THD_MUTEX_UNLOCK (&databases_mutex); return status[1]; }why_db_handle = (WHY)(database->dbb_database_handle);/* 2. Create why_trans_handle - it's new, but points to the same jrd transaction as original before callback. */why_trans_handle = (WHY) gds__alloc ((SLONG) sizeof (struct hndl));if (! why_trans_handle) { status[0] = gds_arg_gds; status[1] = gds__virmemexh; status[2] = gds_arg_end; THD_MUTEX_UNLOCK (&databases_mutex); return status[1]; }memset (why_trans_handle, 0, sizeof (struct hndl));why_trans_handle->implementation = why_db_handle->implementation;why_trans_handle->handle = jrd_transaction_handle;#define HANDLE_transaction 2 /* exact copy of `HANDLE_transaction' from why.c */why_trans_handle->type = HANDLE_transaction;#undef HANDLE_transactionwhy_trans_handle->parent = why_db_handle;THD_MUTEX_UNLOCK (&databases_mutex);/* 3. Call isc... function */THREAD_EXIT;s = isc_dsql_execute_immediate ( status, &why_db_handle, &why_trans_handle, len, sql_operator, database->dbb_db_SQL_dialect, NULL);THREAD_ENTER;gds__free(why_trans_handle);return s;}STATUS DLL_EXPORT GDS_DSQL_ALLOCATE ( STATUS *user_status, int **db_handle, REQ *req_handle){/************************************** * * d s q l _ a l l o c a t e _ s t a t e m e n t * ************************************** * * Functional description * Allocate a statement handle. * **************************************/DBB database;REQ request;struct tsql thd_context, *tdsql;JMP_BUF env;SET_THREAD_DATA;ERROR_INIT (env);init (NULL_PTR);/* If we haven't been initialized yet, do it now */database = init ((SLONG **) db_handle);tdsql->tsql_default = ALLD_pool();/* allocate the request block */request = (REQ) ALLOCD (type_req);request->req_dbb = database;request->req_pool = tdsql->tsql_default;*req_handle = request;RETURN_SUCCESS;}STATUS DLL_EXPORT GDS_DSQL_EXECUTE ( STATUS *user_status, isc_tr_handle *trans_handle, REQ *req_handle, USHORT in_blr_length, UCHAR *in_blr, 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){/************************************** * * d s q l _ e x e c u t e * ************************************** * * Functional description * Execute a non-SELECT dynamic SQL statement. * **************************************/REQ request;OPN open_cursor;STATUS local_status [ISC_STATUS_LENGTH];struct tsql thd_context, *tdsql;JMP_BUF env;USHORT singleton;STATUS sing_status;SET_THREAD_DATA;ERROR_INIT (env);init (NULL_PTR);sing_status = 0;request = *req_handle;tdsql->tsql_default = request->req_pool;if ((SSHORT) in_msg_type == -1) request->req_type = REQ_EMBED_SELECT;/* Only allow NULL trans_handle if we're starting a transaction */if (*trans_handle == NULL && request->req_type != REQ_START_TRANS) ERRD_post (gds__sqlerr, gds_arg_number, (SLONG) -901, gds_arg_gds, gds__bad_trans_handle, 0);/* If the request is a SELECT or blob statement then this is an open./* If the request is a SELECT or blob statement then this is an open. Make sure the cursor is not already open. */if (request->req_type == REQ_SELECT || request->req_type == REQ_SELECT_UPD || request->req_type == REQ_EMBED_SELECT || request->req_type == REQ_GET_SEGMENT || request->req_type == REQ_PUT_SEGMENT) if (request->req_flags & REQ_cursor_open) { ERRD_post (gds__sqlerr, gds_arg_number, (SLONG) -502, gds_arg_gds, gds__dsql_cursor_open_err, 0); }/* A select with a non zero output length is a singleton select */if (request->req_type == REQ_SELECT && out_msg_length != 0) singleton = TRUE;else singleton = FALSE;if (request->req_type != REQ_EMBED_SELECT) 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);/* If the output message length is zero on a REQ_SELECT then we must * be doing an OPEN cursor operation. * If we do have an output message length, then we're doing * a singleton SELECT. In that event, we don't add the cursor * to the list of open cursors (it's not really open). */if ((request->req_type == REQ_SELECT && out_msg_length == 0) || request->req_type == REQ_SELECT_UPD || request->req_type == REQ_EMBED_SELECT || request->req_type == REQ_GET_SEGMENT || request->req_type == REQ_PUT_SEGMENT) { request->req_flags |= REQ_cursor_open | ((request->req_type == REQ_EMBED_SELECT) ? REQ_embedded_sql_cursor : 0); request->req_open_cursor = open_cursor = (OPN) ALLOCP (type_opn); open_cursor->opn_request = request; open_cursor->opn_transaction = (SLONG*) *trans_handle; THD_MUTEX_LOCK (&cursors_mutex); open_cursor->opn_next = open_cursors; open_cursors = open_cursor; THD_MUTEX_UNLOCK (&cursors_mutex); THREAD_EXIT; gds__transaction_cleanup (local_status, trans_handle, (isc_callback) cleanup_transaction, 0); THREAD_ENTER; }if (!sing_status) RETURN_SUCCESS;else { RESTORE_THREAD_DATA; return sing_status; }}STATUS DLL_EXPORT GDS_DSQL_EXECUTE_IMMED ( STATUS *user_status, int **db_handle, int **trans_handle, USHORT length, TEXT *string, USHORT dialect, USHORT in_blr_length, UCHAR *in_blr, 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){/************************************** * * 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. * **************************************/REQ request;DBB database;USHORT parser_version;STATUS status;struct tsql thd_context, *tdsql;JMP_BUF env;SET_THREAD_DATA;ERROR_INIT (env);database = init (db_handle);tdsql->tsql_default = ALLD_pool();/* allocate the request block, then prepare the request */request = (REQ) ALLOCD (type_req);request->req_dbb = database;request->req_pool = tdsql->tsql_default;request->req_trans = (int *) *trans_handle;if (SETJMP (tdsql->tsql_setjmp)) { status = error(); release_request (request, TRUE); RESTORE_THREAD_DATA; return status; }if (!length) length = strlen (string);/* Figure out which parser version to use *//* Since the API to GDS_DSQL_EXECUTE_IMMED is public and can not be changed, there needs to * 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -