diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index 29538b7450..545e4dafee 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -844,66 +844,64 @@ ISC_STATUS callback_execute_immediate( ISC_STATUS* status, requests = 0; } - // 1. Locate why_db_handle, corresponding to jrd_database_handle + YValve::Attachment* why_db_handle = 0; + YValve::Transaction* why_trans_handle = 0; + dsql_dbb* database = 0; + THREAD_EXIT(); THD_MUTEX_LOCK (&databases_mutex); - dsql_dbb* database; - for (database = databases; database; database = database->dbb_next) + try { - if (WHY_translate_handle(database->dbb_database_handle)->handle.h_dbb == jrd_attachment_handle) + // 1. Locate why_db_handle, corresponding to jrd_database_handle + for (database = databases; database; database = database->dbb_next) { - break; + if (YValve::translate(&database->dbb_database_handle)->handle == jrd_attachment_handle) + { + break; + } } - } - if (! database) { - status[0] = isc_arg_gds; - status[1] = isc_bad_db_handle; - status[2] = isc_arg_end; - THD_MUTEX_UNLOCK(&databases_mutex); - THREAD_ENTER(); - return status[1]; - } - WHY_DBB why_db_handle = WHY_translate_handle(database->dbb_database_handle); + if (! database) + { + Firebird::status_exception::raise(isc_bad_db_handle, isc_arg_end); + } + why_db_handle = YValve::translate(&database->dbb_database_handle); - /* 2. Create why_trans_handle - it's new, but points to the same jrd - transaction as original before callback. */ - WHY_TRA why_trans_handle = WHY_alloc_handle(why_db_handle->implementation, HANDLE_transaction); - if (!why_trans_handle) { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; + // 2. Create why_trans_handle - it's new, but points to the same jrd + // transaction as original before callback. + why_trans_handle = new YValve::Transaction(jrd_transaction_handle, 0, why_db_handle); + } + catch (const std::exception& e) + { THD_MUTEX_UNLOCK(&databases_mutex); THREAD_ENTER(); - return status[1]; + return Firebird::stuff_exception(status, e); } - why_trans_handle->handle.h_tra = jrd_transaction_handle; - why_trans_handle->parent = why_db_handle; - THD_MUTEX_UNLOCK (&databases_mutex); - THREAD_ENTER(); + // 3. Call execute... function + THD_MUTEX_UNLOCK (&databases_mutex); + THREAD_ENTER(); const ISC_STATUS rc = dsql8_execute_immediate_common(status, &database->dbb_database_handle, &why_trans_handle->public_handle, sql_operator.length(), sql_operator.c_str(), database->dbb_db_SQL_dialect, 0, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL, requests); - WHY_cleanup_transaction(why_trans_handle); - WHY_free_handle(why_trans_handle->public_handle); + delete why_trans_handle; return rc; } -WHY_DBB GetWhyAttachment (ISC_STATUS* status, - Jrd::Attachment* jrd_attachment_handle) +YValve::Attachment* GetWhyAttachment(ISC_STATUS* status, + Jrd::Attachment* jrd_attachment_handle) { THREAD_EXIT(); THD_MUTEX_LOCK (&databases_mutex); dsql_dbb* database; - WHY_DBB db_handle = 0; + YValve::Attachment* db_handle = 0; for (database = databases; database; database = database->dbb_next) { - db_handle = WHY_translate_handle(database->dbb_database_handle); - if (db_handle->handle.h_dbb == jrd_attachment_handle) + db_handle = YValve::translate(&database->dbb_database_handle); + if (db_handle->handle == jrd_attachment_handle) { break; } diff --git a/src/jrd/alt.cpp b/src/jrd/alt.cpp index 03712de675..92fc2afaa5 100644 --- a/src/jrd/alt.cpp +++ b/src/jrd/alt.cpp @@ -382,7 +382,7 @@ ISC_STATUS API_ROUTINE gds__create_database(ISC_STATUS* status_vector, ISC_STATUS API_ROUTINE gds__database_cleanup(ISC_STATUS * status_vector, FB_API_HANDLE* db_handle, - DatabaseCleanupRoutine *routine, void* arg) + AttachmentCleanupRoutine* routine, void* arg) { return isc_database_cleanup(status_vector, db_handle, routine, arg); diff --git a/src/jrd/alt_proto.h b/src/jrd/alt_proto.h index 51d9935b6f..a5764829bd 100644 --- a/src/jrd/alt_proto.h +++ b/src/jrd/alt_proto.h @@ -66,7 +66,7 @@ ISC_STATUS API_ROUTINE gds__create_database( ISC_STATUS*, SSHORT, const SCHAR*, FB_API_HANDLE*, SSHORT, const SCHAR*, SSHORT); ISC_STATUS API_ROUTINE gds__database_cleanup(ISC_STATUS*, FB_API_HANDLE*, - DatabaseCleanupRoutine*, void * ); + AttachmentCleanupRoutine*, void * ); ISC_STATUS API_ROUTINE gds__database_info(ISC_STATUS*, FB_API_HANDLE*, SSHORT, const SCHAR*, SSHORT, SCHAR*); diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index d3820f2d70..e8bb98d781 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -496,13 +496,9 @@ USHORT BLB_get_segment(thread_db* tdbb, SET_TDBB(tdbb); Database* dbb = tdbb->tdbb_database; -#ifdef SUPERSERVER - if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); -#endif - /* If we reached end of file, we're still there */ if (blob->blb_flags & BLB_eof) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index abfdcaf239..bc28e1a714 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -3859,11 +3859,9 @@ static SLONG fast_load(thread_db* tdbb, pointers[level] = levelPointer; } -#ifdef SUPERSERVER if (--tdbb->tdbb_quantum < 0) { error = JRD_reschedule(tdbb, 0, false); } -#endif } // To finish up, put an end of level marker on the last bucket @@ -6414,7 +6412,6 @@ static CONTENTS remove_leaf_node(thread_db* tdbb, index_insertion* insertion, WI } while (--l); } -#ifdef SUPERSERVER // Until deletion of duplicate nodes becomes efficient, limit // leaf level traversal by rescheduling. if (--tdbb->tdbb_quantum < 0) { @@ -6423,7 +6420,6 @@ static CONTENTS remove_leaf_node(thread_db* tdbb, index_insertion* insertion, WI ERR_punt(); } } -#endif } // If we've needed to search thru a significant number of pages, warn the diff --git a/src/jrd/common.h b/src/jrd/common.h index e7854ff229..4c8f8bf25b 100644 --- a/src/jrd/common.h +++ b/src/jrd/common.h @@ -84,9 +84,10 @@ # endif #endif +#define CANCEL_OPERATION + #ifdef SUPERSERVER #define GOVERNOR -#define CANCEL_OPERATION #define FB_ARCHITECTURE isc_info_db_class_server_access #else #define FB_ARCHITECTURE isc_info_db_class_classic_access diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 0867214c69..66662af958 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -578,10 +578,8 @@ void EXE_receive(thread_db* tdbb, DEV_BLKCHK(request, type_req); -#ifdef SUPERSERVER if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); -#endif jrd_tra* transaction = request->req_transaction; @@ -722,10 +720,8 @@ void EXE_send(thread_db* tdbb, SET_TDBB(tdbb); DEV_BLKCHK(request, type_req); -#ifdef SUPERSERVER if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); -#endif if (!(request->req_flags & req_active)) ERR_post(isc_req_sync, isc_arg_end); @@ -1630,16 +1626,12 @@ static jrd_nod* looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node) { try { -#ifdef SUPERSERVER - if (request->req_operation == jrd_req::req_evaluate && (--tdbb->tdbb_quantum < 0)) { JRD_reschedule(tdbb, 0, true); } -#endif - #if defined(DEBUG_GDS_ALLOC) && FALSE int node_type = node->nod_type; #endif diff --git a/src/jrd/execute_statement.cpp b/src/jrd/execute_statement.cpp index 2eb0bb2d43..defcb27852 100644 --- a/src/jrd/execute_statement.cpp +++ b/src/jrd/execute_statement.cpp @@ -34,7 +34,6 @@ #include "../jrd/jrd.h" #include "../jrd/tra.h" #include "../jrd/dsc.h" -#include "../jrd/y_handle.h" #include "../jrd/thd.h" #include "../jrd/err_proto.h" #include "../jrd/mov_proto.h" @@ -44,6 +43,7 @@ #include "../jrd/thread_proto.h" #define WHY_NO_API #include "../jrd/why_proto.h" +#include "../jrd/y_handle.h" #include "../jrd/align.h" #include "../jrd/execute_statement.h" @@ -53,8 +53,7 @@ using namespace Jrd; using namespace Firebird; -WHY_DBB GetWhyAttachment(ISC_STATUS* status, - Attachment* jrd_attachment_handle); +YValve::Attachment* GetWhyAttachment(ISC_STATUS*, Attachment*); static const SSHORT sqlType[] = { @@ -112,19 +111,14 @@ void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool Si memcpy(StartOfSqlOperator, SqlText.c_str(), sizeof(StartOfSqlOperator) - 1); StartOfSqlOperator[sizeof(StartOfSqlOperator) - 1] = 0; - WHY_DBB temp_dbb = GetWhyAttachment(tdbb->tdbb_status_vector, + YValve::Attachment* temp_dbb = GetWhyAttachment(tdbb->tdbb_status_vector, tdbb->tdbb_attachment); if (!temp_dbb) ERR_punt(); Attachment = temp_dbb->public_handle; - WHY_TRA temp_tra = WHY_alloc_handle(temp_dbb->implementation, HANDLE_transaction); - if (!temp_tra) - ERR_post(isc_virmemexh, isc_arg_end); - Transaction = temp_tra->public_handle; - temp_tra->handle.h_tra = tdbb->tdbb_transaction; - temp_tra->parent = temp_dbb; + YValve::Transaction* temp_tra = new YValve::Transaction(tdbb->tdbb_transaction, &Transaction, temp_dbb); Statement = 0; Sqlda = MakeSqlda(tdbb, nVars ? nVars : 1); @@ -290,12 +284,9 @@ void ExecuteStatement::Close(thread_db* tdbb) delete[] p; Sqlda = 0; if (Transaction) { - THREAD_EXIT(); - WHY_cleanup_transaction(WHY_translate_handle(Transaction)); - THREAD_ENTER(); + delete YValve::translate(&Transaction); + Transaction = 0; } - WHY_free_handle(Transaction); - Transaction = 0; delete[] Buffer; Buffer = 0; } diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index cfb4e770ca..969ae84272 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -488,10 +488,8 @@ void IDX_create_index( delete record; } -#ifdef SUPERSERVER if (--tdbb->tdbb_quantum < 0) cancel = JRD_reschedule(tdbb, 0, false); -#endif } gc_record->rec_flags &= ~REC_gc_active; diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 40d80e4fab..6eb9d159c9 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -4424,7 +4424,6 @@ void JRD_print_procedure_info(thread_db* tdbb, const char* mesg) #endif /* DEBUG_PROCS */ -#ifdef MULTI_THREAD bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt) { /************************************** @@ -4439,9 +4438,10 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt) * **************************************/ -/* Force garbage colletion activity to yield the - processor in case client threads haven't had - an opportunity to enter the scheduling queue. */ +#ifdef MULTI_THREAD + // Force garbage collection activity to yield the + // processor in case client threads haven't had + // an opportunity to enter the scheduling queue. if (!(tdbb->tdbb_flags & TDBB_sweeper)) SCH_schedule(); @@ -4450,6 +4450,7 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt) THREAD_YIELD(); THREAD_ENTER(); } +#endif // Test various flags and unwind/throw if required. // But do that only if we're not in the verb cleanup state, @@ -4533,13 +4534,16 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt) } tdbb->tdbb_quantum = (tdbb->tdbb_quantum <= 0) ? +#ifdef MULTI_THREAD (quantum ? quantum : (ThreadPriorityScheduler::boosted() ? - Config::getPriorityBoost() : 1) * QUANTUM) : + Config::getPriorityBoost() : 1) * QUANTUM) : +#else + (quantum ? quantum : QUANTUM) : +#endif tdbb->tdbb_quantum; return false; } -#endif void JRD_restore_context(void) @@ -5014,7 +5018,8 @@ static ISC_STATUS error(ISC_STATUS* user_status) use count is erroneously left set. */ #if (defined DEV_BUILD && !defined MULTI_THREAD) - if (dbb && dbb->dbb_use_count && !(dbb->dbb_flags & DBB_security_db)) { + if (dbb && dbb->dbb_use_count && !(dbb->dbb_flags & DBB_security_db)) + { dbb->dbb_use_count = 0; ISC_STATUS* p = user_status; *p++ = isc_arg_gds; @@ -6123,6 +6128,129 @@ void JRD_set_cache_default(ULONG* num_ptr) } +static ISC_STATUS shutdown_dbb(thread_db* tdbb, Database* dbb, Attachment** released) +{ +/************************************** + * + * s h u t d o w n _ d b b + * + ************************************** + * + * Functional description + * rollback every transaction, + * release every attachment, + * and shutdown database. + * + **************************************/ + if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) && + !(dbb->dbb_ast_flags & DBB_shutdown && + dbb->dbb_ast_flags & DBB_shutdown_locks)) + { + Attachment* att_next; + for (Attachment* attach = dbb->dbb_attachments; attach; attach = att_next) + { + att_next = attach->att_next; + tdbb->tdbb_database = dbb; + tdbb->tdbb_attachment = attach; + tdbb->tdbb_request = NULL; + tdbb->tdbb_transaction = NULL; + tdbb->tdbb_flags |= TDBB_shutdown_manager; + Jrd::ContextPoolHolder context(tdbb, 0); + ++dbb->dbb_use_count; + + // purge_attachment() below can do an ERR_post + ISC_STATUS_ARRAY user_status; + tdbb->tdbb_status_vector = user_status; + + try + { + // purge attachment, rollback any open transactions +#if defined(V4_THREADING) && !defined(SUPERSERVER) + V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini); +#endif + purge_attachment(tdbb, user_status, attach, true); +#if defined(V4_THREADING) && !defined(SUPERSERVER) + V4_JRD_MUTEX_UNLOCK(databases_mutex); +#endif + } + catch (const std::exception& ex) + { + if (released) + { + *released = 0; + } + return error(user_status, ex); + } + + // attach became invalid pointer + // if we have someone, intereted in that fact, inform him + if (released) + { + *released++ = attach; + } + } + } + if (released) + { + *released = 0; + } + return FB_SUCCESS; +} + + +static ISC_STATUS shutdown_all() +{ +/************************************** + * + * s h u t d o w n _ a l l + * + ************************************** + * + * Functional description + * rollback every transaction, + * release every attachment, + * and shutdown every database. + * + **************************************/ + THREAD_ENTER(); + // NOTE!!! + // This routine doesn't contain THREAD_EXIT to help ensure + // that no threads will get in and try to access the data + // structures we released here + + thread_db thd_context; + thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context); + + if (initialized) { + JRD_SS_MUTEX_LOCK; + } + + Database* dbb_next; + for (Database* dbb = databases; dbb; dbb = dbb_next) + { + dbb_next = dbb->dbb_next; + + ISC_STATUS rc = shutdown_dbb(tdbb, dbb, 0); + if (rc != FB_SUCCESS) + { + if (initialized) + { + JRD_SS_MUTEX_UNLOCK; + } + return rc; + } + } + + if (initialized) { + JRD_SS_MUTEX_UNLOCK; + } + + JRD_restore_context(); + + return FB_SUCCESS; +} + + #ifdef SERVER_SHUTDOWN TEXT* JRD_num_attachments(TEXT* const buf, USHORT buf_len, USHORT flag, USHORT* atts, USHORT* dbs) @@ -6356,92 +6484,9 @@ static void ExtractDriveLetter(const TEXT* file_name, ULONG* drive_mask) #endif -ISC_STATUS shutdown_all() -{ -/************************************** - * - * s h u t d o w n _ a l l - * - ************************************** - * - * Functional description - * rollback every transaction, - * release every attachment, - * and shutdown every database. - * - **************************************/ - THREAD_ENTER(); - // NOTE!!! - // This routine doesn't contain THREAD_EXIT to help ensure - // that no threads will get in and try to access the data - // structures we released here - - thread_db thd_context; - thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context); - - if (initialized) { - JRD_SS_MUTEX_LOCK; - } - ISC_STATUS_ARRAY user_status; - - Database* dbb_next; - for (Database* dbb = databases; dbb; dbb = dbb_next) - { - dbb_next = dbb->dbb_next; - if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) && - !(dbb->dbb_ast_flags & DBB_shutdown && - dbb->dbb_ast_flags & DBB_shutdown_locks)) - { - Attachment* att_next; - for (Attachment* attach = dbb->dbb_attachments; attach; attach = att_next) - { - att_next = attach->att_next; - tdbb->tdbb_database = dbb; - tdbb->tdbb_attachment = attach; - tdbb->tdbb_request = NULL; - tdbb->tdbb_transaction = NULL; - tdbb->tdbb_flags |= TDBB_shutdown_manager; - Jrd::ContextPoolHolder context(tdbb, 0); - - ++dbb->dbb_use_count; - - /* purge_attachment below can do an ERR_post */ - - tdbb->tdbb_status_vector = user_status; - - try { - /* purge attachment, rollback any open transactions */ - -#if defined(V4_THREADING) && !defined(SUPERSERVER) - V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini); -#endif - purge_attachment(tdbb, user_status, attach, true); -#if defined(V4_THREADING) && !defined(SUPERSERVER) - V4_JRD_MUTEX_UNLOCK(databases_mutex); -#endif - } // try - catch (const std::exception& ex) { - if (initialized) { - JRD_SS_MUTEX_UNLOCK; - } - return error(user_status, ex); - } - } - } - } - - if (initialized) { - JRD_SS_MUTEX_UNLOCK; - } - - JRD_restore_context(); - - return FB_SUCCESS; -} - - #ifdef SUPERSERVER -static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg) { +static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg) +{ /************************************** * * s h u t d o w n _ t h r e a d @@ -6476,9 +6521,9 @@ void JRD_shutdown_all(bool asyncMode) * asynchronous shutdown. * **************************************/ -#ifdef SUPERSERVER int flShutdownComplete = 0; +#ifdef SUPERSERVER if (asyncMode) { gds__thread_start(shutdown_thread, &flShutdownComplete, @@ -6492,6 +6537,7 @@ void JRD_shutdown_all(bool asyncMode) } } else // sync mode +#endif // SUPERSERVER { flShutdownComplete = (shutdown_all() == FB_SUCCESS); } @@ -6500,8 +6546,45 @@ void JRD_shutdown_all(bool asyncMode) { gds__log("Forced server shutdown - not all databases closed"); } -#endif // SUPERSERVER } + +#else // SERVER_SHUTDOWN + +// This conditional compilation, though sitting under not +// defined SERVER_SHUTDOWN, performs full or partial shutdown +// of database. SERVER_SHUTDOWN defined controls some other +// aspects of operation, therefore was left "as is". +// Who wants to invent better naem for it, please do it. + +void JRD_process_close() +{ + shutdown_all(); +} + +void JRD_database_close(Attachment** handle, Attachment** released) +{ + THREAD_ENTER(); + thread_db thd_context; + thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context); + + Database* dbb = databases; + for (; dbb; dbb = dbb->dbb_next) + { + for (Attachment* attach = dbb->dbb_attachments; attach; attach = attach->att_next) + { + if (attach == *handle) + { + goto found; + } + } + } + return; + +found: + // got dbb to be closed + shutdown_dbb(tdbb, dbb, released); +} + #endif /* SERVER_SHUTDOWN */ diff --git a/src/jrd/jrd_proto.h b/src/jrd/jrd_proto.h index 191707acdf..68d9afcff0 100644 --- a/src/jrd/jrd_proto.h +++ b/src/jrd/jrd_proto.h @@ -148,6 +148,9 @@ const USHORT JRD_info_dbnames = 2; TEXT* JRD_num_attachments(TEXT* const, USHORT, USHORT, USHORT*, USHORT*); void JRD_shutdown_all(bool); +#else /* SERVER_SHUTDOWN */ +void JRD_process_close(); +void JRD_database_close(Jrd::Attachment**, Jrd::Attachment**); #endif /* SERVER_SHUTDOWN */ void JRD_set_cache_default(ULONG *); diff --git a/src/jrd/os/isc_i_proto.h b/src/jrd/os/isc_i_proto.h index 54c23d38be..bfd7b81357 100644 --- a/src/jrd/os/isc_i_proto.h +++ b/src/jrd/os/isc_i_proto.h @@ -34,8 +34,8 @@ int ISC_kill(SLONG, SLONG, void *); #else // And that are functions to manage UNIX signals int ISC_kill(SLONG, SLONG); -void ISC_signal(int, FPTR_VOID_PTR, void *); -void ISC_signal_cancel(int, FPTR_VOID_PTR, void *); +bool ISC_signal(int, FPTR_VOID_PTR, void *); +void ISC_signal_cancel(int, FPTR_VOID_PTR, void *); #endif void ISC_signal_init(void); diff --git a/src/jrd/os/posix/isc_ipc.cpp b/src/jrd/os/posix/isc_ipc.cpp index ea28baeebd..2f2261ae75 100644 --- a/src/jrd/os/posix/isc_ipc.cpp +++ b/src/jrd/os/posix/isc_ipc.cpp @@ -36,7 +36,7 @@ * */ - /* $Id: isc_ipc.cpp,v 1.17.4.5 2008-08-28 06:37:33 alexpeshkoff Exp $ */ + /* $Id: isc_ipc.cpp,v 1.17.4.6 2008-09-15 11:25:41 alexpeshkoff Exp $ */ #include "firebird.h" #include @@ -128,7 +128,7 @@ static int volatile relay_pipe = 0; static void cleanup(void* arg); -static void isc_signal2(int signal, FPTR_VOID handler, void* arg, ULONG); +static bool isc_signal2(int signal, FPTR_VOID handler, void* arg, ULONG); static SLONG overflow_handler(void* arg); static SIG que_signal(int signal, FPTR_VOID handler, void* arg, int flags); @@ -242,6 +242,9 @@ int ISC_kill(SLONG pid, SLONG signal_number) * Notify somebody else. * **************************************/ + if (! pid) + pid = getpid(); + for (;;) { const int status = kill(pid, signal_number); @@ -302,7 +305,7 @@ int ISC_kill(SLONG pid, SLONG signal_number) } -void ISC_signal(int signal_number, FPTR_VOID_PTR handler, void* arg) +bool ISC_signal(int signal_number, FPTR_VOID_PTR handler, void* arg) { /************************************** * @@ -314,11 +317,11 @@ void ISC_signal(int signal_number, FPTR_VOID_PTR handler, void* arg) * Multiplex multiple handers into single signal. * **************************************/ - isc_signal2(signal_number, reinterpret_cast(handler), arg, SIG_user); + return isc_signal2(signal_number, reinterpret_cast(handler), arg, SIG_user); } -static void isc_signal2( +static bool isc_signal2( int signal_number, FPTR_VOID handler, void* arg, ULONG flags) { @@ -334,6 +337,7 @@ static void isc_signal2( **************************************/ SIG sig; + bool rc = false; /* The signal handler needs the process id */ if (!process_id) @@ -377,6 +381,7 @@ static void isc_signal2( { que_signal(signal_number, reinterpret_cast(oact.sa_handler), NULL, SIG_client); + rc = true; } } @@ -385,6 +390,8 @@ static void isc_signal2( que_signal(signal_number, handler, arg, flags); THD_MUTEX_UNLOCK(&sig_mutex); + + return rc; } diff --git a/src/jrd/rse.cpp b/src/jrd/rse.cpp index 9c82912d2f..a247510771 100644 --- a/src/jrd/rse.cpp +++ b/src/jrd/rse.cpp @@ -1794,15 +1794,11 @@ static bool get_record(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); -#ifdef SUPERSERVER - if (--tdbb->tdbb_quantum < 0) { JRD_reschedule(tdbb, 0, true); } -#endif - /* check request flags for special processing */ jrd_req* request = tdbb->tdbb_request; diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index bf0e6313b5..9e3696f8fc 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -821,10 +821,8 @@ static FETCH_CODE fetch_page(thread_db* tdbb, Database* dbb = tdbb->tdbb_database; CHECK_DBB(dbb); -#ifdef SUPERSERVER if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); -#endif window->win_page = page_number; window->win_flags = 0; diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 710c01a4f2..86eac4d3eb 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -3607,14 +3607,12 @@ static void garbage_collect(thread_db* tdbb, if (rpb->rpb_record) { going.push(rpb->rpb_record); } -#ifdef SUPERSERVER + /* Don't monopolize the server while chasing long back version chains. */ - if (--tdbb->tdbb_quantum < 0) { JRD_reschedule(tdbb, 0, true); } -#endif } BLB_garbage_collect(tdbb, going, staying, prior_page, rpb->rpb_relation); @@ -4069,14 +4067,12 @@ static void list_staying(thread_db* tdbb, record_param* rpb, RecordStack& stayin break; } depth++; -#ifdef SUPERSERVER + /* Don't monopolize the server while chasing long back version chains. */ - if (--tdbb->tdbb_quantum < 0) { JRD_reschedule(tdbb, 0, true); } -#endif } if (timed_out) { continue; diff --git a/src/jrd/why.cpp b/src/jrd/why.cpp index c36ccd7163..508146e600 100644 --- a/src/jrd/why.cpp +++ b/src/jrd/why.cpp @@ -43,6 +43,7 @@ */ #include "firebird.h" +#include "memory_routines.h" // needed for get_long #include #include @@ -52,6 +53,13 @@ #include #include "../jrd/gdsassert.h" +/* includes specific for DSQL */ + +#include "../dsql/sqlda.h" + +/* end DSQL-specific includes */ + +#include "../jrd/why_proto.h" #include "../jrd/y_handle.h" #include "gen/iberror.h" #include "../jrd/msg_encode.h" @@ -63,13 +71,9 @@ #include "../jrd/fil.h" #include "../jrd/flu.h" #include "../jrd/db_alias.h" +#include "../jrd/os/path_utils.h" #include "../common/classes/ClumpletWriter.h" - -/* includes specific for DSQL */ - -#include "../dsql/sqlda.h" - -/* end DSQL-specific includes */ +#include "../common/utils_proto.h" #include "../jrd/flu_proto.h" #include "../jrd/gds_proto.h" @@ -85,10 +89,21 @@ #include "../dsql/dsql_proto.h" #include "../dsql/prepa_proto.h" #include "../dsql/utld_proto.h" -#include "../jrd/why_proto.h" #include "../common/classes/rwlock.h" #include "../common/classes/auto.h" +#include "../common/classes/init.h" +#include "../jrd/constants.h" +#if !defined (SUPERCLIENT) && !defined (REQUESTER) && !defined(SERVER_SHUTDOWN) +#define CANCEL_disable 1 +#define CANCEL_enable 2 +#define CANCEL_raise 3 +//extern "C" ISC_STATUS jrd8_cancel_operation(ISC_STATUS *, Jrd::Attachment**, USHORT); +void JRD_process_close(); +void JRD_database_close(Jrd::Attachment**, Jrd::Attachment**); +#endif + +using namespace YValve; // In 2.0 it's hard to include ibase.h in why.cpp due to API declaration conflicts. // Taking into account that given y-valve lives it's last version, @@ -126,14 +141,6 @@ const UCHAR isc_dpb_version1 = 1; const int IO_RETRY = 20; -#ifdef DEV_BUILD -#define CHECK_STATUS(v) check_status_vector(v, !FB_SUCCESS) -#define CHECK_STATUS_SUCCESS(v) check_status_vector(v, FB_SUCCESS) -#else -#define CHECK_STATUS(v) /* nothing */ -#define CHECK_STATUS_SUCCESS(v) /* nothing */ -#endif - inline void init_status(ISC_STATUS* vector) { vector[0] = isc_arg_gds; @@ -147,42 +154,33 @@ inline bool is_network_error(const ISC_STATUS* vector) vector[1] == isc_net_read_err; } -#define TRANSLATE_HANDLE(public_handle, handle, handle_type, error_code) \ - if (!((handle) = WHY_translate_handle(public_handle)) || (handle)->type != handle_type) \ - return bad_handle (user_status, error_code); +static void bad_handle(ISC_STATUS); +//#define NULL_CHECK(ptr, code) if (*ptr) return bad_handle (user_status, code) +inline void nullCheck(const FB_API_HANDLE* ptr, ISC_STATUS code) +{ + // this function is called for incoming API handlers, + // proposed to be created by the call + if (*ptr) + { + bad_handle(code); + } +} -#define FIND_TRANSACTION(public_handle, handle, database, error_code) \ - if (!((handle) = find_transaction(database, WHY_translate_handle(public_handle))) || (handle)->type != HANDLE_transaction) \ - return bad_handle (user_status, error_code); - -#define NULL_CHECK(ptr, code, type) if (*ptr) return bad_handle (user_status, code) -#define GET_STATUS { if (!(status = user_status)) status = local; init_status(status); } -#define RETURN_SUCCESS { subsystem_exit(); CHECK_STATUS_SUCCESS (status); return FB_SUCCESS; } +//#define GET_STATUS { if (!(status = user_status)) status = local; init_status(status); } + // gone to YEntry +//#define RETURN_SUCCESS { subsystem_exit(); CHECK_STATUS_SUCCESS (status); return FB_SUCCESS; } + // gone to YEntry #if defined(REQUESTER) || defined (SUPERCLIENT) #define NO_LOCAL_DSQL #endif -#if defined (SERVER_SHUTDOWN) && !defined (SUPERCLIENT) && !defined (REQUESTER) +#if !defined (SUPERCLIENT) && !defined (REQUESTER) static BOOLEAN shutdown_flag = FALSE; -#endif /* SERVER_SHUTDOWN && !SUPERCLIENT && !REQUESTER */ +#endif /* !SUPERCLIENT && !REQUESTER */ typedef ISC_STATUS(*PTR) (ISC_STATUS* user_status, ...); -/* Database cleanup handlers */ - -struct clean -{ - struct clean* clean_next; - union { - DatabaseCleanupRoutine* DatabaseRoutine; - TransactionCleanupRoutine *TransactionRoutine; - }; - void* clean_arg; -}; - -typedef clean *CLEAN; - /* Transaction element block */ struct teb @@ -191,59 +189,29 @@ struct teb int teb_tpb_length; UCHAR *teb_tpb; }; - typedef teb TEB; -#ifdef DEBUG_GDS_ALLOC -#define alloc(x) alloc_debug(x, __FILE__, __LINE__) -static SCHAR *alloc_debug(SLONG, const char*, int); -#else -static SCHAR *alloc(SLONG); -#endif static void free_block(void*); -class HandlePublicKey { -public: - static const FB_API_HANDLE& generate(const void* sender, why_hndl* value) { - return value->public_handle; - } -}; - -typedef Firebird::BePlusTree HandleMapping; - -static Firebird::AutoPtr handleMapping; -static ULONG handle_sequence_number = 0; -static Firebird::RWLock handleMappingLock; - -why_hndl* WHY_alloc_handle(int implementation, int handle_type) +namespace YValve { -/************************************** - * - * W H Y _ a l l o c _ h a n d l e - * - ************************************** - * - * Functional description - * Allocate an indirect handle. - * - **************************************/ - WHY_HNDL handle = (WHY_HNDL) alloc((SLONG) sizeof(why_hndl)); + typedef Firebird::BePlusTree HandleMapping; - if (handle) + static Firebird::AutoPtr handleMapping; + static ULONG handle_sequence_number = 0; + static Firebird::RWLock handleMappingLock; + + static Firebird::InitInstance > attachments; + + Handle::Handle(UCHAR t, FB_API_HANDLE* pub, Attachment* par, USHORT imp) + : type(t), flags(0), implementation(par ? par->implementation : imp), + parent(par), user_handle(0) { - handle->implementation = implementation; - handle->type = handle_type; + fb_assert(par || (imp != USHORT(~0))); -#ifdef DEBUG_GDS_ALLOC -/* As the memory for the handle is handed back to the client, InterBase - * cannot free the memory unless the client returns to us. As a result, - * the memory allocator might try to report this as unfreed, but it - * ain't our fault. So flag it to make the allocator be happy. - */ - gds_alloc_flag_unfreed((void *) handle); -#endif handleMappingLock.beginWrite(); - try { + try + { if (!handleMapping) handleMapping = FB_NEW(*getDefaultMemoryPool()) HandleMapping(getDefaultMemoryPool()); @@ -258,94 +226,136 @@ why_hndl* WHY_alloc_handle(int implementation, int handle_type) // Avoid generating NULL handle when sequence number wraps if (!temp) temp = ++handle_sequence_number; - handle->public_handle = (FB_API_HANDLE)(IPTR) temp; - } while (!handleMapping->add(handle)); + public_handle = (FB_API_HANDLE)(IPTR)temp; + } while (!handleMapping->add(this)); handleMappingLock.endWrite(); - } catch(const std::exception&) { - // Handle out-of-memory conditions + } + catch (const std::exception&) { handleMappingLock.endWrite(); - free_block(handle); - handle = NULL; + throw; + } + + if (pub) + { + *pub = public_handle; } } - return handle; -} + Handle* Handle::translate(FB_API_HANDLE handle) { + Firebird::ReadLockGuard sync(handleMappingLock); -why_hndl* WHY_translate_handle(FB_API_HANDLE handle) { - Firebird::ReadLockGuard sync(handleMappingLock); + if (handleMapping) + { + HandleMapping::Accessor accessor(handleMapping); + if (accessor.locate(handle)) + { + Handle* h = accessor.current(); + if (h->flags & HANDLE_shutdown) + { + Firebird::status_exception::raise(isc_shutdown, isc_arg_string, + h->parent ? h->parent->db_path.c_str() : "(unknown)", + isc_arg_end); + } + return h; + } + } - if (!handleMapping) return NULL; - - HandleMapping::Accessor accessor(handleMapping); - if (accessor.locate(handle)) - return accessor.current(); - - return NULL; -} - -void WHY_free_handle(FB_API_HANDLE handle) { - Firebird::WriteLockGuard sync(handleMappingLock); - - // Silently ignore bad handles for now - if (handleMapping && handleMapping->locate(handle)) { - why_hndl* temp = handleMapping->current(); - handleMapping->fastRemove(); - free_block(temp); + return 0; } + + Jrd::Attachment* Handle::getAttachmentHandle() + { + return parent ? parent->handle : 0; + } + + void Handle::cancel() + { + if (!parent) + { + return; + } + parent->cancel2(); + } + + Handle::~Handle() + { + if (user_handle) + { + *user_handle = 0; + } + + Firebird::WriteLockGuard sync(handleMappingLock); + + // Silently ignore bad handles for PROD_BUILD + if (handleMapping && handleMapping->locate(public_handle)) + { + handleMapping->fastRemove(); + } +#ifdef DEV_BUILD + else + { + //Attempt to release bad handle + fb_assert(false); + } +#endif + } + + Attachment::Attachment(StAtt* h, FB_API_HANDLE* pub, USHORT impl) + : Handle(hType(), pub, 0, impl), + transactions(*getDefaultMemoryPool()), + requests(*getDefaultMemoryPool()), + blobs(*getDefaultMemoryPool()), + statements(*getDefaultMemoryPool()), + handle(h), + db_path(*getDefaultMemoryPool()) + { + toParent(attachments(), this); + parent = this; + } + + Attachment::~Attachment() + { + cleanup.call(&public_handle); + fromParent(attachments(), this); + } + } -inline static WHY_HNDL allocate_handle(int implementation, why_hndl* h, int handle_type) -{ - WHY_HNDL handle = WHY_alloc_handle(implementation, handle_type); - handle->handle.h_why = h; - return handle; -} - -inline static WHY_HNDL allocate_handle(int implementation, dsql_req* h, int handle_type) -{ - WHY_HNDL handle = WHY_alloc_handle(implementation, handle_type); - handle->handle.h_dsql = h; - return handle; -} - -inline static WHY_HNDL allocate_handle(int implementation, Jrd::jrd_tra* h, int handle_type) -{ - WHY_HNDL handle = WHY_alloc_handle(implementation, handle_type); - handle->handle.h_tra = h; - return handle; -} - - -// CVC: Just don't get the idea of private functions with C linkage. -// Probably a finer grain would be better here. -// There's an exported variable several lines below. -static ISC_STATUS bad_handle(ISC_STATUS *, ISC_STATUS); - #ifdef DEV_BUILD -static void check_status_vector(const ISC_STATUS*, ISC_STATUS); +static void check_status_vector(const ISC_STATUS*); #endif -static ISC_STATUS error(const ISC_STATUS*, const ISC_STATUS*); -static ISC_STATUS error2(const ISC_STATUS*, const ISC_STATUS*); + static void event_ast(void*, USHORT, const UCHAR*); static void exit_handler(event_t*); -static WHY_TRA find_transaction(WHY_DBB, WHY_TRA); -static int get_database_info(ISC_STATUS *, WHY_TRA, TEXT **); + +static Transaction* find_transaction(Attachment*, Transaction*); + +inline Transaction* findTransaction(FB_API_HANDLE* public_handle, Attachment *a) +{ + Transaction* t = find_transaction(a, translate(public_handle)); + if (! t) + { + bad_handle(isc_bad_trans_handle); + } + + return t; +} + +static int get_database_info(ISC_STATUS *, Transaction*, TEXT **); static const PTR get_entrypoint(int, int); -static SCHAR *get_sqlda_buffer(SCHAR *, USHORT, XSQLDA *, USHORT, USHORT *); -static ISC_STATUS get_transaction_info(ISC_STATUS *, WHY_TRA, TEXT **); +static USHORT sqlda_buffer_size(XSQLDA*, USHORT); +static ISC_STATUS get_transaction_info(ISC_STATUS *, Transaction*, TEXT **); static void iterative_sql_info(ISC_STATUS *, FB_API_HANDLE*, SSHORT, const SCHAR *, SSHORT, SCHAR *, USHORT, XSQLDA *); static ISC_STATUS open_blob(ISC_STATUS*, FB_API_HANDLE*, FB_API_HANDLE*, FB_API_HANDLE*, SLONG*, USHORT, const UCHAR*, SSHORT, SSHORT); -static ISC_STATUS prepare(ISC_STATUS *, WHY_TRA); -static void release_dsql_support(sqlda_sup*); -static void release_handle(WHY_HNDL); +static ISC_STATUS prepare(ISC_STATUS *, Transaction*); +static void release_dsql_support(sqlda_sup&); static void save_error_string(ISC_STATUS *); -static void subsystem_enter(void); -static void subsystem_exit(void); +static void subsystem_enter(void) throw(); +static void subsystem_exit(void) throw(); #ifndef REQUESTER static event_t why_event[1]; @@ -397,6 +407,300 @@ const int MAXERRORSTRINGLENGTH = 250; static TEXT glbstr1[MAXERRORSTRINGLENGTH]; static const TEXT glbunknown[10] = ""; +namespace +{ +/* + * class YEntry: + * 1. Provides correct status vector for operation and init() it. + * 2. Tracks subsystem_enter/exit() calls. + * For single-threaded systems: + * 3. Knows location of primary handle and detachs database when + * cancel / shutdown takes place. + * In some cases (primarily - attach/create) specific handle may + * be missing. + */ + + class Status + { + public: + Status(ISC_STATUS* v) throw() + : local_vector(v ? v : local_status), doExit(true) + { + init_status(local_vector); + } + + operator ISC_STATUS*() const + { + return local_vector; + } + + // don't exit on missing user_status + // That feature is suspicious: on windows after + // printf() and exit() will happen silent exit. AP-2007. + void ok() + { + doExit = false; + } + + ~Status() + { +#ifdef DEV_BUILD + check_status_vector(local_vector); +#endif + +#ifndef SUPERSERVER + if (local_vector == local_status && + local_vector[0] == isc_arg_gds && + local_vector[1] != FB_SUCCESS && + doExit) + { + // user did not specify status, but error took place: + // should better specify it next time :-( + gds__print_status(local_vector); + exit((int) local_vector[1]); + } +#endif + } + private: + ISC_STATUS_ARRAY local_status; + ISC_STATUS* local_vector; + bool doExit; + }; + +#ifndef SERVER_SHUTDOWN // appears this macro has now nothing with shutdown + + int totalAttachmentCount() + { + return attachments().getCount(); + } + + template + void markHandlesShutdown(Array handles) + { + for (size_t n = 0; n < handles.getCount(); ++n) + { + handles[n]->flags |= HANDLE_shutdown; + } + } + + void markShutdown(Attachment* attach) + { + attach->flags |= HANDLE_shutdown; + + markHandlesShutdown(attach->transactions); + markHandlesShutdown(attach->statements); + markHandlesShutdown(attach->requests); + markHandlesShutdown(attach->blobs); + } + + void markShutdown(Jrd::Attachment** list) + { + while (Jrd::Attachment* ja = *list++) + { + for (size_t n = 0; n < attachments().getCount(); ++n) + { + if (attachments()[n]->handle == ja) + { + markShutdown(attachments()[n]); + break; + } + } + } + } + + class YEntry : public Status + { + public: + YEntry(ISC_STATUS* v) throw() + : Status(v), recursive(false) + { + subsystem_enter(); + + if (handle || killed) { + recursive = true; + return; + } + + handle = 0; + vector = (ISC_STATUS*)(*this); + inside = true; + if (!init) + { + init = true; + installCtrlCHandler(); + } + } + + void setPrimaryHandle(Handle* h) + { + handle = h; + } + + ~YEntry() + { + subsystem_exit(); + + if (recursive) + { + return; + } + + if (killed) + { +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + JRD_process_close(); +#endif + propagateKill(); + } + + if (fatal()) + { + if (handle) + { + Jrd::Attachment* attach = handle->getAttachmentHandle(); + Firebird::HalfStaticArray releasedBuffer; + Jrd::Attachment** released = + releasedBuffer.getBuffer(totalAttachmentCount() + 1); + *released = 0; +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + JRD_database_close(&attach, released); +#endif + markShutdown(released); + } + } + + inside = false; + handle = 0; + } + private: + YEntry(const YEntry&); //prohibit copy constructor + + bool recursive; //loopback call from ExecState, Udf, etc. + + static bool inside; + static Handle* handle; + static ISC_STATUS* vector; + static bool init; + static int killed; + static bool proc2, proc15; + + static void installCtrlCHandler() throw() + { + try + { + proc2 = ISC_signal(2, Handler2, 0); + proc15 = ISC_signal(15, Handler15, 0); + } + catch (...) + { + gds__log("Failure setting ctrl-C handlers"); + } + } + + static void propagateKill() + { + ISC_signal_cancel(2, Handler2, 0); + ISC_signal_cancel(15, Handler15, 0); + + // if signal is not processed by someone else, exit now + if (!(killed == 2 ? proc2 : proc15)) + { + exit(0); + } + + // Someone else watches signals - let him shutdown gracefully + for (size_t n = 0; n < attachments().getCount(); ++n) + { + markShutdown(attachments()[n]); + } + } + + static void Handler2(void*) + { + if (killed) + { + return; // do nothing - already killed + } + killed = 2; + Handler(); + } + + static void Handler15(void*) + { + if (killed) + { + return; // do nothing - already killed + } + killed = 15; + Handler(); + } + + static void Handler() + { +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + shutdown_flag = true; +#endif + if (inside) + { + if (handle) + { + handle->cancel(); + } + } + else + { + // this function must in theory use only signal-safe code + // but as long as we have not entered engine, + // any call to it should be safe +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + JRD_process_close(); +#endif + propagateKill(); + } + } + + bool fatal() + { + return vector[0] == isc_arg_gds && + (vector[1] == isc_shutdown || + vector[1] == isc_cancelled); + } + }; + + bool YEntry::init = false; + bool YEntry::inside = false; + Handle* YEntry::handle = 0; + ISC_STATUS* YEntry::vector = 0; + int YEntry::killed = 0; + bool YEntry::proc2 = false; + bool YEntry::proc15 = false; + +#else + + class YEntry : public Status + { + public: + YEntry(ISC_STATUS* v) : Status(v) + { + subsystem_enter(); + } + + void setPrimaryHandle(Handle* h) + { + } + + ~YEntry() + { + subsystem_exit(); + } + private: + YEntry(const YEntry&); //prohibit copy constructor + }; + +#endif +} // anonymous namespace + + #ifdef VMS #define CALL(proc, handle) (*get_entrypoint(proc, handle)) #else @@ -550,7 +854,7 @@ const int PROC_SERVICE_START = 51; const int PROC_ROLLBACK_RETAINING = 52; const int PROC_CANCEL_OPERATION = 53; -const int PROC_INTL_FUNCTION = 54; +const int PROC_INTL_FUNCTION = 54; // internal call const int PROC_count = 55; @@ -692,6 +996,18 @@ static const SCHAR describe_bind_info[] = }; +namespace YValve +{ + void Attachment::cancel2() + { +#if !defined (SUPERCLIENT) && !defined (REQUESTER) && !defined(SERVER_SHUTDOWN) + ISC_STATUS_ARRAY local; + jrd8_cancel_operation(local, &handle, CANCEL_raise); +#endif + } +} + + ISC_STATUS API_ROUTINE GDS_ATTACH_DATABASE(ISC_STATUS* user_status, SSHORT file_length, const TEXT* file_name, @@ -710,82 +1026,64 @@ ISC_STATUS API_ROUTINE GDS_ATTACH_DATABASE(ISC_STATUS* user_status, * that recognizes it. * **************************************/ - ISC_STATUS *status, *ptr; - ISC_STATUS_ARRAY local, temp; - USHORT n, length, org_length, temp_length; - WHY_DBB database; - Firebird::PathName expanded_filename, temp_filename; -#if defined(UNIX) - TEXT single_user[5]; -#endif + ISC_STATUS *ptr; + ISC_STATUS_ARRAY temp; + StAtt* handle = 0; + Attachment* database = 0; + USHORT n; - GET_STATUS; - - NULL_CHECK(public_handle, isc_bad_db_handle, HANDLE_database); - if (!file_name) + YEntry status(user_status); + try { - status[0] = isc_arg_gds; - status[1] = isc_bad_db_format; - status[2] = isc_arg_string; - status[3] = (ISC_STATUS) ""; - status[4] = isc_arg_end; - return error2(status, local); - } + nullCheck(public_handle, isc_bad_db_handle); - if (dpb_length > 0 && !dpb) - { - status[0] = isc_arg_gds; - status[1] = isc_bad_dpb_form; - status[2] = isc_arg_end; - return error2(status, local); - } - -#if defined (SERVER_SHUTDOWN) && !defined (SUPERCLIENT) && !defined (REQUESTER) - if (shutdown_flag) - { - status[0] = isc_arg_gds; - status[1] = isc_shutwarn; - status[2] = isc_arg_end; - return error2(status, local); - } -#endif /* SERVER_SHUTDOWN && !SUPERCLIENT && !REQUESTER */ - - subsystem_enter(); - SUBSYSTEM_USAGE_INCR; - - try { - ptr = status; - - org_length = file_length; - - if (org_length) + if (!file_name) { - const TEXT* p = file_name + org_length - 1; - while (*p == ' ') - { - --p; - } - org_length = p - file_name + 1; + Firebird::status_exception::raise(isc_bad_db_format, + isc_arg_string, + "", + isc_arg_end); } + if (dpb_length > 0 && !dpb) + { + Firebird::status_exception::raise(isc_bad_dpb_form, + isc_arg_end); + } + +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + if (shutdown_flag) + { + Firebird::status_exception::raise(isc_shutwarn, + isc_arg_end); + } +#endif /* !SUPERCLIENT && !REQUESTER */ + + SUBSYSTEM_USAGE_INCR; + + ptr = status; + /* copy the file name to a temp buffer, since some of the following utilities can modify it */ - temp_length = org_length ? org_length : strlen(file_name); - temp_filename.assign(file_name, temp_length); + Firebird::PathName temp_filename(file_name, + file_length ? file_length : strlen(file_name)); + temp_filename.rtrim(); + file_length = temp_filename.length(); + Firebird::PathName expanded_filename; if (!ISC_check_if_remote(temp_filename, true)) { - Firebird::PathName database; - if (ResolveDatabaseAlias(temp_filename, database)) + Firebird::PathName database_filename; + if (ResolveDatabaseAlias(temp_filename, database_filename)) { - ISC_expand_filename(database, false); - expanded_filename = database; + ISC_expand_filename(database_filename, false); + expanded_filename = database_filename; } else if (iscSetPath(temp_filename, expanded_filename)) { temp_filename = expanded_filename; - org_length = temp_filename.length(); + file_length = temp_filename.length(); } else { @@ -810,69 +1108,52 @@ ISC_STATUS API_ROUTINE GDS_ATTACH_DATABASE(ISC_STATUS* user_status, { continue; } - WHY_ATT handle = NULL; - if (!CALL(PROC_ATTACH_DATABASE, n) (ptr, org_length, temp_filename.c_str(), + if (!CALL(PROC_ATTACH_DATABASE, n) (ptr, temp_filename.length(), temp_filename.c_str(), &handle, newDpb.getBufferLength(), reinterpret_cast(newDpb.getBuffer()), expanded_filename.c_str())) { - length = expanded_filename.length(); - database = allocate_handle(n, handle, HANDLE_database); - if (database) - { - database->db_path = (TEXT*) alloc((SLONG) (length + 1)); - } - if (!database || !database->db_path) - { - /* No memory. Make a half-hearted to detach and get out. */ + database = new Attachment(handle, public_handle, n); + database->db_path = expanded_filename; - if (database) - release_handle(database); - CALL(PROC_DETACH, n) (ptr, handle); - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - break; - } - - *public_handle = database->public_handle; - TEXT* p = database->db_path; - memcpy(p, expanded_filename.c_str(), length); - p[length] = 0; - - database->cleanup = NULL; status[0] = isc_arg_gds; status[1] = 0; - /* Check to make sure that status[2] is not a warning. If it is, then - * the rest of the vector should be untouched. If it is not, then make - * this element isc_arg_end - * - * This cleanup is done to remove any erroneous errors from trying multiple - * protocols for a database attach - */ + /* Check to make sure that status[2] is not a warning. If it is, then + * the rest of the vector should be untouched. If it is not, then make + * this element isc_arg_end + * + * This cleanup is done to remove any erroneous errors from trying multiple + * protocols for a database attach + */ if (status[2] != isc_arg_warning) { status[2] = isc_arg_end; } - subsystem_exit(); - CHECK_STATUS_SUCCESS(status); return status[1]; } - if (ptr[1] != isc_unavailable) { + if (ptr[1] != isc_unavailable) + { ptr = temp; } } } catch(const std::exception& e) { - Firebird::stuff_exception(status, e); - SUBSYSTEM_USAGE_DECR; - return error(status, local); + if (handle) + { + CALL(PROC_DETACH, n) (temp, handle); + } + if (database) + { + delete database; + } + + Firebird::stuff_exception(status, e); } SUBSYSTEM_USAGE_DECR; - return error(status, local); + return status[1]; } @@ -893,22 +1174,21 @@ ISC_STATUS API_ROUTINE GDS_BLOB_INFO(ISC_STATUS* user_status, * Provide information on blob object. * **************************************/ - ISC_STATUS_ARRAY local; - ISC_STATUS *status; + YEntry status(user_status); + try + { + Blob* blob = translate(blob_handle); + status.setPrimaryHandle(blob); + CALL(PROC_BLOB_INFO, blob->implementation) (status, &blob->handle, + item_length, items, + buffer_length, buffer); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - GET_STATUS; - const why_hndl* blob; - TRANSLATE_HANDLE(*blob_handle, blob, HANDLE_blob, isc_bad_segstr_handle); - subsystem_enter(); - - CALL(PROC_BLOB_INFO, blob->implementation) (status, &blob->handle, - item_length, items, - buffer_length, buffer); - - if (status[1]) - return error(status, local); - - RETURN_SUCCESS; + return status[1]; } @@ -925,42 +1205,36 @@ ISC_STATUS API_ROUTINE GDS_CANCEL_BLOB(ISC_STATUS * user_status, * Abort a partially completed blob. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_BLB blob, *ptr; - WHY_ATT dbb; - - if (!*blob_handle) { - if (user_status) { + if (!*blob_handle) + { + if (user_status) + { user_status[0] = isc_arg_gds; user_status[1] = 0; user_status[2] = isc_arg_end; - CHECK_STATUS_SUCCESS(user_status); } return FB_SUCCESS; } - GET_STATUS; - TRANSLATE_HANDLE(*blob_handle, blob, HANDLE_blob, isc_bad_segstr_handle); - subsystem_enter(); + YEntry status(user_status); + try + { + Blob* blob = translate(blob_handle); + status.setPrimaryHandle(blob); - if (CALL(PROC_CANCEL_BLOB, blob->implementation) (status, &blob->handle)) - return error(status, local); - -/* Get rid of connections to database */ - - dbb = blob->parent; - - for (ptr = &dbb->blobs; *ptr; ptr = &(*ptr)->next) - if (*ptr == blob) { - *ptr = blob->next; - break; + if (! CALL(PROC_CANCEL_BLOB, blob->implementation) (status, &blob->handle)) + { + status.setPrimaryHandle(0); + delete blob; + *blob_handle = 0; } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - release_handle(blob); - *blob_handle = 0; - - RETURN_SUCCESS; + return status[1]; } @@ -978,20 +1252,21 @@ ISC_STATUS API_ROUTINE GDS_CANCEL_EVENTS(ISC_STATUS * user_status, * Try to cancel an event. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; - - GET_STATUS; - TRANSLATE_HANDLE(*handle, database, HANDLE_database, isc_bad_db_handle); - subsystem_enter(); - - if (CALL(PROC_CANCEL_EVENTS, database->implementation) (status, + YEntry status(user_status); + try + { + Attachment* database = translate(handle); + status.setPrimaryHandle(database); + CALL(PROC_CANCEL_EVENTS, database->implementation) (status, &database->handle, - id)) - return error(status, local); + id); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -1010,23 +1285,21 @@ ISC_STATUS API_ROUTINE GDS_CANCEL_OPERATION(ISC_STATUS * user_status, * Try to cancel an operation. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; - - GET_STATUS; - TRANSLATE_HANDLE(*handle, database, HANDLE_database, isc_bad_db_handle); - subsystem_enter(); - - if (CALL(PROC_CANCEL_OPERATION, database->implementation) (status, - &database-> - handle, - option)) + YEntry status(user_status); + try { - return error(status, local); + Attachment* database = translate(handle); + status.setPrimaryHandle(database); + CALL(PROC_CANCEL_OPERATION, database->implementation) (status, + &database->handle, + option); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - RETURN_SUCCESS; + return status[1]; } #endif @@ -1044,34 +1317,23 @@ ISC_STATUS API_ROUTINE GDS_CLOSE_BLOB(ISC_STATUS * user_status, * Abort a partially completed blob. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_BLB blob, *ptr; - WHY_ATT dbb; + YEntry status(user_status); + try + { + Blob* blob = translate(blob_handle); + status.setPrimaryHandle(blob); - GET_STATUS; - TRANSLATE_HANDLE(*blob_handle, blob, HANDLE_blob, isc_bad_segstr_handle); - subsystem_enter(); + CALL(PROC_CLOSE_BLOB, blob->implementation) (status, &blob->handle); + status.setPrimaryHandle(0); + delete blob; + *blob_handle = 0; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - CALL(PROC_CLOSE_BLOB, blob->implementation) (status, &blob->handle); - - if (status[1]) - return error(status, local); - -/* Get rid of connections to database */ - - dbb = blob->parent; - - for (ptr = &dbb->blobs; *ptr; ptr = &(*ptr)->next) - if (*ptr == blob) { - *ptr = blob->next; - break; - } - - release_handle(blob); - *blob_handle = 0; - - RETURN_SUCCESS; + return status[1]; } @@ -1088,60 +1350,58 @@ ISC_STATUS API_ROUTINE GDS_COMMIT(ISC_STATUS * user_status, * Commit a transaction. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction, sub; - //CLEAN clean; + YEntry status(user_status); + try + { + Transaction* transaction = translate(tra_handle); + Transaction* sub; + status.setPrimaryHandle(transaction); - GET_STATUS; - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); - -/* Handle single transaction case */ - - if (transaction->implementation != SUBSYSTEMS) { - if (CALL(PROC_COMMIT, transaction->implementation) (status, + if (transaction->implementation != SUBSYSTEMS) { + // Handle single transaction case + if (CALL(PROC_COMMIT, transaction->implementation) (status, &transaction-> handle)) - { - return error(status, local); + { + return status[1]; + } } + else { + // Handle two phase commit. Start by putting everybody into + // limbo. If anybody fails, punt + if (!(transaction->flags & HANDLE_TRANSACTION_limbo)) + { + if (prepare(status, transaction)) + { + return status[1]; + } + } + + // Everybody is in limbo, now commit everybody. + // In theory, this can't fail + + for (sub = transaction->next; sub; sub = sub->next) + { + if (CALL(PROC_COMMIT, sub->implementation) (status, &sub->handle)) + { + return status[1]; + } + } + } + + status.setPrimaryHandle(0); + while (sub = transaction) { + transaction = sub->next; + delete sub; + } + *tra_handle = 0; } - else { - /* Handle two phase commit. Start by putting everybody into - limbo. If anybody fails, punt */ - - if (!(transaction->flags & HANDLE_TRANSACTION_limbo)) - if (prepare(status, transaction)) - return error(status, local); - - /* Everybody is in limbo, now commit everybody. - In theory, this can't fail */ - - for (sub = transaction->next; sub; sub = sub->next) - if (CALL(PROC_COMMIT, sub->implementation) (status, &sub->handle)) - return error(status, local); + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - subsystem_exit(); - -/* Call the associated cleanup handlers */ - - WHY_cleanup_transaction(transaction); - //while (clean = transaction->cleanup) { - // transaction->cleanup = clean->clean_next; - // clean->TransactionRoutine(transaction, clean->clean_arg); - // free_block(clean); - //} - - while (sub = transaction) { - transaction = sub->next; - release_handle(sub); - } - *tra_handle = 0; - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -1162,23 +1422,31 @@ ISC_STATUS API_ROUTINE GDS_COMMIT_RETAINING(ISC_STATUS * user_status, * is still running. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction, sub; + YEntry status(user_status); + try + { + Transaction* transaction = translate(tra_handle); + Transaction* sub; + status.setPrimaryHandle(transaction); - GET_STATUS; - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); + for (Transaction* sub = transaction; sub; sub = sub->next) + { + if (sub->implementation != SUBSYSTEMS && + CALL(PROC_COMMIT_RETAINING, sub->implementation) (status, + &sub->handle)) + { + return status[1]; + } + } - for (sub = transaction; sub; sub = sub->next) - if (sub->implementation != SUBSYSTEMS && - CALL(PROC_COMMIT_RETAINING, sub->implementation) (status, - &sub->handle)) - return error(status, local); + transaction->flags |= HANDLE_TRANSACTION_limbo; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - transaction->flags |= HANDLE_TRANSACTION_limbo; - - RETURN_SUCCESS; + return status[1]; } @@ -1197,40 +1465,35 @@ ISC_STATUS API_ROUTINE GDS_COMPILE(ISC_STATUS* user_status, * Functional description * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT dbb; - WHY_REQ request = NULL; - - GET_STATUS; - NULL_CHECK(req_handle, isc_bad_req_handle, HANDLE_request); - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); - subsystem_enter(); - - if (CALL(PROC_COMPILE, dbb->implementation) (status, &dbb->handle, - &request, blr_length, - blr)) + YEntry status(user_status); + Attachment* dbb = 0; + StReq* rq = 0; + try { - return error(status, local); + dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + nullCheck(req_handle, isc_bad_req_handle); + + if (CALL(PROC_COMPILE, dbb->implementation) (status, &dbb->handle, + &rq, blr_length, + blr)) + { + return status[1]; + } + + new Request(rq, req_handle, dbb); + } + catch (const std::exception& e) + { + *req_handle = 0; + if (dbb && rq) + { + CALL(PROC_RELEASE_REQUEST, dbb->implementation) (status, rq); + } + Firebird::stuff_exception(status, e); } - request = allocate_handle(dbb->implementation, request, HANDLE_request); - if (!request) { - /* No memory. Make a half-hearted attempt to release request. */ - - CALL(PROC_RELEASE_REQUEST, dbb->implementation) (status, request->handle.h_why); - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error(status, local); - } - - *req_handle = request->public_handle; - request->parent = dbb; - request->next = dbb->requests; - dbb->requests = request; - - RETURN_SUCCESS; + return status[1]; } @@ -1249,15 +1512,23 @@ ISC_STATUS API_ROUTINE GDS_COMPILE2(ISC_STATUS* user_status, * Functional description * **************************************/ + Status status(user_status); + try + { + if (GDS_COMPILE(status, db_handle, req_handle, blr_length, blr)) + { + return status[1]; + } - if (GDS_COMPILE(user_status, db_handle, req_handle, blr_length, blr)) - /* Note: if user_status == NULL then GDS_COMPILE handled it */ - return user_status[1]; + Request *request = translate(req_handle); + request->user_handle = req_handle; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - WHY_REQ request = WHY_translate_handle(*req_handle); - request->user_handle = req_handle; - - return FB_SUCCESS; + return status[1]; } @@ -1327,83 +1598,63 @@ ISC_STATUS API_ROUTINE GDS_CREATE_DATABASE(ISC_STATUS* user_status, * Create a nice, squeaky clean database, uncorrupted by user data. * **************************************/ - ISC_STATUS *status, *ptr; - ISC_STATUS_ARRAY local, temp; - USHORT n, length, org_length, temp_length; - WHY_DBB database; - Firebird::PathName expanded_filename, temp_filename; -#ifdef UNIX - TEXT single_user[5]; -#endif + ISC_STATUS *ptr; + ISC_STATUS_ARRAY temp; + StAtt* handle = 0; + Attachment* database = 0; + USHORT n; - GET_STATUS; - NULL_CHECK(public_handle, isc_bad_db_handle, HANDLE_database); - if (!file_name) + YEntry status(user_status); + try { - status[0] = isc_arg_gds; - status[1] = isc_bad_db_format; - status[2] = isc_arg_string; - status[3] = (ISC_STATUS) ""; - status[4] = isc_arg_end; - return error2(status, local); - } + nullCheck(public_handle, isc_bad_db_handle); - if (dpb_length > 0 && !dpb) - { - status[0] = isc_arg_gds; - status[1] = isc_bad_dpb_form; - status[2] = isc_arg_end; - return error2(status, local); - } - -#if defined (SERVER_SHUTDOWN) && !defined (SUPERCLIENT) && !defined (REQUESTER) - if (shutdown_flag) - { - status[0] = isc_arg_gds; - status[1] = isc_shutwarn; - status[2] = isc_arg_end; - return error2(status, local); - } -#endif /* SERVER_SHUTDOWN && !SUPERCLIENT && !REQUESTER */ - - subsystem_enter(); - SUBSYSTEM_USAGE_INCR; - - try { - ptr = status; - - org_length = file_length; - - if (org_length) + if (!file_name) { - const TEXT* p = file_name + org_length - 1; - while (*p == ' ') - --p; - org_length = p - file_name + 1; + Firebird::status_exception::raise(isc_bad_db_format, + isc_arg_string, + "", + isc_arg_end); } + if (dpb_length > 0 && !dpb) + { + Firebird::status_exception::raise(isc_bad_dpb_form, + isc_arg_end); + } + +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + if (shutdown_flag) + { + Firebird::status_exception::raise(isc_shutwarn, + isc_arg_end); + } +#endif /* !SUPERCLIENT && !REQUESTER */ + + SUBSYSTEM_USAGE_INCR; + + ptr = status; + /* copy the file name to a temp buffer, since some of the following utilities can modify it */ - if (org_length) - temp_length = org_length; - else - temp_length = strlen(file_name); - - temp_filename.assign(file_name, temp_length); + Firebird::PathName temp_filename(file_name, + file_length ? file_length : strlen(file_name)); + temp_filename.rtrim(); + file_length = temp_filename.length(); + Firebird::PathName expanded_filename; if (!ISC_check_if_remote(temp_filename, true)) { - Firebird::PathName database; - if (ResolveDatabaseAlias(temp_filename, database)) + Firebird::PathName database_filename; + if (ResolveDatabaseAlias(temp_filename, database_filename)) { - ISC_expand_filename(database, false); - expanded_filename = database; + ISC_expand_filename(database_filename, false); + expanded_filename = database_filename; } else if (iscSetPath(temp_filename, expanded_filename)) { temp_filename = expanded_filename; - org_length = temp_filename.length(); } else { @@ -1425,66 +1676,32 @@ ISC_STATUS API_ROUTINE GDS_CREATE_DATABASE(ISC_STATUS* user_status, for (n = 0; n < SUBSYSTEMS; n++) { if (why_enabled && !(why_enabled & (1 << n))) + { continue; - WHY_ATT handle = NULL; - if (!CALL(PROC_CREATE_DATABASE, n) (ptr, org_length, temp_filename.c_str(), + } + if (!CALL(PROC_CREATE_DATABASE, n) (ptr, temp_filename.length(), temp_filename.c_str(), &handle, newDpb.getBufferLength(), reinterpret_cast(newDpb.getBuffer()), 0, expanded_filename.c_str())) { #ifdef WIN_NT - /* Now we can expand, the file exists. */ + /* Now we can expand, the file exists. */ expanded_filename = temp_filename; - ISC_expand_filename (expanded_filename, true); - length = expanded_filename.length(); -#else - length = org_length; - if (!length) - { - length = temp_filename.length(); - } + ISC_expand_filename (expanded_filename, true); #endif - database = allocate_handle(n, handle, HANDLE_database); - if (database) - { - database->db_path = (TEXT *) alloc((SLONG) (length + 1)); - } - if (!database || !database->db_path) - { - /* No memory. Make a half-hearted to drop database. The - database was successfully created but the user wouldn't - be able to tell. */ - - if (database) - release_handle(database); - CALL(PROC_DROP_DATABASE, n) (ptr, handle); - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - break; - } - - fb_assert(database); - fb_assert(database->db_path); - - *public_handle = database->public_handle; - TEXT* p = database->db_path; - + database = new Attachment(handle, public_handle, n); #ifdef WIN_NT - memcpy(p, expanded_filename.c_str(), length); + database->db_path = expanded_filename; #else - memcpy(p, temp_filename.c_str(), length); + database->db_path = temp_filename; #endif - p[length] = 0; - database->cleanup = NULL; status[0] = isc_arg_gds; status[1] = 0; if (status[2] != isc_arg_warning) status[2] = isc_arg_end; - subsystem_exit(); - CHECK_STATUS_SUCCESS(status); + return status[1]; } if (ptr[1] != isc_unavailable) @@ -1494,18 +1711,24 @@ ISC_STATUS API_ROUTINE GDS_CREATE_DATABASE(ISC_STATUS* user_status, catch(const std::exception& e) { Firebird::stuff_exception(status, e); - SUBSYSTEM_USAGE_DECR; - return error(status, local); + if (handle) + { + CALL(PROC_DROP_DATABASE, n) (temp, handle); + } + if (database) + { + delete database; + } } SUBSYSTEM_USAGE_DECR; - return error(status, local); + return status[1]; } ISC_STATUS API_ROUTINE isc_database_cleanup(ISC_STATUS * user_status, FB_API_HANDLE * handle, - DatabaseCleanupRoutine * routine, + AttachmentCleanupRoutine * routine, void* arg) { /************************************** @@ -1518,31 +1741,20 @@ ISC_STATUS API_ROUTINE isc_database_cleanup(ISC_STATUS * user_status, * Register a database specific cleanup handler. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; - CLEAN clean; + YEntry status(user_status); + try + { + Attachment* database = translate(handle); + status.setPrimaryHandle(database); - GET_STATUS; - TRANSLATE_HANDLE(*handle, database, HANDLE_database, isc_bad_db_handle); - - if (!(clean = (CLEAN) alloc((SLONG) sizeof(struct clean)))) { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); + database->cleanup.add(routine, arg); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - clean->clean_next = database->cleanup; - database->cleanup = clean; - clean->DatabaseRoutine = routine; - clean->clean_arg = arg; - - status[0] = isc_arg_gds; - status[1] = 0; - status[2] = isc_arg_end; - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -1563,25 +1775,24 @@ ISC_STATUS API_ROUTINE GDS_DATABASE_INFO(ISC_STATUS* user_status, * Provide information on database object. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; - - GET_STATUS; - TRANSLATE_HANDLE(*handle, database, HANDLE_database, isc_bad_db_handle); - subsystem_enter(); - - if (CALL(PROC_DATABASE_INFO, database->implementation) (status, + YEntry status(user_status); + try + { + Attachment* database = translate(handle); + status.setPrimaryHandle(database); + CALL(PROC_DATABASE_INFO, database->implementation) (status, &database->handle, item_length, items, buffer_length, - buffer)) - { - return error(status, local); + buffer); } - - RETURN_SUCCESS; + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } + + return status[1]; } @@ -1601,52 +1812,24 @@ ISC_STATUS API_ROUTINE GDS_DDL(ISC_STATUS* user_status, * Do meta-data update. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; - WHY_TRA transaction; - - GET_STATUS; - TRANSLATE_HANDLE(*db_handle, database, HANDLE_database, isc_bad_db_handle); - FIND_TRANSACTION(*tra_handle, transaction, database, isc_bad_trans_handle); - subsystem_enter(); - - if (get_entrypoint(PROC_DDL, database->implementation) != no_entrypoint) + YEntry status(user_status); + try { - if (!CALL(PROC_DDL, database->implementation) (status, - &database->handle, - &transaction->handle, - length, ddl)) - { - RETURN_SUCCESS; - } - if (status[1] != isc_unavailable) - { - return error(status, local); - } + Attachment* database = translate(db_handle); + status.setPrimaryHandle(database); + Transaction* transaction = findTransaction(tra_handle, database); + + CALL(PROC_DDL, database->implementation) (status, + &database->handle, + &transaction->handle, + length, ddl); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - subsystem_exit(); - -/* Assume that we won't find an entrypoint to call. */ - - no_entrypoint(status); - -#ifndef SUPERCLIENT - PTR entrypoint; - const TEXT* image = images[database->implementation].path; - if (image != NULL && - ((entrypoint = (PTR) Jrd::Module::lookup(image, "DYN_ddl")) != - NULL || - FALSE) && - !((*entrypoint) (status, db_handle, tra_handle, length, ddl))) - { - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; - } -#endif - - return error2(status, local); + return status[1]; } @@ -1663,109 +1846,71 @@ ISC_STATUS API_ROUTINE GDS_DETACH(ISC_STATUS * user_status, * Close down a database. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; - WHY_BLB blob; - //CLEAN clean; - - GET_STATUS; - - WHY_ATT dbb; - -#ifdef WIN_NT -/* This code was added to fix an IDAPI problem where our DLL exit handler - * was getting called before theirs. Our exit handler frees the attachment - * but does not NULL the handle. Their exit handler trys to detach, causing - * a GPF. - * We should check with IDAPI periodically to see if we still need this. - */ - -// 02-May-2004, Nickolay Samofatov. We really need to check if BDE still -// needs this junk and how exactly problem looks like. I disable the code -// for now because handleMapping provides means for reliable detection of -// bad handles, no tricks are needed. -// -// if (IsBadReadPtr(handle, sizeof(FB_API_HANDLE))) -// return bad_handle(user_status, isc_bad_db_handle); -#endif /* WIN_NT */ - - TRANSLATE_HANDLE(*handle, dbb, HANDLE_database, isc_bad_db_handle); + YEntry status(user_status); + try + { + Attachment* dbb = translate(handle); + size_t i; #if defined(SUPERSERVER) && !defined(EMBEDDED) -/* Drop all DSQL statements to reclaim DSQL memory pools. */ + // Drop all DSQL statements to reclaim DSQL memory pools. - WHY_STMT statement; - while (statement = dbb->statements) { - FB_API_HANDLE temp_handle; + while ((i = dbb->statements.getCount())) + { + FB_API_HANDLE temp_handle; + Statement* statement = dbb->statements[i - 1]; + if (!statement->user_handle) { + temp_handle = statement->public_handle; + statement->user_handle = &temp_handle; + } - if (!statement->user_handle) { - temp_handle = statement->public_handle; - statement->user_handle = &temp_handle; + subsystem_exit(); + ISC_STATUS rc = GDS_DSQL_FREE(status, statement->user_handle, DSQL_drop); + subsystem_enter(); + + if (rc) + { + return status[1]; + } } - - if (GDS_DSQL_FREE(status, statement->user_handle, DSQL_drop)) - return error2(status, local); - } #endif - subsystem_enter(); - if (CALL(PROC_DETACH, dbb->implementation) (status, &dbb->handle)) - return error(status, local); + if (CALL(PROC_DETACH, dbb->implementation) (status, &dbb->handle)) + return status[1]; -/* Release associated request handles */ + // Release associated request handles - if (dbb->db_path) - free_block(dbb->db_path); - - while (request = dbb->requests) { - dbb->requests = request->next; - if (request->user_handle) - *request->user_handle = 0; - release_handle(request); - } + while ((i = dbb->requests.getCount())) + { + delete dbb->requests[i - 1]; + } #ifndef SUPERSERVER - WHY_STMT statement; - while (statement = dbb->statements) { - dbb->statements = statement->next; - if (statement->user_handle) { - *statement->user_handle = 0; + while ((i = dbb->statements.getCount())) + { + release_dsql_support(dbb->statements[i - 1]->das); + delete dbb->statements[i - 1]; } - release_dsql_support(statement->das); - release_handle(statement); - } #endif - while (blob = dbb->blobs) { - dbb->blobs = blob->next; - if (blob->user_handle) - *blob->user_handle = 0; - release_handle(blob); + while ((i = dbb->blobs.getCount())) + { + delete dbb->blobs[i - 1]; + } + + SUBSYSTEM_USAGE_DECR; + + delete dbb; + *handle = 0; } - - SUBSYSTEM_USAGE_DECR; - subsystem_exit(); - -/* Call the associated cleanup handlers */ - - // Obviously, this code can't be replaced by WHY_cleanup_transaction! - // But this requires changes in database and transaction cleanup - // routines first parameter. - for (clean* cln = dbb->cleanup; cln; cln = dbb->cleanup) + catch (const std::exception& e) { - dbb->cleanup = cln->clean_next; - cln->DatabaseRoutine(handle, cln->clean_arg); - free_block(cln); + Firebird::stuff_exception(status, e); } - release_handle(dbb); - *handle = 0; - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -1810,90 +1955,72 @@ ISC_STATUS API_ROUTINE GDS_DROP_DATABASE(ISC_STATUS * user_status, * Close down a database and then purge it. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; - WHY_BLB blob; - CLEAN clean; - - GET_STATUS; - WHY_ATT dbb; - TRANSLATE_HANDLE(*handle, dbb, HANDLE_database, isc_bad_db_handle); + YEntry status(user_status); + try + { + Attachment* dbb = translate(handle); + size_t i; #if defined(SUPERSERVER) && !defined(EMBEDDED) -/* Drop all DSQL statements to reclaim DSQL memory pools. */ + // Drop all DSQL statements to reclaim DSQL memory pools. - WHY_STMT statement; - while (statement = dbb->statements) { - FB_API_HANDLE temp_handle; + while ((i = dbb->statements.getCount())) + { + FB_API_HANDLE temp_handle; + Statement* statement = dbb->statements[i - 1]; + if (!statement->user_handle) { + temp_handle = statement->public_handle; + statement->user_handle = &temp_handle; + } - if (!statement->user_handle) { - temp_handle = statement->public_handle; - statement->user_handle = &temp_handle; + subsystem_exit(); + ISC_STATUS rc = GDS_DSQL_FREE(status, statement->user_handle, DSQL_drop); + subsystem_enter(); + + if (rc) + { + return status[1]; + } } - - if (GDS_DSQL_FREE(status, statement->user_handle, DSQL_drop)) - return error2(status, local); - } #endif - subsystem_enter(); - - (CALL(PROC_DROP_DATABASE, dbb->implementation) (status, &dbb->handle)); + CALL(PROC_DROP_DATABASE, dbb->implementation) (status, &dbb->handle); if (status[1] && (status[1] != isc_drdb_completed_with_errs)) - return error(status, local); + return status[1]; -/* Release associated request handles */ + // Release associated request handles - if (dbb->db_path) - free_block(dbb->db_path); - - while (request = dbb->requests) { - dbb->requests = request->next; - if (request->user_handle) - *request->user_handle = 0; - release_handle(request); - } + while ((i = dbb->requests.getCount())) + { + delete dbb->requests[i - 1]; + } #ifndef SUPERSERVER - WHY_STMT statement; - while (statement = dbb->statements) { - dbb->statements = statement->next; - if (statement->user_handle) - *statement->user_handle = 0; - release_dsql_support(statement->das); - release_handle(statement); - } + while ((i = dbb->statements.getCount())) + { + release_dsql_support(dbb->statements[i - 1]->das); + delete dbb->statements[i - 1]; + } #endif - while (blob = dbb->blobs) { - dbb->blobs = blob->next; - if (blob->user_handle) - *blob->user_handle = 0; - release_handle(blob); + while ((i = dbb->blobs.getCount())) + { + delete dbb->blobs[i - 1]; + } + + SUBSYSTEM_USAGE_DECR; + + delete dbb; + *handle = 0; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - SUBSYSTEM_USAGE_DECR; - subsystem_exit(); - -/* Call the associated cleanup handlers */ - - while ((clean = dbb->cleanup) != NULL) { - dbb->cleanup = clean->clean_next; - clean->DatabaseRoutine(handle, clean->clean_arg); - free_block(clean); - } - - release_handle(dbb); - *handle = 0; - - if (status[1]) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -1925,14 +2052,23 @@ ISC_STATUS API_ROUTINE GDS_DSQL_ALLOC2(ISC_STATUS * user_status, * Allocate a statement handle. * **************************************/ + Status status(user_status); + try + { + if (GDS_DSQL_ALLOCATE(user_status, db_handle, stmt_handle)) + { + return status[1]; + } - if (GDS_DSQL_ALLOCATE(user_status, db_handle, stmt_handle)) - return user_status[1]; + Statement *statement = translate(stmt_handle); + statement->user_handle = stmt_handle; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - WHY_STMT statement = WHY_translate_handle(*stmt_handle); - statement->user_handle = stmt_handle; - - return FB_SUCCESS; + return status[1]; } @@ -1950,16 +2086,17 @@ ISC_STATUS API_ROUTINE GDS_DSQL_ALLOCATE(ISC_STATUS * user_status, * Allocate a statement handle. * **************************************/ - ISC_STATUS* status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - GET_STATUS; + YEntry status(user_status); + Attachment* dbb = 0; + StStm* stmt_handle = 0; + UCHAR flag = 0; -/* check the statement handle to make sure it's NULL and then initialize it. */ - - NULL_CHECK(public_stmt_handle, isc_bad_stmt_handle, HANDLE_statement); - WHY_ATT dbb; - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); + try + { + dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + // check the statement handle to make sure it's NULL and then initialize it. + nullCheck(public_stmt_handle, isc_bad_stmt_handle); /* Attempt to have the implementation which processed the database attach process the allocate statement. This may not be feasible (e.g., the @@ -1967,68 +2104,48 @@ ISC_STATUS API_ROUTINE GDS_DSQL_ALLOCATE(ISC_STATUS * user_status, something) in which case, execute the functionality locally (and hence remotely through the original Y-valve). */ - ISC_STATUS s = isc_unavailable; - WHY_STMT stmt_handle = NULL; - PTR entry = get_entrypoint(PROC_DSQL_ALLOCATE, dbb->implementation); - if (entry != no_entrypoint) { - subsystem_enter(); - s = (*entry) (status, &dbb->handle, &stmt_handle); - subsystem_exit(); + ISC_STATUS s = isc_unavailable; + PTR entry = get_entrypoint(PROC_DSQL_ALLOCATE, dbb->implementation); + if (entry != no_entrypoint) + { + s = (*entry) (status, &dbb->handle, &stmt_handle); + } + +#ifndef NO_LOCAL_DSQL + if (s == isc_unavailable) { + // if the entry point didn't exist or if the routine said the server + // didn't support the protocol... do it locally + + flag = HANDLE_STATEMENT_local; + s = dsql8_allocate_statement(status, db_handle, &stmt_handle); + } +#endif + + if (status[1]) + { + return status[1]; + } + + Statement* statement = new Statement(stmt_handle, public_stmt_handle, dbb); + statement->flags = flag; } - UCHAR flag = 0; + catch (const std::exception& e) + { + *public_stmt_handle = 0; + if (dbb && stmt_handle) + { #ifndef NO_LOCAL_DSQL - dsql_req* dstatement = 0; - if (s == isc_unavailable) { - /* if the entry point didn't exist or if the routine said the server - didn't support the protocol... do it locally */ - - flag = HANDLE_STATEMENT_local; - - subsystem_enter(); - s = dsql8_allocate_statement(status, db_handle, &dstatement); - subsystem_exit(); - } + if (flag & HANDLE_STATEMENT_local) + dsql8_free_statement(status, &stmt_handle, DSQL_drop); + else #endif - - if (status[1]) - return error2(status, local); - - statement = -#ifndef NO_LOCAL_DSQL - (flag & HANDLE_STATEMENT_local) ? - allocate_handle(dbb->implementation, dstatement, HANDLE_statement) : -#endif - allocate_handle(dbb->implementation, stmt_handle, HANDLE_statement); - - if (!statement) { - /* No memory. Make a half-hearted attempt to drop statement. */ - - subsystem_enter(); - -#ifndef NO_LOCAL_DSQL - if (flag & HANDLE_STATEMENT_local) - dsql8_free_statement(status, &dstatement, DSQL_drop); - else -#endif - CALL(PROC_DSQL_FREE, dbb->implementation) (status, stmt_handle, + CALL(PROC_DSQL_FREE, dbb->implementation) (status, stmt_handle, DSQL_drop); - - subsystem_exit(); - - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); + } + Firebird::stuff_exception(status, e); } - *public_stmt_handle = statement->public_handle; - statement->parent = dbb; - statement->next = dbb->statements; - dbb->statements = statement; - statement->flags = flag; - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -2047,49 +2164,36 @@ ISC_STATUS API_ROUTINE isc_dsql_describe(ISC_STATUS * user_status, * Describe output parameters for a prepared statement. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - USHORT buffer_len; - SCHAR *buffer, local_buffer[512]; - - GET_STATUS; - - if (!(buffer = get_sqlda_buffer(local_buffer, sizeof(local_buffer), sqlda, - dialect, &buffer_len))) + Status status(user_status); + try { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); - } + Firebird::HalfStaticArray local_buffer; + USHORT buffer_len = sqlda_buffer_size(sqlda, dialect); + SCHAR *buffer = local_buffer.getBuffer(buffer_len); - if (!GDS_DSQL_SQL_INFO( status, - stmt_handle, - sizeof(describe_select_info), - describe_select_info, - buffer_len, - buffer)) + if (!GDS_DSQL_SQL_INFO( status, + stmt_handle, + sizeof(describe_select_info), + describe_select_info, + buffer_len, + buffer)) + { + iterative_sql_info( status, + stmt_handle, + sizeof(describe_select_info), + describe_select_info, + buffer_len, + buffer, + dialect, + sqlda); + } + } + catch (const std::exception& e) { - iterative_sql_info( status, - stmt_handle, - sizeof(describe_select_info), - describe_select_info, - buffer_len, - buffer, - dialect, - sqlda); + Firebird::stuff_exception(status, e); } - if (buffer != local_buffer) { - free_block(buffer); - } - - if (status[1]) { - return error2(status, local); - } - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -2108,49 +2212,36 @@ ISC_STATUS API_ROUTINE isc_dsql_describe_bind(ISC_STATUS * user_status, * Describe input parameters for a prepared statement. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - USHORT buffer_len; - SCHAR *buffer, local_buffer[512]; - - GET_STATUS; - - if (!(buffer = get_sqlda_buffer(local_buffer, sizeof(local_buffer), sqlda, - dialect, &buffer_len))) + Status status(user_status); + try { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); - } + Firebird::HalfStaticArray local_buffer; + USHORT buffer_len = sqlda_buffer_size(sqlda, dialect); + SCHAR *buffer = local_buffer.getBuffer(buffer_len); - if (!GDS_DSQL_SQL_INFO( status, - stmt_handle, - sizeof(describe_bind_info), - describe_bind_info, - buffer_len, - buffer)) + if (!GDS_DSQL_SQL_INFO( status, + stmt_handle, + sizeof(describe_bind_info), + describe_bind_info, + buffer_len, + buffer)) + { + iterative_sql_info( status, + stmt_handle, + sizeof(describe_bind_info), + describe_bind_info, + buffer_len, + buffer, + dialect, + sqlda); + } + } + catch (const std::exception& e) { - iterative_sql_info( status, - stmt_handle, - sizeof(describe_bind_info), - describe_bind_info, - buffer_len, - buffer, - dialect, - sqlda); + Firebird::stuff_exception(status, e); } - if (buffer != local_buffer) { - free_block(buffer); - } - - if (status[1]) { - return error2(status, local); - } - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -2193,55 +2284,58 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXECUTE2(ISC_STATUS* user_status, * Execute a non-SELECT dynamic SQL statement. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - USHORT in_blr_length, in_msg_type, in_msg_length, - out_blr_length, out_msg_type, out_msg_length; - sqlda_sup* dasup; + Status status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - if (! (dasup = statement->das)) - return bad_handle(user_status, isc_unprepared_stmt); - - if (UTLD_parse_sqlda(status, dasup, &in_blr_length, &in_msg_type, - &in_msg_length, dialect, in_sqlda, - DASUP_CLAUSE_bind)) + try { - return error2(status, local); - } + USHORT in_blr_length, in_msg_type, in_msg_length, + out_blr_length, out_msg_type, out_msg_length; + + Statement* statement = translate(stmt_handle); + + sqlda_sup* dasup = &(statement->das); + statement->checkPrepared(); + + if (UTLD_parse_sqlda(status, dasup, &in_blr_length, &in_msg_type, + &in_msg_length, dialect, in_sqlda, + DASUP_CLAUSE_bind)) + { + return status[1]; + } - if (UTLD_parse_sqlda - (status, dasup, &out_blr_length, &out_msg_type, &out_msg_length, - dialect, out_sqlda, DASUP_CLAUSE_select)) + if (UTLD_parse_sqlda + (status, dasup, &out_blr_length, &out_msg_type, &out_msg_length, + dialect, out_sqlda, DASUP_CLAUSE_select)) + { + return status[1]; + } + + if (GDS_DSQL_EXECUTE2_M(status, tra_handle, stmt_handle, + in_blr_length, + dasup->dasup_clauses[DASUP_CLAUSE_bind].dasup_blr, + in_msg_type, in_msg_length, + dasup->dasup_clauses[DASUP_CLAUSE_bind].dasup_msg, + out_blr_length, + dasup->dasup_clauses[DASUP_CLAUSE_select]. + dasup_blr, out_msg_type, out_msg_length, + dasup->dasup_clauses[DASUP_CLAUSE_select]. + dasup_msg)) + { + return status[1]; + } + + if (UTLD_parse_sqlda(status, dasup, NULL, NULL, NULL, + dialect, out_sqlda, DASUP_CLAUSE_select)) + { + return status[1]; + } + } + catch (const std::exception& e) { - return error2(status, local); + Firebird::stuff_exception(status, e); } - if (GDS_DSQL_EXECUTE2_M(status, tra_handle, stmt_handle, - in_blr_length, - dasup->dasup_clauses[DASUP_CLAUSE_bind].dasup_blr, - in_msg_type, in_msg_length, - dasup->dasup_clauses[DASUP_CLAUSE_bind].dasup_msg, - out_blr_length, - dasup->dasup_clauses[DASUP_CLAUSE_select]. - dasup_blr, out_msg_type, out_msg_length, - dasup->dasup_clauses[DASUP_CLAUSE_select]. - dasup_msg)) - { - return error2(status, local); - } - - if (UTLD_parse_sqlda(status, dasup, NULL, NULL, NULL, - dialect, out_sqlda, DASUP_CLAUSE_select)) - { - return error2(status, local); - } - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -2295,104 +2389,82 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXECUTE2_M(ISC_STATUS* user_status, * Execute a non-SELECT dynamic SQL statement. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - WHY_TRA transaction = NULL, handle = NULL; - PTR entry; - //CLEAN clean; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - if (*tra_handle) - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); + status.setPrimaryHandle(statement); + Transaction* transaction = 0; + if (*tra_handle) + { + transaction = translate(tra_handle); + } + StTra *handle = 0; + PTR entry; #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) { - subsystem_enter(); - dsql8_execute(status, tra_handle, &statement->handle.h_dsql, + if (statement->flags & HANDLE_STATEMENT_local) { + dsql8_execute(status, tra_handle, &statement->handle, in_blr_length, in_blr, in_msg_type, in_msg_length, in_msg, out_blr_length, out_blr, out_msg_type, out_msg_length, out_msg); - subsystem_exit(); - } - else -#endif - { - if (transaction) { - handle = find_transaction(statement->parent, transaction); - if (!handle) - return bad_handle (user_status, isc_bad_trans_handle); - handle = handle->handle.h_why; } - subsystem_enter(); - entry = get_entrypoint(PROC_DSQL_EXECUTE2, statement->implementation); - if (entry != no_entrypoint && - (*entry) (status, - &handle, - &statement->handle, - in_blr_length, - in_blr, - in_msg_type, - in_msg_length, - in_msg, - out_blr_length, - out_blr, - out_msg_type, - out_msg_length, out_msg) != isc_unavailable); - else if (!out_blr_length && !out_msg_type && !out_msg_length) - CALL(PROC_DSQL_EXECUTE, statement->implementation) (status, - &handle, - &statement-> - handle, - in_blr_length, - in_blr, - in_msg_type, - in_msg_length, - in_msg); else - no_entrypoint(status); - subsystem_exit(); - - if (!status[1]) +#endif { - if (transaction && !handle) { - /* Call the associated cleanup handlers */ - - WHY_cleanup_transaction(transaction); - //while (clean = transaction->cleanup) { - // transaction->cleanup = clean->clean_next; - // clean->TransactionRoutine(transaction, clean->clean_arg); - // free_block(clean); - //} - - release_handle(transaction); - *tra_handle = 0; - } - else if (!transaction && handle) - { - transaction = allocate_handle( statement->implementation, - handle, - HANDLE_transaction); - if (transaction) { - transaction->parent = statement->parent; - *tra_handle = transaction->public_handle; + if (transaction) { + Transaction *t = find_transaction(statement->parent, transaction); + if (!t) + { + bad_handle(isc_bad_trans_handle); } - else { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; + handle = t->handle; + } + entry = get_entrypoint(PROC_DSQL_EXECUTE2, statement->implementation); + if (entry != no_entrypoint && + (*entry) (status, + &handle, + &statement->handle, + in_blr_length, + in_blr, + in_msg_type, + in_msg_length, + in_msg, + out_blr_length, + out_blr, + out_msg_type, + out_msg_length, out_msg) != isc_unavailable); + else if (!out_blr_length && !out_msg_type && !out_msg_length) + CALL(PROC_DSQL_EXECUTE, statement->implementation) (status, + &handle, + &statement->handle, + in_blr_length, + in_blr, + in_msg_type, + in_msg_length, + in_msg); + else + no_entrypoint(status); + + if (!status[1]) + { + if (transaction && !handle) { + delete transaction; + *tra_handle = 0; + } + else if (!transaction && handle) + { + transaction = new Transaction(handle, tra_handle, statement->parent); } } } } - - if (status[1]) { - return error2(status, local); + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -2463,59 +2535,54 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXEC_IMMED2(ISC_STATUS* user_status, * Prepare a statement for execution. * **************************************/ - ISC_STATUS s, *status; - ISC_STATUS_ARRAY local; - USHORT in_blr_length, in_msg_type, in_msg_length, - out_blr_length, out_msg_type, out_msg_length; + Status status(user_status); + ISC_STATUS s = 0; sqlda_sup dasup; - - GET_STATUS; - memset(&dasup, 0, sizeof(sqlda_sup)); - if (UTLD_parse_sqlda(status, &dasup, &in_blr_length, &in_msg_type, - &in_msg_length, dialect, in_sqlda, - DASUP_CLAUSE_bind)) + + try { - return error2(status, local); - } + USHORT in_blr_length, in_msg_type, in_msg_length, + out_blr_length, out_msg_type, out_msg_length; + + if (UTLD_parse_sqlda(status, &dasup, &in_blr_length, &in_msg_type, + &in_msg_length, dialect, in_sqlda, + DASUP_CLAUSE_bind)) + { + return status[1]; + } - if (UTLD_parse_sqlda - (status, &dasup, &out_blr_length, &out_msg_type, &out_msg_length, - dialect, out_sqlda, DASUP_CLAUSE_select)) - { - return error2(status, local); - } + if (UTLD_parse_sqlda + (status, &dasup, &out_blr_length, &out_msg_type, &out_msg_length, + dialect, out_sqlda, DASUP_CLAUSE_select)) + { + return status[1]; + } - s = GDS_DSQL_EXEC_IMM2_M(status, db_handle, tra_handle, - length, string, dialect, - in_blr_length, - dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_blr, - in_msg_type, in_msg_length, - dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_msg, - out_blr_length, - dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_blr, - out_msg_type, out_msg_length, - dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_msg); - if (!s) - { - s = UTLD_parse_sqlda(status, &dasup, NULL, NULL, NULL, dialect, + s = GDS_DSQL_EXEC_IMM2_M(status, db_handle, tra_handle, + length, string, dialect, + in_blr_length, + dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_blr, + in_msg_type, in_msg_length, + dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_msg, + out_blr_length, + dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_blr, + out_msg_type, out_msg_length, + dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_msg); + status.ok(); + if (!s) + { + s = UTLD_parse_sqlda(status, &dasup, NULL, NULL, NULL, dialect, out_sqlda, DASUP_CLAUSE_select); + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + s = status[1]; } - if (dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_blr) - gds__free((SLONG *) - (dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_blr)); - if (dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_msg) - gds__free((SLONG *) - (dasup.dasup_clauses[DASUP_CLAUSE_bind].dasup_msg)); - if (dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_blr) - gds__free((SLONG *) - (dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_blr)); - if (dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_msg) - gds__free((SLONG *) - (dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_msg)); - - CHECK_STATUS(status); + release_dsql_support(dasup); return s; } @@ -2605,13 +2672,7 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXEC_IMM2_M(ISC_STATUS* user_status, * Prepare a statement for execution. * **************************************/ - FB_API_HANDLE crdb_trans_handle; - ISC_STATUS_ARRAY local, temp_status; - SCHAR buffer[16]; - BOOLEAN ret_v3_error; - - ISC_STATUS* status; - GET_STATUS; + Status status(user_status); bool stmt_eaten; if (PREPARSE_execute( status, @@ -2623,23 +2684,27 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXEC_IMM2_M(ISC_STATUS* user_status, dialect)) { if (status[1]) - return error2(status, local); + { + return status[1]; + } - crdb_trans_handle = 0; + ISC_STATUS_ARRAY temp_status; + FB_API_HANDLE crdb_trans_handle = 0; if (GDS_START_TRANSACTION(status, &crdb_trans_handle, 1, db_handle, 0, 0)) { save_error_string(status); GDS_DROP_DATABASE(temp_status, db_handle); *db_handle = 0; - return error2(status, local); + return status[1]; } - ret_v3_error = FALSE; + BOOLEAN ret_v3_error = FALSE; if (!stmt_eaten) { /* Check if against < 4.0 database */ const SCHAR ch = isc_info_base_level; + SCHAR buffer[16]; if (!GDS_DATABASE_INFO(status, db_handle, 1, &ch, sizeof(buffer), buffer)) { @@ -2661,35 +2726,33 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXEC_IMM2_M(ISC_STATUS* user_status, save_error_string(status); GDS_DROP_DATABASE(temp_status, db_handle); *db_handle = 0; - return error2(status, local); + return status[1]; } - else { - if (GDS_COMMIT(status, &crdb_trans_handle)) { - GDS_ROLLBACK(temp_status, &crdb_trans_handle); - save_error_string(status); - GDS_DROP_DATABASE(temp_status, db_handle); - *db_handle = 0; - return error2(status, local); - } + + if (GDS_COMMIT(status, &crdb_trans_handle)) { + GDS_ROLLBACK(temp_status, &crdb_trans_handle); + save_error_string(status); + GDS_DROP_DATABASE(temp_status, db_handle); + *db_handle = 0; + return status[1]; } if (ret_v3_error) { - ISC_STATUS* s = status; - *s++ = isc_arg_gds; - *s++ = isc_srvr_version_too_old; - *s = isc_arg_end; - return error2(status, local); + status[0] = isc_arg_gds; + status[1] = isc_srvr_version_too_old; + status[2] = isc_arg_end; + return status[1]; } - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + + return status[1]; } - else - return GDS_DSQL_EXEC_IMM3_M(user_status, db_handle, tra_handle, - length, string, dialect, - in_blr_length, in_blr, in_msg_type, - in_msg_length, in_msg, out_blr_length, - out_blr, out_msg_type, out_msg_length, - out_msg); + + return GDS_DSQL_EXEC_IMM3_M(user_status, db_handle, tra_handle, + length, string, dialect, + in_blr_length, in_blr, in_msg_type, + in_msg_length, in_msg, out_blr_length, + out_blr, out_msg_type, out_msg_length, + out_msg); } @@ -2720,25 +2783,25 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXEC_IMM3_M(ISC_STATUS* user_status, * Prepare a statement for execution. * **************************************/ - ISC_STATUS s, *status; - ISC_STATUS_ARRAY local; - WHY_ATT dbb; - WHY_TRA transaction = NULL, handle = NULL; - PTR entry; - //CLEAN clean; + YEntry status(user_status); + try + { + Attachment* dbb = translate(db_handle); + status.setPrimaryHandle(dbb); -/* If we haven't been initialized yet, do it now */ + Transaction* transaction = 0; + StTra* handle = 0; - GET_STATUS; - - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); - if (*tra_handle) { - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - handle = find_transaction(dbb, transaction); - if (!handle) - return bad_handle (user_status, isc_bad_trans_handle); - handle = handle->handle.h_why; - } + if (*tra_handle) + { + transaction = find_transaction(dbb, translate(tra_handle)); + Transaction* t = find_transaction(dbb, transaction); + if (!t) + { + bad_handle(isc_bad_trans_handle); + } + handle = t->handle; + } /* Attempt to have the implementation which processed the database attach process the prepare statement. This may not be feasible (e.g., the @@ -2746,92 +2809,59 @@ ISC_STATUS API_ROUTINE GDS_DSQL_EXEC_IMM3_M(ISC_STATUS* user_status, something) in which case, execute the functionality locally (and hence remotely through the original Y-valve). */ - s = isc_unavailable; - entry = get_entrypoint(PROC_DSQL_EXEC_IMMED2, dbb->implementation); - if (entry != no_entrypoint) { - subsystem_enter(); - s = (*entry) (status, - &dbb->handle, - &handle, - length, - string, - dialect, - in_blr_length, - in_blr, - in_msg_type, - in_msg_length, - in_msg, - out_blr_length, - out_blr, out_msg_type, out_msg_length, out_msg); - subsystem_exit(); - } - - if (s == isc_unavailable && !out_msg_length) { - entry = get_entrypoint(PROC_DSQL_EXEC_IMMED, dbb->implementation); - if (entry != no_entrypoint) - { - subsystem_enter(); - s = (*entry) (status, - &dbb->handle, - &handle, - length, - string, - dialect, - in_blr_length, - in_blr, in_msg_type, in_msg_length, in_msg); - subsystem_exit(); + ISC_STATUS s = isc_unavailable; + PTR entry = get_entrypoint(PROC_DSQL_EXEC_IMMED2, dbb->implementation); + if (entry != no_entrypoint) { + s = (*entry) (status, &dbb->handle, &handle, + length, string, dialect, + in_blr_length, in_blr, + in_msg_type, in_msg_length, in_msg, + out_blr_length, out_blr, + out_msg_type, out_msg_length, out_msg); } - } - if (s != isc_unavailable && !status[1]) - if (transaction && !handle) { - /* Call the associated cleanup handlers */ - - WHY_cleanup_transaction(transaction); - //while (clean = transaction->cleanup) { - // transaction->cleanup = clean->clean_next; - // clean->TransactionRoutine(transaction, clean->clean_arg); - // free_block(clean); - //} - - release_handle(transaction); - *tra_handle = 0; - } - else if (!transaction && handle) { - transaction = allocate_handle(dbb->implementation, handle, HANDLE_transaction); - if (transaction) { - transaction->parent = dbb; - *tra_handle = transaction->public_handle; + if (s == isc_unavailable && !out_msg_length) { + entry = get_entrypoint(PROC_DSQL_EXEC_IMMED, dbb->implementation); + if (entry != no_entrypoint) + { + s = (*entry) (status, &dbb->handle, &handle, + length, string, dialect, + in_blr_length, in_blr, + in_msg_type, in_msg_length, in_msg); } - else { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); + } + + if (s != isc_unavailable && !status[1]) + { + if (transaction && !handle) { + delete transaction; + *tra_handle = 0; + } + else if (!transaction && handle) { + transaction = new Transaction(handle, tra_handle, dbb); } } #ifndef NO_LOCAL_DSQL - if (s == isc_unavailable) { - /* if the entry point didn't exist or if the routine said the server - didn't support the protocol... do it locally */ + if (s == isc_unavailable) { + // if the entry point didn't exist or if the routine said the server + // didn't support the protocol... do it locally - subsystem_enter(); - dsql8_execute_immediate(status, db_handle, tra_handle, + dsql8_execute_immediate(status, db_handle, tra_handle, length, string, dialect, in_blr_length, in_blr, in_msg_type, in_msg_length, in_msg, out_blr_length, out_blr, out_msg_type, out_msg_length, out_msg); - subsystem_exit(); - } + } #endif + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - if (status[1]) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -2850,45 +2880,49 @@ ISC_STATUS API_ROUTINE GDS_DSQL_FETCH(ISC_STATUS* user_status, * Fetch next record from a dynamic SQL cursor * **************************************/ - ISC_STATUS s, *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - USHORT blr_length, msg_type, msg_length; - sqlda_sup* dasup; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - if (!sqlda) { - status[0] = isc_arg_gds; - status[1] = isc_dsql_sqlda_err; - status[2] = isc_arg_end; - return error2(status, local); - } - - if (!(dasup = statement->das)) - return bad_handle(user_status, isc_unprepared_stmt); - - if (UTLD_parse_sqlda(status, dasup, &blr_length, &msg_type, &msg_length, - dialect, sqlda, DASUP_CLAUSE_select)) - return error2(status, local); - - if ((s = GDS_DSQL_FETCH_M(status, stmt_handle, blr_length, - dasup->dasup_clauses[DASUP_CLAUSE_select].dasup_blr, - 0, msg_length, - dasup->dasup_clauses[DASUP_CLAUSE_select].dasup_msg)) - && s != 101) + Status status(user_status); + try { - CHECK_STATUS(status); - return s; + if (!sqlda) + { + Firebird::status_exception::raise(isc_dsql_sqlda_err, isc_arg_end); + } + + Statement* statement = translate(stmt_handle); + + statement->checkPrepared(); + sqlda_sup& dasup = statement->das; + + USHORT blr_length, msg_type, msg_length; + if (UTLD_parse_sqlda(status, &dasup, &blr_length, &msg_type, &msg_length, + dialect, sqlda, DASUP_CLAUSE_select)) + { + return status[1]; + } + + ISC_STATUS s = GDS_DSQL_FETCH_M(status, stmt_handle, blr_length, + dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_blr, + 0, msg_length, + dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_msg); + if (s && s != 101) + { + status.ok(); + return s; + } + + if (UTLD_parse_sqlda(status, &dasup, NULL, NULL, NULL, + dialect, sqlda, DASUP_CLAUSE_select)) + { + return status[1]; + } + status.ok(); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - if (UTLD_parse_sqlda(status, dasup, NULL, NULL, NULL, - dialect, sqlda, DASUP_CLAUSE_select)) - return error2(status, local); - - CHECK_STATUS(status); - return s; + return status[1]; } @@ -2965,50 +2999,44 @@ ISC_STATUS API_ROUTINE GDS_DSQL_FETCH_M(ISC_STATUS* user_status, * Fetch next record from a dynamic SQL cursor * **************************************/ - ISC_STATUS s, *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - subsystem_enter(); + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); + status.setPrimaryHandle(statement); + ISC_STATUS s = #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) - s = dsql8_fetch(status, - &statement->handle.h_dsql, blr_length, blr, msg_type, - msg_length, msg -#ifdef SCROLLABLE_CURSORS - , (USHORT) 0, (ULONG) 1); -#else - ); -#endif - else -#endif - s = CALL(PROC_DSQL_FETCH, statement->implementation) (status, - &statement-> - handle, + (statement->flags & HANDLE_STATEMENT_local) ? + dsql8_fetch(status, &statement->handle, blr_length, blr, + msg_type, msg_length, msg) : +#ifdef SCROLLABLE_CURSORS + , (USHORT) 0, (ULONG) 1) : +#endif // SCROLLABLE_CURSORS +#endif // NO_LOCAL_DSQL + CALL(PROC_DSQL_FETCH, statement->implementation) (status, + &statement->handle, blr_length, blr, msg_type, - msg_length, msg + msg_length, msg); #ifdef SCROLLABLE_CURSORS , (USHORT) 0, (ULONG) 1); -#else - ); -#endif +#endif // SCROLLABLE_CURSORS - subsystem_exit(); + if (s == 100 || s == 101) + { + status.ok(); + return s; + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - CHECK_STATUS(status); - if (s == 100 || s == 101) - return s; - else if (s) - return error2(status, local); - - return FB_SUCCESS; + return status[1]; } @@ -3085,49 +3113,37 @@ ISC_STATUS API_ROUTINE GDS_DSQL_FREE(ISC_STATUS * user_status, * release request for an sql statement * *****************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - WHY_DBB dbb, *ptr; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - subsystem_enter(); + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) - dsql8_free_statement(status, &statement->handle.h_dsql, option); - else + if (statement->flags & HANDLE_STATEMENT_local) + dsql8_free_statement(status, &statement->handle, option); + else #endif - CALL(PROC_DSQL_FREE, statement->implementation) (status, - &statement->handle, - option); + CALL(PROC_DSQL_FREE, statement->implementation) (status, + &statement->handle, + option); + if (status[1]) + { + return status[1]; + } - subsystem_exit(); - - if (status[1]) - return error2(status, local); - -/* Release the handle and any request hanging off of it. */ - - if (option & DSQL_drop) { - /* Get rid of connections to database */ - - dbb = statement->parent; - for (ptr = &dbb->statements; *ptr; ptr = &(*ptr)->next) - if (*ptr == statement) { - *ptr = statement->next; - break; - } - - release_dsql_support(statement->das); - release_handle(statement); - *stmt_handle = 0; + if (option & DSQL_drop) + { + release_dsql_support(statement->das); + delete statement; + *stmt_handle = 0; + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3146,27 +3162,32 @@ ISC_STATUS API_ROUTINE GDS_DSQL_INSERT(ISC_STATUS* user_status, * Insert next record into a dynamic SQL cursor * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - USHORT blr_length, msg_type, msg_length; - sqlda_sup* dasup; + Status status(user_status); + try + { + Statement* statement = translate(stmt_handle); - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); + statement->checkPrepared(); + sqlda_sup& dasup = statement->das; + USHORT blr_length, msg_type, msg_length; + if (UTLD_parse_sqlda(status, &dasup, &blr_length, &msg_type, &msg_length, + dialect, sqlda, DASUP_CLAUSE_bind)) + { + return status[1]; + } - if (!(dasup = statement->das)) - return bad_handle(user_status, isc_unprepared_stmt); + return GDS_DSQL_INSERT_M(status, stmt_handle, blr_length, + dasup.dasup_clauses[DASUP_CLAUSE_bind]. + dasup_blr, 0, msg_length, + dasup.dasup_clauses[DASUP_CLAUSE_bind]. + dasup_msg); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - if (UTLD_parse_sqlda(status, dasup, &blr_length, &msg_type, &msg_length, - dialect, sqlda, DASUP_CLAUSE_bind)) - return error2(status, local); - - return GDS_DSQL_INSERT_M(status, stmt_handle, blr_length, - dasup->dasup_clauses[DASUP_CLAUSE_bind]. - dasup_blr, 0, msg_length, - dasup->dasup_clauses[DASUP_CLAUSE_bind]. - dasup_msg); + return status[1]; } @@ -3188,37 +3209,33 @@ ISC_STATUS API_ROUTINE GDS_DSQL_INSERT_M(ISC_STATUS* user_status, * Insert next record into a dynamic SQL cursor * **************************************/ - ISC_STATUS s, *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - subsystem_enter(); + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); + status.setPrimaryHandle(statement); + statement->checkPrepared(); + sqlda_sup& dasup = statement->das; #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) - s = dsql8_insert(status, - &statement->handle.h_dsql, blr_length, blr, msg_type, - msg_length, msg); - else + if (statement->flags & HANDLE_STATEMENT_local) + dsql8_insert(status, &statement->handle, + blr_length, blr, msg_type, msg_length, msg); + else #endif - s = CALL(PROC_DSQL_INSERT, statement->implementation) (status, - &statement-> - handle, - blr_length, - blr, msg_type, + CALL(PROC_DSQL_INSERT, statement->implementation) (status, + &statement->handle, + blr_length, blr, + msg_type, msg_length, msg); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - subsystem_exit(); - - if (s) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3240,61 +3257,48 @@ ISC_STATUS API_ROUTINE GDS_DSQL_PREPARE(ISC_STATUS* user_status, * Prepare a statement for execution. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - USHORT buffer_len; - SCHAR *buffer, local_buffer[BUFFER_MEDIUM]; - sqlda_sup* dasup; - - GET_STATUS; - - if (!(buffer = get_sqlda_buffer(local_buffer, sizeof(local_buffer), sqlda, - dialect, &buffer_len))) + Status status(user_status); + try { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); - } + Statement* statement = translate(stmt_handle); + sqlda_sup& dasup = statement->das; - if (!GDS_DSQL_PREPARE_M(status, - tra_handle, - stmt_handle, - length, - string, - dialect, - sizeof(sql_prepare_info), - sql_prepare_info, - buffer_len, - buffer)) - { - WHY_STMT statement = WHY_translate_handle(*stmt_handle); - release_dsql_support(statement->das); + USHORT buffer_len = sqlda_buffer_size(sqlda, dialect); + Firebird::HalfStaticArray localBuffer; + SCHAR* buffer = localBuffer.getBuffer(buffer_len); + memset(buffer, 0, buffer_len); - if (!(dasup = (sqlda_sup*) alloc((SLONG) sizeof(sqlda_sup)))) { - statement->requests = 0; - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - } - else { - statement->das = dasup; - dasup->dasup_dialect = dialect; + if (!GDS_DSQL_PREPARE_M(status, + tra_handle, + stmt_handle, + length, + string, + dialect, + sizeof(sql_prepare_info), + sql_prepare_info, + buffer_len, + buffer)) + { + statement->flags &= ~HANDLE_STATEMENT_prepared; + release_dsql_support(dasup); + memset(&dasup, 0, sizeof(dasup)); + + dasup.dasup_dialect = dialect; iterative_sql_info(status, stmt_handle, sizeof(sql_prepare_info), - sql_prepare_info, buffer_len, buffer, dialect, - sqlda); + sql_prepare_info, buffer_len, buffer, + dialect, sqlda); + + // statement prepared OK + statement->flags |= HANDLE_STATEMENT_prepared; } } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - if (buffer != local_buffer) - free_block(buffer); - - if (status[1]) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3319,50 +3323,51 @@ ISC_STATUS API_ROUTINE GDS_DSQL_PREPARE_M(ISC_STATUS* user_status, * Prepare a statement for execution. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - WHY_TRA handle = NULL, transaction = NULL; + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); + status.setPrimaryHandle(statement); - GET_STATUS; - - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - if (*tra_handle) { - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - handle = find_transaction(statement->parent, transaction); - if (!handle) - return bad_handle (user_status, isc_bad_trans_handle); - handle = handle->handle.h_why; - } - - subsystem_enter(); + StTra *handle = 0; + if (*tra_handle) + { + Transaction* transaction = translate(tra_handle); + transaction = find_transaction(statement->parent, transaction); + if (!transaction) + { + bad_handle (isc_bad_trans_handle); + } + handle = transaction->handle; + } #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) - dsql8_prepare(status, tra_handle, &statement->handle.h_dsql, - length, string, dialect, item_length, items, - buffer_length, buffer); - else + if (statement->flags & HANDLE_STATEMENT_local) + { + dsql8_prepare(status, tra_handle, &statement->handle, + length, string, dialect, item_length, items, + buffer_length, buffer); + } + else #endif + { + CALL(PROC_DSQL_PREPARE, statement->implementation) (status, + &handle, + &statement->handle, + length, + string, dialect, + item_length, + items, + buffer_length, + buffer); + } + } + catch (const std::exception& e) { - CALL(PROC_DSQL_PREPARE, statement->implementation) (status, - &handle, - &statement-> - handle, length, - string, dialect, - item_length, - items, - buffer_length, - buffer); + Firebird::stuff_exception(status, e); } - subsystem_exit(); - - if (status[1]) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3381,32 +3386,28 @@ ISC_STATUS API_ROUTINE GDS_DSQL_SET_CURSOR(ISC_STATUS* user_status, * Set a cursor name for a dynamic request. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - subsystem_enter(); + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); + status.setPrimaryHandle(statement); #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) - dsql8_set_cursor(status, &statement->handle.h_dsql, cursor, type); - else + if (statement->flags & HANDLE_STATEMENT_local) + dsql8_set_cursor(status, &statement->handle, cursor, type); + else #endif - CALL(PROC_DSQL_SET_CURSOR, statement->implementation) (status, - &statement-> - handle, cursor, - type); + CALL(PROC_DSQL_SET_CURSOR, statement->implementation) (status, + &statement-> + handle, cursor, + type); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - subsystem_exit(); - - if (status[1]) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3427,36 +3428,47 @@ ISC_STATUS API_ROUTINE GDS_DSQL_SQL_INFO(ISC_STATUS* user_status, * Provide information on sql statement. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_STMT statement; - - GET_STATUS; - TRANSLATE_HANDLE(*stmt_handle, statement, HANDLE_statement, isc_bad_stmt_handle); - - subsystem_enter(); + YEntry status(user_status); + try + { + Statement* statement = translate(stmt_handle); + status.setPrimaryHandle(statement); #ifndef NO_LOCAL_DSQL - if (statement->flags & HANDLE_STATEMENT_local) - dsql8_sql_info(status, &statement->handle.h_dsql, item_length, items, + if (statement->flags & HANDLE_STATEMENT_local) + dsql8_sql_info(status, &statement->handle, item_length, items, buffer_length, buffer); - else + else #endif - CALL(PROC_DSQL_SQL_INFO, statement->implementation) (status, - &statement-> - handle, - item_length, - items, - buffer_length, - buffer); + { + if (( (item_length == 1) && (items[0] == isc_info_sql_stmt_type) || + (item_length == 2) && (items[0] == isc_info_sql_stmt_type) && + (items[1] == isc_info_end || items[1] == 0) ) && + (statement->flags & HANDLE_STATEMENT_prepared) && + statement->das.dasup_stmt_type) + { + *buffer++ = isc_info_sql_stmt_type; + put_short((UCHAR*) buffer, 4); + buffer += 2; + put_long((UCHAR*) buffer, statement->das.dasup_stmt_type); + } + else + { + CALL(PROC_DSQL_SQL_INFO, statement->implementation) (status, + &statement->handle, + item_length, + items, + buffer_length, + buffer); + } + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - subsystem_exit(); - - if (status[1]) - return error2(status, local); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3504,32 +3516,34 @@ ISC_STATUS API_ROUTINE isc_wait_for_event(ISC_STATUS * user_status, * Que request for event notification. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - SLONG value, id; - event_t* event_ptr; - - GET_STATUS; - - if (!why_initialized) { - gds__register_cleanup((FPTR_VOID_PTR) exit_handler, why_event); - why_initialized = TRUE; - ISC_event_init(why_event, 0, 0); - } - - value = ISC_event_clear(why_event); - - if (GDS_QUE_EVENTS - (status, handle, &id, length, events, event_ast, buffer)) + Status status(user_status); + try { - return error2(status, local); + if (!why_initialized) + { + gds__register_cleanup((FPTR_VOID_PTR) exit_handler, why_event); + why_initialized = TRUE; + ISC_event_init(why_event, 0, 0); + } + + SLONG value = ISC_event_clear(why_event); + SLONG id; + + if (GDS_QUE_EVENTS + (status, handle, &id, length, events, event_ast, buffer)) + { + return status[1]; + } + + event_t* event_ptr = why_event; + ISC_event_wait(1, &event_ptr, &value, -1, 0, NULL); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - event_ptr = why_event; - ISC_event_wait(1, &event_ptr, &value, -1, 0, NULL); - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } #endif @@ -3553,26 +3567,24 @@ ISC_STATUS API_ROUTINE GDS_INTL_FUNCTION(ISC_STATUS * user_status, * (candidate for removal when engine functions can be called by DSQL) * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*handle, database, HANDLE_database, isc_bad_db_handle); - subsystem_enter(); - - if (CALL(PROC_INTL_FUNCTION, database->implementation) (status, - &database->handle, - function, - charSetNumber, - strLen, - str, - result)) + try { - return error(status, local); + Attachment* dbb = translate(handle); + status.setPrimaryHandle(dbb); + + CALL(PROC_INTL_FUNCTION, dbb->implementation) (status, + &dbb->handle, + function, charSetNumber, + strLen, str, result); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - RETURN_SUCCESS; + return status[1]; } @@ -3592,30 +3604,30 @@ ISC_STATUS API_ROUTINE GDS_GET_SEGMENT(ISC_STATUS * user_status, * Abort a partially completed blob. * **************************************/ - ISC_STATUS *status, code; - ISC_STATUS_ARRAY local; - WHY_BLB blob; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*blob_handle, blob, HANDLE_blob, isc_bad_segstr_handle); - subsystem_enter(); + try + { + Blob* blob = translate(blob_handle); + status.setPrimaryHandle(blob); - code = CALL(PROC_GET_SEGMENT, blob->implementation) (status, - &blob->handle, - length, - buffer_length, - buffer); + ISC_STATUS code = + CALL(PROC_GET_SEGMENT, blob->implementation) (status, &blob->handle, + length, + buffer_length, buffer); - if (code) { - if (code == isc_segstr_eof || code == isc_segment) { - subsystem_exit(); - CHECK_STATUS(status); + if (code == isc_segstr_eof || code == isc_segment) + { + status.ok(); return code; } - return error(status, local); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - RETURN_SUCCESS; + return status[1]; } @@ -3641,30 +3653,29 @@ ISC_STATUS API_ROUTINE GDS_GET_SLICE(ISC_STATUS* user_status, * Snatch a slice of an array. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT dbb; - WHY_TRA transaction; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); - FIND_TRANSACTION(*tra_handle, transaction, dbb, isc_bad_trans_handle); - subsystem_enter(); + try + { + Attachment* dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + Transaction* transaction = findTransaction(tra_handle, dbb); - if (CALL(PROC_GET_SLICE, dbb->implementation) (status, + CALL(PROC_GET_SLICE, dbb->implementation) (status, &dbb->handle, &transaction->handle, array_id, - sdl_length, - sdl, - param_length, - param, - slice_length, - slice, - return_length)) - return error(status, local); + sdl_length, sdl, + param_length, param, + slice_length, slice, + return_length); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -3681,50 +3692,24 @@ ISC_STATUS gds__handle_cleanup(ISC_STATUS * user_status, * Clean up a dangling y-valve handle. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_HNDL handle; - WHY_TRA transaction, sub; - //CLEAN clean; + Status status(user_status); - GET_STATUS; + try + { + Transaction* transaction = translate(user_handle); - handle = WHY_translate_handle(*user_handle); - - if (!handle) { - status[0] = isc_arg_gds; - status[1] = isc_bad_db_handle; - status[2] = isc_arg_end; - return error2(status, local); - } - - switch (handle->type) { - case HANDLE_transaction: - - /* Call the associated cleanup handlers */ - - transaction = (WHY_TRA) handle; - WHY_cleanup_transaction(transaction); - //while (clean = transaction->cleanup) { - // transaction->cleanup = clean->clean_next; - // clean->TransactionRoutine(transaction, clean->clean_arg); - // free_block(clean); - //} - while (sub = transaction) { + while (transaction) { + Transaction* sub = transaction; transaction = sub->next; - release_handle(sub); + delete sub; } - break; - - default: - status[0] = isc_arg_gds; - status[1] = isc_bad_db_handle; - status[2] = isc_arg_end; - return error2(status, local); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -3809,23 +3794,30 @@ ISC_STATUS API_ROUTINE GDS_PREPARE2(ISC_STATUS* user_status, * phase commit. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction, sub; + YEntry status(user_status); + try + { + Transaction* transaction = translate(tra_handle); + status.setPrimaryHandle(transaction); - GET_STATUS; - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); + for (Transaction* sub = transaction; sub; sub = sub->next) + { + if (sub->implementation != SUBSYSTEMS && + CALL(PROC_PREPARE, sub->implementation) (status, &sub->handle, + msg_length, msg)) + { + return status[1]; + } + } - for (sub = transaction; sub; sub = sub->next) - if (sub->implementation != SUBSYSTEMS && - CALL(PROC_PREPARE, sub->implementation) (status, &sub->handle, - msg_length, msg)) - return error(status, local); + transaction->flags |= HANDLE_TRANSACTION_limbo; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - transaction->flags |= HANDLE_TRANSACTION_limbo; - - RETURN_SUCCESS; + return status[1]; } @@ -3844,21 +3836,23 @@ ISC_STATUS API_ROUTINE GDS_PUT_SEGMENT(ISC_STATUS* user_status, * Abort a partially completed blob. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_BLB blob; + YEntry status(user_status); + try + { + Blob* blob = translate(blob_handle); + status.setPrimaryHandle(blob); - GET_STATUS; - TRANSLATE_HANDLE(*blob_handle, blob, HANDLE_blob, isc_bad_segstr_handle); - subsystem_enter(); - - if (CALL(PROC_PUT_SEGMENT, blob->implementation) (status, + CALL(PROC_PUT_SEGMENT, blob->implementation) (status, &blob->handle, buffer_length, - buffer)) - return error(status, local); + buffer); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -3883,17 +3877,15 @@ ISC_STATUS API_ROUTINE GDS_PUT_SLICE(ISC_STATUS* user_status, * Snatch a slice of an array. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT dbb; - WHY_TRA transaction; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); - FIND_TRANSACTION(*tra_handle, transaction, dbb, isc_bad_trans_handle); - subsystem_enter(); + try + { + Attachment* dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + Transaction* transaction = findTransaction(tra_handle, dbb); - if (CALL(PROC_PUT_SLICE, dbb->implementation) (status, + CALL(PROC_PUT_SLICE, dbb->implementation) (status, &dbb->handle, &transaction->handle, array_id, @@ -3902,10 +3894,14 @@ ISC_STATUS API_ROUTINE GDS_PUT_SLICE(ISC_STATUS* user_status, param_length, param, slice_length, - slice)) - return error(status, local); + slice); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -3927,22 +3923,23 @@ ISC_STATUS API_ROUTINE GDS_QUE_EVENTS(ISC_STATUS* user_status, * Que request for event notification. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT database; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*handle, database, HANDLE_database, isc_bad_db_handle); + try + { + Attachment* dbb = translate(handle); + status.setPrimaryHandle(dbb); - subsystem_enter(); + CALL(PROC_QUE_EVENTS, dbb->implementation) (status, &dbb->handle, + id, length, events, + ast, arg); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - if (CALL(PROC_QUE_EVENTS, database->implementation) (status, - &database->handle, - id, length, events, - ast, arg)) - return error(status, local); - - RETURN_SUCCESS; + return status[1]; } @@ -3969,23 +3966,26 @@ ISC_STATUS API_ROUTINE GDS_RECEIVE(ISC_STATUS* user_status, msg, level, (USHORT) blr_continue, /* means continue in same direction as before */ (ULONG) 1); #else - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); - if (CALL(PROC_RECEIVE, request->implementation) (status, + CALL(PROC_RECEIVE, request->implementation) (status, &request->handle, msg_type, msg_length, msg, - level)) - return error(status, local); + level); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; #endif } @@ -4011,25 +4011,28 @@ ISC_STATUS API_ROUTINE GDS_RECEIVE2(ISC_STATUS* user_status, * then get a record from the host program. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); - if (CALL(PROC_RECEIVE, request->implementation) (status, + CALL(PROC_RECEIVE, request->implementation) (status, &request->handle, msg_type, msg_length, msg, level, direction, - offset)) - return error(status, local); + offset); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } #endif @@ -4050,40 +4053,34 @@ ISC_STATUS API_ROUTINE GDS_RECONNECT(ISC_STATUS* user_status, * Connect to a transaction in limbo. * **************************************/ - ISC_STATUS* status; - ISC_STATUS_ARRAY local; + YEntry status(user_status); + StTra* handle = 0; - GET_STATUS; - NULL_CHECK(tra_handle, isc_bad_trans_handle, HANDLE_transaction); - WHY_ATT database; - TRANSLATE_HANDLE(*db_handle, database, HANDLE_database, isc_bad_db_handle); - subsystem_enter(); - - WHY_TRA transaction = NULL; - - if (CALL(PROC_RECONNECT, database->implementation) (status, - &database->handle, - &transaction, - length, id)) + try { - return error(status, local); + nullCheck(tra_handle, isc_bad_trans_handle); + Attachment* dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + + if (CALL(PROC_RECONNECT, dbb->implementation) (status, &dbb->handle, + &handle, + length, id)) + { + return status[1]; + } + + new Transaction(handle, tra_handle, dbb); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + if (handle) + { + *tra_handle = 0; + } } - transaction = allocate_handle( database->implementation, - transaction, - HANDLE_transaction); - if (transaction) { - transaction->parent = database; - *tra_handle = transaction->public_handle; - } - else { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error(status, local); - } - - RETURN_SUCCESS; + return status[1]; } @@ -4100,35 +4097,26 @@ ISC_STATUS API_ROUTINE GDS_RELEASE_REQUEST(ISC_STATUS * user_status, * Release a request. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request, *ptr; - WHY_DBB dbb; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - subsystem_enter(); - - if (CALL(PROC_RELEASE_REQUEST, request->implementation) (status, - &request->handle)) + try { - return error(status, local); + Request* request = translate(req_handle); + status.setPrimaryHandle(request); + + if (!CALL(PROC_RELEASE_REQUEST, request->implementation) (status, + &request->handle)) + { + delete request; + *req_handle = 0; + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } -/* Get rid of connections to database */ - - dbb = request->parent; - - for (ptr = &dbb->requests; *ptr; ptr = &(*ptr)->next) - if (*ptr == request) { - *ptr = request->next; - break; - } - - release_handle(request); - *req_handle = 0; - - RETURN_SUCCESS; + return status[1]; } @@ -4150,26 +4138,27 @@ ISC_STATUS API_ROUTINE GDS_REQUEST_INFO(ISC_STATUS* user_status, * Provide information on blob object. * **************************************/ - ISC_STATUS* status; - ISC_STATUS_ARRAY local; - WHY_REQ request; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); - if (CALL(PROC_REQUEST_INFO, request->implementation) (status, + CALL(PROC_REQUEST_INFO, request->implementation) (status, &request->handle, level, item_length, items, buffer_length, - buffer)) + buffer); + } + catch (const std::exception& e) { - return error(status, local); + Firebird::stuff_exception(status, e); } - RETURN_SUCCESS; + return status[1]; } #if defined (SOLARIS) || defined (WIN_NT) @@ -4229,23 +4218,30 @@ ISC_STATUS API_ROUTINE GDS_ROLLBACK_RETAINING(ISC_STATUS * user_status, * Abort a transaction, but keep all cursors open. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction, sub; + YEntry status(user_status); + try + { + Transaction* transaction = translate(tra_handle); + status.setPrimaryHandle(transaction); - GET_STATUS; - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); + for (Transaction* sub = transaction; sub; sub = sub->next) + { + if (sub->implementation != SUBSYSTEMS && + CALL(PROC_ROLLBACK_RETAINING, sub->implementation) (status, + &sub->handle)) + { + return status[1]; + } + } - for (sub = transaction; sub; sub = sub->next) - if (sub->implementation != SUBSYSTEMS && - CALL(PROC_ROLLBACK_RETAINING, sub->implementation) (status, - &sub->handle)) - return error(status, local); + transaction->flags |= HANDLE_TRANSACTION_limbo; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - transaction->flags |= HANDLE_TRANSACTION_limbo; - - RETURN_SUCCESS; + return status[1]; } @@ -4262,48 +4258,42 @@ ISC_STATUS API_ROUTINE GDS_ROLLBACK(ISC_STATUS * user_status, * Abort a transaction. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction, sub; - //CLEAN clean; + YEntry status(user_status); + try + { + Transaction* transaction = translate(tra_handle); + status.setPrimaryHandle(transaction); - GET_STATUS; - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); - - for (sub = transaction; sub; sub = sub->next) - if (sub->implementation != SUBSYSTEMS && - CALL(PROC_ROLLBACK, sub->implementation) (status, &sub->handle)) - { - if (!is_network_error(status) || - (transaction->flags & HANDLE_TRANSACTION_limbo) ) + for (Transaction* sub = transaction; sub; sub = sub->next) + if (sub->implementation != SUBSYSTEMS && + CALL(PROC_ROLLBACK, sub->implementation) (status, &sub->handle)) { - return error(status, local); + if (!is_network_error(status) || + (transaction->flags & HANDLE_TRANSACTION_limbo) ) + { + return status[1]; + } } + + if (is_network_error(status)) + { + init_status(status); } - if (is_network_error(status)) - init_status(status); - - subsystem_exit(); - -/* Call the associated cleanup handlers */ - - WHY_cleanup_transaction(transaction); - //while (clean = transaction->cleanup) { - // transaction->cleanup = clean->clean_next; - // clean->TransactionRoutine(transaction, clean->clean_arg); - // free_block(clean); - //} - - while (sub = transaction) { - transaction = sub->next; - release_handle(sub); + while (transaction) + { + Transaction* sub = transaction; + transaction = sub->next; + delete sub; + } + *tra_handle = 0; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - *tra_handle = 0; - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -4323,13 +4313,11 @@ ISC_STATUS API_ROUTINE GDS_SEEK_BLOB(ISC_STATUS * user_status, * Seek a blob. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_BLB blob; - - GET_STATUS; - TRANSLATE_HANDLE(*blob_handle, blob, HANDLE_blob, isc_bad_segstr_handle); - subsystem_enter(); + YEntry status(user_status); + try + { + Blob* blob = translate(blob_handle); + status.setPrimaryHandle(blob); /*** if (blob->flags & HANDLE_BLOB_filter) @@ -4340,15 +4328,18 @@ if (blob->flags & HANDLE_BLOB_filter) } else ***/ - CALL(PROC_SEEK_BLOB, blob->implementation) (status, - &blob->handle, - mode, - offset, result); - if (status[1]) - return error(status, local); + CALL(PROC_SEEK_BLOB, blob->implementation) (status, + &blob->handle, + mode, + offset, result); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -4369,20 +4360,23 @@ ISC_STATUS API_ROUTINE GDS_SEND(ISC_STATUS* user_status, * Get a record from the host program. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); - if (CALL(PROC_SEND, request->implementation) (status, &request->handle, + CALL(PROC_SEND, request->implementation) (status, &request->handle, msg_type, msg_length, msg, - level)) - return error(status, local); + level); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -4404,91 +4398,89 @@ ISC_STATUS API_ROUTINE GDS_SERVICE_ATTACH(ISC_STATUS* user_status, * that recognizes it. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local, temp; + StSvc* handle = 0; + Service* service = 0; + ISC_STATUS_ARRAY temp; + USHORT n; + YEntry status(user_status); - GET_STATUS; - NULL_CHECK(public_handle, isc_bad_svc_handle, HANDLE_service); + try + { + nullCheck(public_handle, isc_bad_svc_handle); - if (!service_name) { - status[0] = isc_arg_gds; - status[1] = isc_service_att_err; - status[2] = isc_arg_gds; - status[3] = isc_svc_name_missing; - status[4] = isc_arg_end; - return error2(status, local); - } - - if (spb_length > 0 && !spb) { - status[0] = isc_arg_gds; - status[1] = isc_bad_spb_form; - status[2] = isc_arg_end; - return error2(status, local); - } - -#if defined (SERVER_SHUTDOWN) && !defined (SUPERCLIENT) && !defined (REQUESTER) - if (shutdown_flag) { - status[0] = isc_arg_gds; - status[1] = isc_shutwarn; - status[2] = isc_arg_end; - return error2(status, local); - } -#endif /* SERVER_SHUTDOWN && !SUPERCLIENT && !REQUESTER */ - - subsystem_enter(); - SUBSYSTEM_USAGE_INCR; - - ISC_STATUS* ptr = status; - - USHORT org_length = service_length; - - if (org_length) { - const TEXT* p = service_name + org_length - 1; - while (*p == ' ') - p--; - org_length = p - service_name + 1; - } - - for (USHORT n = 0; n < SUBSYSTEMS; n++) { - if (why_enabled && !(why_enabled & (1 << n))) - continue; - WHY_SVC handle = 0; - if (!CALL(PROC_SERVICE_ATTACH, n) (ptr, - org_length, - service_name, - &handle, spb_length, spb)) + if (!service_name) { - WHY_SVC service = allocate_handle(n, handle, HANDLE_service); - if (!service) - { - /* No memory. Make a half-hearted attempt to detach service. */ - - CALL(PROC_SERVICE_DETACH, n) (ptr, handle); - *public_handle = 0; - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - break; - } - - *public_handle = service->public_handle; - service->cleanup = NULL; - status[0] = isc_arg_gds; - status[1] = 0; - if (status[2] != isc_arg_warning) - status[2] = isc_arg_end; - subsystem_exit(); - CHECK_STATUS_SUCCESS(status); - return status[1]; + Firebird::status_exception::raise(isc_service_att_err, + isc_arg_gds, isc_svc_name_missing, isc_arg_end); + } + + if (spb_length > 0 && !spb) + { + Firebird::status_exception::raise(isc_bad_spb_form, isc_arg_end); + } + +#if !defined (SUPERCLIENT) && !defined (REQUESTER) + if (shutdown_flag) + { + Firebird::status_exception::raise(isc_shutwarn, isc_arg_end); + } +#endif /* !SUPERCLIENT && !REQUESTER */ + + SUBSYSTEM_USAGE_INCR; + + USHORT org_length = service_length; + if (org_length) { + const TEXT* p = service_name + org_length - 1; + while (*p == ' ') + p--; + org_length = p - service_name + 1; + } + + ISC_STATUS* ptr = status; + for (n = 0; n < SUBSYSTEMS; n++) + { + if (why_enabled && !(why_enabled & (1 << n))) + { + continue; + } + if (!CALL(PROC_SERVICE_ATTACH, n) (ptr, + org_length, service_name, + &handle, + spb_length, spb)) + { + service = new Service(handle, public_handle, n); + status[0] = isc_arg_gds; + status[1] = 0; + if (status[2] != isc_arg_warning) + { + status[2] = isc_arg_end; + } + return status[1]; + } + if (ptr[1] != isc_unavailable) + { + ptr = temp; + } + } + + SUBSYSTEM_USAGE_DECR; + if (status[1] == isc_unavailable) + { + status[1] = isc_service_att_err; + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + if (handle) + { + CALL(PROC_SERVICE_DETACH, n) (temp, handle); + *public_handle = 0; + delete service; } - if (ptr[1] != isc_unavailable) - ptr = temp; } - SUBSYSTEM_USAGE_DECR; - if (status[1] == isc_unavailable) - status[1] = isc_service_att_err; - return error(status, local); + return status[1]; } @@ -4505,35 +4497,29 @@ ISC_STATUS API_ROUTINE GDS_SERVICE_DETACH(ISC_STATUS * user_status, * Close down a service. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_SVC service; - CLEAN clean; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*handle, service, HANDLE_service, isc_bad_svc_handle); - subsystem_enter(); + try + { + Service* service = translate(handle); - if (CALL(PROC_SERVICE_DETACH, service->implementation) (status, - &service->handle)) - return error(status, local); + if (CALL(PROC_SERVICE_DETACH, service->implementation) (status, + &service->handle)) + { + return status[1]; + } - SUBSYSTEM_USAGE_DECR; - subsystem_exit(); + SUBSYSTEM_USAGE_DECR; -/* Call the associated cleanup handlers */ - - while ((clean = service->cleanup) != NULL) { - service->cleanup = clean->clean_next; - clean->DatabaseRoutine(handle, clean->clean_arg); - free_block(clean); + delete service; + *handle = 0; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - release_handle(service); - *handle = 0; - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -4562,24 +4548,28 @@ ISC_STATUS API_ROUTINE GDS_SERVICE_QUERY(ISC_STATUS* user_status, * network). This parameter will be implemented at * a later date. **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_SVC service; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*handle, service, HANDLE_service, isc_bad_svc_handle); - subsystem_enter(); + try + { + Service* service = translate(handle); - if (CALL(PROC_SERVICE_QUERY, service->implementation) (status, &service->handle, 0, /* reserved */ + CALL(PROC_SERVICE_QUERY, service->implementation) (status, + &service->handle, + 0, /* reserved */ send_item_length, send_items, recv_item_length, recv_items, buffer_length, - buffer)) - return error(status, local); + buffer); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -4604,23 +4594,23 @@ ISC_STATUS API_ROUTINE GDS_SERVICE_START(ISC_STATUS* user_status, * network). This parameter will be implemented at * a later date. **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_SVC service; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*handle, service, HANDLE_service, isc_bad_svc_handle); - subsystem_enter(); + try + { + Service* service = translate(handle); - if (CALL(PROC_SERVICE_START, service->implementation) (status, + CALL(PROC_SERVICE_START, service->implementation) (status, &service->handle, NULL, - spb_length, spb)) + spb_length, spb); + } + catch (const std::exception& e) { - return error(status, local); + Firebird::stuff_exception(status, e); } - RETURN_SUCCESS; + return status[1]; } @@ -4642,25 +4632,27 @@ ISC_STATUS API_ROUTINE GDS_START_AND_SEND(ISC_STATUS* user_status, * Get a record from the host program. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; - WHY_TRA transaction; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - FIND_TRANSACTION(*tra_handle, transaction, request->parent, isc_bad_trans_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); + Transaction* transaction = findTransaction(tra_handle, request->parent); - if (CALL(PROC_START_AND_SEND, request->implementation) (status, + CALL(PROC_START_AND_SEND, request->implementation) (status, &request->handle, &transaction-> handle, msg_type, msg_length, msg, - level)) - return error(status, local); + level); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -4679,23 +4671,25 @@ ISC_STATUS API_ROUTINE GDS_START(ISC_STATUS * user_status, * Get a record from the host program. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; - WHY_TRA transaction; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - FIND_TRANSACTION(*tra_handle, transaction, request->parent, isc_bad_trans_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); + Transaction* transaction = findTransaction(tra_handle, request->parent); - if (CALL(PROC_START, request->implementation) (status, + CALL(PROC_START, request->implementation) (status, &request->handle, &transaction->handle, - level)) - return error(status, local); + level); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -4715,92 +4709,78 @@ ISC_STATUS API_ROUTINE GDS_START_MULTIPLE(ISC_STATUS * user_status, * Start a transaction. * **************************************/ - ISC_STATUS *status, *s; - ISC_STATUS_ARRAY local, temp; - WHY_TRA transaction, sub, *ptr; - WHY_DBB database; - USHORT n; TEB* vector = (TEB*) vec; + ISC_STATUS_ARRAY temp; + Transaction* transaction = 0; + Attachment* dbb = 0; + StTra* handle = 0; + + YEntry status(user_status); - GET_STATUS; - NULL_CHECK(tra_handle, isc_bad_trans_handle, HANDLE_transaction); - transaction = NULL; - subsystem_enter(); - - for (n = 0, ptr = &transaction; n < count; - n++, ptr = &(*ptr)->next, vector++) { - database = WHY_translate_handle(*vector->teb_database); - if (!database || database->type != HANDLE_database) { - s = status; - *s++ = isc_arg_gds; - *s++ = isc_bad_db_handle; - *s = isc_arg_end; - return error(status, local); - } - if (CALL(PROC_START_TRANSACTION, database->implementation) (status, - ptr, - 1, - &database->handle, - vector->teb_tpb_length, - vector->teb_tpb)) - { - while (sub = transaction) { - transaction = sub->next; - CALL(PROC_ROLLBACK, sub->implementation) (temp, &sub->handle); - release_handle(sub); - } - return error(status, local); - } - - sub = allocate_handle( database->implementation, - *ptr, - HANDLE_transaction); - if (!sub) - { - /* No memory. Make a half-hearted attempt to rollback all sub-transactions. */ - - CALL(PROC_ROLLBACK, database->implementation) (temp, ptr); - *ptr = 0; - while (sub = transaction) { - transaction = sub->next; - CALL(PROC_ROLLBACK, sub->implementation) (temp, &sub->handle); - release_handle(sub); - } - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error(status, local); - } - - sub->parent = database; - *ptr = sub; - } - - if (transaction->next) + try { - sub = allocate_handle(SUBSYSTEMS, (class Jrd::jrd_tra *)0, HANDLE_transaction); - if (!sub) - { - /* No memory. Make a half-hearted attempt to rollback all sub-transactions. */ + nullCheck(tra_handle, isc_bad_trans_handle); - while (sub = transaction) { - transaction = sub->next; - CALL(PROC_ROLLBACK, sub->implementation) (temp, &sub->handle); - release_handle(sub); - } - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error(status, local); + if (count <= 0) + { + Firebird::status_exception::raise(isc_bad_trans_handle, + /* Do we need new error code here ? */ isc_arg_end); } - sub->next = transaction; - *tra_handle = sub->public_handle; - } - else - *tra_handle = transaction->public_handle; + Transaction** ptr; + USHORT n; + for (n = 0, ptr = &transaction; n < count; + n++, ptr = &(*ptr)->next, vector++) { + dbb = translate(vector->teb_database); - RETURN_SUCCESS; + if (CALL(PROC_START_TRANSACTION, dbb->implementation) (status, + &handle, + 1, + &dbb->handle, + vector->teb_tpb_length, + vector->teb_tpb)) + { + Firebird::status_exception::raise(status); + } + + *ptr = new Transaction(handle, 0, dbb); + handle = 0; + } + + if (transaction->next) + { + Transaction *sub = new Transaction(tra_handle, SUBSYSTEMS); + sub->next = transaction; + } + else { + *tra_handle = transaction->public_handle; + } + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + + if (handle || transaction) + { + *tra_handle = 0; + } + while (transaction) + { + Transaction *sub = transaction; + transaction = sub->next; + if (sub->handle) + { + CALL(PROC_ROLLBACK, sub->implementation) (temp, &sub->handle); + } + delete sub; + } + if (handle && dbb) + { + CALL(PROC_ROLLBACK, dbb->implementation) (temp, handle); + } + } + + return status[1]; } @@ -4818,40 +4798,32 @@ ISC_STATUS API_ROUTINE_VARARG GDS_START_TRANSACTION(ISC_STATUS * user_status, * Start a transaction. * **************************************/ - TEB tebs[16], *teb, *end; - ISC_STATUS status; - va_list ptr; + Status status(user_status); + try + { + Firebird::HalfStaticArray tebs; + TEB* teb = tebs.getBuffer(count); - if (count <= FB_NELEM(tebs)) - teb = tebs; - else - teb = (TEB *) alloc((SLONG) (sizeof(struct teb) * count)); + const TEB* const end = teb + count; + va_list ptr; + va_start(ptr, count); - if (!teb) { - user_status[0] = isc_arg_gds; - user_status[1] = status = isc_virmemexh; - user_status[2] = isc_arg_end; - return status; + for (TEB* teb_iter = teb; teb_iter < end; teb_iter++) { + teb_iter->teb_database = va_arg(ptr, FB_API_HANDLE*); + teb_iter->teb_tpb_length = va_arg(ptr, int); + teb_iter->teb_tpb = va_arg(ptr, UCHAR *); + } + va_end(ptr); + + GDS_START_MULTIPLE(user_status, tra_handle, count, teb); + status.ok(); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - end = teb + count; - va_start(ptr, count); - - for (; teb < end; teb++) { - teb->teb_database = va_arg(ptr, FB_API_HANDLE*); - teb->teb_tpb_length = va_arg(ptr, int); - teb->teb_tpb = va_arg(ptr, UCHAR *); - } - va_end(ptr); - - teb = end - count; - - status = GDS_START_MULTIPLE(user_status, tra_handle, count, teb); - - if (teb != tebs) - free_block(teb); - - return status; + return status[1]; } @@ -4875,29 +4847,29 @@ ISC_STATUS API_ROUTINE GDS_TRANSACT_REQUEST(ISC_STATUS* user_status, * Execute a procedure. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_ATT dbb; - WHY_TRA transaction; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); + try + { + Attachment* dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + Transaction* transaction = findTransaction(tra_handle, dbb); - if (CALL(PROC_TRANSACT_REQUEST, dbb->implementation) (status, + CALL(PROC_TRANSACT_REQUEST, dbb->implementation) (status, &dbb->handle, &transaction-> handle, blr_length, blr, in_msg_length, in_msg, out_msg_length, - out_msg)) + out_msg); + } + catch (const std::exception& e) { - return error(status, local); + Firebird::stuff_exception(status, e); } - RETURN_SUCCESS; + return status[1]; } @@ -4916,60 +4888,17 @@ ISC_STATUS API_ROUTINE gds__transaction_cleanup(ISC_STATUS * user_status, * Register a transaction specific cleanup handler. * **************************************/ - ISC_STATUS *status, *s; - ISC_STATUS_ARRAY local; - WHY_TRA transaction; - CLEAN clean; - - GET_STATUS; - transaction = WHY_translate_handle(*tra_handle); - if (!transaction || transaction->type != HANDLE_transaction) { - s = status; - *s++ = isc_arg_gds; - *s++ = isc_bad_db_handle; - *s = isc_arg_end; - return error2(status, local); - } - -/* Only add the cleanup handler if the transaction doesn't already know - about it. */ - - for (clean = transaction->cleanup; clean; clean = clean->clean_next) + Status status(user_status); + try { - if (clean->TransactionRoutine == routine && clean->clean_arg == arg) - { - break; - } + translate(tra_handle)->cleanup.add(routine, arg); } - - if (!clean) + catch (const std::exception& e) { - if (clean = (CLEAN) alloc((SLONG) sizeof(struct clean))) - { -#ifdef DEBUG_GDS_ALLOC - /* If client doesn't commit/rollback/detach - or drop, this could be left unfreed. */ - - gds_alloc_flag_unfreed((void *) clean); -#endif - clean->clean_next = transaction->cleanup; - transaction->cleanup = clean; - clean->TransactionRoutine = routine; - clean->clean_arg = arg; - } - else { - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error2(status, local); - } + Firebird::stuff_exception(status, e); } - status[0] = isc_arg_gds; - status[1] = FB_SUCCESS; - status[2] = isc_arg_end; - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -4990,53 +4919,60 @@ ISC_STATUS API_ROUTINE GDS_TRANSACTION_INFO(ISC_STATUS* user_status, * Provide information on transaction object. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction, sub; - SSHORT buffer_len, item_len; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*tra_handle, transaction, HANDLE_transaction, isc_bad_trans_handle); - subsystem_enter(); + try + { + Transaction* transaction = translate(tra_handle); + status.setPrimaryHandle(transaction); - if (transaction->implementation != SUBSYSTEMS) { - if (CALL(PROC_TRANSACTION_INFO, transaction->implementation) (status, + if (transaction->implementation != SUBSYSTEMS) { + CALL(PROC_TRANSACTION_INFO, transaction->implementation) (status, &transaction-> handle, item_length, items, buffer_length, + buffer); + } + else { + SSHORT item_len = item_length; + SSHORT buffer_len = buffer_length; + for (Transaction* sub = transaction->next; sub; sub = sub->next) { + if (CALL(PROC_TRANSACTION_INFO, sub->implementation) (status, + &sub-> + handle, + item_len, + items, + buffer_len, buffer)) - return error(status, local); - } - else { - item_len = item_length; - buffer_len = buffer_length; - for (sub = transaction->next; sub; sub = sub->next) { - if (CALL(PROC_TRANSACTION_INFO, sub->implementation) (status, - &sub-> - handle, - item_len, - items, - buffer_len, - buffer)) - return error(status, local); + { + return status[1]; + } - UCHAR* ptr = buffer; - const UCHAR* const end = buffer + buffer_len; - while (ptr < end && *ptr == isc_info_tra_id) - ptr += 3 + gds__vax_integer(ptr + 1, 2); + UCHAR* ptr = buffer; + const UCHAR* const end = buffer + buffer_len; + while (ptr < end && *ptr == isc_info_tra_id) + { + ptr += 3 + gds__vax_integer(ptr + 1, 2); + } - if (ptr >= end || *ptr != isc_info_end) { - RETURN_SUCCESS; + if (ptr >= end || *ptr != isc_info_end) + { + return status[1]; + } + + buffer_len = end - ptr; + buffer = ptr; } - - buffer_len = end - ptr; - buffer = ptr; } } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; + return status[1]; } @@ -5055,52 +4991,27 @@ ISC_STATUS API_ROUTINE GDS_UNWIND(ISC_STATUS * user_status, * asynchronously. * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_REQ request; + YEntry status(user_status); - GET_STATUS; - TRANSLATE_HANDLE(*req_handle, request, HANDLE_request, isc_bad_req_handle); - subsystem_enter(); + try + { + Request* request = translate(req_handle); + status.setPrimaryHandle(request); - if (CALL(PROC_UNWIND, request->implementation) (status, + CALL(PROC_UNWIND, request->implementation) (status, &request->handle, - level)) - return error(status, local); + level); + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); + } - RETURN_SUCCESS; -} - -#ifdef DEBUG_GDS_ALLOC -static SCHAR *alloc_debug(SLONG length, const char* file, int line) -#else -static SCHAR *alloc(SLONG length) -#endif -{ -/************************************** - * - * a l l o c - * - ************************************** - * - * Functional description - * Allocate some memory. - * - **************************************/ - SCHAR *block; - -#ifdef DEBUG_GDS_ALLOC - if (block = reinterpret_cast(gds__alloc_debug((SLONG) (sizeof(SCHAR) * length), file, line))) -#else - if (block = reinterpret_cast(gds__alloc((SLONG) (sizeof(SCHAR) * length)))) -#endif - memset(block, 0, length); - return block; + return status[1]; } -static ISC_STATUS bad_handle(ISC_STATUS * user_status, - ISC_STATUS code) +static void bad_handle(ISC_STATUS code) { /************************************** * @@ -5112,22 +5023,12 @@ static ISC_STATUS bad_handle(ISC_STATUS * user_status, * Generate an error for a bad handle. * **************************************/ - ISC_STATUS *s, *status; - ISC_STATUS_ARRAY local; - - GET_STATUS; - s = status; - *s++ = isc_arg_gds; - *s++ = code; - *s = isc_arg_end; - - return error2(status, local); + Firebird::status_exception::raise(code, isc_arg_end); } #ifdef DEV_BUILD -static void check_status_vector(const ISC_STATUS* status, - ISC_STATUS expected) +static void check_status_vector(const ISC_STATUS* status) { /************************************** * @@ -5155,13 +5056,12 @@ static void check_status_vector(const ISC_STATUS* status, /* Vector [2] could either end the vector, or start a warning in either case the status vector is a success */ - if ((expected == FB_SUCCESS) - && (s[1] != FB_SUCCESS - || (s[2] != isc_arg_end && s[2] != isc_arg_gds - && s[2] != - isc_arg_warning))) + if ((s[1] == FB_SUCCESS) && + (s[2] != isc_arg_end) && + (s[2] != isc_arg_gds) && + (s[2] != isc_arg_warning)) { - SV_MSG("Success vector expected"); + SV_MSG("Bad success vector format"); } ULONG length; @@ -5256,7 +5156,7 @@ static void check_status_vector(const ISC_STATUS* status, // Make this repetitive block a function. // Call all cleanup routines registered with the transaction. -void WHY_cleanup_transaction(WHY_TRA transaction) +/*void WHY_cleanup_transaction(Transaction* transaction) { for (clean* cln = transaction->cleanup; cln; cln = transaction->cleanup) { @@ -5264,61 +5164,7 @@ void WHY_cleanup_transaction(WHY_TRA transaction) cln->TransactionRoutine(transaction->public_handle, cln->clean_arg); free_block(cln); } -} - -static ISC_STATUS error(const ISC_STATUS* user_status, - const ISC_STATUS* local) -{ -/************************************** - * - * e r r o r - * - ************************************** - * - * Functional description - * An error returned has been trapped. If the user specified - * a status vector, return a status code. Otherwise print the - * error code(s) and abort. - * - **************************************/ - - subsystem_exit(); - - return error2(user_status, local); -} - - -static ISC_STATUS error2(const ISC_STATUS* user_status, - const ISC_STATUS* local) -{ -/************************************** - * - * e r r o r 2 - * - ************************************** - * - * Functional description - * An error returned has been trapped. If the user specified - * a status vector, return a status code. Otherwise print the - * error code(s) and abort. - * - **************************************/ - - CHECK_STATUS(user_status); - -#ifdef SUPERSERVER - return user_status[1]; -#else - if (user_status != local) - return user_status[1]; - - gds__print_status(user_status); - exit((int) user_status[1]); - - return FB_SUCCESS; -#endif -} - +}*/ #ifndef REQUESTER static void event_ast(void* buffer_void, @@ -5370,8 +5216,8 @@ static void exit_handler(event_t* why_eventL) #endif -static WHY_TRA find_transaction(WHY_DBB dbb, - WHY_TRA transaction) +static Transaction* find_transaction(Attachment* dbb, + Transaction* transaction) { /************************************** * @@ -5411,7 +5257,7 @@ static void free_block(void* block) static int get_database_info(ISC_STATUS * status, - WHY_TRA transaction, + Transaction* transaction, TEXT ** ptr) { /************************************** @@ -5433,9 +5279,9 @@ static int get_database_info(ISC_STATUS * status, // Our caller (prepare) assumed each call consumes at most 256 bytes (item, len, data) // hence if we don't check here, we have a B.O. TEXT* p = *ptr; - WHY_DBB database = transaction->parent; + Attachment* database = transaction->parent; *p++ = TDR_DATABASE_PATH; - const TEXT* q = database->db_path; + const TEXT* q = database->db_path.c_str(); size_t len = strlen(q); if (len > 254) len = 254; @@ -5493,25 +5339,21 @@ static const PTR get_entrypoint(int proc, } -static SCHAR *get_sqlda_buffer(SCHAR * buffer, - USHORT local_buffer_length, - XSQLDA * sqlda, - USHORT dialect, - USHORT * buffer_length) +static USHORT sqlda_buffer_size(XSQLDA * sqlda, + USHORT dialect) { /************************************** * - * g e t _ s q l d a _ b u f f e r + * s q l d a _ b u f f e r _ s i z e * ************************************** * * Functional description - * Get a buffer that is large enough to store - * the info items relating to an SQLDA. + * Calculate size of a buffer that is large enough + * to store the info items relating to an SQLDA. * **************************************/ USHORT n_variables; - SLONG length; USHORT sql_dialect; /* If dialect / 10 == 0, then it has not been combined with the @@ -5529,18 +5371,15 @@ static SCHAR *get_sqlda_buffer(SCHAR * buffer, else n_variables = ((SQLDA *) sqlda)->sqln; - length = 32 + n_variables * 172; - *buffer_length = (USHORT)((length > 65500L) ? 65500L : length); - if (*buffer_length > local_buffer_length) - buffer = alloc((SLONG) * buffer_length); + ULONG length = 32 + n_variables * 172; - return buffer; + return (USHORT)((length > 65500L) ? 65500L : length); } -static ISC_STATUS get_transaction_info(ISC_STATUS * status, - WHY_TRA transaction, - TEXT ** ptr) +static ISC_STATUS get_transaction_info(ISC_STATUS* user_status, + Transaction* transaction, + TEXT** ptr) { /************************************** * @@ -5553,34 +5392,42 @@ static ISC_STATUS get_transaction_info(ISC_STATUS * status, * description record. * **************************************/ - TEXT buffer[16]; + Status status(user_status); - TEXT* p = *ptr; - - if (CALL(PROC_TRANSACTION_INFO, transaction->implementation) (status, - &transaction-> - handle, - sizeof - (prepare_tr_info), - prepare_tr_info, - sizeof - (buffer), - buffer)) + try { - CHECK_STATUS(status); - return status[1]; + TEXT buffer[16]; + TEXT* p = *ptr; + status.ok(); + + if (CALL(PROC_TRANSACTION_INFO, transaction->implementation) (status, + &transaction-> + handle, + sizeof + (prepare_tr_info), + prepare_tr_info, + sizeof + (buffer), + buffer)) + { + return status[1]; + } + + const TEXT* q = buffer + 3; + *p++ = TDR_TRANSACTION_ID; + + const USHORT length = + (USHORT)gds__vax_integer(reinterpret_cast(buffer + 1), 2); + *p++ = length; // Warning: USHORT coerced to char + memcpy(p, q, length); + *ptr = p + length; + } + catch (const std::exception& e) + { + Firebird::stuff_exception(status, e); } - const TEXT* q = buffer + 3; - *p++ = TDR_TRANSACTION_ID; - - const USHORT length = (USHORT)gds__vax_integer(reinterpret_cast(buffer + 1), 2); - *p++ = length; // Warning: USHORT coerced to char - memcpy(p, q, length); - *ptr = p + length; - - CHECK_STATUS_SUCCESS(status); - return FB_SUCCESS; + return status[1]; } @@ -5654,64 +5501,52 @@ static ISC_STATUS open_blob(ISC_STATUS* user_status, * Open an existing blob (extended edition). * **************************************/ - ISC_STATUS *status; - ISC_STATUS_ARRAY local; - WHY_TRA transaction; - - GET_STATUS; - NULL_CHECK(public_blob_handle, isc_bad_segstr_handle, HANDLE_blob); - - WHY_ATT dbb; - TRANSLATE_HANDLE(*db_handle, dbb, HANDLE_database, isc_bad_db_handle); - FIND_TRANSACTION(*tra_handle, transaction, dbb, isc_bad_trans_handle); - subsystem_enter(); - - USHORT flags = 0; - USHORT from, to; - gds__parse_bpb(bpb_length, bpb, &from, &to); - - WHY_BLB blob_handle = NULL; - - if (get_entrypoint(proc2, dbb->implementation) != no_entrypoint && - CALL(proc2, dbb->implementation) (status, - &dbb->handle, - &transaction->handle, - &blob_handle, - blob_id, - bpb_length, - bpb) != isc_unavailable) + YEntry status(user_status); + StBlb* blob_handle = 0; + try { - flags = 0; - } - else if (!to || from == to) - CALL(proc, dbb->implementation) (status, - &dbb->handle, - &transaction->handle, - &blob_handle, blob_id); + nullCheck(public_blob_handle, isc_bad_segstr_handle); - if (status[1]) { - return error(status, local); - } + Attachment* dbb = translate(db_handle); + status.setPrimaryHandle(dbb); + Transaction* transaction = findTransaction(tra_handle, dbb); - WHY_BLB blob = allocate_handle(dbb->implementation, blob_handle, HANDLE_blob); - if (!blob) + USHORT flags = 0; + USHORT from, to; + gds__parse_bpb(bpb_length, bpb, &from, &to); + + if (get_entrypoint(proc2, dbb->implementation) != no_entrypoint && + CALL(proc2, dbb->implementation) (status, + &dbb->handle, + &transaction->handle, + &blob_handle, + blob_id, + bpb_length, + bpb) != isc_unavailable) + { + flags = 0; + } + else if (!to || from == to) + { + CALL(proc, dbb->implementation) (status, + &dbb->handle, + &transaction->handle, + &blob_handle, blob_id); + } + + if (status[1]) { + return status[1]; + } + + Blob* blob = new Blob(blob_handle, public_blob_handle, dbb); + blob->flags |= flags; + } + catch (const std::exception& e) { - /* No memory. Make a half-hearted attempt to cancel the blob. */ - - CALL(PROC_CANCEL_BLOB, dbb->implementation) (status, blob_handle); - status[0] = isc_arg_gds; - status[1] = isc_virmemexh; - status[2] = isc_arg_end; - return error(status, local); + Firebird::stuff_exception(status, e); } - *public_blob_handle = blob->public_handle; - blob->flags |= flags; - blob->parent = dbb; - blob->next = dbb->blobs; - dbb->blobs = blob; - - RETURN_SUCCESS; + return status[1]; } @@ -5739,8 +5574,8 @@ static ISC_STATUS no_entrypoint(ISC_STATUS * user_status, ...) } // extern "C" -static ISC_STATUS prepare(ISC_STATUS * status, - WHY_TRA transaction) +static ISC_STATUS prepare(ISC_STATUS* user_status, + Transaction* transaction) { /************************************** * @@ -5753,9 +5588,13 @@ static ISC_STATUS prepare(ISC_STATUS * status, * for a multi-database transaction. * **************************************/ - WHY_TRA sub; + Status status(user_status); + status.ok(); + + Transaction* sub; TEXT tdr_buffer[1024]; - int length = 0, transcount = 0; + size_t length = 0; + int transcount = 0; for (sub = transaction->next; sub; sub = sub->next) { @@ -5777,11 +5616,11 @@ static ISC_STATUS prepare(ISC_STATUS * status, information for the target databases. */ TEXT* p = description; - if (!p) { + if (!p) + { status[0] = isc_arg_gds; status[1] = isc_virmemexh; status[2] = isc_arg_end; - CHECK_STATUS(status); return status[1]; } @@ -5810,26 +5649,26 @@ static ISC_STATUS prepare(ISC_STATUS * status, if (description != tdr_buffer) { free_block(description); } - CHECK_STATUS(status); return status[1]; } if (description != tdr_buffer) free_block(description); - CHECK_STATUS_SUCCESS(status); return FB_SUCCESS; } -static void why_priv_gds__free_if_set(void* pMem) +inline void why_priv_gds__free_if_set(SCHAR** pMem) { - if (pMem) { - gds__free(pMem); + if (*pMem) + { + gds__free(*pMem); + *pMem = 0; } } -static void release_dsql_support(sqlda_sup* dasup) +static void release_dsql_support(sqlda_sup& dasup) { /************************************** * @@ -5841,34 +5680,12 @@ static void release_dsql_support(sqlda_sup* dasup) * Release some memory. * **************************************/ - if (!dasup) { - return; - } + sqlda_sup::dasup_clause* pClauses = dasup.dasup_clauses; - /* for C++, add "dasup::" before "dasup_clause" */ - sqlda_sup::dasup_clause* pClauses = dasup->dasup_clauses; - - why_priv_gds__free_if_set(pClauses[DASUP_CLAUSE_bind].dasup_blr); - why_priv_gds__free_if_set(pClauses[DASUP_CLAUSE_select].dasup_blr); - why_priv_gds__free_if_set(pClauses[DASUP_CLAUSE_bind].dasup_msg); - why_priv_gds__free_if_set(pClauses[DASUP_CLAUSE_select].dasup_msg); - free_block(dasup); -} - - -static void release_handle(WHY_HNDL handle) -{ -/************************************** - * - * r e l e a s e _ h a n d l e - * - ************************************** - * - * Functional description - * Release unused and unloved handle. - * - **************************************/ - WHY_free_handle(handle->public_handle); + why_priv_gds__free_if_set(&pClauses[DASUP_CLAUSE_bind].dasup_blr); + why_priv_gds__free_if_set(&pClauses[DASUP_CLAUSE_select].dasup_blr); + why_priv_gds__free_if_set(&pClauses[DASUP_CLAUSE_bind].dasup_msg); + why_priv_gds__free_if_set(&pClauses[DASUP_CLAUSE_select].dasup_msg); } @@ -5949,7 +5766,7 @@ static void save_error_string(ISC_STATUS * status) } -static void subsystem_enter(void) +static void subsystem_enter(void) throw() { /************************************** * @@ -5962,38 +5779,42 @@ static void subsystem_enter(void) * **************************************/ -#ifdef EMBEDDED - THD_INIT; -#endif - - THREAD_ENTER(); -#if !(defined REQUESTER || defined SUPERCLIENT || defined SUPERSERVER) - isc_enter_count++; - if (subsystem_usage == 0 || - (subsystem_FPE_reset & - (FPE_RESET_NEXT_API_CALL | FPE_RESET_ALL_API_CALL))) + try { - ISC_enter(); - subsystem_FPE_reset &= ~FPE_RESET_NEXT_API_CALL; - } + THREAD_ENTER(); +#if !(defined REQUESTER || defined SUPERCLIENT || defined SUPERSERVER) + isc_enter_count++; + if (subsystem_usage == 0 || + (subsystem_FPE_reset & + (FPE_RESET_NEXT_API_CALL | FPE_RESET_ALL_API_CALL))) + { + ISC_enter(); + subsystem_FPE_reset &= ~FPE_RESET_NEXT_API_CALL; + } #endif #ifdef DEBUG_FPE_HANDLING - { + { /* It's difficult to make a FPE to occur inside the engine - for debugging * just force one to occur every-so-often. */ - static ULONG counter = 0; - if (((counter++) % 10) == 0) - { - fprintf(stderr, "Forcing FPE to occur within engine\n"); - kill(getpid(), SIGFPE); + static ULONG counter = 0; + if (((counter++) % 10) == 0) + { + fprintf(stderr, "Forcing FPE to occur within engine\n"); + kill(getpid(), SIGFPE); + } } - } #endif /* DEBUG_FPE_HANDLING */ + } + catch(const std::exception&) + { + // ToDo: show full exception message here + gds__log("Unexpected exception in subsystem_enter()"); + } } -static void subsystem_exit(void) +static void subsystem_exit(void) throw() { /************************************** * @@ -6006,20 +5827,28 @@ static void subsystem_exit(void) * **************************************/ -#if !(defined REQUESTER || defined SUPERCLIENT || defined SUPERSERVER) - if (subsystem_usage == 0 || - (subsystem_FPE_reset & - (FPE_RESET_NEXT_API_CALL | FPE_RESET_ALL_API_CALL))) + try { - ISC_exit(); - } - isc_enter_count--; +#if !(defined REQUESTER || defined SUPERCLIENT || defined SUPERSERVER) + if (subsystem_usage == 0 || + (subsystem_FPE_reset & + (FPE_RESET_NEXT_API_CALL | FPE_RESET_ALL_API_CALL))) + { + ISC_exit(); + } + isc_enter_count--; #endif - THREAD_EXIT(); + THREAD_EXIT(); + } + catch(const std::exception&) + { + // ToDo: show full exception message here + gds__log("Unexpected exception in subsystem_exit()"); + } } -#if defined (SERVER_SHUTDOWN) && !defined (SUPERCLIENT) && !defined (REQUESTER) +#if !defined (SUPERCLIENT) && !defined (REQUESTER) BOOLEAN WHY_set_shutdown(BOOLEAN flag) { /************************************** diff --git a/src/jrd/why_proto.h b/src/jrd/why_proto.h index c06a88588a..14f82f89cb 100644 --- a/src/jrd/why_proto.h +++ b/src/jrd/why_proto.h @@ -255,8 +255,6 @@ SLONG API_ROUTINE isc_reset_fpe(USHORT); #endif /* JRD_IBASE_H */ #endif /* WHY_NO_API */ -typedef void DatabaseCleanupRoutine(FB_API_HANDLE*, void*); - #ifdef CANCEL_OPERATION #define CANCEL_disable 1 #define CANCEL_enable 2 @@ -264,8 +262,11 @@ typedef void DatabaseCleanupRoutine(FB_API_HANDLE*, void*); ISC_STATUS API_ROUTINE gds__cancel_operation(ISC_STATUS*, FB_API_HANDLE*, USHORT); #endif +typedef void AttachmentCleanupRoutine(FB_API_HANDLE*, void*); +typedef void TransactionCleanupRoutine(FB_API_HANDLE, void*); + ISC_STATUS API_ROUTINE isc_database_cleanup(ISC_STATUS*, FB_API_HANDLE*, - DatabaseCleanupRoutine*, void*); + AttachmentCleanupRoutine*, void*); int API_ROUTINE gds__disable_subsystem(TEXT*); int API_ROUTINE gds__enable_subsystem(TEXT*); @@ -275,7 +276,6 @@ ISC_STATUS gds__handle_cleanup(ISC_STATUS*, FB_API_HANDLE*); #define INTL_FUNCTION_OCTET_LENGTH 2 ISC_STATUS API_ROUTINE gds__intl_function(ISC_STATUS*, FB_API_HANDLE*, USHORT, UCHAR, USHORT, const UCHAR*, USHORT*); -typedef void TransactionCleanupRoutine(FB_API_HANDLE, void*); ISC_STATUS API_ROUTINE gds__transaction_cleanup(ISC_STATUS*, FB_API_HANDLE*, TransactionCleanupRoutine*, void*); void WHY_cleanup_transaction(struct why_hndl* transaction); @@ -290,9 +290,5 @@ BOOLEAN WHY_get_shutdown(); } /* extern "C"*/ #endif -struct why_hndl* WHY_alloc_handle(int implementation, int handle_type); -struct why_hndl* WHY_translate_handle(FB_API_HANDLE handle); -void WHY_free_handle(FB_API_HANDLE handle); - #endif // JRD_WHY_PROTO_H diff --git a/src/jrd/y_handle.h b/src/jrd/y_handle.h index fc2ed21ce3..82107a348c 100644 --- a/src/jrd/y_handle.h +++ b/src/jrd/y_handle.h @@ -25,12 +25,15 @@ #ifndef JRD_Y_HANDLE_H #define JRD_Y_HANDLE_H -/* - * These definitions placed into separate file - * to avoid multiple definition of struct why_hndl in why.cpp - * and dsql.cpp - * - */ +#include "../common/classes/alloc.h" +#include "../common/classes/array.h" +#include "../common/classes/fb_string.h" +#include "../dsql/sqlda_pub.h" +#include "../dsql/sqlda.h" +#include "../jrd/thread_proto.h" + +#include "gen/iberror.h" + namespace Jrd { class Attachment; @@ -38,52 +41,352 @@ namespace Jrd { class jrd_req; } -union any_handle { - struct why_hndl* h_why; - class dsql_req* h_dsql; - Jrd::Attachment* h_dbb; - Jrd::jrd_tra* h_tra; -}; +class dsql_req; -struct why_hndl +namespace YValve { - UCHAR type; - UCHAR flags; - USHORT implementation; - FB_API_HANDLE public_handle; - union any_handle handle; - struct why_hndl* parent; - struct why_hndl* next; - union { - struct why_hndl* requests; - struct sqlda_sup* das; + // flags + const UCHAR HANDLE_TRANSACTION_limbo = 1; + const UCHAR HANDLE_BLOB_filter = 2; /* Blob is locally filtered */ + const UCHAR HANDLE_STATEMENT_local = 4; /* Process DSQL statement locally */ + const UCHAR HANDLE_STATEMENT_prepared = 8; + const UCHAR HANDLE_shutdown = 0x10; // Database shutdown + + // forwards + class Attachment; + class Transaction; + class Request; + class Blob; + class Statement; + class Service; + + // force use of default memory pool for Y-Valve objects + class DefaultMemory + { + public: + void* operator new(size_t size) + { + return getDefaultMemoryPool()->allocate(size); + } + + void operator delete(void* mem) + { + getDefaultMemoryPool()->deallocate(mem); + } }; - struct why_hndl* statements; - struct why_hndl* blobs; - FB_API_HANDLE* user_handle; - struct clean* cleanup; - TEXT* db_path; -}; + + // stored handle types + typedef Jrd::jrd_tra StTra; + typedef void StReq; + typedef void StBlb; + typedef Jrd::Attachment StAtt; + typedef dsql_req StStm; + typedef void StSvc; -typedef why_hndl *WHY_HNDL; -typedef why_hndl *WHY_REQ; -typedef why_hndl *WHY_DBB; -typedef why_hndl *WHY_TRA; -typedef why_hndl *WHY_BLB; -typedef why_hndl *WHY_ATT; -typedef why_hndl *WHY_STMT; -typedef why_hndl *WHY_SVC; + template + class Clean : public DefaultMemory + { + private: + struct st_clean + { + CleanupRoutine *Routine; + void* clean_arg; + st_clean(CleanupRoutine *r, void* a) + : Routine(r), clean_arg(a) { } + st_clean() + : Routine(0), clean_arg(0) { } + }; + Firebird::HalfStaticArray calls; -const int HANDLE_invalid = 0; -const int HANDLE_database = 1; -const int HANDLE_transaction = 2; -const int HANDLE_request = 3; -const int HANDLE_blob = 4; -const int HANDLE_statement = 5; -const int HANDLE_service = 6; + public: + Clean() : calls(*getDefaultMemoryPool()) { } -const int HANDLE_TRANSACTION_limbo = 1; -const int HANDLE_BLOB_filter = 2; /* Blob is locally filtered */ -const int HANDLE_STATEMENT_local = 4; /* Process DSQL statement locally */ + void add(CleanupRoutine *r, void* a) + { + for (size_t i = 0; i < calls.getCount(); ++i) + { + if (calls[i].Routine == r && + calls[i].clean_arg == a) + { + return; + } + } + calls.add(st_clean(r, a)); + } + + void call(CleanupArg public_handle) + { + for (size_t i = 0; i < calls.getCount(); ++i) + { + if (calls[i].Routine) + { + THREAD_EXIT(); + calls[i].Routine(public_handle, calls[i].clean_arg); + THREAD_ENTER(); + } + } + } + }; + + class Handle : public DefaultMemory + { + public: + UCHAR type; + UCHAR flags; + USHORT implementation; + FB_API_HANDLE public_handle; + Attachment* parent; + FB_API_HANDLE* user_handle; + + protected: + Handle(UCHAR t, FB_API_HANDLE* pub, Attachment* par, USHORT imp = ~0); + + public: + static Handle* translate(FB_API_HANDLE); + Jrd::Attachment* getAttachmentHandle(); + void cancel(); + ~Handle(); + + // required to put pointers to it into the tree + static const FB_API_HANDLE& generate(const void* sender, Handle* value) { + return value->public_handle; + } + }; + + template + void toParent(Firebird::SortedArray& members, HType* newMember) + { + members.add(newMember); + } + + template + void fromParent(Firebird::SortedArray& members, HType* newMember) + { + size_t pos; + if (members.find(newMember, pos)) + { + members.remove(pos); + } +#ifdef DEV_BUILD + else + { + //Attempt to deregister not registered member + fb_assert(false); + } +#endif + } + + template + ToHandle* translate(FB_API_HANDLE* handle) + { + if (handle && *handle) + { + Handle* rc = Handle::translate(*handle); + if (rc && rc->type == ToHandle::hType()) + { + return reinterpret_cast(rc); + } + } + + Firebird::status_exception::raise(ToHandle::hError(), + isc_arg_end); + // compiler warning silencer + return 0; + } + + class Attachment : public Handle + { + public: + Firebird::SortedArray transactions; + Firebird::SortedArray requests; + Firebird::SortedArray blobs; + Firebird::SortedArray statements; + + Clean cleanup; + StAtt* handle; + Firebird::PathName db_path; + + static ISC_STATUS hError() + { + return isc_bad_db_handle; + } + + static UCHAR hType() + { + return 1; + } + + public: + Attachment(StAtt*, FB_API_HANDLE*, USHORT); + void cancel2(); + ~Attachment(); + }; + + class Transaction : public Handle + { + public: + Clean cleanup; + Transaction* next; + StTra* handle; + + static ISC_STATUS hError() + { + return isc_bad_trans_handle; + } + + static UCHAR hType() + { + return 2; + } + + public: + Transaction(StTra* h, FB_API_HANDLE* pub, Attachment* par) + : Handle(hType(), pub, par), + next(0), handle(h) + { + toParent(parent->transactions, this); + } + + Transaction(FB_API_HANDLE* pub, USHORT implementation) + : Handle(hType(), pub, 0, implementation), + next(0), handle(0) + { + // toParent(parent->transactions, this); + } + + ~Transaction() + { + cleanup.call(public_handle); + if (parent) + { + fromParent(parent->transactions, this); + } + } + }; + + class Request : public Handle + { + public: + StReq* handle; + + static ISC_STATUS hError() + { + return isc_bad_req_handle; + } + + static UCHAR hType() + { + return 3; + } + + public: + Request(StReq* h, FB_API_HANDLE* pub, Attachment* par) + : Handle(hType(), pub, par), handle(h) + { + toParent(parent->requests, this); + } + + ~Request() + { + fromParent(parent->requests, this); + } + }; + + class Blob : public Handle + { + public: + StBlb* handle; + + static ISC_STATUS hError() + { + return isc_bad_segstr_handle; + } + + static UCHAR hType() + { + return 4; + } + + public: + Blob(StBlb* h, FB_API_HANDLE* pub, Attachment* par) + : Handle(hType(), pub, par), handle(h) + { + toParent(parent->blobs, this); + } + + ~Blob() + { + fromParent(parent->blobs, this); + } + }; + + class Statement : public Handle + { + public: + StStm* handle; + struct sqlda_sup das; + + static ISC_STATUS hError() + { + return isc_bad_stmt_handle; + } + + static UCHAR hType() + { + return 5; + } + + public: + Statement(StStm* h, FB_API_HANDLE* pub, Attachment* par) + : Handle(hType(), pub, par), handle(h) + { + toParent(parent->statements, this); + memset(&das, 0, sizeof das); + } + + void checkPrepared() + { + if (!(flags & HANDLE_STATEMENT_prepared)) + { + Firebird::status_exception::raise(isc_unprepared_stmt, isc_arg_end); + } + } + + ~Statement() + { + fromParent(parent->statements, this); + } + }; + + class Service : public Handle + { + public: + Clean cleanup; + StSvc* handle; + + static ISC_STATUS hError() + { + return isc_bad_svc_handle; + } + + static UCHAR hType() + { + return 6; + } + + public: + Service(StSvc* h, FB_API_HANDLE* pub, USHORT impl) + : Handle(hType(), pub, 0, impl), handle(h) + + { + } + + ~Service() + { + cleanup.call(&public_handle); + } + }; + +} #endif // JRD_Y_HANDLE_H diff --git a/src/remote/server.cpp b/src/remote/server.cpp index cbeff8c306..47940c1b50 100644 --- a/src/remote/server.cpp +++ b/src/remote/server.cpp @@ -4429,6 +4429,15 @@ ISC_STATUS rem_port::send_response( PACKET* sendL, this->send(sendL); +#ifndef SUPERSERVER + // In case of CS remote listener we have a single connection system. + // If database is shut down, it's no use running fb_inet_server any more. + if (exit_code == isc_shutdown) + { + exit(0); + } +#endif + return exit_code; }