From: <ale...@us...> - 2014-01-15 13:02:14
|
Revision: 59039 http://sourceforge.net/p/firebird/code/59039 Author: alexpeshkoff Date: 2014-01-15 13:02:08 +0000 (Wed, 15 Jan 2014) Log Message: ----------- Implemented CORE-4317: Make ISQL use new object API with 32-bit length for object sizes (messages, SQL statements, etc.) Implementation also includes changes in GPRE, but this utility is not complete - only commands, used in ISQL, are working in code generator for new API. New interface IUtl is added - it performs tasks, related with database objects (attachment, transaction, etc.), but not requiring routing in YValve, i.e. client only tasks. Modified Paths: -------------- firebird/trunk/builds/posix/make.rules firebird/trunk/builds/posix/prefix.linux_amd64 firebird/trunk/src/auth/SecureRemotePassword/Message.h firebird/trunk/src/common/MsgMetadata.cpp firebird/trunk/src/common/MsgMetadata.h firebird/trunk/src/common/classes/ImplementHelper.h firebird/trunk/src/common/classes/TempFile.cpp firebird/trunk/src/common/classes/TempFile.h firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp firebird/trunk/src/gpre/gpre.cpp firebird/trunk/src/gpre/gpreswi.h firebird/trunk/src/gpre/lang_proto.h firebird/trunk/src/include/firebird/Interface.h firebird/trunk/src/include/firebird/Provider.h firebird/trunk/src/isql/extract.epp firebird/trunk/src/isql/isql.epp firebird/trunk/src/isql/isql.h firebird/trunk/src/isql/isql_proto.h firebird/trunk/src/isql/show.epp firebird/trunk/src/isql/show_proto.h firebird/trunk/src/msgs/facilities2.sql firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/remote/client/BlrFromMessage.cpp firebird/trunk/src/yvalve/MasterImplementation.cpp firebird/trunk/src/yvalve/MasterImplementation.h firebird/trunk/src/yvalve/perf.cpp firebird/trunk/src/yvalve/prepa_proto.h firebird/trunk/src/yvalve/preparse.cpp firebird/trunk/src/yvalve/utl.cpp firebird/trunk/src/yvalve/utl_proto.h firebird/trunk/src/yvalve/why.cpp firebird/trunk/src/yvalve/why_proto.h Added Paths: ----------- firebird/trunk/src/gpre/obj_cxx.cpp firebird/trunk/src/include/firebird/Utl.h Modified: firebird/trunk/builds/posix/make.rules =================================================================== --- firebird/trunk/builds/posix/make.rules 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/builds/posix/make.rules 2014-01-15 13:02:08 UTC (rev 59039) @@ -62,7 +62,7 @@ GPRE_FLAGS= -m -z -n JRD_GPRE_FLAGS = -n -z -gds_cxx -ids -DSQL_GPRE_FLAGS = -m -z -n +ISQL_GPRE_FLAGS = -m -z -n -ocxx .SUFFIXES: .c .e .epp .cpp @@ -74,12 +74,9 @@ $(OBJ)/jrd/%.cpp: $(SRC_ROOT)/jrd/%.epp $(GPRE_CURRENT) $(JRD_GPRE_FLAGS) $(firstword $<) $@ -$(OBJ)/dsql/%.cpp: $(SRC_ROOT)/dsql/%.epp - $(GPRE_CURRENT) $(DSQL_GPRE_FLAGS) $< $@ +$(OBJ)/isql/%.cpp: $(SRC_ROOT)/isql/%.epp + $(GPRE_CURRENT) $(ISQL_GPRE_FLAGS) $< $@ -$(OBJ)/yvalve/%.cpp: $(SRC_ROOT)/yvalve/%.epp - $(GPRE_CURRENT) $(DSQL_GPRE_FLAGS) $< $@ - $(OBJ)/%.cpp: $(SRC_ROOT)/%.epp $(GPRE_CURRENT) $(GPRE_FLAGS) $(firstword $<) $@ Modified: firebird/trunk/builds/posix/prefix.linux_amd64 =================================================================== --- firebird/trunk/builds/posix/prefix.linux_amd64 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/builds/posix/prefix.linux_amd64 2014-01-15 13:02:08 UTC (rev 59039) @@ -24,4 +24,4 @@ PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS) #DEV_FLAGS=-DUSE_VALGRIND $(COMMON_FLAGS) $(WARN_FLAGS) -DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS) +DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS) -fmax-errors=8 Modified: firebird/trunk/src/auth/SecureRemotePassword/Message.h =================================================================== --- firebird/trunk/src/auth/SecureRemotePassword/Message.h 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/auth/SecureRemotePassword/Message.h 2014-01-15 13:02:08 UTC (rev 59039) @@ -92,6 +92,7 @@ }; +// With template magic, we make the fields strongly-typed. template <> bool Message::checkType<SLONG>(unsigned t, unsigned sz) { @@ -105,13 +106,18 @@ } template <> +bool Message::checkType<ISC_INT64>(unsigned t, unsigned sz) +{ + return t == SQL_INT64 && sz == sizeof(ISC_INT64); +} + +template <> bool Message::checkType<FB_BOOLEAN>(unsigned t, unsigned sz) { return t == SQL_BOOLEAN && sz == sizeof(FB_BOOLEAN); } -// With template magic, we make the fields strongly-typed. template <typename T> class Field { Modified: firebird/trunk/src/common/MsgMetadata.cpp =================================================================== --- firebird/trunk/src/common/MsgMetadata.cpp 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/common/MsgMetadata.cpp 2014-01-15 13:02:08 UTC (rev 59039) @@ -81,7 +81,7 @@ } } - virtual void FB_CARG setSubType(IStatus* status, unsigned index, unsigned subType) + virtual void FB_CARG setSubType(IStatus* status, unsigned index, int subType) { try { @@ -162,6 +162,22 @@ } } + virtual void FB_CARG remove(IStatus* status, unsigned index) + { + try + { + MutexLockGuard g(mtx, FB_FUNCTION); + + indexError(index, "remove"); + + msgMetadata->items.remove(index); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + } + virtual void FB_CARG moveNameToIndex(IStatus* status, const char* name, unsigned index) { try Modified: firebird/trunk/src/common/MsgMetadata.h =================================================================== --- firebird/trunk/src/common/MsgMetadata.h 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/common/MsgMetadata.h 2014-01-15 13:02:08 UTC (rev 59039) @@ -79,7 +79,7 @@ string owner; string alias; unsigned type; - unsigned subType; + int subType; unsigned length; int scale; unsigned charSet; @@ -164,7 +164,7 @@ return false; } - virtual unsigned FB_CARG getSubType(IStatus* status, unsigned index) const + virtual int FB_CARG getSubType(IStatus* status, unsigned index) const { if (index < items.getCount()) return items[index].subType; Modified: firebird/trunk/src/common/classes/ImplementHelper.h =================================================================== --- firebird/trunk/src/common/classes/ImplementHelper.h 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/common/classes/ImplementHelper.h 2014-01-15 13:02:08 UTC (rev 59039) @@ -250,6 +250,16 @@ }; +// Misc utl access +class UtlInterfacePtr : public AccessAutoInterface<IUtl> +{ +public: + UtlInterfacePtr() + : AccessAutoInterface<IUtl>(getMasterInterface()->getUtlInterface()) + { } +}; + + // When process exits, dynamically loaded modules (for us plugin modules) // are unloaded first. As the result all global variables in plugin are already destroyed // when yvalve is starting fb_shutdown(). This causes almost unavoidable segfault. Modified: firebird/trunk/src/common/classes/TempFile.cpp =================================================================== --- firebird/trunk/src/common/classes/TempFile.cpp 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/common/classes/TempFile.cpp 2014-01-15 13:02:08 UTC (rev 59039) @@ -70,7 +70,7 @@ // we need a class here only to return memory on shutdown and avoid // false memory leak reports -static Firebird::InitInstance<ZeroBuffer> zeros; +static InitInstance<ZeroBuffer> zeros; // // TempFile::getTempPath @@ -127,6 +127,32 @@ } // +// TempFile::create +// +// Creates a temporary file and returns its name +// In error case store exception in status arg +// + +PathName TempFile::create(IStatus* status, const PathName& prefix, const PathName& directory) +{ + PathName filename; + + try { + TempFile file(*getDefaultMemoryPool(), prefix, directory, false); + filename = file.getName(); + } + catch (const Exception& ex) + { + if (status) + { + ex.stuffException(status); + } + } + + return filename; +} + +// // TempFile::init // // Creates temporary file with a unique filename Modified: firebird/trunk/src/common/classes/TempFile.h =================================================================== --- firebird/trunk/src/common/classes/TempFile.h 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/common/classes/TempFile.h 2014-01-15 13:02:08 UTC (rev 59039) @@ -29,6 +29,8 @@ namespace Firebird { +class IStatus; + class TempFile : public File { public: @@ -66,6 +68,7 @@ static PathName getTempPath(); static PathName create(const PathName& prefix, const PathName& directory = ""); + static PathName create(IStatus* status, const PathName& prefix, const PathName& directory = ""); private: void init(const PathName&, const PathName&); Modified: firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp =================================================================== --- firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp 2014-01-15 13:02:08 UTC (rev 59039) @@ -765,6 +765,12 @@ { return -1; } + + virtual IUtl* FB_CARG getUtlInterface() + { + fb_assert(false); + return NULL; + } }; Modified: firebird/trunk/src/gpre/gpre.cpp =================================================================== --- firebird/trunk/src/gpre/gpre.cpp 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/gpre/gpre.cpp 2014-01-15 13:02:08 UTC (rev 59039) @@ -468,6 +468,18 @@ gpreGlob.database_name = "gds_database"; break; + case IN_SW_GPRE_OCXX: + gen_routine = OBJ_CXX_action; + gpreGlob.sw_language = lang_cxx; + gpreGlob.ident_pattern = "fb_%d"; + gpreGlob.long_ident_pattern = "fb_%ld"; + gpreGlob.utility_name = "fbUtility"; + gpreGlob.count_name = "fbCount"; + gpreGlob.slack_name = "fbSlack"; + gpreGlob.transaction_name = "fbTrans"; + gpreGlob.database_name = "fbDatabase"; + break; + case IN_SW_GPRE_D: // allocate database block and link to db chain Modified: firebird/trunk/src/gpre/gpreswi.h =================================================================== --- firebird/trunk/src/gpre/gpreswi.h 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/gpre/gpreswi.h 2014-01-15 13:02:08 UTC (rev 59039) @@ -74,6 +74,7 @@ IN_SW_GPRE_D_FLOAT, // use blr_d_float for doubles IN_SW_GPRE_CXX, // source is C++ IN_SW_GPRE_SCXX, // source is C++ with Saber extension + IN_SW_GPRE_OCXX, // c++ with object API IN_SW_GPRE_SQLDA, // use old or new SQLDA IN_SW_GPRE_USER, // default username to use when attaching database IN_SW_GPRE_PASSWORD, // default password to use in attaching database @@ -167,6 +168,7 @@ {IN_SW_GPRE_M , 0, "MANUAL" , 0, 0, 0, false, 0, 0, "\t\tdo not automatically ATTACH to a database"}, {IN_SW_GPRE_N , 0, "NO_LINES" , 0, 0, 0, false, 0, 0, "\tdo not generate C debug lines"}, {IN_SW_GPRE_O , 0, "OUTPUT" , 0, 0, 0, false, 0, 0, "\t\tsend output to standard out"}, + {IN_SW_GPRE_OCXX , 0, "OCXX" , 0, 0, 0, false, 0, 0, "\t\textended C++ program with objects API"}, #ifdef GPRE_PASCAL {IN_SW_GPRE_P , 0, "PASCAL" , 0, 0, 0, false, 0, 0, "\t\textended PASCAL program"}, #endif Modified: firebird/trunk/src/gpre/lang_proto.h =================================================================== --- firebird/trunk/src/gpre/lang_proto.h 2014-01-15 00:31:23 UTC (rev 59038) +++ firebird/trunk/src/gpre/lang_proto.h 2014-01-15 13:02:08 UTC (rev 59039) @@ -38,6 +38,7 @@ void FTN_print_buffer(TEXT*); void INT_action(const act*, int); void INT_CXX_action(const act*, int); +void OBJ_CXX_action(const act*, int); void PAS_action(const act*, int); //int PLI_action(ACT, int); void RMC_action(const act*, int); Added: firebird/trunk/src/gpre/obj_cxx.cpp =================================================================== --- firebird/trunk/src/gpre/obj_cxx.cpp (rev 0) +++ firebird/trunk/src/gpre/obj_cxx.cpp 2014-01-15 13:02:08 UTC (rev 59039) @@ -0,0 +1,3975 @@ +//____________________________________________________________ +// +// PROGRAM: C preprocess +// MODULE: c_cxx.cpp +// DESCRIPTION: C and C++ code generator +// +// 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): ______________________________________.16/09/2003 +// TMN (Mike Nordell) 11.APR.2001 - Reduce compiler warnings +// +// 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port +// +// +//____________________________________________________________ +// +// + +#include "firebird.h" +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include "../jrd/ibase.h" +#include "../gpre/gpre.h" +#include "../gpre/pat.h" +#include "../gpre/msc_proto.h" +#include "../gpre/cmp_proto.h" +#include "../gpre/gpre_proto.h" +#include "../gpre/lang_proto.h" +#include "../gpre/pat_proto.h" +#include "../common/prett_proto.h" +#include "../yvalve/gds_proto.h" +#include "../common/utils_proto.h" + + +static void align(int); +static void asgn_from(const act*, ref*, int); +static void asgn_to(const act*, ref*, int); +static void asgn_to_proc(const ref*, int); +static void gen_any(const act*, int); +static void gen_at_end(const act*, int); +static void gen_based(const act*, int); +static void gen_blob_close(const act*, USHORT); +static void gen_blob_end(const act*, USHORT); +static void gen_blob_for(const act*, USHORT); +static void gen_blob_open(const act*, USHORT); +static void gen_blr(void*, SSHORT, const char*); +static void gen_clear_handles(int); +//static void gen_compatibility_symbol(const TEXT*, const TEXT*, const TEXT*); +static void gen_compile(const act*, int); +static void gen_create_database(const act*, int); +static int gen_cursor_close(const act*, const gpre_req*, int); +static void gen_cursor_init(const act*, int); +static int gen_cursor_open(const act*, const gpre_req*, int); +static void gen_database(int); +static void gen_ddl(const act*, int); +static void gen_drop_database(const act*, int); +static void gen_dyn_close(const act*, int); +static void gen_dyn_declare(const act*, int); +static void gen_dyn_describe(const act*, int, bool); +static void gen_dyn_execute(const act*, int); +static void gen_dyn_fetch(const act*, int); +static void gen_dyn_immediate(const act*, int); +static void gen_dyn_insert(const act*, int); +static void gen_dyn_open(const act*, int); +static void gen_dyn_prepare(const act*, int); +static void gen_emodify(const act*, int); +static void gen_estore(const act*, int); +static void gen_endfor(const act*, int); +static void gen_erase(const act*, int); +static SSHORT gen_event_block(act*); +static void gen_event_init(const act*, int); +static void gen_event_wait(const act*, int); +static void gen_fetch(const act*, int); +static void gen_finish(const act*, int); +static void gen_for(const act*, int); +static void gen_function(const act*, int); +static void gen_get_or_put_slice(const act*, const ref*, bool, int); +static void gen_get_segment(const act*, int); +static void gen_loop(const act*, int); +static TEXT* gen_name(char* const, const ref*, bool); +static void gen_on_error(const act*, USHORT); +static void gen_procedure(const act*, int); +static void gen_put_segment(const act*, int); +static void gen_raw(const UCHAR*, int); +static void gen_ready(const act*, int); +static void gen_receive(const act*, int, const gpre_port*); +static void gen_release(const act*, int); +static void gen_request(const gpre_req*); +static void gen_return_value(const act*, int); +static void gen_routine(const act*, int); +static void gen_s_end(const act*, int); +static void gen_s_fetch(const act*, int); +static void gen_s_start(const act*, int); +static void gen_segment(const act*, int); +static void gen_select(const act*, int); +static void gen_send(const act*, const gpre_port*, int); +static void gen_slice(const act*, const ref*, int); +static void gen_start(const act*, const gpre_port*, int, bool); +static void gen_store(const act*, int); +static void gen_t_start(const act*, int); +static void gen_tpb(const tpb*, int); +static void gen_trans(const act*, int); +static void gen_type(const act*, int); +static void gen_update(const act*, int); +static void gen_variable(const act*, int); +static void gen_whenever(const swe*, int); +static void make_array_declaration(ref*); +static TEXT* make_name(TEXT* const, const gpre_sym*); +static void make_ok_test(const act*, const gpre_req*, int); +static void make_port(const gpre_port*, int); +static void make_ready(const gpre_dbb*, const TEXT*, const TEXT*, USHORT, const gpre_req*); +static void printa(int, const char*, ...) ATTRIBUTE_FORMAT(2,3); +static void printb(const TEXT*, ...) ATTRIBUTE_FORMAT(1,2); +static const TEXT* request_trans(const act*, const gpre_req*); +static const TEXT* status_vector(const act*); +static void t_start_auto(const act*, const gpre_req*, const TEXT*, int, bool); + +static bool global_first_flag = false; +static const TEXT* global_status_name = 0; + +const int INDENT = 3; + +static const char* const NULL_STRING = "NULL"; +static const char* const NULL_STATUS = "NULL"; +static const char* const NULL_SQLDA = "NULL"; + +#ifdef DARWIN +static const char* const GDS_INCLUDE = "<Firebird/ibase.h>"; +#else +static const char* const GDS_INCLUDE = "<ibase.h>"; +#endif + +static const char* const DCL_LONG = "ISC_LONG"; +static const char* const DCL_QUAD = "ISC_QUAD"; + +static inline void begin(const int column) +{ + printa(column, "{"); +} + +static inline void endp(const int column) +{ + printa(column, "}"); +} + +static inline void set_sqlcode(const act* action, const int column) +{ + if (action->act_flags & ACT_sql) + printa(column, "SQLCODE = isc_sqlcode(%s->get());", global_status_name); +} + +static inline void ObjectNotImplemented() +{ + CPR_error("Feature is not implemented for object API"); + throw Firebird::LongJump(); +} + +//____________________________________________________________ +// +// + +void OBJ_CXX_action(const act* action, int column) +{ + + global_status_name = "fbStatus"; + + // Put leading braces where required + + switch (action->act_type) + { + case ACT_alter_database: + case ACT_alter_domain: + case ACT_alter_index: + case ACT_alter_table: + case ACT_blob_close: + case ACT_blob_create: + case ACT_blob_for: + case ACT_blob_open: + case ACT_clear_handles: + case ACT_close: + case ACT_commit: + case ACT_commit_retain_context: + case ACT_create_database: + case ACT_create_domain: + case ACT_create_generator: + case ACT_create_index: + case ACT_create_shadow: + case ACT_create_table: + case ACT_create_view: + case ACT_declare_filter: + case ACT_declare_udf: + case ACT_disconnect: + case ACT_drop_database: + case ACT_drop_domain: + case ACT_drop_filter: + case ACT_drop_index: + case ACT_drop_shadow: + case ACT_drop_table: + case ACT_drop_udf: + case ACT_drop_view: + case ACT_dyn_close: + case ACT_dyn_cursor: + case ACT_dyn_describe: + case ACT_dyn_describe_input: + case ACT_dyn_execute: + case ACT_dyn_fetch: + case ACT_dyn_grant: + case ACT_dyn_immediate: + case ACT_dyn_insert: + case ACT_dyn_open: + case ACT_dyn_prepare: + case ACT_dyn_revoke: + case ACT_fetch: + case ACT_finish: + case ACT_for: + case ACT_get_segment: + case ACT_get_slice: + case ACT_insert: + case ACT_loop: + case ACT_modify: + case ACT_open: + case ACT_prepare: + case ACT_procedure: + case ACT_put_slice: + case ACT_ready: + case ACT_release: + case ACT_rfinish: + case ACT_rollback: + case ACT_rollback_retain_context: + case ACT_s_fetch: + case ACT_s_start: + case ACT_select: + case ACT_store: + case ACT_start: + case ACT_update: + case ACT_statistics: + begin(column); + } + + switch (action->act_type) + { + case ACT_alter_database: + case ACT_alter_domain: + case ACT_alter_index: + case ACT_alter_table: + gen_ddl(action, column); + break; + case ACT_any: + gen_any(action, column); + return; + case ACT_at_end: + gen_at_end(action, column); + return; + case ACT_b_declare: + gen_database(column); + gen_routine(action, column); + return; + case ACT_basedon: + gen_based(action, column); + return; + case ACT_blob_cancel: + gen_blob_close(action, (USHORT) column); + return; + case ACT_blob_close: + gen_blob_close(action, (USHORT) column); + break; + case ACT_blob_create: + gen_blob_open(action, (USHORT) column); + break; + case ACT_blob_for: + gen_blob_for(action, (USHORT) column); + return; + case ACT_blob_handle: + gen_segment(action, column); + return; + case ACT_blob_open: + gen_blob_open(action, (USHORT) column); + break; + case ACT_clear_handles: + gen_clear_handles(column); + break; + case ACT_close: + gen_s_end(action, column); + break; + case ACT_commit: + gen_trans(action, column); + break; + case ACT_commit_retain_context: + gen_trans(action, column); + break; + case ACT_create_database: + gen_create_database(action, column); + break; + case ACT_create_domain: + case ACT_create_generator: + case ACT_create_index: + case ACT_create_shadow: + case ACT_create_table: + case ACT_create_view: + gen_ddl(action, column); + break; + case ACT_cursor: + gen_cursor_init(action, column); + return; + case ACT_database: + gen_database(column); + return; + case ACT_declare_filter: + case ACT_declare_udf: + gen_ddl(action, column); + break; + case ACT_disconnect: + gen_finish(action, column); + break; + case ACT_drop_database: + gen_drop_database(action, column); + break; + case ACT_drop_domain: + case ACT_drop_filter: + case ACT_drop_index: + case ACT_drop_shadow: + case ACT_drop_table: + case ACT_drop_udf: + case ACT_drop_view: + gen_ddl(action, column); + break; + case ACT_dyn_close: + gen_dyn_close(action, column); + break; + case ACT_dyn_cursor: + gen_dyn_declare(action, column); + break; + case ACT_dyn_describe: + gen_dyn_describe(action, column, false); + break; + case ACT_dyn_describe_input: + gen_dyn_describe(action, column, true); + break; + case ACT_dyn_execute: + gen_dyn_execute(action, column); + break; + case ACT_dyn_fetch: + gen_dyn_fetch(action, column); + break; + case ACT_dyn_grant: + gen_ddl(action, column); + break; + case ACT_dyn_immediate: + gen_dyn_immediate(action, column); + break; + case ACT_dyn_insert: + gen_dyn_insert(action, column); + break; + case ACT_dyn_open: + gen_dyn_open(action, column); + break; + case ACT_dyn_prepare: + gen_dyn_prepare(action, column); + break; + case ACT_dyn_revoke: + gen_ddl(action, column); + break; + case ACT_endblob: + gen_blob_end(action, (USHORT) column); + return; + case ACT_enderror: + column += INDENT; + endp(column); + column -= INDENT; + break; + case ACT_endfor: + gen_endfor(action, column); + break; + case ACT_endmodify: + gen_emodify(action, column); + break; + case ACT_endstore: + gen_estore(action, column); + break; + case ACT_erase: + gen_erase(action, column); + return; + case ACT_event_init: + gen_event_init(action, column); + break; + case ACT_event_wait: + gen_event_wait(action, column); + break; + case ACT_fetch: + gen_fetch(action, column); + break; + case ACT_finish: + gen_finish(action, column); + break; + case ACT_for: + gen_for(action, column); + return; + case ACT_function: + gen_function(action, column); + return; + case ACT_get_segment: + gen_get_segment(action, column); + break; + case ACT_get_slice: + gen_slice(action, 0, column); + break; + case ACT_hctef: + endp(column); + break; + case ACT_insert: + gen_s_start(action, column); + break; + case ACT_loop: + gen_loop(action, column); + break; + case ACT_on_error: + gen_on_error(action, (USHORT) column); + return; + case ACT_open: + gen_s_start(action, column); + break; + case ACT_prepare: + gen_trans(action, column); + break; + case ACT_procedure: + gen_procedure(action, column); + break; + case ACT_put_segment: + gen_put_segment(action, column); + break; + case ACT_put_slice: + gen_slice(action, 0, column); + break; + case ACT_ready: + gen_ready(action, column); + break; + case ACT_release: + gen_release(action, column); + break; + case ACT_rfinish: + gen_finish(action, column); + break; + case ACT_rollback: + gen_trans(action, column); + break; + case ACT_rollback_retain_context: + gen_trans(action, column); + break; + case ACT_routine: + gen_routine(action, column); + return; + case ACT_s_end: + gen_s_end(action, column); + return; + case ACT_s_fetch: + gen_s_fetch(action, column); + return; + case ACT_s_start: + gen_s_start(action, column); + break; + case ACT_segment: + gen_segment(action, column); + return; + case ACT_segment_length: + gen_segment(action, column); + return; + case ACT_select: + gen_select(action, column); + break; + case ACT_sql_dialect: + gpreGlob.sw_sql_dialect = ((set_dialect*) action->act_object)->sdt_dialect; + return; + case ACT_start: + gen_t_start(action, column); + break; + case ACT_statistics: + gen_ddl(action, column); + break; + case ACT_store: + gen_store(action, column); + return; + case ACT_store2: + gen_return_value(action, column); + return; + case ACT_type_number: + gen_type(action, column); + return; + case ACT_update: + gen_update(action, column); + break; + case ACT_variable: + gen_variable(action, column); + return; + default: + return; + } + + // Put in a trailing brace for those actions still with us + + if (action->act_flags & ACT_sql) + gen_whenever(action->act_whenever, column); + + if (action->act_error) + fprintf(gpreGlob.out_file, ";"); + else + endp(column); +} + + +//____________________________________________________________ +// +// Align output to a specific column for output. If the +// column is negative, don't do anything. +// + +static void align( int column) +{ + if (column < 0) + return; + + putc('\n', gpreGlob.out_file); + + for (int i = column / 8; i; --i) + putc('\t', gpreGlob.out_file); + + for (int i = column % 8; i; --i) + putc(' ', gpreGlob.out_file); +} + + +//____________________________________________________________ +// +// Build an assignment from a host language variable to +// a port variable. The string assignments are a little +// hairy because the normal mode is varying (null +// terminated) strings, but the fixed subtype makes the +// string a byte stream. Furthering the complication, a +// single character byte stream is handled as a single byte, +// meaining that it is the byte, not the address of the +// byte. +// + +static void asgn_from( const act* action, ref* reference, int column) +{ + TEXT name[MAX_REF_SIZE], variable[MAX_REF_SIZE], temp[MAX_REF_SIZE]; + + for (; reference; reference = reference->ref_next) + { + bool slice_flag = false; + const gpre_fld* field = reference->ref_field; + if (field->fld_array_info) + { + act* slice_action; + ref* source = reference->ref_friend; + if (source && (slice_action = (act*) source->ref_slice) && slice_action->act_object) + { + slice_flag = true; + slice_action->act_type = ACT_put_slice; + gen_slice(slice_action, 0, column); + } + else if (!(reference->ref_flags & REF_array_elem)) + { + printa(column, "%s = fbBlobNull;", gen_name(name, reference, true)); + gen_get_or_put_slice(action, reference, false, column); + continue; + } + } + if (!reference->ref_source && !reference->ref_value && !slice_flag) + continue; + align(column); + gen_name(variable, reference, true); + const TEXT* value; + if (slice_flag) + value = gen_name(temp, reference->ref_friend, true); + else if (reference->ref_source) + value = gen_name(temp, reference->ref_source, true); + else + value = reference->ref_value; + + if (!slice_flag && reference->ref_value && (reference->ref_flags & REF_array_elem)) + { + field = field->fld_array; + } + if (field && field->fld_dtype <= dtype_cstring) + { + if (field->fld_sub_type == 1) + if (field->fld_length == 1) + fprintf(gpreGlob.out_file, "%s = %s;", variable, value); + else + fprintf(gpreGlob.out_file, "isc_ftof (%s, sizeof(%s), %s, %d);", value, + value, variable, field->fld_length); + else if (field->fld_flags & FLD_dbkey) + fprintf(gpreGlob.out_file, "isc_ftof (%s, %d, %s, %d);", value, + field->fld_length, variable, field->fld_length); + else if (gpreGlob.sw_cstring) + fprintf(gpreGlob.out_file, isLangCpp(gpreGlob.sw_language) ? + "isc_vtov ((const char*) %s, (char*) %s, %d);" : + "isc_vtov ((char*) %s, (char*) %s, %d);", + value, variable, field->fld_length); + else if (reference->ref_source) + fprintf(gpreGlob.out_file, "isc_ftof (%s, sizeof(%s), %s, %d);", + value, value, variable, field->fld_length); + else + fprintf(gpreGlob.out_file, "isc_vtof (%s, %s, %d);", + value, variable, field->fld_length); + } + else if (!reference->ref_master || (reference->ref_flags & REF_literal)) + { + fprintf(gpreGlob.out_file, "%s = %s;", variable, value); + } + else + { + fprintf(gpreGlob.out_file, "if (%s < 0)", value); + align(column + 4); + fprintf(gpreGlob.out_file, "%s = -1;", variable); + align(column); + fprintf(gpreGlob.out_file, "else"); + align(column + 4); + fprintf(gpreGlob.out_file, "%s = 0;", variable); + } + } +} + +//____________________________________________________________ +// +// Build an assignment to a host language variable from +// a port variable. +// + +static void asgn_to( const act* action, ref* reference, int column) +{ + char s[MAX_REF_SIZE]; + + ref* source = reference->ref_friend; + const gpre_fld* field = source->ref_field; + + if (field) + { + act* slice_action; + if (field->fld_array_info && (slice_action = (act*) source->ref_slice)) + { + source->ref_value = reference->ref_value; + if (slice_action->act_object) + { + slice_action->act_type = ACT_get_slice; + gen_slice(slice_action, source, column); + } + else + gen_get_or_put_slice(action, source, true, column); + + // Pick up NULL value if one is there + + if (reference = reference->ref_null) + { + align(column); + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, + gen_name(s, reference, true)); + } + return; + } + + gen_name(s, source, true); + if (field->fld_dtype > dtype_cstring) + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, s); + else if (field->fld_sub_type == 1 && field->fld_length == 1) + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, s); + else if (field->fld_flags & FLD_dbkey) + fprintf(gpreGlob.out_file, "isc_ftof (%s, %d, %s, %d);", + s, field->fld_length, reference->ref_value, field->fld_length); + else if (!gpreGlob.sw_cstring || field->fld_sub_type == 1) + fprintf(gpreGlob.out_file, "isc_ftof (%s, %d, %s, sizeof(%s));", + s, field->fld_length, reference->ref_value, reference->ref_value); + else + fprintf(gpreGlob.out_file, isLangCpp(gpreGlob.sw_language) ? + "isc_vtov ((const char*) %s, (char*) %s, sizeof(%s));" : + "isc_vtov ((char*) %s, (char*) %s, sizeof(%s));", + s, reference->ref_value, reference->ref_value); + } + + // Pick up NULL value if one is there + + if (reference = reference->ref_null) + { + align(column); + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, gen_name(s, reference, true)); + } +} + + +//____________________________________________________________ +// +// Build an assignment to a host language variable from +// a port variable. +// + +static void asgn_to_proc(const ref* reference, int column) +{ + char s[MAX_REF_SIZE]; + + for (; reference; reference = reference->ref_next) + { + if (!reference->ref_value) + continue; + const gpre_fld* field = reference->ref_field; + gen_name(s, reference, true); + align(column); + + if (field->fld_dtype > dtype_cstring) + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, s); + else if (field->fld_sub_type == 1 && field->fld_length == 1) + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, s); + else if (field->fld_flags & FLD_dbkey) + fprintf(gpreGlob.out_file, "isc_ftof (%s, %d, %s, %d);", + s, field->fld_length, reference->ref_value, field->fld_length); + else if (!gpreGlob.sw_cstring || field->fld_sub_type == 1) + fprintf(gpreGlob.out_file, "isc_ftof (%s, %d, %s, sizeof(%s));", + s, field->fld_length, reference->ref_value, reference->ref_value); + else + fprintf(gpreGlob.out_file, isLangCpp(gpreGlob.sw_language) ? + "isc_vtov ((const char*) %s, (char*) %s, sizeof(%s));" : + "isc_vtov ((char*) %s, (char*) %s, sizeof(%s));", + s, reference->ref_value, reference->ref_value); + } +} + + +//____________________________________________________________ +// +// Generate a function call for free standing ANY. Somebody else +// will need to generate the actual function. +// + +static void gen_any( const act* action, int column) +{ + align(column); + gpre_req* request = action->act_request; + + fprintf(gpreGlob.out_file, "%s_r (&%s, &%s", + request->req_handle, request->req_handle, request->req_trans); + + gpre_port* port = request->req_vport; + if (port) + for (ref* reference = port->por_references; reference; reference = reference->ref_next) + { + fprintf(gpreGlob.out_file, ", %s", reference->ref_value); + } + + fprintf(gpreGlob.out_file, ")"); +} + + +//____________________________________________________________ +// +// Generate code for AT END clause of FETCH. +// + +static void gen_at_end( const act* action, int column) +{ + char s[MAX_REF_SIZE]; + + const gpre_req* request = action->act_request; + printa(column, "if (!%s) {", gen_name(s, request->req_eof, true)); +} + + +//____________________________________________________________ +// +// Substitute for a BASED ON <field name> clause. +// + +static void gen_based( const act* action, int column) +{ + USHORT datatype; + SLONG length = -1; + + align(column); + bas* based_on = (bas*) action->act_object; + const gpre_fld* field = based_on->bas_field; + + if (based_on->bas_flags & BAS_segment) + { + datatype = gpreGlob.sw_cstring ? dtype_cstring : dtype_text; + if (!(length = field->fld_seg_length)) + length = 256; + if (datatype == dtype_cstring) + length++; + } + else if (field->fld_array_info) + datatype = field->fld_array_info->ary_dtype; + else + datatype = field->fld_dtype; + + switch (datatype) + { + case dtype_short: + fprintf(gpreGlob.out_file, "short"); + break; + + case dtype_long: + fprintf(gpreGlob.out_file, DCL_LONG); + break; + + case dtype_quad: + fprintf(gpreGlob.out_file, DCL_QUAD); + break; + + // Begin date/time/timestamp + case dtype_sql_date: + fprintf(gpreGlob.out_file, "ISC_DATE"); + break; + + case dtype_sql_time: + fprintf(gpreGlob.out_file, "ISC_TIME"); + break; + + case dtype_timestamp: + fprintf(gpreGlob.out_file, "ISC_TIMESTAMP"); + break; + // End date/time/timestamp + + case dtype_int64: + fprintf(gpreGlob.out_file, "ISC_INT64"); + break; + + case dtype_blob: + fprintf(gpreGlob.out_file, "ISC_QUAD"); + break; + + case dtype_cstring: + case dtype_text: + case dtype_varying: + fprintf(gpreGlob.out_file, "char"); + break; + + case dtype_real: + fprintf(gpreGlob.out_file, "float"); + break; + + case dtype_double: + fprintf(gpreGlob.out_file, "double"); + break; + + default: + { + TEXT s[MAX_CURSOR_SIZE]; + sprintf(s, "datatype %d unknown\n", field->fld_dtype); + CPR_error(s); + return; + } + } + + // print the first variable, then precede the rest with commas + + column += INDENT; + + // Notice this variable was named first_flag, same than the global variable. + bool first = true; + + while (based_on->bas_variables) + { + const TEXT* variable = (TEXT*) MSC_pop(&based_on->bas_variables); + if (!first) + fprintf(gpreGlob.out_file, ","); + first = false; + align(column); + fprintf(gpreGlob.out_file, "%s", variable); + if (based_on->bas_flags & BAS_segment) + { + if (*variable != '*') + fprintf(gpreGlob.out_file, "[%"SLONGFORMAT"]", length); + } + else if (field->fld_array_info) + { + // Print out the dimension part of the declaration + + for (const dim* dimension = field->fld_array_info->ary_dimension; + dimension; dimension = dimension->dim_next) + { + fprintf(gpreGlob.out_file, " [%"SLONGFORMAT"]", dimension->dim_upper - dimension->dim_lower + 1); + } + + if (field->fld_array_info->ary_dtype <= dtype_varying && field->fld_length > 1) + { + fprintf(gpreGlob.out_file, " [%d]", field->fld_array->fld_length); + } + } + else + if (*variable != '*' && field->fld_dtype <= dtype_varying && + (field->fld_sub_type != 1 || field->fld_length > 1)) + { + // *??????? + //if (*variable != '*' && field->fld_dtype <= dtype_varying && + // field->fld_length > 1) + // + fprintf(gpreGlob.out_file, "[%d]", field->fld_length); + } + } + + fprintf(gpreGlob.out_file, "%s\n", based_on->bas_terminator); +} + + +//____________________________________________________________ +// +// Make a blob FOR loop. +// + +static void gen_blob_close( const act* action, USHORT column) +{ + const TEXT* pattern1 = "fb_%IFcancel%ELclose%EN_blob (%V1, &%BH);"; + + if (action->act_error) + begin(column); + + const blb* blob; + if (action->act_flags & ACT_sql) + { + column = gen_cursor_close(action, action->act_request, column); + blob = (blb*) action->act_request->req_blobs; + } + else + blob = (blb*) action->act_object; + + PAT args; + args.pat_blob = blob; + args.pat_vector1 = status_vector(action); + args.pat_condition = (action->act_type == ACT_blob_cancel); + PATTERN_expand(column, pattern1, &args); + + if (action->act_flags & ACT_sql) + { + endp(column); + column -= INDENT; + } + + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// End a blob FOR loop. +// + +static void gen_blob_end( const act* action, USHORT column) +{ + PAT args; + TEXT s1[32]; + const TEXT* pattern1 = "}\n\ +&%BH->close(%V1);\n\ +}"; + + args.pat_blob = (const blb*) action->act_object; + if (action->act_error) + { + sprintf(s1, "%s2", global_status_name); + args.pat_vector1 = s1; + } + else + args.pat_vector1 = status_vector(0); + args.pat_condition = (action->act_type == ACT_blob_cancel); + PATTERN_expand(column, pattern1, &args); +} + + +//____________________________________________________________ +// +// Make a blob FOR loop. +// + +static void gen_blob_for( const act* action, USHORT column) +{ + PAT args; + const TEXT* pattern1 = "%IFif (%S1->isSuccess()) {\n\ +%ENwhile (1)\n\ + {"; + + gen_blob_open(action, column); + args.pat_condition = (action->act_error != NULL); + args.pat_string1 = global_status_name; + PATTERN_expand(column, pattern1, &args); + column += INDENT; + gen_get_segment(action, column); + printa(column, "if ((!%s->isSuccess()) && (%s->get()[1] != isc_segment)) break;", + global_status_name, global_status_name); +} + + +//____________________________________________________________ +// +// Generate the call to open (or create) a blob. +// + +static void gen_blob_open( const act* action, USHORT column) +{ + const TEXT* pattern1 = + "%BH = %DH->%IFcreate%ELopen%ENBlob (%V1, %RT, %FR, %N1, %I1);"; + const TEXT* pattern2 = + "%BH = %DH->%IFcreate%ELopen%ENBlob (%V1, %RT, %FR);"; + + if (gpreGlob.sw_auto && (action->act_flags & ACT_sql)) + { + t_start_auto(action, action->act_request, status_vector(action), column, true); + printa(column, "if (%s)", request_trans(action, action->act_request)); + column += INDENT; + } + + if ((action->act_error && (action->act_type != ACT_blob_for)) || (action->act_flags & ACT_sql)) + { + begin(column); + } + + TEXT s[MAX_REF_SIZE]; + const blb* blob; + const ref* reference; + if (action->act_flags & ACT_sql) + { + column = gen_cursor_open(action, action->act_request, column); + blob = (blb*) action->act_request->req_blobs; + reference = ((const open_cursor*) action->act_object)->opn_using; + gen_name(s, reference, true); + } + else + { + blob = (blb*) action->act_object; + reference = blob->blb_reference; + } + + PAT args; + args.pat_condition = (action->act_type == ACT_blob_create); // open or create blob + args.pat_vector1 = status_vector(action); // status vector + args.pat_database = blob->blb_request->req_database; // database handle + args.pat_request = blob->blb_request; // transaction handle + args.pat_blob = blob; // blob handle + args.pat_reference = reference; // blob identifier + args.pat_ident1 = blob->blb_bpb_ident; + + if ((action->act_flags & ACT_sql) && action->act_type == ACT_blob_open) + { + align(column); + fprintf(gpreGlob.out_file, "%s = %s;", s, reference->ref_value); + } + + if (args.pat_value1 = blob->blb_bpb_length) + PATTERN_expand(column, pattern1, &args); + else + PATTERN_expand(column, pattern2, &args); + + if (action->act_flags & ACT_sql) + { + endp(column); + column -= INDENT; + endp(column); + column -= INDENT; + endp(column); + if (gpreGlob.sw_auto) + column -= INDENT; + set_sqlcode(action, column); + if (action->act_type == ACT_blob_create) + { + printa(column, "if (!SQLCODE)"); + align(column + INDENT); + fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, s); + } + } + else if ((action->act_error && (action->act_type != ACT_blob_for))) + endp(column); +} + + +//____________________________________________________________ +// +// Callback routine for BLR pretty printer. +// + +static void gen_blr(void* /*user_arg*/, SSHORT /*offset*/, const char* string) +{ + char line[256]; + + int indent = 2 * INDENT; + const char* p = string; + while (*p == ' ') + { + p++; + indent++; + } + + // Limit indentation to 192 characters + + indent = MIN(indent, 192); + + bool first_line = true; + int length = strlen(p); + do { + const char* q; + if (length + indent > 255) + { + // if we did not find somewhere to break between the 200th and 256th + // character just print out 256 characters + + bool open_quote = false; + for (q = p; (q - p + indent) < 255; q++) + { + if ((q - p + indent) > 220 && *q == ',' && !open_quote) + break; + if (*q == '\'' && *(q - 1) != '\\') + open_quote = !open_quote; + } + ++q; + } + else { + q = p + strlen(p); + } + + // Replace all occurrences of gds__ (or gds__) with isc_ + + char* q1 = line; + for (const char* p1 = p; p1 < q;) + { + if ((*q1++ = *p1++) == 'g') + { + if (p1 < q && (*q1++ = *p1++) == 'd') + { + if (p1 < q && (*q1++ = *p1++) == 's') + { + if (p1 < q && (*q1++ = *p1++) == '_') + { + char d = 0; + if (p1 < q && ((d = *p1++) == '_' || d == '$')) + strncpy(q1 - 4, "isc", 3); + else if (d) + *q1++ = d; + } + } + } + } + } + *q1 = 0; + printa(indent, "%s", line); + length = length - (q - p); + p = q; + if (first_line) + { + indent = MIN(indent + INDENT, 192); + first_line = false; + } + } while (length > 0); +} + + +//____________________________________________________________ +// +// Zap all know handles. +// + +static void gen_clear_handles(int column) +{ + for (gpre_req* request = gpreGlob.requests; request; request = request->req_next) + { + if (!(request->req_flags & REQ_exp_hand)) + printa(column, "%s = 0;", request->req_handle); + } +} + + +//____________________________________________________________ +// +// Generate a symbol to ease compatibility with V3. +// +/* +static void gen_compatibility_symbol(const TEXT* symbol, + const TEXT* v4_prefix, const TEXT* trailer) +{ + const char* v3_prefix = isLangCpp(gpreGlob.sw_language) ? "gds_" : "gds__"; + // v3_prefix = gpreGlob.sw_language == lang_cxx ? "gds_" : "gds__"; + + fprintf(gpreGlob.out_file, "#define %s%s\t%s%s%s\n", v3_prefix, symbol, + v4_prefix, symbol, trailer); +} +*/ + +//____________________________________________________________ +// +// Generate text to compile a request. +// + +static void gen_compile( const act* action, int column) +{ + PAT args; + const TEXT* pattern1 = + "%RH = %DH->compileRequest(%V1, sizeof(%RI), %RI);"; + const TEXT* pattern2 = "if (!%RH%IF && %S1%EN)"; + + const gpre_req* request = action->act_request; + args.pat_request = request; + const gpre_dbb* db = request->req_database; + args.pat_database = db; + args.pat_vector1 = status_vector(action); + args.pat_string1 = request_trans(action, request); + args.pat_condition = (gpreGlob.sw_auto && (action->act_error || (action->act_flags & ACT_sql))); + + if (gpreGlob.sw_auto) + t_start_auto(action, request, status_vector(action), column, true); + + PATTERN_expand((USHORT) column, pattern2, &args); + + args.pat_condition = !(request->req_flags & REQ_exp_hand); + args.pat_value1 = request->req_length; + PATTERN_expand((USHORT) (column + INDENT), pattern1, &args); + + // If blobs are present, zero out all of the blob handles. After this + // point, the handles are the user's responsibility + + const blb* blob = request->req_blobs; + if (blob) + { + fprintf(gpreGlob.out_file, "\n"); + align(column - INDENT); + for (; blob; blob = blob->blb_next) + fprintf(gpreGlob.out_file, "fb_%d = ", blob->blb_ident); + fprintf(gpreGlob.out_file, "0;"); + } +} + + +//____________________________________________________________ +// +// Generate a call to create a database. +// + +static void gen_create_database( const act* action, int column) +{ + const TEXT* pattern1 = + "%DH = fbProvider->createDatabase (%V1, \"%DF\", %IF%S1, %S2%EL0, NULL%EN);"; + TEXT s1[32], s2[32], trname[32]; + + const gpre_req* request = ((const mdbb*) action->act_object)->mdbb_dpb_request; + const gpre_dbb* db = request->req_database; + + sprintf(s1, "fb_%dl", request->req_ident); + sprintf(trname, "fb_%dt", request->req_ident); + + if (request->req_flags & REQ_extend_dpb) + { + sprintf(s2, "fb_%dp", request->req_ident); + if (request->req_length) + printa(column, "%s = fb_%d;", s2, request->req_ident); + else + printa(column, "%s = (char*) 0;", s2); + + printa(column, + "isc_expand_dpb (&%s, &%s, isc_dpb_user_name, %s, isc_dpb_password, %s, isc_dpb_sql_role_name, %s, isc_dpb_lc_messages, %s, isc_dpb_lc_ctype, %s, 0);", + s2, s1, + db->dbb_r_user ? db->dbb_r_user : "(char*) 0", + db->dbb_r_password ? db->dbb_r_password : "(char*) 0", + db->dbb_r_sql_role ? db->dbb_r_sql_role : "(char*) 0", + db->dbb_r_lc_messages ? db->dbb_r_lc_messages : "(char*) 0", + db->dbb_r_lc_ctype ? db->dbb_r_lc_ctype : "(char*) 0"); + } + else + sprintf(s2, "fb_%d", request->req_ident); + + PAT args; + args.pat_vector1 = status_vector(action); + args.pat_request = request; + args.pat_database = db; + args.pat_value1 = strlen(db->dbb_filename); + args.pat_condition = (request->req_length || (request->req_flags & REQ_extend_dpb)); + args.pat_string1 = s1; + args.pat_string2 = s2; + + PATTERN_expand((USHORT) column, pattern1, &args); + + // if the dpb was extended, free it here + + if (request->req_flags & REQ_extend_dpb) + { + if (request->req_length) + printa(column, "if (%s != fb_%d)", s2, request->req_ident); + printa(column + (request->req_length ? INDENT : 0), "isc_free ((char*) %s);", s2); + + // reset the length of the dpb + + printa(column, "%s = %d;", s1, request->req_length); + } + + request = action->act_request; + printa(column, "if (%s->isSuccess())", global_status_name); + column += INDENT; + begin(column); + printa(column, + "%s = %s->startTransaction (%s, 0, NULL);", + trname, db->dbb_name->sym_string, status_vector(action)); + printa(column, "if (%s)", trname); + column += INDENT; + align(column); + fprintf(gpreGlob.out_file, "%s->executeDyn(%s, %s, %d, fb_%d);", + request->req_database->dbb_name->sym_string, status_vector(action), + trname, request->req_length, request->req_ident); + column -= INDENT; + printa(column, "if (%s->isSuccess())", global_status_name); + printa(column + INDENT, "%s->commit(%s);", + trname, status_vector(action)); + printa(column, "if (!%s->isSuccess())", global_status_name); + printa(column + INDENT, "%s->rollback(%s);", + trname, status_vector(NULL)); + set_sqlcode(action, column); + endp(column); + printa(column - INDENT, "else"); + set_sqlcode(action, column); + column -= INDENT; +} + + +//____________________________________________________________ +// +// Generate substitution text for END_STREAM. +// + +static int gen_cursor_close( const act* action, const gpre_req* request, int column) +{ + PAT args; + ObjectNotImplemented(); + const TEXT* pattern1 = "if (%RIs && !isc_dsql_free_statement (%V1, &%RIs, %L1))"; + + args.pat_request = request; + args.pat_vector1 = status_vector(action); + args.pat_long1 = 1; + + PATTERN_expand((USHORT) column, pattern1, &args); + column += INDENT; + begin(column); + + return column; +} + + +//____________________________________________________________ +// +// Generate text to initialize a cursor. +// + +static void gen_cursor_init( const act* action, int column) +{ + + // If blobs are present, zero out all of the blob handles. After this + // point, the handles are the user's responsibility + + if (action->act_request->req_flags & (REQ_sql_blob_open | REQ_sql_blob_create)) + { + printa(column, "fb_%d = 0;", action->act_request->req_blobs->blb_ident); + } +} + + +//____________________________________________________________ +// +// Generate text to open an embedded SQL cursor. +// + +static int gen_cursor_open( const act* action, const gpre_req* request, int column) +{ + PAT args; + TEXT s[MAX_CURSOR_SIZE]; + ObjectNotImplemented(); + const TEXT* pattern1 = "if (!%RIs && %RH%IF && %DH%EN)"; + const TEXT* pattern2 = "if (!%RIs%IF && %DH%EN)"; + const TEXT* pattern3 = "isc_dsql_alloc_statement2 (%V1, &%DH, &%RIs);"; + const TEXT* pattern4 = "if (%RIs%IF && %S3%EN)"; + const TEXT* pattern5 = "if (!isc_dsql_set_cursor_name (%V1, &%RIs, %S1, 0) &&"; + const TEXT* pattern6 = "!isc_dsql_execute_m (%V1, &%S3, &%RIs, 0, %S2, %N2, 0, %S2))"; + + args.pat_request = request; + args.pat_database = request->req_database; + args.pat_vector1 = status_vector(action); + args.pat_condition = gpreGlob.sw_auto; + args.pat_string1 = make_name(s, ((open_cursor*) action->act_object)->opn_cursor); + args.pat_string2 = NULL_STRING; + args.pat_string3 = request_trans(action, request); + args.pat_value2 = -1; + + PATTERN_expand((USHORT) column, (action->act_type == ACT_open) ? pattern1 : pattern2, &args); + PATTERN_expand((USHORT) (column + INDENT), pattern3, &args); + PATTERN_expand((USHORT) column, pattern4, &args); + column += INDENT; + begin(column); + PATTERN_expand((USHORT) column, pattern5, &args); + column += INDENT; + PATTERN_expand((USHORT) column, pattern6, &args); + begin(column); + + return column; +} + + +//____________________________________________________________ +// +// Generate insertion text for the database statement. +// + +static void gen_database(int column) +{ + if (global_first_flag) + return; + + global_first_flag = true; + + fprintf(gpreGlob.out_file, "\n/**** GDS Preprocessor Definitions ****/\n"); + fprintf(gpreGlob.out_file, "#ifndef JRD_IBASE_H\n#include %s\n#endif\n", GDS_INCLUDE); + fprintf(gpreGlob.out_file, "#include <firebird/Provider.h>\n"); + + fprintf(gpreGlob.out_file, "#define CAST_CONST_MSG(A) (reinterpret_cast<const unsigned char*>(A))\n"); + fprintf(gpreGlob.out_file, "#define CAST_MSG(A) (reinterpret_cast<unsigned char*>(A))\n"); + + printa(column, "static %sISC_QUAD", CONST_STR); + printa(column + INDENT, "fbBlobNull = {0, 0};\t/* initializer for blobs */"); + + const TEXT* scope = ""; + + bool all_static = true; + bool all_extern = true; + + const gpre_dbb* db; + for (db = gpreGlob.isc_databases; db; db = db->dbb_next) + { + all_static = all_static && (db->dbb_scope == DBB_STATIC); + all_extern = all_extern && (db->dbb_scope == DBB_EXTERN); + if (db->dbb_scope == DBB_STATIC) + scope = "static "; + else if (db->dbb_scope == DBB_EXTERN) + scope = "extern "; + printa(column, "%sFirebird::IAttachment*", scope); + if (!all_extern) + printa(column + INDENT, "%s = 0;\t\t/* database handle */\n", db->dbb_name->sym_string); + else + printa(column + INDENT, "%s;\t\t/* database handle */\n", db->dbb_name->sym_string); + } + + if (all_static) + scope = "static "; + else if (all_extern) + scope = "extern "; + + printa(column, "%sFirebird::ITransaction*", scope); + if (!all_extern) + printa(column + INDENT, "%s = 0;\t\t/* default transaction handle */", + gpreGlob.transaction_name); + else + printa(column + INDENT, "%s;\t\t/* default transaction handle */", + gpreGlob.transaction_name); + + printa(column, "%sFirebird::IMaster* fbMaster%s;\t\t/* master interface */", + scope, all_extern ? "" : " = fb_get_master_interface()"); + printa(column, "%sFirebird::IProvider* fbProvider%s;\t\t/* provider interface */", + scope, all_extern ? "" : " = fbMaster->getDispatcher()"); + + printa(column, "%sFirebird::IStatus* %s%s;\t/* status vector */", + scope, global_status_name, all_extern ? "" : " = fbMaster->getStatus();"); + printa(column, "%sFirebird::IStatus* %s2%s;\t/* status vector */", + scope, global_status_name, all_extern ? "" : " = fbMaster->getStatus();"); + + for (db = gpreGlob.isc_databases; db; db = db->dbb_next) + for (const tpb* tpb_iterator = db->dbb_tpbs; tpb_iterator; + tpb_iterator = tpb_iterator->tpb_dbb_next) + { + gen_tpb(tpb_iterator, column); + } + + // generate event parameter block for each event in module + + SSHORT max_count = 0; + for (gpre_lls* stack_ptr = gpreGlob.events; stack_ptr; stack_ptr = stack_ptr->lls_next) + { + SSHORT count = gen_event_block((act*) stack_ptr->lls_object); + max_count = MAX(count, max_count); + } + + if (max_count) + printa(column, "%s%s isc_events [%d];\t/* event vector */", scope, DCL_LONG, max_count); + + for (gpre_req* request = gpreGlob.requests; request; request = request->req_next) + { + gen_request(request); + + // Array declarations + + if (gpre_port* port = request->req_primary) + for (ref* reference = port->por_references; reference; reference = reference->ref_next) + { + if (reference->ref_flags & REF_fetch_array) + make_array_declaration(reference); + } + } + + fprintf(gpreGlob.out_file, "\n\n"); +/* + gen_compatibility_symbol("blob_null", "isc_", "\t// compatibility symbols"); + //gen_compatibility_symbol ("database", "isc_", ""); + //gen_compatibility_symbol ("trans", "isc_", ""); + gen_compatibility_symbol("status", "isc_", ""); + gen_compatibility_symbol("status2", "isc_", ""); + gen_compatibility_symbol("array_length", "isc_", ""); + if (max_count) + gen_compatibility_symbol("events", "isc_", ""); + gen_compatibility_symbol("count", "isc_", ""); + gen_compatibility_symbol("slack", "isc_", ""); + gen_compatibility_symbol("utility", "isc_", "\t// end of compatibility symbols"); + */ +} + + +//____________________________________________________________ +// +// Generate a call to update metadata. +// + +static void gen_ddl( const act* action, int column) +{ + // Set up command type for call to RDB$DDL + + const gpre_req* request = action->act_request; + + if (gpreGlob.sw_auto) + { + t_start_auto(action, 0, status_vector(action), column, true); + printa(column, "if (%s)", gpreGlob.transaction_name); + column += INDENT; + } + + align(column); + fprintf(gpreGlob.out_file, "%s->executeDyn(%s, %s, %d, fb_%d);", + request->req_database->dbb_name->sym_string, + status_vector(action), + gpreGlob.transaction_name, request->req_length, request->req_ident); + + if (gpreGlob.sw_auto) + { + column -= INDENT; + printa(column, "if (%s->isSuccess())", global_status_name); + printa(column + INDENT, "%s->commit(%s);", + gpreGlob.transaction_name, status_vector(action)); + printa(column, "if (!%s->isSuccess())", global_status_name); + printa(column + INDENT, "%s->rollback(%s);", + gpreGlob.transaction_name, status_vector(NULL)); + } + + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// Generate a call to drop a database. +// + +static void gen_drop_database( const act* action, int column) +{ + ObjectNotImplemented(); + const gpre_dbb* db = (gpre_dbb*) action->act_object; + align(column); + + fprintf(gpreGlob.out_file, "isc_drop_database (%s, %"SIZEFORMAT", \"%s\", rdb$k_db_type_gds);", + status_vector(action), + strlen(db->dbb_filename), db->dbb_filename); + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// Generate a dynamic SQL statement. +// + +static void gen_dyn_close( const act* action, int column) +{ + TEXT s[MAX_CURSOR_SIZE]; + + ObjectNotImplemented(); + const dyn* statement = (dyn*) action->act_object; + printa(column, "isc_embed_dsql_close (%s, %s);", + global_status_name, make_name(s, statement->dyn_cursor_name)); + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// Generate a dynamic SQL statement. +// + +static void gen_dyn_declare( const act* action, int column) +{ + TEXT s1[MAX_CURSOR_SIZE], s2[MAX_CURSOR_SIZE]; + + ObjectNotImplemented(); + const dyn* statement = (dyn*) action->act_object; + printa(column, "isc_embed_dsql_declare (%s, %s, %s);", + global_status_name, + make_name(s1, statement->dyn_statement_name), + make_name(s2, statement->dyn_cursor_name)); + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// Generate a dynamic SQL statement. +// + +static void gen_dyn_describe(const act* action, int column, bool bind_flag) +{ + TEXT s[MAX_CURSOR_SIZE]; + + ObjectNotImplemented(); + const dyn* statement = (dyn*) action->act_object; + printa(column, "isc_embed_dsql_describe%s (%s, %s, %d, %s);", + bind_flag ? "_bind" : "", + global_status_name, + make_name(s, statement->dyn_statement_name), + gpreGlob.sw_sql_dialect, statement->dyn_sqlda); + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// Generate a dynamic SQL statement. +// + +static void gen_dyn_execute( const act* action, int column) +{ + TEXT s[MAX_CURSOR_SIZE]; + gpre_req* request; + gpre_req req_const; + + ObjectNotImplemented(); + dyn* statement = (dyn*) action->act_object; + const TEXT* transaction; + if (statement->dyn_trans) + { + transaction = statement->dyn_trans; + request = &req_const; + request->req_trans = transaction; + } + else + { + transaction = gpreGlob.transaction_name; + request = NULL; + } + + if (gpreGlob.sw_auto) + { + t_start_auto(action, request, status_vector(action), column, true); + printa(column, "if (%s)", transaction); + column += INDENT; + } + + if (statement->dyn_sqlda2) + printa(column, "isc_embed_dsql_execute2 (%s, &%s, %s, %d, %s, %s);", + global_status_name, + transaction, + make_name(s, statement->dyn_statement_name), + gpreGlob.sw_sql_dialect, + statement->dyn_sqlda ? statement->dyn_sqlda : NULL_STRING, + statement->dyn_sqlda2); + else + printa(column, "isc_embed_dsql_execute (%s, &%s, %s, %d, %s);", + global_status_name, + transaction, + make_name(s, statement->dyn_statement_name), + gpreGlob.sw_sql_dialect, + statement->dyn_sqlda ? statement->dyn_sqlda : NULL_STRING); + + if (gpreGlob.sw_auto) + column -= INDENT; + + set_sqlcode(action, column); +} + + +//____________________________________________________________ +// +// Generate a dynamic SQL statement. +// + +static void gen_dyn_fetch( const act* action, int column) +{ + TEXT s[MAX_CURSOR_SIZE]; + + ObjectNotImplemented(); + const dyn* statement = (dyn*) action->act_object; + printa(column, "SQLCODE = isc_embed_dsql_fetch (%s, %s, %d, %s);", + global_status_name, make_name(s, statement->dyn_cursor_name), + gpreGlob.sw_sql_dialect, + statement->dyn_sqlda ? statement->dyn_sqlda : NULL_SQLDA); + + printa(column, "if (SQLCODE != 100) SQLCODE = isc_sqlcode (%s);", global_status_name); +} + + +//____________________________________________________________ +// +// Generate code for an EXECUTE IMMEDIATE dynamic S... [truncated message content] |