8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 15:23:03 +01:00
firebird-mirror/src/jrd/jrd.cpp

6618 lines
159 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Access Method
* MODULE: jrd.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: User visible entrypoints
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-07-02 11:49:19 +02:00
*
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
* conditionals, as the engine now fully supports
* readonly databases.
2002-07-02 11:49:19 +02:00
* 2001.07.09 Sean Leyne - Restore default setting to Force Write = "On", for
* Windows NT platform, for new database files. This was changed
* with IB 6.0 to OFF and has introduced many reported database
* corruptions.
2002-10-30 07:40:58 +01:00
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2004-03-22 12:38:23 +01:00
#include "../jrd/common.h"
2004-04-29 00:43:34 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <string.h>
#include <stdlib.h>
#include "../jrd/common.h"
#include "../jrd/thd.h"
#include "../jrd/os/thd_priority.h"
2001-05-23 15:26:42 +02:00
#include <stdarg.h>
#ifdef HAVE_UNISTD_H
2001-05-23 15:26:42 +02:00
#include <unistd.h>
#endif
2003-02-19 07:14:39 +01:00
#ifdef HAVE_PWD_H
#include <pwd.h>
2001-12-24 03:51:06 +01:00
#endif
2001-05-23 15:26:42 +02:00
#include <errno.h>
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/jrd.h"
#include "../jrd/irq.h"
#include "../jrd/isc.h"
#include "../jrd/drq.h"
#include "../jrd/req.h"
#include "../jrd/tra.h"
#include "../jrd/blb.h"
#include "../jrd/lck.h"
#include "../jrd/nbak.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/scl.h"
//#include "../jrd/license.h"
2003-07-14 12:35:49 +02:00
#include "../jrd/os/pio.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ods.h"
#include "../jrd/exe.h"
#include "../jrd/val.h"
#include "../jrd/rse.h"
#include "../jrd/all.h"
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
2001-05-23 15:26:42 +02:00
#include "../jrd/log.h"
#endif
2001-05-23 15:26:42 +02:00
#include "../jrd/fil.h"
#include "../jrd/sbm.h"
#include "../jrd/svc.h"
#include "../jrd/sdw.h"
#include "../jrd/lls.h"
#include "../jrd/cch.h"
#include "../jrd/iberr.h"
//#include "../common/classes/timestamp.h"
2001-05-23 15:26:42 +02:00
#include "../intl/charsets.h"
2003-12-22 11:00:59 +01:00
#include "../jrd/sort.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/all_proto.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cch_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dbg_proto.h"
#include "../jrd/dls_proto.h"
#include "../jrd/dyn_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/ext_proto.h"
#include "../jrd/fun_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/iberr_proto.h"
#include "../jrd/inf_proto.h"
#include "../jrd/ini_proto.h"
#include "../jrd/intl_proto.h"
#include "../jrd/inuse_proto.h"
#include "../jrd/isc_f_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/jrd_proto.h"
#include "../jrd/lck_proto.h"
#include "../jrd/log_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/mov_proto.h"
#include "../jrd/pag_proto.h"
#include "../jrd/par_proto.h"
2003-07-14 12:35:49 +02:00
#include "../jrd/os/pio_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/sch_proto.h"
#include "../jrd/scl_proto.h"
#include "../jrd/sdw_proto.h"
#include "../jrd/shut_proto.h"
#include "../jrd/sort_proto.h"
#include "../jrd/svc_proto.h"
#include "../jrd/thread_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/tra_proto.h"
#include "../jrd/val_proto.h"
#include "../jrd/file_params.h"
#include "../jrd/event_proto.h"
#include "../jrd/why_proto.h"
#include "../jrd/flags.h"
2001-05-23 15:26:42 +02:00
#include "../common/config/config.h"
#include "../jrd/plugin_manager.h"
#include "../jrd/db_alias.h"
2005-05-28 00:45:31 +02:00
#include "../jrd/IntlManager.h"
2004-05-03 01:06:37 +02:00
#include "../common/classes/fb_tls.h"
#include "../common/classes/ClumpletReader.h"
2001-05-23 15:26:42 +02:00
#ifdef GARBAGE_THREAD
#include "vio_proto.h"
#endif
using namespace Jrd;
2001-05-23 15:26:42 +02:00
#ifdef SERVER_SHUTDOWN
struct db_file {
db_file* dbf_next;
2001-05-23 15:26:42 +02:00
USHORT dbf_length;
TEXT dbf_data[2];
};
2001-05-23 15:26:42 +02:00
2003-12-22 11:00:59 +01:00
//#include "../jrd/sort.h"
2001-05-23 15:26:42 +02:00
#endif /* SERVER_SHUTDOWN */
2004-05-07 00:11:24 +02:00
const SSHORT WAIT_PERIOD = -1;
2001-05-23 15:26:42 +02:00
#ifdef SUPPORT_RAW_DEVICES
#define unlink PIO_unlink
#endif
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
#define V4_THREADING
#endif /* SUPERSERVER */
# ifdef V4_THREADING
# undef V4_INIT
# undef V4_GLOBAL_MUTEX_LOCK
# undef V4_GLOBAL_MUTEX_UNLOCK
# undef V4_MUTEX_INIT
# undef V4_MUTEX_LOCK
# undef V4_MUTEX_UNLOCK
# undef V4_MUTEX_DESTROY
# undef V4_JRD_MUTEX_LOCK
# undef V4_JRD_MUTEX_UNLOCK
# define V4_INIT THD_INIT
2004-05-15 02:58:46 +02:00
# define V4_GLOBAL_MUTEX_LOCK {THREAD_EXIT(); THD_GLOBAL_MUTEX_LOCK; THREAD_ENTER();}
2001-05-23 15:26:42 +02:00
# define V4_GLOBAL_MUTEX_UNLOCK THD_GLOBAL_MUTEX_UNLOCK
# define V4_MUTEX_INIT(mutx) THD_MUTEX_INIT (mutx)
2004-05-15 02:58:46 +02:00
# define V4_MUTEX_LOCK(mutx) {THREAD_EXIT(); THD_MUTEX_LOCK (mutx); THREAD_ENTER();}
2001-05-23 15:26:42 +02:00
# define V4_MUTEX_UNLOCK(mutx) THD_MUTEX_UNLOCK (mutx)
# define V4_MUTEX_DESTROY(mutx) THD_MUTEX_DESTROY (mutx)
# ifndef SUPERSERVER
2004-05-15 02:58:46 +02:00
# define V4_JRD_MUTEX_LOCK(mutx) {THREAD_EXIT(); THD_JRD_MUTEX_LOCK (mutx); THREAD_ENTER();}
2001-05-23 15:26:42 +02:00
# define V4_JRD_MUTEX_UNLOCK(mutx) THD_JRD_MUTEX_UNLOCK (mutx)
# endif /* SUPERSERVER */
# endif /* V4_THREADING */
#ifdef SUPERSERVER
extern SLONG trace_pools;
static REC_MUTX_T databases_rec_mutex;
// BRS. 03/23/2003
// Those empty defines was substituted with #if defined(V4_THREADING) && !defined(SUPERSERVER)
//#define V4_JRD_MUTEX_LOCK(mutx)
//#define V4_JRD_MUTEX_UNLOCK(mutx)
2001-05-23 15:26:42 +02:00
#define JRD_SS_INIT_MUTEX THD_rec_mutex_init (&databases_rec_mutex)
#define JRD_SS_DESTROY_MUTEX THD_rec_mutex_destroy (&databases_rec_mutex)
2004-05-15 02:58:46 +02:00
#define JRD_SS_MUTEX_LOCK {THREAD_EXIT();\
2001-05-23 15:26:42 +02:00
THD_rec_mutex_lock (&databases_rec_mutex);\
2004-05-15 02:58:46 +02:00
THREAD_ENTER();}
2001-05-23 15:26:42 +02:00
#define JRD_SS_MUTEX_UNLOCK THD_rec_mutex_unlock (&databases_rec_mutex)
#define JRD_SS_THD_MUTEX_LOCK THD_rec_mutex_lock (&databases_rec_mutex)
#define JRD_SS_THD_MUTEX_UNLOCK THD_rec_mutex_unlock (&databases_rec_mutex)
#else
#define JRD_SS_INIT_MUTEX
#define JRD_SS_DESTROY_MUTEX
#define JRD_SS_MUTEX_LOCK
#define JRD_SS_MUTEX_UNLOCK
#define JRD_SS_THD_MUTEX_LOCK
#define JRD_SS_THD_MUTEX_UNLOCK
#endif
#ifdef WIN_NT
#include <windows.h>
2002-11-11 11:03:35 +01:00
/* these should stop a most annoying warning */
2001-05-23 15:26:42 +02:00
#undef TEXT
#define TEXT SCHAR
#endif // WIN_NT
2004-04-19 17:29:29 +02:00
void Jrd::Trigger::compile(thread_db* tdbb)
2002-10-24 13:16:59 +02:00
{
if (!request && !compile_in_progress)
{
SET_TDBB(tdbb);
compile_in_progress = true;
// Allocate statement memory pool
JrdMemoryPool* new_pool = JrdMemoryPool::createPool();
// Trigger request is not compiled yet. Lets do it now
USHORT par_flags = (USHORT)
(flags & TRG_ignore_perm) ? csb_ignore_perm : 0;
if (type & 1)
par_flags |= csb_pre_trigger;
else
par_flags |= csb_post_trigger;
2002-09-26 20:13:02 +02:00
try {
Jrd::ContextPoolHolder context(tdbb, new_pool);
2004-04-19 17:29:29 +02:00
PAR_blr(tdbb, relation, blr.begin(), NULL, NULL, &request, true,
par_flags);
2002-10-24 13:16:59 +02:00
}
2003-02-13 14:33:57 +01:00
catch (const std::exception&) {
compile_in_progress = false;
if (request) {
2004-11-24 10:22:07 +01:00
CMP_release(tdbb, request);
request = NULL;
}
else {
JrdMemoryPool::deletePool(new_pool);
2002-10-24 13:16:59 +02:00
}
2002-09-26 20:13:02 +02:00
throw;
}
request->req_trg_name = name;
if (sys_trigger)
2004-04-19 17:29:29 +02:00
{
2002-10-24 13:16:59 +02:00
request->req_flags |= req_sys_trigger;
2004-04-19 17:29:29 +02:00
}
if (flags & TRG_ignore_perm)
2004-04-19 17:29:29 +02:00
{
2002-10-24 13:16:59 +02:00
request->req_flags |= req_ignore_perm;
2004-04-19 17:29:29 +02:00
}
2002-10-24 13:16:59 +02:00
compile_in_progress = false;
}
}
2004-04-19 17:29:29 +02:00
void Jrd::Trigger::release(thread_db* tdbb)
2002-10-24 13:16:59 +02:00
{
2004-04-19 17:29:29 +02:00
if (blr.getCount() == 0 //sys_trigger
|| !request || CMP_clone_is_active(request))
{
return; // FALSE;
2002-10-24 13:16:59 +02:00
}
CMP_release(tdbb, request);
2002-10-24 13:16:59 +02:00
request = NULL;
return; // TRUE;
}
2001-05-23 15:26:42 +02:00
/* Option block for database parameter block */
class DatabaseOptions
2001-05-23 15:26:42 +02:00
{
public:
2001-05-23 15:26:42 +02:00
USHORT dpb_wal_action;
SLONG dpb_sweep_interval;
ULONG dpb_page_buffers;
bool dpb_set_page_buffers;
2001-05-23 15:26:42 +02:00
ULONG dpb_buffers;
USHORT dpb_debug;
USHORT dpb_verify;
USHORT dpb_sweep;
USHORT dpb_trace;
USHORT dpb_disable;
USHORT dpb_dbkey_scope;
USHORT dpb_page_size;
bool dpb_activate_shadow;
bool dpb_delete_shadow;
2001-05-23 15:26:42 +02:00
USHORT dpb_no_garbage;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
bool dpb_quit_log;
#endif
2001-05-23 15:26:42 +02:00
USHORT dpb_shutdown;
SSHORT dpb_shutdown_delay;
USHORT dpb_online;
SSHORT dpb_force_write;
UCHAR dpb_set_force_write;
UCHAR dpb_no_reserve;
UCHAR dpb_set_no_reserve;
SSHORT dpb_interp;
USHORT dpb_single_user;
bool dpb_overwrite;
bool dpb_sec_attach;
bool dpb_disable_wal;
bool dpb_gsec_attach;
2001-05-23 15:26:42 +02:00
SLONG dpb_connect_timeout;
SLONG dpb_dummy_packet_interval;
bool dpb_db_readonly;
bool dpb_set_db_readonly;
bool dpb_gfix_attach;
bool dpb_gstat_attach;
2001-05-23 15:26:42 +02:00
USHORT dpb_sql_dialect;
USHORT dpb_set_db_sql_dialect;
// here begin compound objects
// for constructor to work properly dpb_sys_user_name
// MUST be FIRST
Firebird::string dpb_sys_user_name;
Firebird::string dpb_user_name;
Firebird::string dpb_password;
Firebird::string dpb_password_enc;
Firebird::string dpb_role_name;
Firebird::string dpb_journal;
Firebird::string dpb_key;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
Firebird::PathName dpb_log;
#endif
Firebird::PathName dpb_lc_messages;
Firebird::string dpb_lc_ctype;
Firebird::string dpb_gbak_attach;
Firebird::PathName dpb_working_directory;
Firebird::string dpb_set_db_charset;
Firebird::string dpb_network_protocol;
Firebird::string dpb_remote_address;
public:
DatabaseOptions()
{
memset(this, 0,
reinterpret_cast<char*>(&this->dpb_sys_user_name) -
reinterpret_cast<char*>(this));
}
void get(const UCHAR*, USHORT);
2004-05-24 19:31:47 +02:00
};
static blb* check_blob(thread_db*, ISC_STATUS*, blb**);
static ISC_STATUS check_database(thread_db*, Attachment*, ISC_STATUS*);
2001-05-23 15:26:42 +02:00
static void cleanup(void*);
static ISC_STATUS commit(ISC_STATUS*, jrd_tra**, const bool);
static bool drop_files(const jrd_file*);
static ISC_STATUS error(ISC_STATUS*, const std::exception& ex);
2003-04-10 08:49:16 +02:00
static ISC_STATUS error(ISC_STATUS*);
static void find_intl_charset(thread_db*, Attachment*, const DatabaseOptions*);
static jrd_tra* find_transaction(thread_db*, jrd_tra*, ISC_STATUS);
static ISC_STATUS handle_error(ISC_STATUS*, ISC_STATUS, thread_db*);
static void verify_request_synchronization(jrd_req*& request, SSHORT level);
namespace {
enum vdnResult {vdnFail, vdnOk, vdnSecurity};
}
static vdnResult verify_database_name(const Firebird::PathName&, ISC_STATUS*);
2001-05-23 15:26:42 +02:00
#if defined (WIN_NT)
#ifdef SERVER_SHUTDOWN
static void ExtractDriveLetter(const TEXT*, ULONG*);
#else // SERVER_SHUTDOWN
2001-05-23 15:26:42 +02:00
static void setup_NT_handlers(void);
static BOOLEAN handler_NT(SSHORT);
#endif // SERVER_SHUTDOWN
2001-05-23 15:26:42 +02:00
#endif // WIN_NT
static Database* init(thread_db*, ISC_STATUS*, const Firebird::PathName&, bool);
static ISC_STATUS prepare(thread_db*, jrd_tra*, ISC_STATUS*, USHORT, const UCHAR*);
static void release_attachment(Attachment*);
static ISC_STATUS return_success(thread_db*);
static bool rollback(thread_db*, jrd_tra*, ISC_STATUS*, const bool);
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
static void shutdown_database(Database*, const bool);
static void strip_quotes(Firebird::string&);
static void purge_attachment(thread_db*, ISC_STATUS*, Attachment*, const bool);
2001-05-23 15:26:42 +02:00
2003-12-03 09:19:24 +01:00
static bool initialized = false;
2004-03-07 08:58:55 +01:00
static Database* databases = NULL;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
static MUTX_T databases_mutex[1];
#endif
2001-05-23 15:26:42 +02:00
static ULONG JRD_cache_default;
#ifdef GOVERNOR
const int ATTACHMENTS_PER_USER = 1;
2001-05-23 15:26:42 +02:00
static ULONG JRD_max_users = 0;
static ULONG num_attached = 0;
#endif /* GOVERNOR */
2003-09-22 19:56:35 +02:00
#if !defined(REQUESTER)
2001-05-23 15:26:42 +02:00
int debug;
2003-09-22 19:56:35 +02:00
#endif // !REQUESTER
2001-05-23 15:26:42 +02:00
//____________________________________________________________
//
// check whether we need to perform an autocommit;
// do it here to prevent committing every record update
// in a statement
//
static void check_autocommit(jrd_req* request, thread_db* tdbb)
2001-05-23 15:26:42 +02:00
{
/* dimitr: we should ignore autocommit for requests
created by EXECUTE STATEMENT */
if (request->req_transaction->tra_callback_count > 0)
return;
2001-05-23 15:26:42 +02:00
if (request->req_transaction->tra_flags & TRA_perform_autocommit)
{
request->req_transaction->tra_flags &= ~TRA_perform_autocommit;
TRA_commit(tdbb, request->req_transaction, true);
2001-05-23 15:26:42 +02:00
}
}
2003-04-10 08:49:16 +02:00
inline static void api_entry_point_init(ISC_STATUS* user_status)
2001-05-23 15:26:42 +02:00
{
2003-11-08 17:40:17 +01:00
user_status[0] = isc_arg_gds;
user_status[1] = FB_SUCCESS;
2003-11-08 17:40:17 +01:00
user_status[2] = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
inline static thread_db* JRD_MAIN_set_thread_data(thread_db& thd_context)
2001-05-23 15:26:42 +02:00
{
thread_db* tdbb = &thd_context;
2001-05-23 15:26:42 +02:00
JRD_set_context(tdbb);
return tdbb;
}
2004-11-24 10:22:07 +01:00
#define CHECK_HANDLE(blk, type, error) \
2001-12-24 03:51:06 +01:00
if (!blk || MemoryPool::blk_type(blk) != type) \
2001-05-23 15:26:42 +02:00
return handle_error (user_status, error, tdbb)
2004-11-24 10:22:07 +01:00
#define NULL_CHECK(ptr, code) \
2001-05-23 15:26:42 +02:00
if (*ptr) return handle_error (user_status, code, tdbb)
const int SWEEP_INTERVAL = 20000;
2001-05-23 15:26:42 +02:00
const char DBL_QUOTE = '\042';
const char SINGLE_QUOTE = '\'';
const int BUFFER_LENGTH128 = 128;
bool invalid_client_SQL_dialect = false;
2001-05-23 15:26:42 +02:00
#define GDS_ATTACH_DATABASE jrd8_attach_database
#define GDS_BLOB_INFO jrd8_blob_info
#define GDS_CANCEL_BLOB jrd8_cancel_blob
#define GDS_CANCEL_EVENTS jrd8_cancel_events
#define GDS_CANCEL_OPERATION jrd8_cancel_operation
#define GDS_CLOSE_BLOB jrd8_close_blob
#define GDS_COMMIT jrd8_commit_transaction
#define GDS_COMMIT_RETAINING jrd8_commit_retaining
#define GDS_COMPILE jrd8_compile_request
#define GDS_CREATE_BLOB2 jrd8_create_blob2
#define GDS_CREATE_DATABASE jrd8_create_database
#define GDS_DATABASE_INFO jrd8_database_info
#define GDS_DDL jrd8_ddl
#define GDS_DETACH jrd8_detach_database
#define GDS_DROP_DATABASE jrd8_drop_database
#define GDS_INTL_FUNCTION jrd8_intl_function
2001-05-23 15:26:42 +02:00
#define GDS_GET_SEGMENT jrd8_get_segment
#define GDS_GET_SLICE jrd8_get_slice
#define GDS_OPEN_BLOB2 jrd8_open_blob2
#define GDS_PREPARE jrd8_prepare_transaction
#define GDS_PUT_SEGMENT jrd8_put_segment
#define GDS_PUT_SLICE jrd8_put_slice
#define GDS_QUE_EVENTS jrd8_que_events
#define GDS_RECONNECT jrd8_reconnect_transaction
#define GDS_RECEIVE jrd8_receive
#define GDS_RELEASE_REQUEST jrd8_release_request
#define GDS_REQUEST_INFO jrd8_request_info
#define GDS_ROLLBACK jrd8_rollback_transaction
#define GDS_ROLLBACK_RETAINING jrd8_rollback_retaining
#define GDS_SEEK_BLOB jrd8_seek_blob
#define GDS_SEND jrd8_send
#define GDS_SERVICE_ATTACH jrd8_service_attach
#define GDS_SERVICE_DETACH jrd8_service_detach
#define GDS_SERVICE_QUERY jrd8_service_query
#define GDS_SERVICE_START jrd8_service_start
#define GDS_START_AND_SEND jrd8_start_and_send
#define GDS_START jrd8_start_request
#define GDS_START_MULTIPLE jrd8_start_multiple
#define GDS_START_TRANSACTION jrd8_start_transaction
#define GDS_TRANSACT_REQUEST jrd8_transact_request
#define GDS_TRANSACTION_INFO jrd8_transaction_info
#define GDS_UNWIND jrd8_unwind_request
/* External hook definitions */
/* dimitr: just uncomment the following line to use this feature.
Requires support from the PIO modules. Only Win32 is 100% ready
for this so far. Note that the database encryption code in the
PIO layer seems to be incompatible with the SUPERSERVER_V2 code.
2003.02.09 */
//#define ISC_DATABASE_ENCRYPTION
static const char* CRYPT_IMAGE = "fbcrypt";
static const char* ENCRYPT = "encrypt";
static const char* DECRYPT = "decrypt";
2001-05-23 15:26:42 +02:00
2004-05-03 01:06:37 +02:00
namespace {
TLS_DECLARE(bool, thread_security_disabled);
}
void JRD_thread_security_disable(bool disable)
{
/**************************************
*
* J R D _ t h r e a d _ s e c u r i t y _ d i s a b l e
*
**************************************
*
* Functional description
* Disable database attache security for this thread for the purposes of database attach
*
**************************************/
TLS_SET(thread_security_disabled, disable);
}
2001-05-23 15:26:42 +02:00
bool JRD_get_thread_security_disabled()
{
/**************************************
*
* J R D _ g e t _ t h r e a d _ s e c u r i t y _ d i s a b l e d
*
**************************************
*
* Functional description
* Don't run internal handles thru the security gauntlet.
*
**************************************/
return TLS_GET(thread_security_disabled);
}
void JRD_print_pools(const char* filename) {
FILE *out = fopen(filename, "w");
ALL_print_memory_pool_info(out, databases);
fclose(out);
}
2004-10-28 07:23:16 +02:00
ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
SSHORT _file_length,
const TEXT* _file_name,
Attachment** handle,
SSHORT dpb_length,
const UCHAR* dpb,
const TEXT* _expanded_filename)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ a t t a c h _ d a t a b a s e
*
**************************************
*
* Functional description
* Attach a moldy, grungy, old database
* sullied by user data.
*
**************************************/
api_entry_point_init(user_status);
if (*handle) {
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, 0);
2001-05-23 15:26:42 +02:00
}
Firebird::PathName file_name(_file_name,
_file_length ? _file_length : strlen(_file_name));
Firebird::PathName expanded_name(file_name);
2001-05-23 15:26:42 +02:00
/* Resolve given alias name */
const bool is_alias = ResolveDatabaseAlias(expanded_name, expanded_name);
if (is_alias)
{
ISC_expand_filename(expanded_name, false);
}
else
{
expanded_name = _expanded_filename;
}
2001-05-23 15:26:42 +02:00
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
/* Check database against conf file. */
const vdnResult vdn = verify_database_name(expanded_name, user_status);
if (!is_alias && vdn == vdnFail)
{
JRD_restore_context();
return user_status[1];
}
else
user_status[0] = 0; // Clear status vector
2001-05-23 15:26:42 +02:00
/* Unless we're already attached, do some initialization */
2004-03-07 08:58:55 +01:00
Database* dbb = init(tdbb, user_status, expanded_name, true);
2001-05-23 15:26:42 +02:00
if (!dbb) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
JRD_restore_context();
return user_status[1];
}
// use database context pool
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
2001-05-23 15:26:42 +02:00
dbb->dbb_flags |= DBB_being_opened;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = dbb;
/* Initialize special error handling */
ISC_STATUS* status;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = status = user_status;
Attachment* attachment;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_attachment = attachment = NULL;
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
/* Count active thread in database */
++dbb->dbb_use_count;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
bool initing_security = false;
2001-05-23 15:26:42 +02:00
#endif
/* The following line seems to fix a bug that appears on
SCO EVEREST. It probably has to do with the fact that
the error handler below used to contain the first reference to
variable transaction, which is actually initialized a few lines
below that. */
attachment = *(&attachment);
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
/* Process database parameter block */
DatabaseOptions options;
options.get(dpb, dpb_length);
2001-05-23 15:26:42 +02:00
#ifndef NO_NFS
/* Don't check nfs if single user */
if (!options.dpb_single_user)
#endif
{
/* Check to see if the database is truly local or if it just looks
that way */
if (ISC_check_if_remote(expanded_name, true)) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_unavailable, 0);
2003-04-06 11:08:58 +02:00
}
2001-05-23 15:26:42 +02:00
}
2004-11-08 09:01:26 +01:00
/* If database to be opened is SecurityDatabase, then only
gsec or SecurityDatabase may open it. This protects from use
of old gsec to write wrong password hashes into it. */
if (vdn == vdnSecurity && !options.dpb_gsec_attach && !options.dpb_sec_attach)
{
ERR_post(isc_no_priv,
isc_arg_string, "direct",
isc_arg_string, "security database",
isc_arg_string,
ERR_string(file_name),
0);
}
2001-05-23 15:26:42 +02:00
/* Worry about encryption key */
if (dbb->dbb_decrypt) {
if (dbb->dbb_filename.hasData() &&
(dbb->dbb_encrypt_key.hasData() || options.dpb_key.hasData()))
{
if ((dbb->dbb_encrypt_key.hasData() && options.dpb_key.isEmpty()) ||
(dbb->dbb_encrypt_key.empty() && options.dpb_key.hasData()) ||
(dbb->dbb_encrypt_key != options.dpb_key))
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_no_priv,
isc_arg_string, "encryption",
isc_arg_string, "database",
isc_arg_string,
ERR_string(file_name),
0);
}
2001-05-23 15:26:42 +02:00
}
else if (options.dpb_key.hasData())
{
dbb->dbb_encrypt_key = options.dpb_key;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
}
tdbb->tdbb_attachment = attachment = FB_NEW(*dbb->dbb_permanent) Attachment(dbb);
attachment->att_filename = expanded_name;
attachment->att_network_protocol = options.dpb_network_protocol;
attachment->att_remote_address = options.dpb_remote_address;
2001-05-23 15:26:42 +02:00
attachment->att_next = dbb->dbb_attachments;
dbb->dbb_attachments = attachment;
dbb->dbb_flags &= ~DBB_being_opened;
dbb->dbb_sys_trans->tra_attachment = attachment;
tdbb->tdbb_quantum = (ThreadPriorityScheduler::boosted() ?
Config::getPriorityBoost() : 1) * QUANTUM;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
2002-09-26 11:26:40 +02:00
tdbb->tdbb_flags = 0;
2001-05-23 15:26:42 +02:00
attachment->att_charset = options.dpb_interp;
if (options.dpb_lc_messages.hasData()) {
attachment->att_lc_messages = options.dpb_lc_messages;
2001-05-23 15:26:42 +02:00
}
if (options.dpb_no_garbage)
attachment->att_flags |= ATT_no_cleanup;
if (options.dpb_gbak_attach.hasData())
2001-05-23 15:26:42 +02:00
attachment->att_flags |= ATT_gbak_attachment;
if (options.dpb_gstat_attach)
attachment->att_flags |= ATT_gstat_attachment;
if (options.dpb_gfix_attach)
attachment->att_flags |= ATT_gfix_attachment;
if (options.dpb_working_directory.hasData()) {
attachment->att_working_directory = options.dpb_working_directory;
2001-05-23 15:26:42 +02:00
}
/* If we're a not a secondary attachment, initialize some stuff */
bool first = false;
2001-05-23 15:26:42 +02:00
LCK_init(tdbb, LCK_OWNER_attachment); /* For the attachment */
attachment->att_flags |= ATT_lck_init_done;
if (dbb->dbb_filename.empty())
2001-12-24 03:51:06 +01:00
{
first = true;
dbb->dbb_filename = expanded_name;
// NS: Use alias as database ID only if accessing database using file name is not possible.
//
// This way we:
// 1. Ensure uniqueness of ID even in presence of multiple processes
// 2. Make sure that ID value can be used to connect back to database
//
if (is_alias && vdn == vdnFail)
dbb->dbb_database_name = file_name;
else
dbb->dbb_database_name = expanded_name;
2001-05-23 15:26:42 +02:00
/* Extra LCK_init() done to keep the lock table until the
database is shutdown() after the last detach. */
LCK_init(tdbb, LCK_OWNER_database);
dbb->dbb_flags |= DBB_lck_init_done;
INI_init();
dbb->dbb_file =
PIO_open(dbb, expanded_name, options.dpb_trace != 0, NULL, file_name);
2001-05-23 15:26:42 +02:00
SHUT_init(dbb);
PAG_header(file_name.c_str(), file_name.length(), false);
2001-05-23 15:26:42 +02:00
INI_init2();
PAG_init();
if (options.dpb_set_page_buffers) {
2001-05-23 15:26:42 +02:00
dbb->dbb_page_buffers = options.dpb_page_buffers;
}
CCH_init(tdbb, (ULONG) options.dpb_buffers);
// Initialize backup difference subsystem. This must be done before WAL and shadowing
// is enabled because nbackup it is a lower level subsystem
dbb->dbb_backup_manager = FB_NEW(*dbb->dbb_permanent) BackupManager(tdbb, dbb, nbak_state_unknown);
PAG_init2(0);
2001-05-23 15:26:42 +02:00
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_init(expanded_name, length_expanded);
2001-05-23 15:26:42 +02:00
#endif
/* initialize shadowing as soon as the database is ready for it
but before any real work is done */
SDW_init(options.dpb_activate_shadow,
options.dpb_delete_shadow);
/* dimitr: disabled due to unreliable behaviour of minor ODS upgrades
a) in the case of any failure it's impossible to attach the database
b) there's no way to handle failures properly, because upgrade is
being made in the context of system transaction which doesn't use
the backout logic
2001-05-23 15:26:42 +02:00
INI_update_database();
*/
2001-05-23 15:26:42 +02:00
}
2001-07-12 07:46:06 +02:00
/* Attachments to a ReadOnly database need NOT do garbage collection */
2001-12-24 03:51:06 +01:00
if (dbb->dbb_flags & DBB_read_only) {
2001-07-12 07:46:06 +02:00
attachment->att_flags |= ATT_no_cleanup;
2001-12-24 03:51:06 +01:00
}
2001-07-12 07:46:06 +02:00
if (options.dpb_disable_wal) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_lock_timeout, isc_arg_gds, isc_obj_in_use,
isc_arg_string,
ERR_string(file_name),
0);
2001-05-23 15:26:42 +02:00
}
if (options.dpb_buffers && !dbb->dbb_page_buffers) {
2001-05-23 15:26:42 +02:00
CCH_expand(tdbb, (ULONG) options.dpb_buffers);
}
if (!options.dpb_verify && CCH_exclusive(tdbb, LCK_PW, LCK_NO_WAIT))
{
TRA_cleanup(tdbb);
}
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
initing_security = true;
2001-05-23 15:26:42 +02:00
#endif
if (invalid_client_SQL_dialect)
{
ERR_post(isc_inv_client_dialect_specified, isc_arg_number,
options.dpb_sql_dialect,
isc_arg_gds, isc_valid_client_dialects,
2005-10-14 06:12:36 +02:00
isc_arg_string, "1, 2 or 3", 0);
2001-05-23 15:26:42 +02:00
}
invalid_client_SQL_dialect = false;
2001-05-23 15:26:42 +02:00
if (options.dpb_role_name.hasData())
2001-05-23 15:26:42 +02:00
{
switch (options.dpb_sql_dialect)
{
case 0:
{
/*
** V6 Client --> V6 Server, dummy client SQL dialect 0 was passed
** It means that client SQL dialect was not set by user
** and takes DB SQL dialect as client SQL dialect
*/
if (ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_original)
>= ODS_10_0)
2003-12-03 09:19:24 +01:00
{
if (dbb->dbb_flags & DBB_DB_SQL_dialect_3) {
2001-05-23 15:26:42 +02:00
/*
** DB created in IB V6.0 by client SQL dialect 3
*/
options.dpb_sql_dialect = SQL_DIALECT_V6;
2003-12-03 09:19:24 +01:00
}
else {
2001-05-23 15:26:42 +02:00
/*
** old DB was gbaked in IB V6.0
*/
options.dpb_sql_dialect = SQL_DIALECT_V5;
2003-12-03 09:19:24 +01:00
}
}
else {
2001-05-23 15:26:42 +02:00
options.dpb_sql_dialect = SQL_DIALECT_V5;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
}
break;
case 99:
/*
** V5 Client --> V6 Server, old client has no concept of dialect
*/
options.dpb_sql_dialect = SQL_DIALECT_V5;
break;
default:
/*
** V6 Client --> V6 Server, but client SQL dialect was set
** by user and was passed.
*/
break;
}
switch (options.dpb_sql_dialect)
{
case SQL_DIALECT_V5:
{
strip_quotes(options.dpb_role_name);
options.dpb_role_name.upper();
2001-05-23 15:26:42 +02:00
}
break;
case SQL_DIALECT_V6_TRANSITION:
case SQL_DIALECT_V6:
{
if (options.dpb_role_name.hasData() &&
(options.dpb_role_name[0] == DBL_QUOTE ||
options.dpb_role_name[0] == SINGLE_QUOTE))
2001-05-23 15:26:42 +02:00
{
const char end_quote = options.dpb_role_name[0];
/*
** remove the delimited quotes and escape quote
** from ROLE name
2001-05-23 15:26:42 +02:00
*/
options.dpb_role_name.erase(0, 1);
for (Firebird::string::iterator p =
options.dpb_role_name.begin();
p < options.dpb_role_name.end(); ++p)
2001-05-23 15:26:42 +02:00
{
if (*p == end_quote)
2001-05-23 15:26:42 +02:00
{
if (++p < options.dpb_role_name.end() &&
*p == end_quote)
2001-05-23 15:26:42 +02:00
{
// skip the escape quote here
options.dpb_role_name.erase(p--);
2001-05-23 15:26:42 +02:00
}
else
{
// delimited done
options.dpb_role_name.erase(--p,
options.dpb_role_name.end());
2001-05-23 15:26:42 +02:00
}
}
}
}
else
{
options.dpb_role_name.upper();
2001-05-23 15:26:42 +02:00
}
}
break;
default:
break;
}
}
options.dpb_sql_dialect = 0;
SCL_init(false,
options.dpb_sys_user_name.nullStr(),
options.dpb_user_name.nullStr(),
options.dpb_password.nullStr(),
options.dpb_password_enc.nullStr(),
options.dpb_role_name.nullStr(),
tdbb);
2001-05-23 15:26:42 +02:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
initing_security = false;
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
if (options.dpb_shutdown)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
/* By releasing the DBB_MUTX_init_fini mutex here, we would be allowing
other threads to proceed with their detachments, so that shutdown does
not timeout for exclusive access and other threads don't have to wait
2001-05-23 15:26:42 +02:00
behind shutdown */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
if (!SHUT_database
(dbb, options.dpb_shutdown, options.dpb_shutdown_delay))
{
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
if (user_status[1] != FB_SUCCESS)
ERR_punt();
else
ERR_post(isc_no_priv,
isc_arg_string, "shutdown or online",
isc_arg_string, "database",
isc_arg_string,
ERR_string(file_name),
0);
}
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
}
if (options.dpb_online)
{
/* By releasing the DBB_MUTX_init_fini mutex here, we would be allowing
other threads to proceed with their detachments, so that shutdown does
not timeout for exclusive access and other threads don't have to wait
behind shutdown */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
JRD_SS_MUTEX_UNLOCK;
if (!SHUT_online(dbb, options.dpb_online))
{
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
if (user_status[1] != FB_SUCCESS)
2001-05-23 15:26:42 +02:00
ERR_punt();
else
2003-11-08 17:40:17 +01:00
ERR_post(isc_no_priv,
isc_arg_string, "shutdown or online",
isc_arg_string, "database",
isc_arg_string,
ERR_string(file_name),
0);
2001-05-23 15:26:42 +02:00
}
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
}
#ifdef SUPERSERVER
/* Check if another attachment has or is requesting exclusive database access.
2001-05-23 15:26:42 +02:00
If this is an implicit attachment for the security (password) database, don't
try to get exclusive attachment to avoid a deadlock condition which happens
2001-05-23 15:26:42 +02:00
when a client tries to connect to the security database itself. */
if (!options.dpb_sec_attach) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
bool attachment_succeeded = true;
if (dbb->dbb_ast_flags & DBB_shutdown_single)
attachment_succeeded = CCH_exclusive_attachment(tdbb, LCK_none, -1);
else
CCH_exclusive_attachment(tdbb, LCK_none, LCK_WAIT);
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
if (attachment->att_flags & ATT_shutdown) {
if (dbb->dbb_ast_flags & DBB_shutdown) {
ERR_post(isc_shutdown, isc_arg_string,
ERR_string(file_name), 0);
}
else {
ERR_post(isc_att_shutdown, 0);
}
}
if (!attachment_succeeded) {
ERR_post(isc_shutdown, isc_arg_string,
ERR_string(file_name), 0);
}
2001-05-23 15:26:42 +02:00
}
#endif
/* If database is shutdown then kick 'em out. */
if (dbb->dbb_ast_flags & (DBB_shut_attach | DBB_shut_tran))
2001-12-24 03:51:06 +01:00
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_shutinprog, isc_arg_string,
ERR_string(file_name), 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
if (dbb->dbb_ast_flags & DBB_shutdown) {
// Allow only SYSDBA/owner to access database that is shut down
bool allow_access = attachment->att_user->usr_flags & (USR_locksmith | USR_owner);
// Handle special shutdown modes
if (allow_access) {
if (dbb->dbb_ast_flags & DBB_shutdown_full) {
// Full shutdown. Deny access always
allow_access = false;
}
else if (dbb->dbb_ast_flags & DBB_shutdown_single) {
// Single user maintenance. Allow access only if we were able to take exclusive lock
// Note that logic below this exclusive lock differs for SS and CS builds:
// - CS keeps PW database lock from releasing in AST in single-user maintenance mode
// - for SS this code effectively checks that no other attachments are present
// at call point, ATT_exclusive bit is released just before this procedure exits
// Things are done this way to handle return to online mode nicely.
allow_access = CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD);
}
}
if (!allow_access) {
// Note we throw exception here when entering full-shutdown mode
ERR_post(isc_shutdown, isc_arg_string,
ERR_string(file_name), 0);
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
2001-12-24 03:51:06 +01:00
if (options.dpb_quit_log) {
2001-05-23 15:26:42 +02:00
LOG_disable();
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
#endif
/* Figure out what character set & collation this attachment prefers */
find_intl_charset(tdbb, attachment, &options);
2001-12-24 03:51:06 +01:00
if (options.dpb_verify)
{
if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD)) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_content, isc_arg_gds, isc_cant_validate, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
#ifdef GARBAGE_THREAD
/* Can't allow garbage collection during database validation. */
VIO_fini(tdbb);
#endif
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
if (!VAL_validate(tdbb, options.dpb_verify)) {
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
ERR_punt();
}
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
}
if (options.dpb_journal.hasData()) {
ERR_post(isc_bad_dpb_content,
isc_arg_gds, isc_cant_start_journal,
0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (options.dpb_wal_action)
{
2005-05-02 11:10:06 +02:00
// No WAL anymore. We deleted it.
ERR_post(isc_no_wal, 0);
2001-05-23 15:26:42 +02:00
}
/*
* if the attachment is through gbak and this the attachment is not by owner
* or sysdba then return error. This has been added here to allow for the
2001-05-23 15:26:42 +02:00
* GBAK security feature of only allowing the owner or sysdba to backup a
* database. smistry 10/5/98
*/
if (((attachment->att_flags & ATT_gbak_attachment) ||
(attachment->att_flags & ATT_gfix_attachment) ||
(attachment->att_flags & ATT_gstat_attachment)) &&
!(attachment->att_user->usr_flags & (USR_locksmith | USR_owner)))
{
2001-05-23 15:26:42 +02:00
ERR_post(isc_adm_task_denied, 0);
}
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
if (options.dpb_log) {
if (first) {
if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD)) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_lock_timeout, isc_arg_gds, isc_obj_in_use,
isc_arg_string,
ERR_string(file_name),
0);
}
2001-05-23 15:26:42 +02:00
LOG_enable(options.dpb_log, strlen(options.dpb_log));
}
else {
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_content, isc_arg_gds,
isc_cant_start_logging, 0);
2001-05-23 15:26:42 +02:00
}
}
#endif
if (options.dpb_set_db_sql_dialect) {
2001-05-23 15:26:42 +02:00
PAG_set_db_SQL_dialect(dbb, options.dpb_set_db_sql_dialect);
}
if (options.dpb_sweep_interval != -1) {
2001-05-23 15:26:42 +02:00
PAG_sweep_interval(options.dpb_sweep_interval);
dbb->dbb_sweep_interval = options.dpb_sweep_interval;
}
if (options.dpb_set_force_write) {
2001-05-23 15:26:42 +02:00
PAG_set_force_write(dbb, options.dpb_force_write);
}
if (options.dpb_set_no_reserve) {
2001-05-23 15:26:42 +02:00
PAG_set_no_reserve(dbb, options.dpb_no_reserve);
}
if (options.dpb_set_page_buffers) {
2001-05-23 15:26:42 +02:00
PAG_set_page_buffers(options.dpb_page_buffers);
}
if (options.dpb_set_db_readonly) {
if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD)) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_lock_timeout, isc_arg_gds, isc_obj_in_use,
isc_arg_string,
ERR_string(file_name),
0);
}
PAG_set_db_readonly(dbb, options.dpb_db_readonly);
}
2001-07-12 07:46:06 +02:00
2001-05-23 15:26:42 +02:00
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
/* don't record the attach until now in case the log is added during the attach */
LOG_call(log_attach2, file_name, *handle, dpb_length, dpb,
2001-05-23 15:26:42 +02:00
expanded_filename);
#endif
#ifdef GARBAGE_THREAD
VIO_init(tdbb);
#endif
CCH_release_exclusive(tdbb);
#ifdef GOVERNOR
if (!options.dpb_sec_attach) {
if (JRD_max_users) {
if (num_attached < (JRD_max_users * ATTACHMENTS_PER_USER)) {
2001-05-23 15:26:42 +02:00
num_attached++;
}
else {
2001-05-23 15:26:42 +02:00
ERR_post(isc_max_att_exceeded, 0);
}
}
}
else {
2001-05-23 15:26:42 +02:00
attachment->att_flags |= ATT_security_db;
}
#endif /* GOVERNOR */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
/* if there was an error, the status vector is all set */
2003-11-08 17:40:17 +01:00
if (options.dpb_sweep & isc_dpb_records)
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
2001-12-24 03:51:06 +01:00
if (!(TRA_sweep(tdbb, 0)))
{
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_LOCK;
ERR_punt();
}
JRD_SS_MUTEX_LOCK;
}
if (options.dpb_dbkey_scope) {
2001-05-23 15:26:42 +02:00
attachment->att_dbkey_trans = TRA_start(tdbb, 0, 0);
}
JRD_SS_MUTEX_UNLOCK;
// Recover database after crash during backup difference file merge
dbb->dbb_backup_manager->end_backup(tdbb, true/*do recovery*/);
*handle = attachment;
2001-05-23 15:26:42 +02:00
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *handle);
#endif
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex)
2001-12-24 03:51:06 +01:00
{
ISC_STATUS_ARRAY temp_status;
2001-12-24 03:51:06 +01:00
try
{
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-12-24 03:51:06 +01:00
if (initing_security)
{
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
}
#endif
tdbb->tdbb_status_vector = temp_status;
dbb->dbb_flags &= ~DBB_being_opened;
release_attachment(attachment);
/* At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been
unlocked and mutex databases_mutex has been locked. */
if (MemoryPool::blk_type(dbb) == type_dbb)
{
if (!dbb->dbb_attachments)
{
shutdown_database(dbb, true);
2001-12-24 03:51:06 +01:00
}
else if (attachment)
{
delete attachment;
}
}
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-12-24 03:51:06 +01:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-12-24 03:51:06 +01:00
} // try
2003-02-13 14:33:57 +01:00
catch (const std::exception&) {}
2001-12-24 03:51:06 +01:00
tdbb->tdbb_status_vector = status;
JRD_SS_MUTEX_UNLOCK;
return error(user_status, ex);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_BLOB_INFO(ISC_STATUS* user_status,
blb** blob_handle,
SSHORT item_length,
const SCHAR* items,
SSHORT buffer_length,
SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ b l o b _ i n f o
*
**************************************
*
* Functional description
* Provide information on blob object.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
const blb* blob = check_blob(tdbb, user_status, blob_handle);
2001-05-23 15:26:42 +02:00
if (!blob) {
return user_status[1];
}
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_blob_info2, *blob_handle, item_length, items, buffer_length);
#endif
try {
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
INF_blob_info(blob, items, item_length, buffer, buffer_length);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_CANCEL_BLOB(ISC_STATUS * user_status, blb** blob_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c a n c e l _ b l o b
*
**************************************
*
* Functional description
* Abort a partially completed blob.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
if (*blob_handle) {
blb* blob = check_blob(tdbb, user_status, blob_handle);
if (!blob)
2001-05-23 15:26:42 +02:00
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_cancel_blob, *blob_handle);
#endif
try {
tdbb->tdbb_status_vector = user_status;
BLB_cancel(tdbb, blob);
*blob_handle = NULL;
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
ISC_STATUS GDS_CANCEL_EVENTS(ISC_STATUS* user_status,
Attachment** handle,
SLONG* id)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c a n c e l _ e v e n t s
*
**************************************
*
* Functional description
* Cancel an outstanding event.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *handle, user_status)) {
return user_status[1];
}
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_cancel_events, *handle, *id);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
EVENT_cancel(*id);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
#ifdef CANCEL_OPERATION
ISC_STATUS GDS_CANCEL_OPERATION(ISC_STATUS* user_status,
Attachment** handle,
USHORT option)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c a n c e l _ o p e r a t i o n
*
**************************************
*
* Functional description
* Try to cancel an operation.
*
**************************************/
api_entry_point_init(user_status);
Attachment* attachment = *handle;
2001-05-23 15:26:42 +02:00
/* Check out the database handle. This is mostly code from
the routine "check_database" */
2004-03-07 08:58:55 +01:00
Database* dbb;
2001-05-23 15:26:42 +02:00
if (!attachment ||
2001-12-24 03:51:06 +01:00
(MemoryPool::blk_type(attachment) != type_att) ||
2001-05-23 15:26:42 +02:00
!(dbb = attachment->att_database) ||
2001-12-24 03:51:06 +01:00
MemoryPool::blk_type(dbb) != type_dbb)
{
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, 0);
}
2001-05-23 15:26:42 +02:00
/* Make sure this is a valid attachment */
const Attachment* attach;
2001-05-23 15:26:42 +02:00
for (attach = dbb->dbb_attachments; attach; attach = attach->att_next)
if (attach == attachment)
break;
if (!attach)
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, 0);
2001-05-23 15:26:42 +02:00
switch (option) {
case CANCEL_disable:
attachment->att_flags |= ATT_cancel_disable;
break;
case CANCEL_enable:
attachment->att_flags &= ~ATT_cancel_disable;
break;
case CANCEL_raise:
attachment->att_flags |= ATT_cancel_raise;
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2001-05-23 15:26:42 +02:00
}
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
#endif
ISC_STATUS GDS_CLOSE_BLOB(ISC_STATUS * user_status, blb** blob_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c l o s e _ b l o b
*
**************************************
*
* Functional description
* Abort a partially completed blob.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
blb* blob = check_blob(tdbb, user_status, blob_handle);
if (!blob)
2001-05-23 15:26:42 +02:00
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_close_blob, *blob_handle);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
BLB_close(tdbb, blob);
*blob_handle = NULL;
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_COMMIT(ISC_STATUS * user_status, jrd_tra** tra_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c o m m i t
*
**************************************
*
* Functional description
* Commit a transaction.
*
**************************************/
api_entry_point_init(user_status);
if (commit(user_status, tra_handle, false))
2001-05-23 15:26:42 +02:00
return user_status[1];
*tra_handle = NULL;
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_COMMIT_RETAINING(ISC_STATUS * user_status, jrd_tra** tra_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c o m m i t _ r e t a i n i n g
*
**************************************
*
* Functional description
* Commit a transaction.
*
**************************************/
api_entry_point_init(user_status);
return commit(user_status, tra_handle, true);
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_COMPILE(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_req** req_handle,
SSHORT blr_length,
const SCHAR* blr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c o m p i l e
*
**************************************
*
* Functional description
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
NULL_CHECK(req_handle, isc_bad_req_handle);
Attachment* attachment = *db_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_compile, *db_handle, *req_handle, blr_length, blr);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
jrd_req* request =
CMP_compile2(tdbb, reinterpret_cast<const UCHAR*>(blr), FALSE);
request->req_attachment = attachment;
request->req_request = attachment->att_requests;
attachment->att_requests = request;
DEBUG;
*req_handle = request;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *req_handle);
#endif
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_CREATE_BLOB2(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
blb** blob_handle,
bid* blob_id,
USHORT bpb_length,
const UCHAR* bpb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c r e a t e _ b l o b
*
**************************************
*
* Functional description
* Create a new blob.
2001-05-23 15:26:42 +02:00
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
NULL_CHECK(blob_handle, isc_bad_segstr_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *db_handle, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_create_blob2, *db_handle, *tra_handle, *blob_handle, blob_id,
bpb_length, bpb);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
jrd_tra* transaction = find_transaction(tdbb, *tra_handle, isc_segstr_wrong_db);
blb* blob = BLB_create2(tdbb, transaction, blob_id, bpb_length, bpb);
*blob_handle = blob;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *blob_handle);
LOG_call(log_handle_returned, blob_id->bid_stuff.bid_temp_id);
#endif
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_CREATE_DATABASE(ISC_STATUS* user_status,
USHORT _file_length,
const TEXT* _file_name,
Attachment** handle,
USHORT dpb_length,
const UCHAR* dpb,
USHORT db_type,
const TEXT* _expanded_filename)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ c r e a t e _ d a t a b a s e
*
**************************************
*
* Functional description
* Create a nice, squeeky clean database, uncorrupted by user data.
*
**************************************/
api_entry_point_init(user_status);
if (*handle)
{
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, 0);
}
2001-05-23 15:26:42 +02:00
Firebird::PathName file_name(_file_name,
_file_length ? _file_length : strlen(_file_name));
Firebird::PathName expanded_name(file_name);
2001-05-23 15:26:42 +02:00
/* Resolve given alias name */
const bool is_alias = ResolveDatabaseAlias(expanded_name, expanded_name);
if (is_alias)
{
ISC_expand_filename(expanded_name, false);
}
else
{
expanded_name = _expanded_filename;
}
2001-05-23 15:26:42 +02:00
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
/* Check database against conf file. */
const vdnResult vdn = verify_database_name(expanded_name, user_status);
if (!is_alias && vdn == vdnFail)
{
JRD_restore_context();
return user_status[1];
}
else
user_status[0] = 0; // Clear status vector
2004-03-07 08:58:55 +01:00
Database* dbb = init(tdbb, user_status, expanded_name, false);
2003-12-03 09:19:24 +01:00
if (!dbb) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
JRD_restore_context();
return user_status[1];
}
// use database context pool
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
2001-05-23 15:26:42 +02:00
dbb->dbb_flags |= DBB_being_opened;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = dbb;
/* Initialize error handling */
ISC_STATUS* status = user_status;
tdbb->tdbb_status_vector = status;
Attachment* attachment = NULL;
2003-12-03 09:19:24 +01:00
tdbb->tdbb_attachment = attachment;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
/* Count active thread in database */
++dbb->dbb_use_count;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
bool initing_security = false;
2001-05-23 15:26:42 +02:00
#endif
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
/* Process database parameter block */
DatabaseOptions options;
options.get(dpb, dpb_length);
if (!invalid_client_SQL_dialect && options.dpb_sql_dialect == 99) {
2001-05-23 15:26:42 +02:00
options.dpb_sql_dialect = 0;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
#ifndef NO_NFS
/* Don't check nfs if single user */
if (!options.dpb_single_user)
#endif
{
/* Check to see if the database is truly local or if it just looks
that way */
if (ISC_check_if_remote(expanded_name, true))
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_unavailable, 0);
}
2001-05-23 15:26:42 +02:00
}
if (options.dpb_key.hasData())
{
dbb->dbb_encrypt_key = options.dpb_key;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
tdbb->tdbb_attachment = attachment = FB_NEW(*dbb->dbb_permanent) Attachment(dbb);
attachment->att_filename = expanded_name;
attachment->att_network_protocol = options.dpb_network_protocol;
attachment->att_remote_address = options.dpb_remote_address;
2001-05-23 15:26:42 +02:00
attachment->att_next = dbb->dbb_attachments;
dbb->dbb_attachments = attachment;
dbb->dbb_flags &= ~DBB_being_opened;
dbb->dbb_sys_trans->tra_attachment = attachment;
tdbb->tdbb_quantum = QUANTUM;
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
2002-09-26 11:26:40 +02:00
tdbb->tdbb_flags = 0;
2001-05-23 15:26:42 +02:00
if (options.dpb_working_directory.hasData()) {
attachment->att_working_directory = options.dpb_working_directory;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
if (options.dpb_gbak_attach.hasData()) {
2001-05-23 15:26:42 +02:00
attachment->att_flags |= ATT_gbak_attachment;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
switch (options.dpb_sql_dialect) {
case 0:
// This can be issued by QLI, GDEF and old BDE clients.
// In this case assume dialect 1
2001-05-23 15:26:42 +02:00
options.dpb_sql_dialect = SQL_DIALECT_V5;
case SQL_DIALECT_V5:
break;
case SQL_DIALECT_V6:
dbb->dbb_flags |= DBB_DB_SQL_dialect_3;
break;
default:
ERR_post(isc_database_create_failed, isc_arg_string,
2004-03-16 18:35:03 +01:00
expanded_name.c_str(), isc_arg_gds, isc_inv_dialect_specified,
2001-05-23 15:26:42 +02:00
isc_arg_number, options.dpb_sql_dialect, isc_arg_gds,
isc_valid_db_dialects, isc_arg_string, "1 and 3", 0);
break;
}
attachment->att_charset = options.dpb_interp;
if (options.dpb_lc_messages.hasData()) {
attachment->att_lc_messages = options.dpb_lc_messages;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
2003-12-03 09:19:24 +01:00
if (!options.dpb_page_size) {
2001-05-23 15:26:42 +02:00
options.dpb_page_size = DEFAULT_PAGE_SIZE;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
2003-12-03 09:19:24 +01:00
USHORT page_size;
2003-09-13 14:03:11 +02:00
for (page_size = MIN_PAGE_SIZE; page_size < MAX_PAGE_SIZE; page_size <<= 1)
2003-12-03 09:19:24 +01:00
{
2003-09-13 14:03:11 +02:00
if (options.dpb_page_size < page_size << 1)
2001-05-23 15:26:42 +02:00
break;
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
dbb->dbb_page_size =
(page_size > MAX_PAGE_SIZE) ? MAX_PAGE_SIZE : page_size;
LCK_init(tdbb, LCK_OWNER_attachment); /* For the attachment */
attachment->att_flags |= ATT_lck_init_done;
/* Extra LCK_init() done to keep the lock table until the
database is shutdown() after the last detach. */
LCK_init(tdbb, LCK_OWNER_database);
dbb->dbb_flags |= DBB_lck_init_done;
INI_init();
PAG_init();
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
initing_security = true;
2001-05-23 15:26:42 +02:00
#endif
SCL_init(true,
options.dpb_sys_user_name.nullStr(),
options.dpb_user_name.nullStr(),
options.dpb_password.nullStr(),
options.dpb_password_enc.nullStr(),
options.dpb_role_name.nullStr(),
tdbb);
2001-05-23 15:26:42 +02:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
initing_security = false;
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
try
{
// try to create with overwrite = false
2005-09-08 18:41:56 +02:00
dbb->dbb_file = PIO_create(dbb, expanded_name, false);
}
catch (Firebird::status_exception)
{
if (options.dpb_overwrite)
{
if (GDS_ATTACH_DATABASE(user_status, _file_length, _file_name, handle,
dpb_length, dpb, _expanded_filename) == isc_adm_task_denied)
{
throw;
}
bool allow_overwrite = false;
if (*handle)
{
allow_overwrite = (*handle)->att_user->usr_flags & (USR_locksmith | USR_owner);
GDS_DETACH(user_status, handle);
}
else
{
// clear status after failed attach
user_status[0] = 0;
allow_overwrite = true;
}
if (allow_overwrite)
{
// file is a database and the user (SYSDBA or owner) has right to overwrite
dbb->dbb_file =
2005-09-08 18:41:56 +02:00
PIO_create(dbb, expanded_name, options.dpb_overwrite);
}
else
{
ERR_post(isc_no_priv,
isc_arg_string, "overwrite",
isc_arg_string, "database",
isc_arg_string,
ERR_cstring(expanded_name.c_str()), 0);
}
}
else
throw;
}
const jrd_file* first_dbb_file = dbb->dbb_file;
2001-05-23 15:26:42 +02:00
if (options.dpb_set_page_buffers)
dbb->dbb_page_buffers = options.dpb_page_buffers;
CCH_init(tdbb, (ULONG) options.dpb_buffers);
// Initialize backup difference subsystem. This must be done before WAL and shadowing
// is enabled because nbackup it is a lower level subsystem
dbb->dbb_backup_manager = FB_NEW(*dbb->dbb_permanent) BackupManager(tdbb, dbb, nbak_state_normal);
2001-05-23 15:26:42 +02:00
PAG_format_header();
INI_init2();
PAG_format_log();
PAG_format_pip();
if (options.dpb_set_page_buffers)
PAG_set_page_buffers(options.dpb_page_buffers);
if (options.dpb_set_no_reserve)
PAG_set_no_reserve(dbb, options.dpb_no_reserve);
INI_format(attachment->att_user->usr_user_name,
options.dpb_set_db_charset.c_str());
2001-05-23 15:26:42 +02:00
// There is no point to move database online at database creation since it is online by default.
// We do not allow to create database that is fully shut down.
if (options.dpb_online || (options.dpb_shutdown & isc_dpb_shut_mode_mask) == isc_dpb_shut_full)
ERR_post(isc_bad_shutdown_mode, isc_arg_string, ERR_string(file_name), 0);
if (options.dpb_shutdown) {
2001-05-23 15:26:42 +02:00
/* By releasing the DBB_MUTX_init_fini mutex here, we would be allowing
other threads to proceed with their detachments, so that shutdown does
not timeout for exclusive access and other threads don't have to wait
2001-05-23 15:26:42 +02:00
behind shutdown */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
if (!SHUT_database
(dbb, options.dpb_shutdown, options.dpb_shutdown_delay))
{
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2003-11-08 17:40:17 +01:00
ERR_post(isc_no_priv,
isc_arg_string, "shutdown or online",
isc_arg_string, "database",
isc_arg_string,
ERR_string(file_name), 0);
2001-05-23 15:26:42 +02:00
}
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
}
2001-05-23 15:26:42 +02:00
if (options.dpb_sweep_interval != -1) {
PAG_sweep_interval(options.dpb_sweep_interval);
dbb->dbb_sweep_interval = options.dpb_sweep_interval;
}
if (options.dpb_set_force_write)
PAG_set_force_write(dbb, options.dpb_force_write);
/* initialize shadowing semaphore as soon as the database is ready for it
but before any real work is done */
SDW_init(options.dpb_activate_shadow, options.dpb_delete_shadow);
2001-05-23 15:26:42 +02:00
#ifdef GARBAGE_THREAD
VIO_init(tdbb);
#endif
if (options.dpb_set_db_readonly) {
if (!CCH_exclusive (tdbb, LCK_EX, WAIT_PERIOD))
2003-11-08 17:40:17 +01:00
ERR_post (isc_lock_timeout, isc_arg_gds, isc_obj_in_use,
isc_arg_string,
ERR_string (file_name),
0);
PAG_set_db_readonly (dbb, options.dpb_db_readonly);
}
CCH_release_exclusive(tdbb);
2001-05-23 15:26:42 +02:00
/* Figure out what character set & collation this attachment prefers */
find_intl_charset(tdbb, attachment, &options);
2002-07-02 11:49:19 +02:00
#ifdef WIN_NT
dbb->dbb_filename.assign(first_dbb_file->fil_string,
2002-07-02 11:49:19 +02:00
first_dbb_file->fil_length);
#else
dbb->dbb_filename = expanded_name;
2002-07-02 11:49:19 +02:00
#endif
2001-05-23 15:26:42 +02:00
// NS: Use alias as database ID only if accessing database using file name is not possible.
//
// This way we:
// 1. Ensure uniqueness of ID even in presence of multiple processes
// 2. Make sure that ID value can be used to connect back to database
//
if (is_alias && vdn == vdnFail)
dbb->dbb_database_name = file_name;
else
dbb->dbb_database_name = dbb->dbb_filename;
2001-05-23 15:26:42 +02:00
#ifdef GOVERNOR
if (!options.dpb_sec_attach) {
if (JRD_max_users) {
if (num_attached < (JRD_max_users * ATTACHMENTS_PER_USER))
num_attached++;
else
ERR_post(isc_max_att_exceeded, 0);
}
}
else {
attachment->att_flags |= ATT_security_db;
}
#endif /* GOVERNOR */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
*handle = attachment;
CCH_flush(tdbb, FLUSH_FINI, 0);
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex)
2001-12-24 03:51:06 +01:00
{
ISC_STATUS_ARRAY temp_status;
2001-12-24 03:51:06 +01:00
try
{
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-12-24 03:51:06 +01:00
if (initing_security)
{
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
}
#endif
tdbb->tdbb_status_vector = temp_status;
dbb->dbb_flags &= ~DBB_being_opened;
release_attachment(attachment);
/* At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been
unlocked and mutex databases_mutex has been locked. */
if (MemoryPool::blk_type(dbb) == type_dbb)
{
if (!dbb->dbb_attachments)
{
shutdown_database(dbb, true);
2001-12-24 03:51:06 +01:00
}
else if (attachment)
{
delete attachment;
}
}
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-12-24 03:51:06 +01:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-12-24 03:51:06 +01:00
}
2003-02-13 14:33:57 +01:00
catch (const std::exception&) {}
2001-12-24 03:51:06 +01:00
tdbb->tdbb_status_vector = status;
JRD_SS_MUTEX_UNLOCK;
return error(user_status, ex);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_DATABASE_INFO(ISC_STATUS* user_status,
Attachment** handle,
SSHORT item_length,
const SCHAR* items,
SSHORT buffer_length,
SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ d a t a b a s e _ i n f o
*
**************************************
*
* Functional description
* Provide information on database object.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *handle, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_database_info2, *handle, item_length, items, buffer_length);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
INF_database_info(items, item_length, buffer, buffer_length);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_DDL(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
USHORT ddl_length,
const SCHAR* ddl)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ d d l
*
**************************************
*
* Functional description
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Attachment* attachment = *db_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_ddl, *db_handle, *tra_handle, ddl_length, ddl);
#endif
tdbb->tdbb_status_vector = user_status;
jrd_tra* transaction = 0;
2001-12-24 03:51:06 +01:00
try {
2003-11-08 17:40:17 +01:00
transaction = find_transaction(tdbb, *tra_handle, isc_segstr_wrong_db);
2001-12-24 03:51:06 +01:00
DYN_ddl(attachment, transaction, ddl_length,
reinterpret_cast<const UCHAR*>(ddl));
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
/*
2001-05-23 15:26:42 +02:00
* Perform an auto commit for autocommit transactions.
* This is slightly tricky. If the commit retain works,
* all is well. If TRA_commit () fails, we perform
* a rollback_retain (). This will backout the
* effects of the transaction, mark it dead and
2001-05-23 15:26:42 +02:00
* start a new transaction.
*/
2001-12-24 03:51:06 +01:00
if (transaction->tra_flags & TRA_perform_autocommit)
{
2001-05-23 15:26:42 +02:00
transaction->tra_flags &= ~TRA_perform_autocommit;
2001-12-24 03:51:06 +01:00
try {
TRA_commit(tdbb, transaction, true);
2001-12-24 03:51:06 +01:00
}
catch (const std::exception& ex) {
ISC_STATUS_ARRAY temp_status;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = temp_status;
try {
TRA_rollback(tdbb, transaction, true, false);
}
catch (const std::exception&) {
// CVC, TMN: Do nothing, see FB1 code, this will fall into
// the two lines below, achieving the same logic than going
// back to the SETJMP(env) in FB1.
}
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = user_status;
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_DETACH(ISC_STATUS* user_status, Attachment** handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ d e t a c h
*
**************************************
*
* Functional description
* Close down a database.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Attachment* attachment = *handle;
2001-05-23 15:26:42 +02:00
/* Check out the database handle. This is mostly code from
the routine "check_database" */
2004-03-07 08:58:55 +01:00
Database* dbb;
2001-05-23 15:26:42 +02:00
if (!attachment ||
2001-12-24 03:51:06 +01:00
(MemoryPool::blk_type(attachment) != type_att) ||
2001-05-23 15:26:42 +02:00
!(dbb = attachment->att_database) ||
2001-12-24 03:51:06 +01:00
MemoryPool::blk_type(dbb) != type_dbb)
{
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
}
2001-05-23 15:26:42 +02:00
/* Make sure this is a valid attachment */
Attachment* attach;
2001-05-23 15:26:42 +02:00
for (attach = dbb->dbb_attachments; attach; attach = attach->att_next)
if (attach == attachment)
break;
if (!attach)
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
2001-05-23 15:26:42 +02:00
/* if this is the last attachment, mark dbb as not in use */
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
if (dbb->dbb_attachments == attachment && !attachment->att_next &&
!(dbb->dbb_flags & DBB_being_opened))
dbb->dbb_flags |= DBB_not_in_use;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = dbb;
tdbb->tdbb_attachment = attachment;
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
/* Count active thread in database */
++dbb->dbb_use_count;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_detach, *handle);
LOG_call(log_statistics, dbb->dbb_reads, dbb->dbb_writes,
dbb->dbb_max_memory);
#endif
/* purge_attachment below can do an ERR_post */
tdbb->tdbb_status_vector = user_status;
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
/* Purge attachment, don't rollback open transactions */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
2001-05-23 15:26:42 +02:00
#ifdef CANCEL_OPERATION
attachment->att_flags |= ATT_cancel_disable;
#endif
#ifdef GOVERNOR
const ULONG attachment_flags = attachment->att_flags;
2001-05-23 15:26:42 +02:00
#endif
purge_attachment(tdbb, user_status, attachment, false);
2001-05-23 15:26:42 +02:00
#ifdef GOVERNOR
if (JRD_max_users) {
if (!(attachment_flags & ATT_security_db)) {
2003-11-04 00:59:24 +01:00
fb_assert(num_attached > 0);
2001-05-23 15:26:42 +02:00
num_attached--;
}
}
#endif /* GOVERNOR */
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
*handle = NULL;
return return_success(tdbb);
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2002-10-18 16:40:35 +02:00
V4_JRD_MUTEX_LOCK(databases_mutex);
#endif
2002-10-18 16:40:35 +02:00
dbb->dbb_flags &= ~DBB_not_in_use;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2002-10-18 16:40:35 +02:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2002-10-18 16:40:35 +02:00
2001-12-24 03:51:06 +01:00
JRD_SS_MUTEX_UNLOCK;
return error(user_status, ex);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_DROP_DATABASE(ISC_STATUS* user_status, Attachment** handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* i s c _ d r o p _ d a t a b a s e
*
**************************************
*
* Functional description
* Close down and purge a database.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Attachment* attachment = *handle;
2001-05-23 15:26:42 +02:00
/* Check out the database handle. This is mostly code from
the routine "check_database" */
2004-03-07 08:58:55 +01:00
Database* dbb;
2001-05-23 15:26:42 +02:00
if (!attachment ||
2001-12-24 03:51:06 +01:00
(MemoryPool::blk_type(attachment) != type_att) ||
2001-05-23 15:26:42 +02:00
!(dbb = attachment->att_database) ||
2001-12-24 03:51:06 +01:00
MemoryPool::blk_type(dbb) != type_dbb)
{
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
}
2001-05-23 15:26:42 +02:00
/* Make sure this is a valid attachment */
Attachment* attach;
2001-05-23 15:26:42 +02:00
for (attach = dbb->dbb_attachments; attach; attach = attach->att_next)
if (attach == attachment)
break;
if (!attach)
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
2001-05-23 15:26:42 +02:00
bool err = false; // so much for uninitialized vars... if something
// failed before the first call to drop_files, which was the value?
{
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent);
tdbb->tdbb_database = dbb;
tdbb->tdbb_attachment = attachment;
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
2001-05-23 15:26:42 +02:00
/* Count active thread in database */
++dbb->dbb_use_count;
2001-05-23 15:26:42 +02:00
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_drop_database, *handle);
LOG_call(log_statistics, dbb->dbb_reads, dbb->dbb_writes,
2001-05-23 15:26:42 +02:00
dbb->dbb_max_memory);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
Firebird::PathName file_name = tdbb->tdbb_attachment->att_filename;
if (!(attachment->att_user->usr_flags & (USR_locksmith | USR_owner)))
ERR_post(isc_no_priv,
isc_arg_string, "drop",
isc_arg_string, "database",
isc_arg_string, ERR_cstring(file_name), 0);
2003-01-18 17:31:23 +01:00
if (attachment->att_flags & ATT_shutdown) {
if (dbb->dbb_ast_flags & DBB_shutdown) {
ERR_post(isc_shutdown, isc_arg_string,
ERR_cstring(file_name), 0);
}
else {
ERR_post(isc_att_shutdown, 0);
}
}
2003-01-18 17:31:23 +01:00
if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD))
ERR_post(isc_lock_timeout,
isc_arg_gds, isc_obj_in_use,
isc_arg_string, ERR_cstring(file_name), 0);
2003-01-18 17:31:23 +01:00
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_LOCK(databases_mutex);
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
}
catch(const std::exception& ex)
{
return error(user_status, ex);
}
try {
2001-05-23 15:26:42 +02:00
/* Check if same process has more attachments */
if ((attach = dbb->dbb_attachments) && (attach->att_next)) {
ERR_post(isc_no_meta_update, isc_arg_gds, isc_obj_in_use,
isc_arg_string, "DATABASE", 0);
}
2001-05-23 15:26:42 +02:00
#ifdef CANCEL_OPERATION
attachment->att_flags |= ATT_cancel_disable;
2001-05-23 15:26:42 +02:00
#endif
/* Here we have database locked in exclusive mode.
Just mark the header page with an 0 ods version so that no other
process can attach to this database once we release our exclusive
lock and start dropping files. */
WIN window(HEADER_PAGE);
Ods::header_page* header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
CCH_MARK_MUST_WRITE(tdbb, &window);
header->hdr_ods_version = 0;
CCH_RELEASE(tdbb, &window);
2001-05-23 15:26:42 +02:00
} // try
catch (const std::exception& ex) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_UNLOCK(databases_mutex);
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
#endif
JRD_SS_MUTEX_UNLOCK;
return error(user_status, ex);
}
} // dbb permanent context
2001-12-24 03:51:06 +01:00
/* A default catch all */
try {
2001-05-23 15:26:42 +02:00
/* This point on database is useless */
/* mark the dbb unusable */
dbb->dbb_flags |= DBB_not_in_use;
*handle = NULL;
2001-05-23 15:26:42 +02:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
const jrd_file* file = dbb->dbb_file;
const Shadow* shadow = dbb->dbb_shadow;
2001-05-23 15:26:42 +02:00
#ifdef GOVERNOR
if (JRD_max_users) {
fb_assert(num_attached > 0);
num_attached--;
}
2001-05-23 15:26:42 +02:00
#endif /* GOVERNOR */
/* Unlink attachment from database */
release_attachment(attachment);
2001-05-23 15:26:42 +02:00
/* At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been
unlocked and mutex databases_mutex has been locked. */
shutdown_database(dbb, false);
2001-05-23 15:26:42 +02:00
/* drop the files here. */
err = drop_files(file);
for (; shadow; shadow = shadow->sdw_next)
{
err = err || drop_files(shadow->sdw_file);
}
2001-05-23 15:26:42 +02:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
} // try
catch (const std::exception& ex) {
JRD_SS_MUTEX_UNLOCK;
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
2004-03-07 08:58:55 +01:00
Database::deleteDbb(dbb);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = NULL;
if (err) {
2003-11-08 17:40:17 +01:00
user_status[0] = isc_arg_gds;
user_status[1] = isc_drdb_completed_with_errs;
user_status[2] = isc_arg_end;
2001-05-23 15:26:42 +02:00
return user_status[1];
}
return return_success(tdbb);
2001-12-24 03:51:06 +01:00
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_INTL_FUNCTION(ISC_STATUS* user_status, Attachment** handle,
USHORT function, UCHAR charSetNumber, USHORT strLen, const UCHAR* str, USHORT* result)
{
/**************************************
*
* g d s _ i n t l _ f u n c t i o n
*
**************************************
*
* Functional description
* Return INTL informations.
* (candidate for removal when engine functions can be called by DSQL)
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
if (check_database(tdbb, *handle, user_status))
return user_status[1];
try
{
tdbb->tdbb_status_vector = user_status;
CharSet* charSet = INTL_charset_lookup(tdbb, charSetNumber);
switch (function)
{
case INTL_FUNCTION_CHAR_LENGTH:
{
ULONG offendingPos;
if (!charSet->wellFormed(strLen, str, &offendingPos))
{
ERR_post(isc_sqlerr,
isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_malformed_string, 0);
}
else
*result = charSet->length(tdbb, strLen, str, true);
break;
}
case INTL_FUNCTION_OCTET_LENGTH:
{
Firebird::HalfStaticArray<UCHAR, 256> dummy;
*result = charSet->substring(tdbb, strLen, str,
strLen, dummy.getBuffer(strLen), 0,
strLen / charSet->maxBytesPerChar());
break;
}
default:
fb_assert(false);
break;
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
return return_success(tdbb);
}
ISC_STATUS GDS_GET_SEGMENT(ISC_STATUS * user_status,
blb** blob_handle,
USHORT * length,
USHORT buffer_length,
UCHAR * buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ g e t _ s e g m e n t
*
**************************************
*
* Functional description
* Abort a partially completed blob.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
blb* blob = check_blob(tdbb, user_status, blob_handle);
if (!blob)
2001-05-23 15:26:42 +02:00
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_get_segment2, *blob_handle, length, buffer_length);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
*length = BLB_get_segment(tdbb, blob, buffer, buffer_length);
2003-11-08 17:40:17 +01:00
tdbb->tdbb_status_vector[0] = isc_arg_gds;
tdbb->tdbb_status_vector[2] = isc_arg_end;
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
if (blob->blb_flags & BLB_eof) {
JRD_restore_context();
--dbb->dbb_use_count;
2003-11-08 17:40:17 +01:00
return (user_status[1] = isc_segstr_eof);
}
else if (blob->blb_fragment_size) {
JRD_restore_context();
--dbb->dbb_use_count;
2003-11-08 17:40:17 +01:00
return (user_status[1] = isc_segment);
}
2001-05-23 15:26:42 +02:00
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
2003-12-03 09:19:24 +01:00
ISC_STATUS GDS_GET_SLICE(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
ISC_QUAD* array_id,
USHORT sdl_length,
2003-12-03 09:19:24 +01:00
const UCHAR* sdl,
USHORT param_length,
2003-12-03 09:19:24 +01:00
const UCHAR* param,
SLONG slice_length,
2003-12-03 09:19:24 +01:00
UCHAR* slice,
SLONG* return_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ g e t _ s l i c e
*
**************************************
*
* Functional description
* Snatch a slice of an array.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *db_handle, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_get_slice2, *db_handle, *tra_handle, *array_id, sdl_length,
sdl, param_length, param, slice_length);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
jrd_tra* transaction =
2003-11-08 17:40:17 +01:00
find_transaction(tdbb, *tra_handle, isc_segstr_wrong_db);
if (!array_id->gds_quad_low && !array_id->gds_quad_high) {
MOVE_CLEAR(slice, slice_length);
*return_length = 0;
}
else
*return_length = BLB_get_slice(tdbb,
2001-05-23 15:26:42 +02:00
transaction,
reinterpret_cast<bid*>(array_id),
2001-05-23 15:26:42 +02:00
sdl,
param_length,
reinterpret_cast<const SLONG*>(param),
2001-05-23 15:26:42 +02:00
slice_length, slice);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_OPEN_BLOB2(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
blb** blob_handle,
bid* blob_id,
USHORT bpb_length,
const UCHAR* bpb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ o p e n _ b l o b 2
*
**************************************
*
* Functional description
* Open an existing blob.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
NULL_CHECK(blob_handle, isc_bad_segstr_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *db_handle, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_open_blob2, *db_handle, *tra_handle, *blob_handle, blob_id,
bpb_length, bpb);
#endif
try
{
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
jrd_tra* transaction =
2003-11-08 17:40:17 +01:00
find_transaction(tdbb, *tra_handle, isc_segstr_wrong_db);
blb* blob = BLB_open2(tdbb, transaction, blob_id, bpb_length, bpb);
*blob_handle = blob;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *blob_handle);
#endif
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_PREPARE(ISC_STATUS * user_status,
jrd_tra** tra_handle,
USHORT length,
const UCHAR* msg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ p r e p a r e
*
**************************************
*
* Functional description
* Prepare a transaction for commit. First phase of a two
* phase commit.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
CHECK_HANDLE((*tra_handle), type_tra, isc_bad_trans_handle);
jrd_tra* transaction = *tra_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, transaction->tra_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_prepare2, *tra_handle, length, msg);
#endif
if (prepare(tdbb, transaction, user_status, length, msg))
return error(user_status);
return return_success(tdbb);
}
ISC_STATUS GDS_PUT_SEGMENT(ISC_STATUS* user_status,
blb** blob_handle,
USHORT buffer_length,
const UCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ p u t _ s e g m e n t
*
**************************************
*
* Functional description
* Abort a partially completed blob.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
blb* blob = check_blob(tdbb, user_status, blob_handle);
if (!blob)
2001-05-23 15:26:42 +02:00
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_put_segment, *blob_handle, buffer_length, buffer);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
BLB_put_segment(tdbb, blob, buffer, buffer_length);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
2003-12-03 09:19:24 +01:00
ISC_STATUS GDS_PUT_SLICE(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
ISC_QUAD* array_id,
USHORT sdl_length,
2003-12-03 09:19:24 +01:00
const UCHAR* sdl,
USHORT param_length,
2003-12-03 09:19:24 +01:00
const UCHAR* param,
SLONG slice_length,
2003-12-03 09:19:24 +01:00
UCHAR* slice)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ p u t _ s l i c e
*
**************************************
*
* Functional description
* Snatch a slice of an array.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *db_handle, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_put_slice, *db_handle, *tra_handle, *array_id, sdl_length,
sdl, param_length, param, slice_length, slice);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
jrd_tra* transaction =
2003-11-08 17:40:17 +01:00
find_transaction(tdbb, *tra_handle, isc_segstr_wrong_db);
BLB_put_slice(tdbb,
2001-05-23 15:26:42 +02:00
transaction,
reinterpret_cast<bid*>(array_id),
2001-05-23 15:26:42 +02:00
sdl,
param_length,
reinterpret_cast<const SLONG*>(param), slice_length, slice);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_QUE_EVENTS(ISC_STATUS* user_status,
Attachment** handle,
SLONG* id,
SSHORT length,
const UCHAR* items,
2003-12-22 11:00:59 +01:00
FPTR_EVENT_CALLBACK ast,
void* arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ q u e _ e v e n t s
*
**************************************
*
* Functional description
* Que a request for event notification.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, *handle, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_que_events, *handle, length, items);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
Lock* lock = dbb->dbb_lock;
Attachment* attachment = tdbb->tdbb_attachment;
if (!attachment->att_event_session &&
!(attachment->att_event_session = EVENT_create_session(user_status)))
{
return error(user_status);
}
*id = EVENT_que(user_status,
attachment->att_event_session,
lock->lck_length,
(const TEXT*) & lock->lck_key, length, items, ast, arg);
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *id);
#endif
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_RECEIVE(ISC_STATUS * user_status,
jrd_req** req_handle,
USHORT msg_type,
USHORT msg_length,
SCHAR * msg,
SSHORT level
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
, USHORT direction,
ULONG offset
2001-05-23 15:26:42 +02:00
#endif
)
{
/**************************************
*
* g d s _ $ r e c e i v e
*
**************************************
*
* Functional description
* Get a record from the host program.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
CHECK_HANDLE((*req_handle), type_req, isc_bad_req_handle);
jrd_req* request = *req_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, request->req_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_receive2, *req_handle, msg_type, msg_length, level);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
verify_request_synchronization(request, level);
2006-01-28 05:12:42 +01:00
#ifdef SCROLLABLE_CURSORS
if (direction)
EXE_seek(tdbb, request, direction, offset);
2006-01-28 05:12:42 +01:00
#endif
EXE_receive(tdbb, request, msg_type, msg_length,
2003-10-07 12:43:20 +02:00
reinterpret_cast<UCHAR*>(msg));
check_autocommit(request, tdbb);
if (request->req_flags & req_warning) {
request->req_flags &= ~req_warning;
return error(user_status);
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
ISC_STATUS GDS_RECONNECT(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
SSHORT length,
const UCHAR* id)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ r e c o n n e c t
*
**************************************
*
* Functional description
* Connect to a transaction in limbo.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
NULL_CHECK(tra_handle, isc_bad_trans_handle);
Attachment* attachment = *db_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_reconnect, *db_handle, *tra_handle, length, id);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
jrd_tra* transaction = TRA_reconnect(tdbb, id, length);
*tra_handle = transaction;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *tra_handle);
#endif
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_RELEASE_REQUEST(ISC_STATUS * user_status, jrd_req** req_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ r e l e a s e _ r e q u e s t
*
**************************************
*
* Functional description
* Release a request.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
CHECK_HANDLE((*req_handle), type_req, isc_bad_req_handle);
jrd_req* request = *req_handle;
Attachment* attachment = request->req_attachment;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_release_request, *req_handle);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
CMP_release(tdbb, request);
*req_handle = NULL;
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_REQUEST_INFO(ISC_STATUS* user_status,
jrd_req** req_handle,
SSHORT level,
SSHORT item_length,
const SCHAR* items,
SSHORT buffer_length,
SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ r e q u e s t _ i n f o
*
**************************************
*
* Functional description
* Provide information on blob object.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
jrd_req* request = *req_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(request, type_req, isc_bad_req_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, request->req_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_request_info2, *req_handle, level, item_length, items,
buffer_length);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
verify_request_synchronization(request, level);
2001-05-23 15:26:42 +02:00
INF_request_info(request, items, item_length, buffer, buffer_length);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_ROLLBACK_RETAINING(ISC_STATUS * user_status,
jrd_tra** tra_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* i s c _ r o l l b a c k _ r e t a i n i n g
*
**************************************
*
* Functional description
* Abort a transaction but keep the environment valid
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
jrd_tra* transaction = *tra_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(transaction, type_tra, isc_bad_trans_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, transaction->tra_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_rollback, *tra_handle);
#endif
if (rollback(tdbb, transaction, user_status, true))
2001-05-23 15:26:42 +02:00
return error(user_status);
return return_success(tdbb);
}
ISC_STATUS GDS_ROLLBACK(ISC_STATUS * user_status, jrd_tra** tra_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ r o l l b a c k
*
**************************************
*
* Functional description
* Abort a transaction.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
jrd_tra* transaction = *tra_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(transaction, type_tra, isc_bad_trans_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, transaction->tra_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_rollback, *tra_handle);
#endif
if (rollback(tdbb, transaction, user_status, false))
2001-05-23 15:26:42 +02:00
return error(user_status);
*tra_handle = NULL;
return return_success(tdbb);
}
ISC_STATUS GDS_SEEK_BLOB(ISC_STATUS * user_status,
blb** blob_handle,
SSHORT mode,
SLONG offset,
SLONG * result)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s e e k _ b l o b
*
**************************************
*
* Functional description
* Seek a stream blob.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
blb* blob = check_blob(tdbb, user_status, blob_handle);
if (!blob)
2001-05-23 15:26:42 +02:00
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_blob_seek, *blob_handle, mode, offset);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
*result = BLB_lseek(blob, mode, offset);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_SEND(ISC_STATUS * user_status,
jrd_req** req_handle,
USHORT msg_type,
USHORT msg_length,
SCHAR * msg,
SSHORT level)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s e n d
*
**************************************
*
* Functional description
* Get a record from the host program.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
CHECK_HANDLE((*req_handle), type_req, isc_bad_req_handle);
jrd_req* request = *req_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, request->req_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_send, *req_handle, msg_type, msg_length, msg, level);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
verify_request_synchronization(request, level);
EXE_send(tdbb, request, msg_type, msg_length,
2003-10-07 12:43:20 +02:00
reinterpret_cast<UCHAR*>(msg));
check_autocommit(request, tdbb);
if (request->req_flags & req_warning) {
request->req_flags &= ~req_warning;
return error(user_status);
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
2003-12-03 09:19:24 +01:00
ISC_STATUS GDS_SERVICE_ATTACH(ISC_STATUS* user_status,
USHORT service_length,
2003-12-03 09:19:24 +01:00
const TEXT* service_name,
Service** svc_handle,
USHORT spb_length,
2003-12-03 09:19:24 +01:00
const SCHAR* spb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s e r v i c e _ a t t a c h
*
**************************************
*
* Functional description
* Connect to an Interbase service.
*
**************************************/
api_entry_point_init(user_status);
if (*svc_handle)
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_svc_handle, 0);
2001-05-23 15:26:42 +02:00
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = user_status;
try
{
tdbb->tdbb_database = NULL;
*svc_handle = SVC_attach(service_length, service_name, spb_length, spb);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_SERVICE_DETACH(ISC_STATUS* user_status, Service** svc_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s e r v i c e _ d e t a c h
*
**************************************
*
* Functional description
* Close down a service.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Service* service = *svc_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(service, type_svc, isc_bad_svc_handle);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = user_status;
try
{
tdbb->tdbb_database = NULL;
SVC_detach(service);
*svc_handle = NULL;
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_SERVICE_QUERY(ISC_STATUS* user_status,
Service** svc_handle,
ULONG* reserved,
USHORT send_item_length,
const SCHAR* send_items,
USHORT recv_item_length,
const SCHAR* recv_items,
USHORT buffer_length,
SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s e r v i c e _ q u e r y
*
**************************************
*
* Functional description
* Provide information on service object.
*
* NOTE: The parameter RESERVED must not be used
* for any purpose as there are networking issues
* involved (as with any handle that goes over the
* network). This parameter will be implemented at
2001-05-23 15:26:42 +02:00
* a later date.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Service* service = *svc_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(service, type_svc, isc_bad_svc_handle);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = NULL;
try
{
if (service->svc_spb_version == isc_spb_version1)
SVC_query(service, send_item_length, send_items, recv_item_length,
recv_items, buffer_length, buffer);
else {
/* For SVC_query2, we are going to completly dismantle user_status (since at this point it is
* meaningless anyway). The status vector returned by this function can hold information about
* the call to query the service manager and/or a service thread that may have been running.
*/
SVC_query2(service, tdbb, send_item_length, send_items,
recv_item_length, recv_items, buffer_length, buffer);
/* if there is a status vector from a service thread, copy it into the thread status */
int len, warning;
PARSE_STATUS(service->svc_status, len, warning);
if (len) {
MOVE_FASTER(service->svc_status, tdbb->tdbb_status_vector,
2003-04-10 08:49:16 +02:00
sizeof(ISC_STATUS) * len);
/* Empty out the service status vector */
memset(service->svc_status, 0,
2003-04-10 08:49:16 +02:00
ISC_STATUS_LENGTH * sizeof(ISC_STATUS));
}
if (user_status[1])
return error(user_status);
2001-05-23 15:26:42 +02:00
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
ISC_STATUS GDS_SERVICE_START(ISC_STATUS* user_status,
Service** svc_handle,
ULONG* reserved,
USHORT spb_length,
const SCHAR* spb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ s e r v i c e _ s t a r t
*
**************************************
*
* Functional description
* Start the specified service
*
* NOTE: The parameter RESERVED must not be used
* for any purpose as there are networking issues
* involved (as with any handle that goes over the
* network). This parameter will be implemented at
2001-05-23 15:26:42 +02:00
* a later date.
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Service* service = *svc_handle;
2001-05-23 15:26:42 +02:00
CHECK_HANDLE(service, type_svc, isc_bad_svc_handle);
tdbb->tdbb_status_vector = user_status;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = NULL;
try
{
SVC_start(service, spb_length, spb);
if (service->svc_status[1]) {
2003-04-10 08:49:16 +02:00
ISC_STATUS* svc_status = service->svc_status;
ISC_STATUS* tdbb_status = tdbb->tdbb_status_vector;
while (*svc_status) {
*tdbb_status++ = *svc_status++;
}
*tdbb_status = isc_arg_end;
}
if (user_status[1]) {
return error(user_status);
2001-05-23 15:26:42 +02:00
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
2003-12-03 09:19:24 +01:00
ISC_STATUS GDS_START_AND_SEND(ISC_STATUS* user_status,
jrd_req** req_handle,
jrd_tra** tra_handle,
USHORT msg_type,
USHORT msg_length,
2003-12-03 09:19:24 +01:00
SCHAR* msg,
SSHORT level)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s t a r t _ a n d _ s e n d
*
**************************************
*
* Functional description
* Get a record from the host program.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
jrd_req* request = *req_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(request, type_req, isc_bad_req_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, request->req_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_start_and_send, *req_handle, *tra_handle, msg_type,
msg_length, msg, level);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
jrd_tra* transaction = find_transaction(tdbb, *tra_handle, isc_req_wrong_db);
if (level)
request = CMP_clone_request(tdbb, request, level, false);
EXE_unwind(tdbb, request);
EXE_start(tdbb, request, transaction);
EXE_send(tdbb, request, msg_type, msg_length,
2003-10-07 12:43:20 +02:00
reinterpret_cast<UCHAR*>(msg));
check_autocommit(request, tdbb);
if (request->req_flags & req_warning) {
request->req_flags &= ~req_warning;
return error(user_status);
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
ISC_STATUS GDS_START(ISC_STATUS * user_status,
jrd_req** req_handle,
jrd_tra** tra_handle,
SSHORT level)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s t a r t
*
**************************************
*
* Functional description
* Get a record from the host program.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
jrd_req* request = *req_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(request, type_req, isc_bad_req_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, request->req_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_start, *req_handle, *tra_handle, level);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
jrd_tra* transaction =
2003-11-08 17:40:17 +01:00
find_transaction(tdbb, *tra_handle, isc_req_wrong_db);
if (level)
request = CMP_clone_request(tdbb, request, level, false);
EXE_unwind(tdbb, request);
EXE_start(tdbb, request, transaction);
check_autocommit(request, tdbb);
if (request->req_flags & req_warning) {
request->req_flags &= ~req_warning;
return error(user_status);
}
}
catch (const std::exception& ex)
{
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
return return_success(tdbb);
}
ISC_STATUS GDS_START_MULTIPLE(ISC_STATUS * user_status,
jrd_tra** tra_handle,
USHORT count,
TEB * vector)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s t a r t _ m u l t i p l e
*
**************************************
*
* Functional description
* Start a transaction.
*
**************************************/
TEB* v;
2001-05-23 15:26:42 +02:00
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
NULL_CHECK(tra_handle, isc_bad_trans_handle);
const TEB* const end = vector + count;
2001-05-23 15:26:42 +02:00
for (v = vector; v < end; v++) {
if (check_database(tdbb, *v->teb_database, user_status))
return user_status[1];
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
}
if (check_database(tdbb, *vector->teb_database, user_status))
return user_status[1];
jrd_tra* prior = NULL;
jrd_tra* transaction = NULL;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
for (v = vector; v < end; v++)
{
Attachment* attachment = *v->teb_database;
2001-12-24 03:51:06 +01:00
if (check_database(tdbb, attachment, user_status)) {
2001-05-23 15:26:42 +02:00
return user_status[1];
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_start_multiple, *tra_handle, count, vector);
#endif
tdbb->tdbb_status_vector = user_status;
transaction =
TRA_start(tdbb, v->teb_tpb_length,
reinterpret_cast<const char*>(v->teb_tpb));
2001-05-23 15:26:42 +02:00
transaction->tra_sibling = prior;
prior = transaction;
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
}
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
Database* dbb = tdbb->tdbb_database;
2001-12-24 03:51:06 +01:00
--dbb->dbb_use_count;
if (prior) {
ISC_STATUS_ARRAY temp_status;
rollback(tdbb, prior, temp_status, false);
2001-12-24 03:51:06 +01:00
}
return error(user_status, ex);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
*tra_handle = transaction;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_handle_returned, *tra_handle);
#endif
return return_success(tdbb);
}
ISC_STATUS GDS_START_TRANSACTION(ISC_STATUS * user_status,
jrd_tra** tra_handle,
SSHORT count,
...)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ s t a r t _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Start a transaction.
*
**************************************/
api_entry_point_init(user_status);
TEB tebs[16];
TEB* teb;
const TEB* end;
va_list ptr;
va_start(ptr, count);
2001-05-23 15:26:42 +02:00
for (teb = tebs, end = teb + count; teb < end; teb++) {
teb->teb_database = va_arg(ptr, Attachment**);
2001-05-23 15:26:42 +02:00
teb->teb_tpb_length = va_arg(ptr, int);
teb->teb_tpb = va_arg(ptr, UCHAR *);
}
va_end(ptr);
2001-05-23 15:26:42 +02:00
return GDS_START_MULTIPLE(user_status, tra_handle, count, tebs);
}
ISC_STATUS GDS_TRANSACT_REQUEST(ISC_STATUS* user_status,
Attachment** db_handle,
jrd_tra** tra_handle,
USHORT blr_length,
2003-12-03 09:19:24 +01:00
const SCHAR* blr,
USHORT in_msg_length,
SCHAR* in_msg,
USHORT out_msg_length,
SCHAR* out_msg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* i s c _ t r a n s a c t _ r e q u e s t
*
**************************************
*
* Functional description
* Execute a procedure.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
Attachment* attachment = *db_handle;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_transact_request, *db_handle, *tra_handle,
blr_length, blr, in_msg_length, in_msg, out_msg_length);
#endif
jrd_req* request = NULL;
JrdMemoryPool* new_pool = 0;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = user_status;
try
{
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
jrd_tra* transaction = find_transaction(tdbb, *tra_handle, isc_req_wrong_db);
jrd_nod* in_message = NULL;
jrd_nod* out_message = NULL;
2001-05-23 15:26:42 +02:00
{
new_pool = JrdMemoryPool::createPool();
Jrd::ContextPoolHolder context(tdbb, new_pool);
2001-05-23 15:26:42 +02:00
CompilerScratch* csb = PAR_parse(tdbb, reinterpret_cast<const UCHAR*>(blr), FALSE);
request = CMP_make_request(tdbb, csb);
CMP_verify_access(tdbb, request);
2001-05-23 15:26:42 +02:00
jrd_nod* node;
for (size_t i = 0; i < csb->csb_rpt.getCount(); i++)
2001-12-24 03:51:06 +01:00
{
if ( (node = csb->csb_rpt[i].csb_message) )
{
if ((int) (IPTR) node->nod_arg[e_msg_number] == 0)
{
in_message = node;
}
else if ((int) (IPTR) node->nod_arg[e_msg_number] == 1)
{
out_message = node;
}
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
} // new context
2001-05-23 15:26:42 +02:00
request->req_attachment = attachment;
USHORT len;
2001-12-24 03:51:06 +01:00
if (in_msg_length)
{
2001-05-23 15:26:42 +02:00
if (in_message) {
2004-03-30 06:10:52 +02:00
const Format* format = (Format*) in_message->nod_arg[e_msg_format];
2001-05-23 15:26:42 +02:00
len = format->fmt_length;
}
2001-12-24 03:51:06 +01:00
else {
2001-05-23 15:26:42 +02:00
len = 0;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
if (in_msg_length != len)
2001-12-24 03:51:06 +01:00
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_port_len,
isc_arg_number, (SLONG) in_msg_length,
isc_arg_number, (SLONG) len, 0);
2001-12-24 03:51:06 +01:00
}
if ((U_IPTR) in_msg & (ALIGNMENT - 1)) {
2001-05-23 15:26:42 +02:00
MOVE_FAST(in_msg, (SCHAR *) request + in_message->nod_impure,
in_msg_length);
2001-12-24 03:51:06 +01:00
}
else {
2001-05-23 15:26:42 +02:00
MOVE_FASTER(in_msg, (SCHAR *) request + in_message->nod_impure,
in_msg_length);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
EXE_start(tdbb, request, transaction);
if (out_message) {
2004-03-30 06:10:52 +02:00
const Format* format = (Format*) out_message->nod_arg[e_msg_format];
2001-05-23 15:26:42 +02:00
len = format->fmt_length;
}
2001-12-24 03:51:06 +01:00
else {
2001-05-23 15:26:42 +02:00
len = 0;
2001-12-24 03:51:06 +01:00
}
if (out_msg_length != len) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_port_len,
isc_arg_number, (SLONG) out_msg_length,
isc_arg_number, (SLONG) len, 0);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (out_msg_length) {
if ((U_IPTR) out_msg & (ALIGNMENT - 1)) {
2001-05-23 15:26:42 +02:00
MOVE_FAST((SCHAR *) request + out_message->nod_impure, out_msg,
out_msg_length);
2001-12-24 03:51:06 +01:00
}
else {
2001-05-23 15:26:42 +02:00
MOVE_FASTER((SCHAR *) request + out_message->nod_impure, out_msg,
out_msg_length);
2001-12-24 03:51:06 +01:00
}
}
2001-05-23 15:26:42 +02:00
check_autocommit(request, tdbb);
CMP_release(tdbb, request);
return return_success(tdbb);
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex)
2001-12-24 03:51:06 +01:00
{
/* Set up to trap error in case release pool goes wrong. */
try {
if (request) {
CMP_release(tdbb, request);
}
else if (new_pool) {
JrdMemoryPool::deletePool(new_pool);
2001-12-24 03:51:06 +01:00
}
} // try
2003-02-13 14:33:57 +01:00
catch (const std::exception&) {
2001-12-24 03:51:06 +01:00
}
return error(user_status, ex);
2001-12-24 03:51:06 +01:00
} // catch
2001-05-23 15:26:42 +02:00
}
ISC_STATUS GDS_TRANSACTION_INFO(ISC_STATUS* user_status,
jrd_tra** tra_handle,
SSHORT item_length,
const SCHAR* items,
SSHORT buffer_length,
SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ t r a n s a c t i o n _ i n f o
*
**************************************
*
* Functional description
* Provide information on blob object.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
jrd_tra* transaction = *tra_handle;
2003-11-08 17:40:17 +01:00
CHECK_HANDLE(transaction, type_tra, isc_bad_trans_handle);
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, transaction->tra_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_transaction_info2, *tra_handle, item_length, items,
buffer_length);
#endif
tdbb->tdbb_status_vector = user_status;
try
{
INF_transaction_info(transaction, items, item_length, buffer,
2001-05-23 15:26:42 +02:00
buffer_length);
}
catch (const std::exception& ex)
{
return error(user_status, ex);
}
2001-05-23 15:26:42 +02:00
return return_success(tdbb);
}
ISC_STATUS GDS_UNWIND(ISC_STATUS * user_status,
jrd_req** req_handle,
SSHORT level)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g d s _ $ u n w i n d
*
**************************************
*
* Functional description
* Unwind a running request. This is potentially nasty since it can
* be called asynchronously.
*
**************************************/
api_entry_point_init(user_status);
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
CHECK_HANDLE((*req_handle), type_req, isc_bad_req_handle);
jrd_req* request = *req_handle;
2001-05-23 15:26:42 +02:00
/* Make sure blocks look and feel kosher */
2004-03-07 08:58:55 +01:00
Database* dbb;
Attachment* attachment = request->req_attachment;
if (!attachment ||
2001-12-24 03:51:06 +01:00
(MemoryPool::blk_type(attachment) != type_att) ||
2001-05-23 15:26:42 +02:00
!(dbb = attachment->att_database) ||
2001-12-24 03:51:06 +01:00
MemoryPool::blk_type(dbb) != type_dbb)
{
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
/* Make sure this is a valid attachment */
Attachment* attach;
2001-05-23 15:26:42 +02:00
for (attach = dbb->dbb_attachments; attach; attach = attach->att_next)
2001-12-24 03:51:06 +01:00
{
if (attach == attachment) {
2001-05-23 15:26:42 +02:00
break;
2001-12-24 03:51:06 +01:00
}
}
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (!attach) {
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = dbb;
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call(log_unwind, *req_handle, level);
#endif
/* Set up error handling to restore old state */
tdbb->tdbb_status_vector = user_status;
tdbb->tdbb_attachment = attachment;
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
/* Pick up and validate request level */
verify_request_synchronization(request, level);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
2001-05-23 15:26:42 +02:00
/* Unwind request. This just tweaks some bits */
EXE_unwind(tdbb, request);
2001-05-23 15:26:42 +02:00
/* Restore old state and get out */
JRD_restore_context();
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
user_status[0] = isc_arg_gds;
user_status[2] = isc_arg_end;
2001-05-23 15:26:42 +02:00
return (user_status[1] = FB_SUCCESS);
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(user_status, ex);
2001-12-24 03:51:06 +01:00
JRD_restore_context();
return user_status[1];
}
2001-05-23 15:26:42 +02:00
}
#ifdef MULTI_THREAD
void JRD_blocked(Attachment* blocking, BlockingThread** bt_que)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ b l o c k e d
*
**************************************
*
* Functional description
* We're blocked by another thread. Unless it would cause
* a deadlock, wait for the other other thread (it will
* wake us up.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
/* Check for deadlock. If there is one, complain */
Attachment* attachment;
2001-05-23 15:26:42 +02:00
for (attachment = blocking;
attachment;
attachment = attachment->att_blocking)
{
if (attachment == tdbb->tdbb_attachment) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_deadlock, 0);
2001-05-23 15:26:42 +02:00
}
}
BlockingThread* block = dbb->dbb_free_btbs;
2001-05-23 15:26:42 +02:00
if (block) {
dbb->dbb_free_btbs = block->btb_next;
}
else {
block = FB_NEW(*dbb->dbb_permanent) BlockingThread;
2001-05-23 15:26:42 +02:00
}
2004-04-20 07:57:31 +02:00
block->btb_thread_id = SCH_current_thread();
block->btb_next = *bt_que;
*bt_que = block;
2001-05-23 15:26:42 +02:00
attachment = tdbb->tdbb_attachment;
attachment->att_blocking = blocking;
SCH_hiber();
attachment->att_blocking = NULL;
}
#endif
#ifdef SUPERSERVER
bool JRD_getdir(Firebird::PathName& buf)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ g e t d i r
*
**************************************
*
* Functional description
* Current working directory is cached in the attachment
* block. get it out. This function could be called before
2001-05-23 15:26:42 +02:00
* an attachment is created. In such a case thread specific
* data (t_data) will hold the user name which will be used
2001-05-23 15:26:42 +02:00
* to get the users home directory.
*
**************************************/
char* t_data = NULL;
char b[MAXPATHLEN];
2001-05-23 15:26:42 +02:00
ThreadData::getSpecificData((void**) &t_data);
2001-05-23 15:26:42 +02:00
if (t_data) {
#ifdef WIN_NT
GetCurrentDirectory(MAXPATHLEN, b);
buf = b;
2001-05-23 15:26:42 +02:00
#else
const struct passwd* pwd;
strcpy(b, t_data);
pwd = getpwnam(b);
2001-05-23 15:26:42 +02:00
if (pwd)
buf = pwd->pw_dir;
else /* No home dir for this users here. Default to server dir */
return fb_getcwd(buf);
2001-05-23 15:26:42 +02:00
#endif
}
else
{
thread_db* tdbb = JRD_get_thread_data();
2001-05-23 15:26:42 +02:00
/** If the server has not done a JRD_set_thread_data prior to this call
(which will be the case when connecting via IPC), thread_db will
2001-05-23 15:26:42 +02:00
be NULL so do not attempt to get the attachment handle from
thread_db. Just return false as described below.
NOTE: The only time
2001-05-23 15:26:42 +02:00
this code is entered via IPC is if the database name = "".
**/
/** In case of backup/restore APIs, JRD_set_thread_data has been done but
2001-05-23 15:26:42 +02:00
the thread's context is a 'gbak' specific, so don't try extract
attachment from there.
**/
Attachment* attachment;
if (tdbb && (tdbb->getType() == ThreadData::tddDBB))
2001-05-23 15:26:42 +02:00
attachment = tdbb->tdbb_attachment;
else
return false;
2001-05-23 15:26:42 +02:00
/**
2001-05-23 15:26:42 +02:00
An older version of client will not be sending isc_dpb_working directory
so in all probabilities attachment->att_working_directory will be null.
return false so that ISC_expand_filename will create the file in fbserver's dir
2001-05-23 15:26:42 +02:00
**/
if (!attachment || attachment->att_working_directory.empty())
{
return false;
}
buf = attachment->att_working_directory;
2001-05-23 15:26:42 +02:00
}
return true;
2001-05-23 15:26:42 +02:00
}
#endif /* SUPERSERVER */
void JRD_mutex_lock(MUTX_PTR mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ m u t e x _ l o c k
*
**************************************
*
* Functional description
* Lock a mutex and note this fact
* in the thread context block.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
INUSE_insert(&tdbb->tdbb_mutexes, mutex, true);
2001-05-23 15:26:42 +02:00
THD_MUTEX_LOCK(mutex);
}
void JRD_mutex_unlock(MUTX_PTR mutex)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ m u t e x _ u n l o c k
*
**************************************
*
* Functional description
* Unlock a mutex and note this fact
* in the thread context block.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
INUSE_remove(&tdbb->tdbb_mutexes, mutex, false);
2001-05-23 15:26:42 +02:00
THD_MUTEX_UNLOCK(mutex);
}
#ifdef SUPERSERVER
void JRD_print_all_counters(const char* fname)
2001-05-23 15:26:42 +02:00
{
/*****************************************************
*
* J R D _ p r i n t _ a l l _ c o u n t e r s
*
*****************************************************
*
* Functional description
* print memory counters from DSQL, ENGINE & REMOTE
* component
*
******************************************************/
2003-05-09 18:05:24 +02:00
// Skidder: This may be ported to new memory pools, but
// I think this debugging feature may be safely eradicated
return;
2001-05-23 15:26:42 +02:00
}
#endif
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_PROCS
void JRD_print_procedure_info(thread_db* tdbb, const char* mesg)
2001-05-23 15:26:42 +02:00
{
/*****************************************************
*
* J R D _ p r i n t _ p r o c e d u r e _ i n f o
*
*****************************************************
*
* Functional description
* print name , use_count of all procedures in
2001-05-23 15:26:42 +02:00
* cache
*
******************************************************/
TEXT fname[MAXPATHLEN];
gds__prefix(fname, "proc_info.log");
2004-04-29 00:43:34 +02:00
FILE* fptr = fopen(fname, "a+");
if (!fptr) {
2001-05-23 15:26:42 +02:00
char buff[256];
sprintf(buff, "Failed to open %s\n", fname);
gds__log(buff, 0);
return;
}
if (mesg)
2004-04-29 00:43:34 +02:00
fputs(mesg, fptr);
fprintf(fptr,
2001-05-23 15:26:42 +02:00
"Prc Name , prc id , flags , Use Count , Alter Count\n");
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
vec<jrd_prc*>* procedures = tdbb->tdbb_database->dbb_procedures;
if (procedures) {
vec<jrd_prc*>::iterator ptr, end;
2001-12-24 03:51:06 +01:00
for (ptr = procedures->begin(), end = procedures->end();
2006-02-10 04:28:43 +01:00
ptr < end; ++ptr)
{
const jrd_prc* procedure = *ptr;
if (procedure)
2004-04-29 00:43:34 +02:00
fprintf(fptr, "%s , %d, %X, %d, %d\n",
(procedure->prc_name->hasData()) ?
procedure->prc_name->c_str() : "NULL",
procedure->prc_id,
procedure->prc_flags, procedure->prc_use_count,
0); // procedure->prc_alter_count
}
2001-05-23 15:26:42 +02:00
}
else
2004-04-29 00:43:34 +02:00
fprintf(fptr, "No Cached Procedures\n");
2001-05-23 15:26:42 +02:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
2004-04-29 00:43:34 +02:00
fclose(fptr);
2001-05-23 15:26:42 +02:00
}
#endif /* DEBUG_PROCS */
#ifdef MULTI_THREAD
bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ r e s c h e d u l e
*
**************************************
*
* Functional description
* Somebody has kindly offered to relinquish
* control so that somebody else may run.
*
**************************************/
/* Force garbage colletion 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();
else {
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
THREAD_YIELD();
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
}
/* If database has been shutdown then get out */
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
Attachment* attachment = tdbb->tdbb_attachment;
if (attachment)
{
Firebird::PathName file_name = attachment->att_filename;
2001-05-23 15:26:42 +02:00
if (dbb->dbb_ast_flags & DBB_shutdown &&
attachment->att_flags & ATT_shutdown)
{
2001-05-23 15:26:42 +02:00
if (punt) {
CCH_unwind(tdbb, false);
ERR_post(isc_shutdown, isc_arg_string,
ERR_cstring(file_name), 0);
2001-05-23 15:26:42 +02:00
}
else {
ISC_STATUS* status = tdbb->tdbb_status_vector;
2001-05-23 15:26:42 +02:00
*status++ = isc_arg_gds;
*status++ = isc_shutdown;
*status++ = isc_arg_string;
*status++ = (ISC_STATUS) ERR_cstring(file_name);
*status++ = isc_arg_end;
return true;
}
}
else if (attachment->att_flags & ATT_shutdown &&
!(tdbb->tdbb_flags & TDBB_shutdown_manager))
{
if (punt) {
CCH_unwind(tdbb, false);
ERR_post(isc_att_shutdown, 0);
}
else {
ISC_STATUS* status = tdbb->tdbb_status_vector;
*status++ = isc_arg_gds;
*status++ = isc_att_shutdown;
2001-05-23 15:26:42 +02:00
*status++ = isc_arg_end;
return true;
2001-05-23 15:26:42 +02:00
}
}
#ifdef CANCEL_OPERATION
/* If a cancel has been raised, defer its acknowledgement
when executing in the context of an internal request or
the system transaction. */
if ((attachment->att_flags & ATT_cancel_raise) &&
!(attachment->att_flags & ATT_cancel_disable))
{
const jrd_tra* transaction;
jrd_req* request = tdbb->tdbb_request;
if ((!request ||
2001-05-23 15:26:42 +02:00
!(request->req_flags & (req_internal | req_sys_trigger))) &&
(!(transaction = tdbb->tdbb_transaction) ||
!(transaction->tra_flags & TRA_system)))
{
2001-05-23 15:26:42 +02:00
attachment->att_flags &= ~ATT_cancel_raise;
if (punt) {
CCH_unwind(tdbb, false);
2001-05-23 15:26:42 +02:00
ERR_post(isc_cancelled, 0);
}
else {
ISC_STATUS* status = tdbb->tdbb_status_vector;
2001-05-23 15:26:42 +02:00
*status++ = isc_arg_gds;
*status++ = isc_cancelled;
*status++ = isc_arg_end;
return true;
2001-05-23 15:26:42 +02:00
}
}
}
#endif
}
tdbb->tdbb_quantum = (tdbb->tdbb_quantum <= 0) ?
(quantum ? quantum : (ThreadPriorityScheduler::boosted() ?
Config::getPriorityBoost() : 1) * QUANTUM) :
tdbb->tdbb_quantum;
2001-05-23 15:26:42 +02:00
return false;
2001-05-23 15:26:42 +02:00
}
#endif
void JRD_restore_context(void)
{
/**************************************
*
* J R D _ r e s t o r e _ c o n t e x t
*
**************************************
*
* Functional description
* Restore the previous thread specific data
* and cleanup and objects that remain in use.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2001-05-23 15:26:42 +02:00
bool cleaned_up =
INUSE_cleanup(&tdbb->tdbb_mutexes, (FPTR_VOID_PTR) THD_mutex_unlock);
// Logical OR would use short circuit boolean: function may not be called.
// Left as bitwise OR. Condition may be reversed to use logical OR.
//cleaned_up |=
// INUSE_cleanup(&tdbb->tdbb_rw_locks, (FPTR_VOID_PTR) THD_wlck_unlock);
2001-05-23 15:26:42 +02:00
/* Charlie will fill this in
cleaned_up |= INUSE_cleanup (&tdbb->tdbb_pages, (FPTR_VOID_PTR) CCH_?);
2001-05-23 15:26:42 +02:00
*/
ThreadData::restoreSpecific();
2001-05-23 15:26:42 +02:00
#ifdef DEV_BUILD
if (tdbb->tdbb_status_vector &&
!tdbb->tdbb_status_vector[1]
&& cleaned_up)
{
gds__log("mutexes or pages in use on successful return");
}
#endif
}
void JRD_inuse_clear(thread_db* tdbb)
{
/**************************************
*
* J R D _ i n u s e _ c l e a r
*
**************************************
*
* Functional description
* Prepare thread_db for later use .Initialize the in-use
* blocks so that we can unwind cleanly if an error occurs.
* Used in constructor and JRD_set_context().
*
**************************************/
INUSE_clear(&tdbb->tdbb_mutexes);
//INUSE_clear(&tdbb->tdbb_rw_locks);
//INUSE_clear(&tdbb->tdbb_pages); // Unused
}
void JRD_set_context(thread_db* tdbb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ s e t _ c o n t e x t
*
**************************************
*
* Functional description
* Set the thread specific data. Initialize
* the in-use blocks so that we can unwind
* cleanly if an error occurs.
*
**************************************/
JRD_inuse_clear(tdbb);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = NULL;
tdbb->putSpecific();
2001-05-23 15:26:42 +02:00
}
#ifdef MULTI_THREAD
void JRD_unblock(BlockingThread** bt_que)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ u n b l o c k
*
**************************************
*
* Functional description
* Unblock a linked list of blocked threads. Rather
* than worrying about which, let 'em all loose.
*
**************************************/
Database* dbb = GET_DBB();
2001-05-23 15:26:42 +02:00
BlockingThread* block;
while (block = *bt_que) {
*bt_que = block->btb_next;
2001-05-23 15:26:42 +02:00
if (block->btb_thread_id) {
2004-04-20 07:57:31 +02:00
SCH_wake(block->btb_thread_id);
2001-05-23 15:26:42 +02:00
}
block->btb_next = dbb->dbb_free_btbs;
dbb->dbb_free_btbs = block;
}
}
#endif
void jrd_vtof(const char* string, char* field, SSHORT length)
{
/**************************************
*
* j r d _ v t o f
*
**************************************
*
* Functional description
* Move a null terminated string to a fixed length
* field.
* If the length of the string pointed to by 'field'
* is less than 'length', this function pads the
* destination string with space upto 'length' bytes.
*
* The call is primarily generated by the preprocessor.
*
* This is the same code as gds__vtof but is used internally.
*
**************************************/
while (*string) {
*field++ = *string++;
if (--length <= 0) {
return;
}
}
if (length) {
memset(field, ' ', length);
2001-05-23 15:26:42 +02:00
}
}
static blb* check_blob(thread_db* tdbb, ISC_STATUS* user_status, blb** blob_handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ b l o b
*
**************************************
*
* Functional description
* Check out a blob handle for goodness. Return
* the address of the blob if ok, NULL otherwise.
*
**************************************/
jrd_tra* transaction = 0;
2001-05-23 15:26:42 +02:00
SET_TDBB(tdbb);
// this const made to check no accidental changes happen
const blb* const blob = *blob_handle;
2001-05-23 15:26:42 +02:00
if (!blob ||
2001-12-24 03:51:06 +01:00
(MemoryPool::blk_type(blob) != type_blb) ||
2001-05-23 15:26:42 +02:00
check_database(tdbb, blob->blb_attachment, user_status) ||
!(transaction = blob->blb_transaction) ||
MemoryPool::blk_type(transaction) != type_tra)
{
2003-11-08 17:40:17 +01:00
handle_error(user_status, isc_bad_segstr_handle, tdbb);
2001-05-23 15:26:42 +02:00
return NULL;
}
tdbb->tdbb_transaction = transaction;
return const_cast<blb*>(blob); // harmless, see comment above
2001-05-23 15:26:42 +02:00
}
static ISC_STATUS check_database(thread_db* tdbb, Attachment* attachment, ISC_STATUS * user_status)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ d a t a b a s e
*
**************************************
*
* Functional description
* Check an attachment for validity, setting
* up environment.
*
**************************************/
SET_TDBB(tdbb);
/* Make sure blocks look and feel kosher */
2004-03-07 08:58:55 +01:00
Database* dbb;
2001-05-23 15:26:42 +02:00
if (!attachment ||
2001-12-24 03:51:06 +01:00
(MemoryPool::blk_type(attachment) != type_att) ||
2001-05-23 15:26:42 +02:00
!(dbb = attachment->att_database) ||
2001-12-24 03:51:06 +01:00
MemoryPool::blk_type(dbb)!= type_dbb)
{
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
}
2001-05-23 15:26:42 +02:00
/* Make sure this is a valid attachment */
#ifndef SUPERSERVER
const Attachment* attach;
2001-05-23 15:26:42 +02:00
for (attach = dbb->dbb_attachments; attach; attach = attach->att_next)
if (attach == attachment)
break;
if (!attach)
2003-11-08 17:40:17 +01:00
return handle_error(user_status, isc_bad_db_handle, tdbb);
2001-05-23 15:26:42 +02:00
#endif
tdbb->tdbb_database = dbb;
tdbb->tdbb_attachment = attachment;
tdbb->tdbb_quantum = QUANTUM;
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
Jrd::ContextPoolHolder context(tdbb, 0);
2002-09-26 11:26:40 +02:00
tdbb->tdbb_flags = 0;
2001-05-23 15:26:42 +02:00
/* Count active threads in database */
++dbb->dbb_use_count;
// Want to avoid problems of literal strings v/s non-const pointers.
static TEXT string[] = "can't continue after bugcheck";
ISC_STATUS* ptr;
2001-05-23 15:26:42 +02:00
if (dbb->dbb_flags & DBB_bugcheck) {
tdbb->tdbb_status_vector = ptr = user_status;
2003-11-08 17:40:17 +01:00
*ptr++ = isc_arg_gds;
*ptr++ = isc_bug_check;
*ptr++ = isc_arg_string;
*ptr++ = (ISC_STATUS) string; // Warning: possible address truncation.
2003-11-08 17:40:17 +01:00
*ptr = isc_arg_end;
2001-05-23 15:26:42 +02:00
return error(user_status);
}
if (attachment->att_flags & ATT_shutdown ||
((dbb->dbb_ast_flags & DBB_shutdown) &&
((dbb->dbb_ast_flags & DBB_shutdown_full) ||
!(attachment->att_user->usr_flags & (USR_locksmith | USR_owner)))))
{
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = ptr = user_status;
2003-11-08 17:40:17 +01:00
*ptr++ = isc_arg_gds;
if (dbb->dbb_ast_flags & DBB_shutdown) {
*ptr++ = isc_shutdown;
*ptr++ = isc_arg_string;
*ptr++ = (ISC_STATUS) ERR_cstring(attachment->att_filename);
}
else {
*ptr++ = isc_att_shutdown;
}
2003-11-08 17:40:17 +01:00
*ptr = isc_arg_end;
2001-05-23 15:26:42 +02:00
return error(user_status);
}
#ifdef CANCEL_OPERATION
if ((attachment->att_flags & ATT_cancel_raise) &&
!(attachment->att_flags & ATT_cancel_disable))
{
2001-05-23 15:26:42 +02:00
attachment->att_flags &= ~ATT_cancel_raise;
tdbb->tdbb_status_vector = ptr = user_status;
*ptr++ = isc_arg_gds;
*ptr++ = isc_cancelled;
*ptr++ = isc_arg_end;
return error(user_status);
}
#endif
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
static void cleanup(void* arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c l e a n u p
*
**************************************
*
* Functional description
* Exit handler for image exit.
*
**************************************/
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_MUTEX_DESTROY(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_DESTROY_MUTEX;
2003-12-03 09:19:24 +01:00
initialized = false;
2001-05-23 15:26:42 +02:00
databases = NULL;
}
2003-04-10 08:49:16 +02:00
static ISC_STATUS commit(
ISC_STATUS* user_status,
jrd_tra** tra_handle, const bool retaining_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c o m m i t
*
**************************************
*
* Functional description
* Commit a transaction.
*
**************************************/
thread_db thd_context;
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
CHECK_HANDLE((*tra_handle), type_tra, isc_bad_trans_handle);
jrd_tra* transaction = *tra_handle;
jrd_tra* next = transaction;
2001-05-23 15:26:42 +02:00
if (check_database(tdbb, transaction->tra_attachment, user_status))
return user_status[1];
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
LOG_call((retaining_flag) ? log_commit_retaining : log_commit,
*tra_handle);
#endif
ISC_STATUS* ptr = user_status;
2001-05-23 15:26:42 +02:00
if (transaction->tra_sibling &&
!(transaction->tra_flags & TRA_prepared) &&
prepare(tdbb, transaction, ptr, 0, NULL))
2001-12-24 03:51:06 +01:00
{
2001-05-23 15:26:42 +02:00
return error(user_status);
}
2001-12-24 03:51:06 +01:00
try {
while ( (transaction = next) ) {
2001-05-23 15:26:42 +02:00
next = transaction->tra_sibling;
check_database(tdbb, transaction->tra_attachment, user_status);
tdbb->tdbb_status_vector = ptr;
TRA_commit(tdbb, transaction, retaining_flag);
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
}
return return_success(tdbb);
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
Database* dbb = tdbb->tdbb_database;
2001-12-24 03:51:06 +01:00
--dbb->dbb_use_count;
return error(user_status, ex);
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
static bool drop_files(const jrd_file* file)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d r o p _ f i l e s
*
**************************************
*
* Functional description
* drop a linked list of files
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status;
2001-05-23 15:26:42 +02:00
status[1] = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
for (; file; file = file->fil_next)
{
if (unlink(file->fil_string))
{
IBERR_build_status(status, isc_io_error,
2003-11-08 17:40:17 +01:00
isc_arg_string, "unlink",
isc_arg_string,
2003-01-18 17:31:23 +01:00
ERR_cstring(file->fil_string),
2001-05-23 15:26:42 +02:00
isc_arg_gds, isc_io_delete_err,
SYS_ERR, errno,
0);
Database* dbb = GET_DBB();
2001-05-23 15:26:42 +02:00
gds__log_status(dbb->dbb_file->fil_string, status);
}
}
return status[1] ? true : false;
2001-05-23 15:26:42 +02:00
}
static jrd_tra* find_transaction(thread_db* tdbb, jrd_tra* transaction, ISC_STATUS error_code)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f i n d _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Find the element of a possible multiple database transaction
* that corresponds to the current database.
*
**************************************/
SET_TDBB(tdbb);
2001-12-24 03:51:06 +01:00
if (!transaction || MemoryPool::blk_type(transaction) != type_tra)
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_trans_handle, 0);
2001-05-23 15:26:42 +02:00
for (; transaction; transaction = transaction->tra_sibling)
if (transaction->tra_attachment == tdbb->tdbb_attachment) {
tdbb->tdbb_transaction = transaction;
return transaction;
}
ERR_post(error_code, 0);
return NULL; /* Added to remove compiler warnings */
2001-05-23 15:26:42 +02:00
}
static ISC_STATUS error(ISC_STATUS* user_status, const std::exception& ex)
{
/**************************************
*
* e r r o r
*
**************************************
*
* Functional description
* An error returned has been trapped. Return a status code.
*
**************************************/
Firebird::stuff_exception(user_status, ex);
return error(user_status);
}
static ISC_STATUS error(ISC_STATUS* user_status)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e r r o r
*
**************************************
*
* Functional description
* An error returned has been trapped. Return a status code.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2001-05-23 15:26:42 +02:00
/* Decrement count of active threads in database */
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
if (dbb) {
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
}
JRD_restore_context();
/* This is debugging code which is meant to verify that
the database use count is cleared on exit from the
engine. Database shutdown cannot succeed if the database
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)) {
dbb->dbb_use_count = 0;
ISC_STATUS* p = user_status;
2003-11-08 17:40:17 +01:00
*p++ = isc_arg_gds;
*p++ = isc_random;
*p++ = isc_arg_string;
2003-04-10 08:49:16 +02:00
*p++ = (ISC_STATUS) "database use count set on error return";
2003-11-08 17:40:17 +01:00
*p = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
#endif
return user_status[1];
}
static void find_intl_charset(thread_db* tdbb, Attachment* attachment, const DatabaseOptions* options)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f i n d _ i n t l _ c h a r s e t
*
**************************************
*
* Functional description
* Attachment has declared it's prefered character set
* as part of LC_CTYPE, passed over with the attachment
* block. Now let's resolve that to an internal subtype id.
*
**************************************/
SET_TDBB(tdbb);
if (options->dpb_lc_ctype.isEmpty()) {
2001-05-23 15:26:42 +02:00
/* No declaration of character set, act like 3.x Interbase */
attachment->att_charset = DEFAULT_ATTACHMENT_CHARSET;
2001-05-23 15:26:42 +02:00
return;
}
2006-04-05 18:34:18 +02:00
USHORT id;
2001-05-23 15:26:42 +02:00
2004-11-27 07:51:58 +01:00
const UCHAR* lc_ctype =
reinterpret_cast<const UCHAR*>(options->dpb_lc_ctype.c_str());
2005-05-28 00:45:31 +02:00
if (MET_get_char_coll_subtype(tdbb, &id, lc_ctype, options->dpb_lc_ctype.length()) &&
INTL_defined_type(tdbb, id & 0xFF) &&
2005-05-28 00:45:31 +02:00
((id & 0xFF) != CS_BINARY))
2001-05-23 15:26:42 +02:00
{
2005-05-28 00:45:31 +02:00
attachment->att_charset = id & 0xFF;
2001-05-23 15:26:42 +02:00
}
else
{
/* Report an error - we can't do what user has requested */
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_content,
isc_arg_gds, isc_charset_not_found,
isc_arg_string, ERR_cstring(options->dpb_lc_ctype),
2001-05-23 15:26:42 +02:00
0);
}
}
void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ o p t i o n s
*
**************************************
*
* Functional description
* Parse database parameter block picking up options and things.
*
**************************************/
SSHORT num_old_files = 0;
Database* dbb = GET_DBB();
2001-05-23 15:26:42 +02:00
dpb_buffers = JRD_cache_default;
dpb_sweep_interval = -1;
dpb_overwrite = false;
dpb_sql_dialect = 99;
invalid_client_SQL_dialect = false;
2001-05-23 15:26:42 +02:00
if (dpb_length == 0)
{
return;
}
if (dpb == NULL)
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_form, 0);
}
Firebird::ClumpletReader rdr(Firebird::ClumpletReader::Tagged, dpb, dpb_length);
2001-05-23 15:26:42 +02:00
if (rdr.getBufferTag() != isc_dpb_version1)
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_form, isc_arg_gds, isc_wrodpbver, 0);
}
2001-05-23 15:26:42 +02:00
for (; !(rdr.isEof()); rdr.moveNext())
2001-05-23 15:26:42 +02:00
{
switch (rdr.getClumpTag())
2001-05-23 15:26:42 +02:00
{
case isc_dpb_working_directory:
{
rdr.getPath(dpb_working_directory);
2001-05-23 15:26:42 +02:00
// CLASSIC have no thread data. Init to zero.
char* t_data = 0;
ThreadData::getSpecificData((void **) &t_data);
2001-05-23 15:26:42 +02:00
/*
2001-05-23 15:26:42 +02:00
Null value for working_directory implies remote database. So get
the users HOME directory
*/
#ifndef WIN_NT
if (dpb_working_directory.isEmpty()) {
struct passwd *passwd = NULL;
2001-05-23 15:26:42 +02:00
if (t_data)
passwd = getpwnam(t_data);
if (passwd)
{
dpb_working_directory = passwd->pw_dir;
2001-05-23 15:26:42 +02:00
}
else { /*No home dir for this users here. Default to server dir */
fb_getcwd(dpb_working_directory);
2001-05-23 15:26:42 +02:00
}
}
#endif
if (t_data)
{
free(t_data);
t_data = NULL;
}
/* Null out the thread local data so that further references will fail */
ThreadData::putSpecificData(0);
2001-05-23 15:26:42 +02:00
}
break;
case isc_dpb_set_page_buffers:
dpb_page_buffers = rdr.getInt();
if (dpb_page_buffers &&
(dpb_page_buffers < MIN_PAGE_BUFFERS ||
dpb_page_buffers > MAX_PAGE_BUFFERS))
2001-05-23 15:26:42 +02:00
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_content, 0);
2001-05-23 15:26:42 +02:00
}
dpb_set_page_buffers = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_num_buffers:
dpb_buffers = rdr.getInt();
if (dpb_buffers < 10)
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_bad_dpb_content, 0);
}
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_page_size:
dpb_page_size = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_debug:
dpb_debug = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_sweep:
dpb_sweep = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_sweep_interval:
dpb_sweep_interval = rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_verify:
dpb_verify = (USHORT) rdr.getInt();
if (dpb_verify & isc_dpb_ignore)
2001-05-23 15:26:42 +02:00
dbb->dbb_flags |= DBB_damaged;
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_trace:
dpb_trace = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_damaged:
if (rdr.getInt() & 1)
2001-05-23 15:26:42 +02:00
dbb->dbb_flags |= DBB_damaged;
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_enable_journal:
rdr.getString(dpb_journal);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_wal_backup_dir:
// ignore, skip
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_drop_walfile:
dpb_wal_action = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_old_dump_id:
case isc_dpb_online_dump:
case isc_dpb_old_file_size:
case isc_dpb_old_num_files:
case isc_dpb_old_start_page:
case isc_dpb_old_start_seqno:
case isc_dpb_old_start_file:
// ignore, skip
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_old_file:
//if (num_old_files >= MAX_OLD_FILES) complain here, for now.
2003-11-08 17:40:17 +01:00
ERR_post(isc_num_old_files, 0);
// following code is never executed now !
2001-05-23 15:26:42 +02:00
num_old_files++;
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_wal_chkptlen:
case isc_dpb_wal_numbufs:
case isc_dpb_wal_bufsize:
case isc_dpb_wal_grp_cmt_wait:
// ignore, skip
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_dbkey_scope:
dpb_dbkey_scope = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_sys_user_name:
rdr.getString(dpb_sys_user_name);
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_sql_role_name:
rdr.getString(dpb_role_name);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_user_name:
rdr.getString(dpb_user_name);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_password:
rdr.getString(dpb_password);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_password_enc:
rdr.getString(dpb_password_enc);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_encrypt_key:
2001-05-23 15:26:42 +02:00
#ifdef ISC_DATABASE_ENCRYPTION
rdr.getString(dpb_key);
2001-05-23 15:26:42 +02:00
#else
/* Just in case there WAS a customer using this unsupported
* feature - post an error when they try to access it in 4.0
*/
2003-11-08 17:40:17 +01:00
ERR_post(isc_uns_ext, isc_arg_gds, isc_random,
isc_arg_string, "Encryption not supported", 0);
2001-05-23 15:26:42 +02:00
#endif
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_no_garbage_collect:
dpb_no_garbage = TRUE;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_disable_journal:
dpb_disable = TRUE;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_activate_shadow:
dpb_activate_shadow = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_delete_shadow:
dpb_delete_shadow = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_force_write:
dpb_set_force_write = TRUE;
dpb_force_write = (SSHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_begin_log:
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
rdr.getPath(dpb_log);
#endif
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_quit_log:
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
dpb_quit_log = true;
#endif
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_no_reserve:
dpb_set_no_reserve = TRUE;
dpb_no_reserve = (UCHAR) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_interp:
dpb_interp = (SSHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_lc_messages:
rdr.getPath(dpb_lc_messages);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_lc_ctype:
rdr.getString(dpb_lc_ctype);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_shutdown:
dpb_shutdown = (USHORT) rdr.getInt();
// Enforce default
if ((dpb_shutdown & isc_dpb_shut_mode_mask) == isc_dpb_shut_default)
dpb_shutdown |= isc_dpb_shut_multi;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_shutdown_delay:
dpb_shutdown_delay = (SSHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_online:
dpb_online = (USHORT) rdr.getInt();
// Enforce default
if ((dpb_online & isc_dpb_shut_mode_mask) == isc_dpb_shut_default)
{
dpb_online |= isc_dpb_shut_normal;
}
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_reserved:
{
Firebird::string single;
rdr.getString(single);
if (single == "YES")
{
dpb_single_user = TRUE;
}
}
break;
2001-05-23 15:26:42 +02:00
case isc_dpb_overwrite:
dpb_overwrite = rdr.getInt() != 0;
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_sec_attach:
dpb_sec_attach = rdr.getInt() != 0;
dpb_buffers = 50;
2001-05-23 15:26:42 +02:00
dbb->dbb_flags |= DBB_security_db;
break;
case isc_dpb_gbak_attach:
rdr.getString(dpb_gbak_attach);
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_gstat_attach:
dpb_gstat_attach = true;
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_gfix_attach:
dpb_gfix_attach = true;
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_gsec_attach:
dpb_gsec_attach = rdr.getBoolean();
break;
2001-05-23 15:26:42 +02:00
case isc_dpb_disable_wal:
dpb_disable_wal = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_connect_timeout:
dpb_connect_timeout = rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dpb_dummy_packet_interval:
dpb_dummy_packet_interval = rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_sql_dialect:
dpb_sql_dialect = (USHORT) rdr.getInt();
if (dpb_sql_dialect > SQL_DIALECT_V6)
invalid_client_SQL_dialect = true;
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_set_db_sql_dialect:
dpb_set_db_sql_dialect = (USHORT) rdr.getInt();
2001-05-23 15:26:42 +02:00
break;
case isc_dpb_set_db_readonly:
dpb_set_db_readonly = true;
dpb_db_readonly = rdr.getInt() != 0;
break;
case isc_dpb_set_db_charset:
rdr.getString(dpb_set_db_charset);
break;
2001-07-12 07:46:06 +02:00
case isc_dpb_address_path: {
Firebird::ClumpletReader address_stack(Firebird::ClumpletReader::UnTagged,
rdr.getBytes(), rdr.getClumpLength());
while (!address_stack.isEof()) {
if (address_stack.getClumpTag() != isc_dpb_address) {
address_stack.moveNext();
continue;
}
Firebird::ClumpletReader address(Firebird::ClumpletReader::UnTagged,
address_stack.getBytes(), address_stack.getClumpLength());
while (!address.isEof()) {
switch (address.getClumpTag()) {
case isc_dpb_addr_protocol:
address.getString(dpb_network_protocol);
break;
case isc_dpb_addr_endpoint:
address.getString(dpb_remote_address);
break;
default:
break;
}
address.moveNext();
}
break;
}
break;
}
2001-05-23 15:26:42 +02:00
default:
break;
2001-05-23 15:26:42 +02:00
}
}
if (! rdr.isEof())
2002-07-02 11:49:19 +02:00
{
ERR_post(isc_bad_dpb_form, 0);
2002-07-02 11:49:19 +02:00
}
2001-05-23 15:26:42 +02:00
}
static ISC_STATUS handle_error(ISC_STATUS* user_status, ISC_STATUS code, thread_db* tdbb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* h a n d l e _ e r r o r
*
**************************************
*
* Functional description
* An invalid handle has been passed in. If there is a user status
* vector, make it reflect the error. If not, emulate the routine
* "error" and abort.
*
**************************************/
if (tdbb)
JRD_restore_context();
ISC_STATUS* vector = user_status;
2003-11-08 17:40:17 +01:00
*vector++ = isc_arg_gds;
2001-05-23 15:26:42 +02:00
*vector++ = code;
2003-11-08 17:40:17 +01:00
*vector = isc_arg_end;
2001-05-23 15:26:42 +02:00
return code;
}
#if defined (WIN_NT) && !defined(SERVER_SHUTDOWN)
static BOOLEAN handler_NT(SSHORT controlAction)
{
/**************************************
*
* h a n d l e r _ N T
*
**************************************
*
* Functional description
* For some actions, get NT to issue a popup asking
* the user to delay.
*
**************************************/
switch (controlAction) {
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return TRUE; /* NT will issue popup */
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
return FALSE; /* let it go */
}
/* So, what are we to return here?! */
return FALSE; /* let it go */
}
#endif
static Database* init(thread_db* tdbb,
2003-04-10 08:49:16 +02:00
ISC_STATUS* user_status,
const Firebird::PathName& expanded_filename,
2003-12-03 09:19:24 +01:00
bool attach_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* i n i t
*
**************************************
*
* Functional description
* Initialize for database access. First call from both CREATE and
* OPEN.
*
**************************************/
MUTX_T temp_mutx[DBB_MUTX_max];
// wlck_t temp_wlck[DBB_WLCK_max];
2001-05-23 15:26:42 +02:00
SET_TDBB(tdbb);
/* If this is the first time through, initialize local mutexes and set
up a cleanup handler. Regardless, then lock the database mutex. */
if (!initialized) {
THD_INIT;
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
THD_GLOBAL_MUTEX_LOCK;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2005-05-28 00:45:31 +02:00
IntlManager::initialize();
PluginManager::load_engine_plugins();
2001-05-23 15:26:42 +02:00
if (!initialized) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_MUTEX_INIT(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
JRD_SS_INIT_MUTEX;
gds__register_cleanup(cleanup, 0);
2003-12-03 09:19:24 +01:00
initialized = true;
2002-12-06 22:12:59 +01:00
JRD_cache_default = Config::getDefaultDbCachePages();
2001-05-23 15:26:42 +02:00
if (JRD_cache_default < MIN_PAGE_BUFFERS)
JRD_cache_default = MIN_PAGE_BUFFERS;
if (JRD_cache_default > MAX_PAGE_BUFFERS)
JRD_cache_default = MAX_PAGE_BUFFERS;
#if defined (WIN_NT) && !defined(SERVER_SHUTDOWN)
setup_NT_handlers();
#endif
}
THD_GLOBAL_MUTEX_UNLOCK;
}
JRD_SS_MUTEX_LOCK;
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_LOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
/* Check to see if the database is already actively attached */
2004-03-07 08:58:55 +01:00
Database* dbb;
for (dbb = databases; dbb; dbb = dbb->dbb_next)
2001-05-23 15:26:42 +02:00
{
2004-03-07 08:58:55 +01:00
if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use)) &&
2001-05-23 15:26:42 +02:00
#ifndef SUPERSERVER
2004-03-07 08:58:55 +01:00
!(dbb->dbb_ast_flags & DBB_shutdown &&
dbb->dbb_ast_flags & DBB_shutdown_locks) &&
2001-05-23 15:26:42 +02:00
#endif
(dbb->dbb_filename == expanded_filename))
2001-05-23 15:26:42 +02:00
{
2004-03-07 08:58:55 +01:00
return (attach_flag) ? dbb : NULL;
2001-05-23 15:26:42 +02:00
}
}
2004-03-07 08:58:55 +01:00
/* Clean up temporary Database */
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
/* MOVE_CLEAR(&temp, (SLONG) sizeof(Database)); */
2001-05-23 15:26:42 +02:00
/* set up the temporary database block with fields that are
2001-05-23 15:26:42 +02:00
required for doing the ALL_init() */
tdbb->tdbb_status_vector = user_status;
2001-12-24 03:51:06 +01:00
tdbb->tdbb_database = 0;
try {
#ifdef SUPERSERVER
Firebird::MemoryStats temp_stats;
JrdMemoryPool* perm = JrdMemoryPool::createDbPool(temp_stats);
2004-03-07 08:58:55 +01:00
dbb = Database::newDbb(*perm);
perm->setStatsGroup(dbb->dbb_memory_stats);
#else
JrdMemoryPool* perm = JrdMemoryPool::createDbPool(MemoryPool::default_stats_group);
2004-03-07 08:58:55 +01:00
dbb = Database::newDbb(*perm);
#endif
2001-12-24 03:51:06 +01:00
//temp.blk_type = type_dbb;
2004-03-07 08:58:55 +01:00
dbb->dbb_permanent = perm;
dbb->dbb_mutexes = temp_mutx;
//dbb->dbb_rw_locks = temp_wlck;
2004-03-07 08:58:55 +01:00
tdbb->tdbb_database = dbb;
2001-12-24 03:51:06 +01:00
ALL_init();
// provide context pool for the rest stuff
Jrd::ContextPoolHolder context(tdbb, perm);
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
dbb->dbb_next = databases;
databases = dbb;
2001-05-23 15:26:42 +02:00
dbb->dbb_mutexes = FB_NEW(*dbb->dbb_permanent) MUTX_T[DBB_MUTX_max];
// dbb->dbb_rw_locks = FB_NEW(*dbb->dbb_permanent) wlck_t[DBB_WLCK_max]; // unused
dbb->dbb_internal = vec<jrd_req*>::newVector(*dbb->dbb_permanent, irq_MAX);
dbb->dbb_dyn_req = vec<jrd_req*>::newVector(*dbb->dbb_permanent, drq_MAX);
2004-03-07 08:58:55 +01:00
dbb->dbb_flags |= DBB_exclusive;
dbb->dbb_sweep_interval = SWEEP_INTERVAL;
2001-05-23 15:26:42 +02:00
/* set a garbage collection policy */
if ((dbb->dbb_flags & (DBB_gc_cooperative | DBB_gc_background)) == 0)
{
Firebird::string gc_policy = Config::getGCPolicy();
gc_policy.lower();
if (gc_policy == GCPolicyCooperative) {
dbb->dbb_flags |= DBB_gc_cooperative;
}
else if (gc_policy == GCPolicyBackground) {
dbb->dbb_flags |= DBB_gc_background;
}
else if (gc_policy == GCPolicyCombined) {
dbb->dbb_flags |= DBB_gc_cooperative | DBB_gc_background;
}
else // config value is invalid, use default
{
if (GCPolicyDefault == GCPolicyCooperative) {
dbb->dbb_flags |= DBB_gc_cooperative;
}
else if (GCPolicyDefault == GCPolicyBackground) {
dbb->dbb_flags |= DBB_gc_background;
}
else if (GCPolicyDefault == GCPolicyCombined) {
dbb->dbb_flags |= DBB_gc_cooperative | DBB_gc_background;
}
else
fb_assert(false);
}
2004-11-10 06:19:20 +01:00
}
2001-05-23 15:26:42 +02:00
/* Initialize a number of subsystems */
TRA_init(tdbb);
/* Lookup some external "hooks" */
PluginManager::Plugin crypt_lib =
PluginManager::enginePluginManager().findPlugin(CRYPT_IMAGE);
if (crypt_lib) {
Firebird::string encrypt_entrypoint(ENCRYPT);
Firebird::string decrypt_entrypoint(DECRYPT);
2004-03-07 08:58:55 +01:00
dbb->dbb_encrypt =
(Database::crypt_routine) crypt_lib.lookupSymbol(encrypt_entrypoint);
dbb->dbb_decrypt =
(Database::crypt_routine) crypt_lib.lookupSymbol(decrypt_entrypoint);
2001-05-23 15:26:42 +02:00
}
INTL_init(tdbb);
SecurityDatabase::initialize();
2004-03-07 08:58:55 +01:00
return dbb;
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(user_status, ex);
2001-12-24 03:51:06 +01:00
return 0;
}
2001-05-23 15:26:42 +02:00
}
static ISC_STATUS prepare(thread_db* tdbb,
jrd_tra* transaction,
2003-04-10 08:49:16 +02:00
ISC_STATUS* status_vector,
2001-05-23 15:26:42 +02:00
USHORT length,
const UCHAR* msg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p r e p a r e
*
**************************************
*
* Functional description
* Attempt to prepare a transaction. If it fails at any point, return
* an error.
*
**************************************/
SET_TDBB(tdbb);
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
for (; transaction; transaction = transaction->tra_sibling) {
check_database(tdbb, transaction->tra_attachment, status_vector);
tdbb->tdbb_status_vector = status_vector;
TRA_prepare(tdbb, transaction, length, msg);
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
}
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(status_vector, ex);
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-12-24 03:51:06 +01:00
--dbb->dbb_use_count;
return status_vector[1];
}
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
static void release_attachment(Attachment* attachment)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ a t t a c h m e n t
*
**************************************
*
* Functional description
* Disconnect attachment block from database block.
* NOTE: This routine assumes that upon entry,
* mutex DBB_MUTX_init_fini will be locked.
* Before exiting, there is a handoff from this
* mutex to the databases_mutex mutex. Upon exit,
* that mutex remains locked. It is the
* responsibility of the caller to unlock it.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
CHECK_DBB(dbb);
if (!attachment) {
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
V4_JRD_MUTEX_LOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
return;
}
if (attachment->att_event_session)
EVENT_delete_session(attachment->att_event_session);
if (attachment->att_id_lock)
LCK_release(tdbb, attachment->att_id_lock);
for (vcl** vector = attachment->att_counts;
2001-05-23 15:26:42 +02:00
vector < attachment->att_counts + DBB_max_count; ++vector)
{
2001-05-23 15:26:42 +02:00
if (*vector)
2005-01-25 07:33:07 +01:00
{
2001-12-24 03:51:06 +01:00
delete *vector;
2005-01-25 07:33:07 +01:00
*vector = 0;
}
}
2001-05-23 15:26:42 +02:00
// Release any validation error vector allocated
2001-05-23 15:26:42 +02:00
if (attachment->att_val_errors) {
2001-12-24 03:51:06 +01:00
delete attachment->att_val_errors;
attachment->att_val_errors = NULL;
2001-05-23 15:26:42 +02:00
}
/* bug #7781, need to null out the attachment pointer of all locks which
were hung off this attachment block, to ensure that the attachment
2001-05-23 15:26:42 +02:00
block doesn't get dereferenced after it is released */
// Disable delivery of ASTs for the moment while queue of locks is in flux
LCK_ast_inhibit();
Lock* long_lock = attachment->att_long_locks;
while (long_lock) {
Lock* next = long_lock->lck_next;
long_lock->lck_attachment = NULL;
long_lock->lck_next = NULL;
long_lock->lck_prior = NULL;
long_lock = next;
2001-05-23 15:26:42 +02:00
}
LCK_ast_enable();
2001-05-23 15:26:42 +02:00
if (attachment->att_flags & ATT_lck_init_done) {
2001-05-23 15:26:42 +02:00
LCK_fini(tdbb, LCK_OWNER_attachment); /* For the attachment */
attachment->att_flags &= ~ATT_lck_init_done;
}
2001-05-23 15:26:42 +02:00
if (attachment->att_compatibility_table)
2001-12-24 03:51:06 +01:00
delete attachment->att_compatibility_table;
2001-05-23 15:26:42 +02:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-05-23 15:26:42 +02:00
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
V4_JRD_MUTEX_LOCK(databases_mutex);
#endif
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (MemoryPool::blk_type(dbb) != type_dbb)
2001-05-23 15:26:42 +02:00
return;
/* remove the attachment block from the dbb linked list */
for (Attachment** ptr = &dbb->dbb_attachments; *ptr; ptr = &(*ptr)->att_next) {
2001-05-23 15:26:42 +02:00
if (*ptr == attachment) {
*ptr = attachment->att_next;
break;
}
}
}
static ISC_STATUS return_success(thread_db* tdbb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e t u r n _ s u c c e s s
*
**************************************
*
* Functional description
* Set up status vector to reflect successful execution.
*
**************************************/
SET_TDBB(tdbb);
/* Decrement count of active threads in database */
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
if (dbb)
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
ISC_STATUS* const user_status = tdbb->tdbb_status_vector;
ISC_STATUS* p = user_status;
2001-05-23 15:26:42 +02:00
/* If the status vector has not been initialized, then
initialize the status vector to indicate success.
2001-05-23 15:26:42 +02:00
Else pass the status vector along at it stands. */
2003-11-08 17:40:17 +01:00
if (p[0] != isc_arg_gds ||
p[1] != FB_SUCCESS ||
2003-11-08 17:40:17 +01:00
(p[2] != isc_arg_end && p[2] != isc_arg_gds &&
2001-05-23 15:26:42 +02:00
p[2] != isc_arg_warning))
{
2003-11-08 17:40:17 +01:00
*p++ = isc_arg_gds;
*p++ = FB_SUCCESS;
2003-11-08 17:40:17 +01:00
*p = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
JRD_restore_context();
/* This is debugging code which is meant to verify that
the database use count is cleared on exit from the
engine. Database shutdown cannot succeed if the database
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)) {
dbb->dbb_use_count = 0;
p = user_status;
2003-11-08 17:40:17 +01:00
*p++ = isc_arg_gds;
*p++ = isc_random;
*p++ = isc_arg_string;
2003-04-10 08:49:16 +02:00
*p++ = (ISC_STATUS) "database use count set on success return";
2003-11-08 17:40:17 +01:00
*p = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
#endif
return user_status[1];
}
static bool rollback(thread_db* tdbb,
jrd_tra* next,
2003-04-10 08:49:16 +02:00
ISC_STATUS* status_vector,
const bool retaining_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r o l l b a c k
*
**************************************
*
* Functional description
* Abort a transaction.
*
**************************************/
jrd_tra* transaction;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY local_status;
2001-05-23 15:26:42 +02:00
SET_TDBB(tdbb);
2001-12-24 03:51:06 +01:00
while ( (transaction = next) )
{
2001-05-23 15:26:42 +02:00
next = transaction->tra_sibling;
check_database(tdbb, transaction->tra_attachment, status_vector);
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
tdbb->tdbb_status_vector = status_vector;
TRA_rollback(tdbb, transaction, retaining_flag, false);
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
--dbb->dbb_use_count;
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
Firebird::stuff_exception(status_vector, ex);
2001-12-24 03:51:06 +01:00
status_vector = local_status;
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-12-24 03:51:06 +01:00
--dbb->dbb_use_count;
continue;
}
2001-05-23 15:26:42 +02:00
}
return (status_vector == local_status);
}
#if defined (WIN_NT) && !defined(SERVER_SHUTDOWN)
static void setup_NT_handlers()
{
/**************************************
*
* s e t u p _ N T _ h a n d l e r s
*
**************************************
*
* Functional description
* Set up Windows NT console control handlers for
* things that can happen. The handler used for
* all cases, handler_NT(), will flush and close
* any open database files.
*
**************************************/
SetConsoleCtrlHandler((PHANDLER_ROUTINE) handler_NT, TRUE);
2001-05-23 15:26:42 +02:00
}
#endif
2004-03-07 08:58:55 +01:00
static void shutdown_database(Database* dbb, const bool release_pools)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s h u t d o w n _ d a t a b a s e
*
**************************************
*
* Functional description
* Shutdown physical database environment.
* NOTE: This routine assumes that upon entry,
* mutex databases_mutex will be locked.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2001-05-23 15:26:42 +02:00
/* Shutdown file and/or remote connection */
#ifdef SUPERSERVER_V2
TRA_header_write(tdbb, dbb, 0L); /* Update transaction info on header page. */
#endif
#ifdef GARBAGE_THREAD
VIO_fini(tdbb);
#endif
CMP_fini(tdbb);
CCH_fini(tdbb);
if (dbb->dbb_backup_manager)
dbb->dbb_backup_manager->shutdown(tdbb);
// FUN_fini(tdbb);
2001-05-23 15:26:42 +02:00
if (dbb->dbb_shadow_lock)
LCK_release(tdbb, dbb->dbb_shadow_lock);
if (dbb->dbb_retaining_lock)
LCK_release(tdbb, dbb->dbb_retaining_lock);
if (dbb->dbb_lock)
LCK_release(tdbb, dbb->dbb_lock);
#ifdef REPLAY_OSRI_API_CALLS_SUBSYSTEM
if (dbb->dbb_log)
LOG_fini();
#endif
/* Shut down any extern relations */
if (dbb->dbb_relations)
{
vec<jrd_rel*>* vector = dbb->dbb_relations;
vec<jrd_rel*>::iterator ptr = vector->begin(), end = vector->end();
2001-05-23 15:26:42 +02:00
for (; ptr < end; ++ptr)
{
if (*ptr && (*ptr)->rel_file)
2001-05-23 15:26:42 +02:00
{
EXT_fini(*ptr);
2001-05-23 15:26:42 +02:00
}
}
}
2004-03-07 08:58:55 +01:00
Database** d_ptr; // Intentionally left outside loop (HP/UX compiler)
2001-05-23 15:26:42 +02:00
for (d_ptr = &databases; *(d_ptr); d_ptr = &(*d_ptr)->dbb_next) {
if (*d_ptr == dbb) {
*d_ptr = dbb->dbb_next;
break;
}
}
if (dbb->dbb_flags & DBB_lck_init_done) {
LCK_fini(tdbb, LCK_OWNER_database); /* For the database */
dbb->dbb_flags &= ~DBB_lck_init_done;
}
/* Remove objects from the in-use strutures before destroying them */
USHORT i;
for (i = 0; i < DBB_MUTX_max; i++) {
INUSE_remove(&tdbb->tdbb_mutexes, dbb->dbb_mutexes + i, true);
2001-05-23 15:26:42 +02:00
}
// for (i = 0; i < DBB_WLCK_max; i++) {
// INUSE_remove(&tdbb->tdbb_rw_locks, dbb->dbb_rw_locks + i, true);
// }
2001-05-23 15:26:42 +02:00
delete[] dbb->dbb_mutexes;
// delete[] dbb->dbb_rw_locks;
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
if (dbb->dbb_flags & DBB_sp_rec_mutex_init) {
THD_rec_mutex_destroy(&dbb->dbb_sp_rec_mutex);
}
#endif
if (release_pools) {
2004-03-07 08:58:55 +01:00
Database::deleteDbb(dbb);
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = NULL;
}
SecurityDatabase::shutdown();
2001-05-23 15:26:42 +02:00
}
static void strip_quotes(Firebird::string& out)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t r i p _ q u o t e s
*
**************************************
*
* Functional description
* Get rid of quotes around strings
*
**************************************/
if (out.isEmpty())
{
2001-05-23 15:26:42 +02:00
return;
}
if (out[0] == DBL_QUOTE || out[0] == SINGLE_QUOTE)
{
// Skip any initial quote
2004-11-27 07:51:58 +01:00
const char quote = out[0];
out.erase(0, 1);
// Search for same quote
size_t pos = out.find(quote);
if (pos != Firebird::string::npos)
{
out.erase(pos);
}
2001-05-23 15:26:42 +02:00
}
}
void JRD_set_cache_default(ULONG* num_ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ s e t _ c a c h e _ d e f a u l t
*
**************************************
*
* Functional description
* Set the number of cache pages to use for each
* database, but don't go less than MIN_PAGE_BUFFERS and
* more than MAX_PAGE_BUFFERS.
* Currently MIN_PAGE_BUFFERS = 50L,
* MAX_PAGE_BUFFERS = 65535L.
*
**************************************/
if (*num_ptr < MIN_PAGE_BUFFERS)
*num_ptr = MIN_PAGE_BUFFERS;
if (*num_ptr > MAX_PAGE_BUFFERS)
*num_ptr = MAX_PAGE_BUFFERS;
JRD_cache_default = *num_ptr;
}
#ifdef SERVER_SHUTDOWN
TEXT* JRD_num_attachments(TEXT* const buf, USHORT buf_len, USHORT flag,
USHORT* atts, USHORT* dbs)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* J R D _ n u m _ a t t a c h m e n t s
*
**************************************
*
* Functional description
* Count the number of active databases and
* attachments. If flag is set then put
* what it says into buf, if it fits. If it does not fit
* then allocate local buffer, put info into there, and
* return pointer to caller (in this case a caller must
* release memory allocated for local buffer).
*
**************************************/
/* protect against NULL value for buf */
TEXT* lbuf = buf;
if (!lbuf)
buf_len = 0;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
/* Check that the buffer is big enough for the requested
* information. If not, unset the flag
*/
if (flag == JRD_info_drivemask) {
if (buf_len < sizeof(ULONG)) {
lbuf = (TEXT*) gds__alloc((SLONG) (sizeof(ULONG)));
if (!lbuf)
2001-05-23 15:26:42 +02:00
flag = 0;
}
}
2001-05-23 15:26:42 +02:00
#endif
USHORT num_dbs = 0;
USHORT num_att = 0;
USHORT total = 0;
ULONG drive_mask = 0L;
db_file* dbf = NULL;
db_file* dbfp = NULL;
2004-05-15 02:58:46 +02:00
THREAD_ENTER();
2001-05-23 15:26:42 +02:00
/* Zip through the list of databases and count the number of local
* connections. If buf is not NULL then copy all the database names
* that will fit into it. */
2004-03-07 08:58:55 +01:00
for (Database* dbb = databases; dbb; dbb = dbb->dbb_next) {
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
/* Get drive letters for db files */
if (flag == JRD_info_drivemask)
{
for (jrd_file* files = dbb->dbb_file; files; files = files->fil_next)
2001-05-23 15:26:42 +02:00
ExtractDriveLetter(files->fil_string, &drive_mask);
}
2001-05-23 15:26:42 +02:00
#endif
if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) &&
2001-05-23 15:26:42 +02:00
!(dbb->dbb_ast_flags & DBB_shutdown
&& dbb->dbb_ast_flags & DBB_shutdown_locks))
{
2001-05-23 15:26:42 +02:00
num_dbs++;
if (flag == JRD_info_dbnames) {
if (dbfp == NULL) {
dbfp = (db_file*) gds__alloc((SLONG) (sizeof(db_file) +
2001-05-23 15:26:42 +02:00
sizeof(TEXT) *
dbb->dbb_filename.length()));
if (!dbfp)
throw std::bad_alloc();
2001-05-23 15:26:42 +02:00
dbf = dbfp;
}
else {
dbfp->dbf_next = (db_file*)
2001-05-23 15:26:42 +02:00
gds__alloc((SLONG)
(sizeof(db_file) +
2001-05-23 15:26:42 +02:00
sizeof(TEXT) *
dbb->dbb_filename.length()));
if (!dbfp)
throw std::bad_alloc();
2001-05-23 15:26:42 +02:00
dbfp = dbfp->dbf_next;
}
if (dbfp) {
dbfp->dbf_length = dbb->dbb_filename.length();
2001-05-23 15:26:42 +02:00
dbfp->dbf_next = NULL;
MOVE_FAST(dbb->dbb_filename.c_str(), dbfp->dbf_data,
2001-05-23 15:26:42 +02:00
dbfp->dbf_length);
total += sizeof(USHORT) + dbfp->dbf_length;
}
else
flag = 0;
}
for (const Attachment* attach = dbb->dbb_attachments; attach;
attach = attach->att_next)
{
2001-05-23 15:26:42 +02:00
num_att++;
#ifdef WIN_NT
/* Get drive letters for temp directories */
if (flag == JRD_info_drivemask) {
mutexed_dir_list* ptr = DLS_get_access();
for (dir_list* dirs = ptr->mdls_dls; dirs; dirs = dirs->dls_next) {
2001-05-23 15:26:42 +02:00
ExtractDriveLetter(dirs->dls_directory, &drive_mask);
}
}
/* Get drive letters for sort files */
if (flag == JRD_info_drivemask)
{
for (const sort_context* scb = attach->att_active_sorts; scb;
scb = scb->scb_next)
2001-05-23 15:26:42 +02:00
{
for (const sort_work_file* sfb = scb->scb_sfb; sfb;
sfb = sfb->sfb_next)
2001-05-23 15:26:42 +02:00
{
ExtractDriveLetter(sfb->sfb_file_name, &drive_mask);
}
}
}
#endif
}
}
}
2004-05-15 02:58:46 +02:00
THREAD_EXIT();
2001-05-23 15:26:42 +02:00
*atts = num_att;
*dbs = num_dbs;
if (dbf)
{
if (flag == JRD_info_dbnames)
{
if (buf_len < (sizeof(USHORT) + total))
2001-05-23 15:26:42 +02:00
{
lbuf = (TEXT *) gds__alloc((SLONG) (sizeof(USHORT) + total));
}
TEXT* lbufp = lbuf;
if (lbufp)
2001-05-23 15:26:42 +02:00
{
/* Put db info into buffer. Format is as follows:
number of dbases sizeof (USHORT)
1st db name length sizeof (USHORT)
1st db name sizeof (TEXT) * length
2nd db name length
2nd db name
...
last db name length
last db name
*/
lbufp += sizeof(USHORT);
total = 0;
for (dbfp = dbf; dbfp; dbfp = dbfp->dbf_next) {
*lbufp++ = (TEXT) dbfp->dbf_length;
*lbufp++ = dbfp->dbf_length >> 8;
MOVE_FAST(dbfp->dbf_data, lbufp, dbfp->dbf_length);
lbufp += dbfp->dbf_length;
total++;
}
2003-11-04 00:59:24 +01:00
fb_assert(total == num_dbs);
2001-05-23 15:26:42 +02:00
lbufp = lbuf;
*lbufp++ = (TEXT) total;
*lbufp++ = total >> 8;
}
}
for (dbfp = dbf; dbfp;) {
db_file* x = dbfp->dbf_next;
2001-05-23 15:26:42 +02:00
gds__free(dbfp);
dbfp = x;
}
}
#ifdef WIN_NT
if (flag == JRD_info_drivemask)
*(ULONG *) lbuf = drive_mask;
#endif
// CVC: Apparently, the original condition will leak memory, because flag
// may be JRD_info_drivemask and memory could be allocated for that purpose,
// as few as sizeof(ULONG), but a leak is a leak! I added the ifdef below.
2001-05-23 15:26:42 +02:00
if (num_dbs == 0)
{
#ifdef WIN_NT
if (flag == JRD_info_drivemask && lbuf != buf)
gds__free(lbuf);
#endif
2001-05-23 15:26:42 +02:00
lbuf = NULL;
}
2001-05-23 15:26:42 +02:00
return lbuf;
}
#ifdef WIN_NT
static void ExtractDriveLetter(const TEXT* file_name, ULONG* drive_mask)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* E x t r a c t D r i v e L e t t e r
*
**************************************
*
* Functional description
* Determine the drive letter of file_name
* and set the proper bit in the bit mask.
* bit 0 = drive A
* bit 1 = drive B and so on...
* This function is used to determine drive
* usage for use with Plug and Play for
* MS Windows 4.0.
*
**************************************/
ULONG mask = 1;
const SHORT shift = (*file_name - 'A');
2001-05-23 15:26:42 +02:00
mask <<= shift;
*drive_mask |= mask;
}
#endif
ISC_STATUS shutdown_all()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2005-04-11 17:33:18 +02:00
* s h u t d o w n _ a l l
2001-05-23 15:26:42 +02:00
*
**************************************
*
* 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);
2001-05-23 15:26:42 +02:00
if (initialized) {
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_LOCK;
}
ISC_STATUS_ARRAY user_status;
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
Database* dbb_next;
for (Database* dbb = databases; dbb; dbb = dbb_next)
2001-05-23 15:26:42 +02:00
{
dbb_next = dbb->dbb_next;
2003-02-16 19:07:53 +01:00
if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) &&
2001-05-23 15:26:42 +02:00
!(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)
2001-05-23 15:26:42 +02:00
{
att_next = attach->att_next;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_database = dbb;
tdbb->tdbb_attachment = attach;
2001-05-23 15:26:42 +02:00
tdbb->tdbb_request = NULL;
tdbb->tdbb_transaction = NULL;
tdbb->tdbb_flags |= TDBB_shutdown_manager;
Jrd::ContextPoolHolder context(tdbb, 0);
2001-05-23 15:26:42 +02:00
++dbb->dbb_use_count;
/* purge_attachment below can do an ERR_post */
tdbb->tdbb_status_vector = user_status;
2001-12-24 03:51:06 +01:00
try {
/* purge attachment, rollback any open transactions */
2001-12-24 03:51:06 +01:00
#if defined(V4_THREADING) && !defined(SUPERSERVER)
2001-12-24 03:51:06 +01:00
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)
2001-12-24 03:51:06 +01:00
V4_JRD_MUTEX_UNLOCK(databases_mutex);
#endif
2001-12-24 03:51:06 +01:00
} // try
catch (const std::exception& ex) {
2001-12-24 03:51:06 +01:00
if (initialized) {
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
2001-12-24 03:51:06 +01:00
}
return error(user_status, ex);
2001-05-23 15:26:42 +02:00
}
}
}
}
2003-08-12 11:55:37 +02:00
if (initialized) {
2001-05-23 15:26:42 +02:00
JRD_SS_MUTEX_UNLOCK;
2003-08-12 11:55:37 +02:00
}
2001-05-23 15:26:42 +02:00
JRD_restore_context();
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
2005-04-11 17:33:18 +02:00
#ifdef SUPERSERVER
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg) {
/**************************************
*
* s h u t d o w n _ t h r e a d
*
**************************************
*
* Functional description
* Shutdown SuperServer. If hangs, server
* is forcely & dirty closed after timeout.
*
**************************************/
*static_cast<int*>(arg) = (shutdown_all() == FB_SUCCESS);
2005-04-11 17:33:18 +02:00
return 0;
}
#endif // SUPERSERVER
void JRD_shutdown_all(bool asyncMode)
2005-04-11 17:33:18 +02:00
{
/**************************************
*
* J R D _ s h u t d o w n _ a l l
*
**************************************
*
* Functional description
2005-06-25 11:34:59 +02:00
* Rollback every transaction, release
* every attachment, and shutdown every
* database. Can be called in either a
* blocking mode or as a request for
* asynchronous shutdown.
2005-04-11 17:33:18 +02:00
*
**************************************/
#ifdef SUPERSERVER
int flShutdownComplete = 0;
if (asyncMode)
2005-04-11 17:33:18 +02:00
{
gds__thread_start(shutdown_thread, &flShutdownComplete,
THREAD_medium, 0, 0);
int timeout = 10; // seconds
while (timeout--)
{
if (flShutdownComplete)
break;
THREAD_SLEEP(1 * 1000);
}
2005-04-11 17:33:18 +02:00
}
else // sync mode
2005-04-11 17:33:18 +02:00
{
flShutdownComplete = (shutdown_all() == FB_SUCCESS);
2005-04-11 17:33:18 +02:00
}
if (!flShutdownComplete)
2005-04-11 17:33:18 +02:00
{
gds__log("Forced server shutdown - not all databases closed");
}
#endif // SUPERSERVER
}
2001-05-23 15:26:42 +02:00
#endif /* SERVER_SHUTDOWN */
static void purge_attachment(thread_db* tdbb,
2003-04-10 08:49:16 +02:00
ISC_STATUS* user_status,
Attachment* attachment,
const bool force_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u r g e _ a t t a c h m e n t
*
**************************************
*
* Functional description
* Zap an attachment, shutting down the database
* if it is the last one.
* NOTE: This routine assumes that upon entry,
* mutex databases_mutex will be locked.
*
**************************************/
SET_TDBB(tdbb);
2004-03-07 08:58:55 +01:00
Database* dbb = attachment->att_database;
2001-05-23 15:26:42 +02:00
const ULONG att_flags = attachment->att_flags;
attachment->att_flags |= ATT_shutdown;
2001-05-23 15:26:42 +02:00
if (!(dbb->dbb_flags & DBB_bugcheck)) {
// Check for any pending transactions
2001-05-23 15:26:42 +02:00
int count = 0;
jrd_tra* next;
for (jrd_tra* transaction = attachment->att_transactions;
2001-05-23 15:26:42 +02:00
transaction;
transaction = next)
{
next = transaction->tra_next;
if (transaction != attachment->att_dbkey_trans)
{
if (transaction->tra_flags & TRA_prepared ||
dbb->dbb_ast_flags & DBB_shutdown ||
att_flags & ATT_shutdown)
2001-05-23 15:26:42 +02:00
{
TRA_release_transaction(tdbb, transaction);
}
else if (force_flag)
TRA_rollback(tdbb, transaction, false, true);
2001-05-23 15:26:42 +02:00
else
++count;
}
}
if (count)
2003-11-08 17:40:17 +01:00
ERR_post(isc_open_trans, isc_arg_number, (SLONG) count, 0);
2001-05-23 15:26:42 +02:00
// If there's a side transaction for db-key scope, get rid of it
2001-05-23 15:26:42 +02:00
jrd_tra* trans_dbk = attachment->att_dbkey_trans;
if (trans_dbk)
2001-05-23 15:26:42 +02:00
{
attachment->att_dbkey_trans = NULL;
if (dbb->dbb_ast_flags & DBB_shutdown ||
att_flags & ATT_shutdown)
2001-05-23 15:26:42 +02:00
{
TRA_release_transaction(tdbb, trans_dbk);
2001-05-23 15:26:42 +02:00
}
else
{
TRA_commit(tdbb, trans_dbk, false);
2001-05-23 15:26:42 +02:00
}
}
SORT_shutdown(attachment);
}
// Unlink attachment from database
2001-05-23 15:26:42 +02:00
release_attachment(attachment);
// At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been
// unlocked and mutex databases_mutex has been locked.
2001-05-23 15:26:42 +02:00
// If there are still attachments, do a partial shutdown
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
if (MemoryPool::blk_type(dbb) == type_dbb)
2001-05-23 15:26:42 +02:00
{
if (dbb->dbb_attachments || (dbb->dbb_flags & DBB_being_opened))
{
2003-11-10 10:16:38 +01:00
// There are still attachments so do a partial shutdown
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
// Both CMP_release() and SCL_release() do advance the pointer
// before the deallocation.
jrd_req* request;
2001-12-24 03:51:06 +01:00
while ( (request = attachment->att_requests) ) {
2001-05-23 15:26:42 +02:00
CMP_release(tdbb, request);
}
SecurityClass* sec_class;
while ( (sec_class = attachment->att_security_classes) ) {
SCL_release(sec_class);
2001-05-23 15:26:42 +02:00
}
UserId* user = attachment->att_user;
if (user) {
2001-12-24 03:51:06 +01:00
delete user;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
delete attachment;
2001-05-23 15:26:42 +02:00
}
else
{
shutdown_database(dbb, true);
2001-05-23 15:26:42 +02:00
}
}
}
// verify_request_synchronization
//
// @brief Finds the sub-requests at the given level and replaces with it the
// original passed request (note the pointer by reference). If that specific
// sub-request is not found, throw the dreaded "request synchronization error".
// Notice that at this time, the calling function's "request" pointer has been
// set to null, so remember that if you write a debugging routine.
// This function replaced a chunk of code repeated four times.
//
// @param request The incoming, parent request to be replaced.
// @param level The level of the sub-request we need to find.
static void verify_request_synchronization(jrd_req*& request, SSHORT level)
{
const USHORT lev = level;
if (lev) {
const vec<jrd_req*>* vector = request->req_sub_requests;
if (!vector || lev >= vector->count() ||
!(request = (*vector)[lev]))
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_req_sync, 0);
}
}
}
/**
verify_database_name
@brief Verify database name for open/create
against given in conf file list of available directories
@param name
@param status
**/
static vdnResult verify_database_name(const Firebird::PathName& name, ISC_STATUS* status)
{
2005-02-24 13:24:38 +01:00
// Check for security2.fdb
static TEXT SecurityNameBuffer[MAXPATHLEN] = "";
static Firebird::PathName ExpandedSecurityNameBuffer(*getDefaultMemoryPool());
if (! SecurityNameBuffer[0]) {
SecurityDatabase::getPath(SecurityNameBuffer);
ExpandedSecurityNameBuffer = SecurityNameBuffer;
ISC_expand_filename(ExpandedSecurityNameBuffer, false);
}
if (name == SecurityNameBuffer || name == ExpandedSecurityNameBuffer)
return vdnSecurity;
// Check for .conf
if (!ISC_verify_database_access(name)) {
2003-11-08 17:40:17 +01:00
status[0] = isc_arg_gds;
status[1] = isc_conf_access_denied;
status[2] = isc_arg_string;
// CVC: Using STATUS to hold pointer to literal string!
2003-10-07 12:43:20 +02:00
status[3] = reinterpret_cast<ISC_STATUS>("database");
2003-11-08 17:40:17 +01:00
status[4] = isc_arg_string;
status[5] = (ISC_STATUS)(U_IPTR) ERR_cstring(name.c_str());
2003-11-08 17:40:17 +01:00
status[6] = isc_arg_end;
return vdnFail;
}
return vdnOk;
}