|
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] |