mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-25 00:03:03 +01:00
1074 lines
36 KiB
C++
1074 lines
36 KiB
C++
/*
|
|
* PROGRAM: JRD access method
|
|
* MODULE: jrd.h
|
|
* DESCRIPTION: Common descriptions
|
|
*
|
|
* 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.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
|
|
*
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
*
|
|
*/
|
|
|
|
#ifndef JRD_JRD_H
|
|
#define JRD_JRD_H
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
#include "../jrd/common.h"
|
|
#include "../jrd/dsc.h"
|
|
#include "../jrd/all.h"
|
|
#include "../jrd/nbak.h"
|
|
#if defined(UNIX) && defined(SUPERSERVER)
|
|
#include <setjmp.h>
|
|
#endif
|
|
|
|
#include "../include/fb_vector.h"
|
|
|
|
#ifdef DEV_BUILD
|
|
#define DEBUG if (debug) DBG_supervisor(debug);
|
|
#define VIO_DEBUG /* remove this for production build */
|
|
#define WALW_DEBUG /* remove this for production build */
|
|
#else /* PROD */
|
|
#define DEBUG
|
|
#undef VIO_DEBUG
|
|
#undef WALW_DEBUG
|
|
#endif
|
|
|
|
#define BUGCHECK(number) ERR_bugcheck (number)
|
|
#define CORRUPT(number) ERR_corrupt (number)
|
|
#define IBERROR(number) ERR_error (number)
|
|
|
|
|
|
#define BLKCHK(blk, type) if (MemoryPool::blk_type(blk) != (USHORT) (type)) BUGCHECK (147)
|
|
|
|
/* DEV_BLKCHK is used for internal consistency checking - where
|
|
* the performance hit in production build isn't desired.
|
|
* (eg: scatter this everywhere)
|
|
*
|
|
* This causes me a problem DEV_BLKCHK fails when the data seems valid
|
|
* After talking to John this could be because the memory is from the local
|
|
* stack rather than the heap. However I found to continue I needed to
|
|
* turn it off by dfining the macro to be empty. But In thinking about
|
|
* it I think that it would be more helful for a mode where these extra
|
|
* DEV checks just gave warnings rather than being fatal.
|
|
* MOD 29-July-2002
|
|
*
|
|
*/
|
|
#ifdef DEV_BUILD
|
|
#define DEV_BLKCHK(blk,type)
|
|
//#define DEV_BLKCHK(blk,type) if (blk) {BLKCHK (blk, type);}
|
|
#else
|
|
#define DEV_BLKCHK(blk,type) /* nothing */
|
|
#endif
|
|
|
|
|
|
/* Thread data block / IPC related data blocks */
|
|
|
|
#include "../jrd/thd.h"
|
|
#include "../jrd/isc.h"
|
|
|
|
/* definition of block types for data allocation in JRD */
|
|
#include "../jrd/jrd_blks.h"
|
|
#include "../include/fb_blk.h"
|
|
|
|
|
|
/* the database block, the topmost block in the metadata
|
|
cache for a database */
|
|
|
|
#define HASH_SIZE 101
|
|
|
|
|
|
// fwd. decl.
|
|
class vec;
|
|
class tdbb;
|
|
|
|
|
|
class dbb : private pool_alloc<type_dbb>
|
|
{
|
|
public:
|
|
typedef int (*crypt_routine) (char*, void*, int, void*);
|
|
|
|
static dbb* newDbb(MemoryPool& p) {
|
|
return FB_NEW(p) dbb(p);
|
|
}
|
|
|
|
// The deleteDbb function MUST be used to delete a dbb object.
|
|
// The function hides some tricky order of operations. Since the
|
|
// memory for the vectors in the dbb is allocated out of the dbb's
|
|
// permanent memory pool, the entire delete() operation needs
|
|
// to complete _before_ the permanent pool is deleted, or else
|
|
// risk an aborted engine.
|
|
static void deleteDbb(dbb *toDelete)
|
|
{
|
|
if (toDelete == 0)
|
|
return;
|
|
JrdMemoryPool *perm = toDelete->dbb_permanent;
|
|
delete toDelete;
|
|
JrdMemoryPool::noDbbDeletePool(perm);
|
|
}
|
|
|
|
class dbb *dbb_next; /* Next database block in system */
|
|
class att *dbb_attachments; /* Active attachments */
|
|
struct bcb *dbb_bcb; /* Buffer control block */
|
|
vec* dbb_relations; /* relation vector */
|
|
vec* dbb_procedures; /* scanned procedures */
|
|
struct lck *dbb_lock; /* granddaddy lock */
|
|
struct jrd_tra *dbb_sys_trans; /* system transaction */
|
|
struct fil *dbb_file; /* files for I/O operations */
|
|
struct sdw *dbb_shadow; /* shadow control block */
|
|
struct lck *dbb_shadow_lock; /* lock for synchronizing addition of shadows */
|
|
SLONG dbb_shadow_sync_count; /* to synchronize changes to shadows */
|
|
struct lck *dbb_retaining_lock; /* lock for preserving commit retaining snapshot */
|
|
struct plc *dbb_connection; /* connection block */
|
|
struct pgc *dbb_pcontrol; /* page control */
|
|
class vcl *dbb_t_pages; /* pages number for transactions */
|
|
class vcl *dbb_gen_id_pages; /* known pages for gen_id */
|
|
struct blf *dbb_blob_filters; /* known blob filters */
|
|
struct lls *dbb_modules; /* external function/filter modules */
|
|
MUTX_T *dbb_mutexes; /* DBB block mutexes */
|
|
WLCK_T *dbb_rw_locks; /* DBB block read/write locks */
|
|
REC_MUTX_T dbb_sp_rec_mutex; /* Recursive mutex for accessing/updating stored procedure metadata */
|
|
SLONG dbb_sort_size; /* Size of sort space per sort */
|
|
|
|
UATOM dbb_ast_flags; /* flags modified at AST level */
|
|
ULONG dbb_flags;
|
|
USHORT dbb_ods_version; /* major ODS version number */
|
|
USHORT dbb_minor_version; /* minor ODS version number */
|
|
USHORT dbb_minor_original; /* minor ODS version at creation */
|
|
USHORT dbb_page_size; /* page size */
|
|
USHORT dbb_dp_per_pp; /* data pages per pointer page */
|
|
USHORT dbb_max_records; /* max record per data page */
|
|
USHORT dbb_max_idx; /* max number of indexes on a root page */
|
|
USHORT dbb_use_count; /* active count of threads */
|
|
USHORT dbb_shutdown_delay; /* seconds until forced shutdown */
|
|
USHORT dbb_refresh_ranges; /* active count of refresh ranges */
|
|
USHORT dbb_prefetch_sequence; /* sequence to pace frequency of prefetch requests */
|
|
USHORT dbb_prefetch_pages; /* prefetch pages per request */
|
|
class str *dbb_spare_string; /* random buffer */
|
|
class str *dbb_filename; /* filename string */
|
|
class str *dbb_encrypt_key; /* encryption key */
|
|
|
|
JrdMemoryPool* dbb_permanent;
|
|
JrdMemoryPool* dbb_bufferpool;
|
|
|
|
typedef JrdMemoryPool* pool_ptr;
|
|
typedef Firebird::vector<pool_ptr> pool_vec_type;
|
|
|
|
pool_vec_type dbb_pools; /* pools */
|
|
USHORT dbb_next_pool_id;
|
|
vec* dbb_internal; /* internal requests */
|
|
vec* dbb_dyn_req; /* internal dyn requests */
|
|
struct jrn *dbb_journal; /* journal block */
|
|
|
|
SLONG dbb_oldest_active; /* Cached "oldest active" transaction */
|
|
SLONG dbb_oldest_transaction; /* Cached "oldest interesting" transaction */
|
|
SLONG dbb_oldest_snapshot; /* Cached "oldest snapshot" of all active transactions */
|
|
SLONG dbb_next_transaction; /* Next transaction id used by NETWARE */
|
|
SLONG dbb_attachment_id; /* Next attachment id for ReadOnly DB's */
|
|
SLONG dbb_page_incarnation; /* Cache page incarnation counter */
|
|
ULONG dbb_page_buffers; /* Page buffers from header page */
|
|
|
|
EVENT_T dbb_writer_event[1]; /* Event to wake up cache writer */
|
|
EVENT_T dbb_writer_event_init[1]; /* Event for initialization cache writer */
|
|
EVENT_T dbb_writer_event_fini[1]; /* Event for finalization cache writer */
|
|
EVENT_T dbb_reader_event[1]; /* Event to wake up cache reader */
|
|
#ifdef GARBAGE_THREAD
|
|
EVENT_T dbb_gc_event[1]; /* Event to wake up garbage collector */
|
|
EVENT_T dbb_gc_event_init[1]; /* Event for initialization garbage collector */
|
|
EVENT_T dbb_gc_event_fini[1]; /* Event for finalization garbage collector */
|
|
#endif
|
|
class att *dbb_update_attachment; /* Attachment with update in process */
|
|
class btb *dbb_update_que; /* Attachments waiting for update */
|
|
class btb *dbb_free_btbs; /* Unused btb blocks */
|
|
|
|
SLONG dbb_current_memory;
|
|
SLONG dbb_max_memory;
|
|
SLONG dbb_reads;
|
|
SLONG dbb_writes;
|
|
SLONG dbb_fetches;
|
|
SLONG dbb_marks;
|
|
SLONG dbb_last_header_write; /* Transaction id of last header page physical write */
|
|
SLONG dbb_flush_cycle; /* Current flush cycle */
|
|
SLONG dbb_sweep_interval; /* Transactions between sweep */
|
|
SLONG dbb_lock_owner_handle; /* Handle for the lock manager */
|
|
|
|
USHORT unflushed_writes; /* unflushed writes */
|
|
time_t last_flushed_write; /* last flushed write time */
|
|
|
|
crypt_routine dbb_encrypt; /* External encryption routine */
|
|
crypt_routine dbb_decrypt; /* External decryption routine */
|
|
|
|
class map *dbb_blob_map; /* mapping of blobs for REPLAY */
|
|
struct log *dbb_log; /* log file for REPLAY */
|
|
Firebird::vector<class TextType*> dbb_text_objects; /* intl text type descriptions */
|
|
Firebird::vector<class CharSetContainer*> dbb_charsets; /* intl character set descriptions */
|
|
struct wal *dbb_wal; /* WAL handle for WAL API */
|
|
struct tpc *dbb_tip_cache; /* cache of latest known state of all transactions in system */
|
|
class vcl *dbb_pc_transactions; /* active precommitted transactions */
|
|
class BackupManager *backup_manager; /* physical backup manager */
|
|
class sym *dbb_hash_table[HASH_SIZE]; /* keep this at the end */
|
|
|
|
private:
|
|
dbb(MemoryPool& p)
|
|
: dbb_pools(1, p, type_dbb),
|
|
dbb_text_objects(p),
|
|
dbb_charsets(p)
|
|
{
|
|
}
|
|
|
|
~dbb()
|
|
{
|
|
pool_vec_type::iterator itr = dbb_pools.begin();
|
|
while (itr != dbb_pools.end())
|
|
{
|
|
if (*itr && *itr == dbb_bufferpool)
|
|
dbb_bufferpool = 0;
|
|
if (*itr && *itr != dbb_permanent)
|
|
JrdMemoryPool::deletePool(*itr);
|
|
else
|
|
itr++;
|
|
}
|
|
if (dbb_bufferpool)
|
|
JrdMemoryPool::deletePool(dbb_bufferpool);
|
|
}
|
|
|
|
// The delete operators are no-oped because the dbb memory is allocated from the
|
|
// dbb's own permanent pool. That pool has already been released by the dbb
|
|
// destructor, so the memory has already been released. Hence the operator
|
|
// delete no-op.
|
|
void operator delete(void *mem) {}
|
|
void operator delete[](void *mem) {}
|
|
|
|
dbb(const dbb&); // no impl.
|
|
const dbb& operator =(const dbb&) { return *this; }
|
|
};
|
|
typedef dbb* DBB;
|
|
|
|
//
|
|
// bit values for dbb_flags
|
|
//
|
|
#define DBB_no_garbage_collect 0x1L
|
|
#define DBB_damaged 0x2L
|
|
#define DBB_exclusive 0x4L /* Database is accessed in exclusive mode */
|
|
#define DBB_bugcheck 0x8L /* Bugcheck has occurred */
|
|
#ifdef GARBAGE_THREAD
|
|
#define DBB_garbage_collector 0x10L /* garbage collector thread exists */
|
|
#define DBB_gc_active 0x20L /* ... and is actively working. */
|
|
#define DBB_gc_pending 0x40L /* garbage collection requested */
|
|
#endif
|
|
#define DBB_force_write 0x80L /* Database is forced write */
|
|
#define DBB_no_reserve 0x100L /* No reserve space for versions */
|
|
#define DBB_add_log 0x200L /* write ahead log has been added */
|
|
#define DBB_delete_log 0x400L /* write ahead log has been deleted */
|
|
#define DBB_cache_manager 0x800L /* Shared cache manager */
|
|
#define DBB_DB_SQL_dialect_3 0x1000L /* database SQL dialect 3 */
|
|
#define DBB_read_only 0x2000L /* DB is ReadOnly (RO). If not set, DB is RW */
|
|
#define DBB_being_opened_read_only 0x4000L /* DB is being opened RO. If unset, opened as RW */
|
|
#define DBB_not_in_use 0x8000L /* DBB to be ignored while attaching */
|
|
#define DBB_lck_init_done 0x10000L /* LCK_init() called for the database */
|
|
#define DBB_sp_rec_mutex_init 0x20000L /* Stored procedure mutex initialized */
|
|
#define DBB_sweep_in_progress 0x40000L /* A database sweep operation is in progress */
|
|
#define DBB_security_db 0x80000L /* ISC security database */
|
|
#define DBB_sweep_thread_started 0x100000L /* A database sweep thread has been started */
|
|
#define DBB_suspend_bgio 0x200000L /* Suspend I/O by background threads */
|
|
#define DBB_being_opened 0x400000L /* database is being attached to */
|
|
|
|
//
|
|
// dbb_ast_flags
|
|
//
|
|
#define DBB_blocking 0x1L // Exclusive mode is blocking
|
|
#define DBB_get_shadows 0x2L // Signal received to check for new shadows
|
|
#define DBB_assert_locks 0x4L // Locks are to be asserted
|
|
#define DBB_shutdown 0x8L // Database is shutdown
|
|
#define DBB_shut_attach 0x10L // no new attachments accepted
|
|
#define DBB_shut_tran 0x20L // no new transactions accepted
|
|
#define DBB_shut_force 0x40L // forced shutdown in progress
|
|
#define DBB_shutdown_locks 0x80L // Database locks release by shutdown
|
|
|
|
//
|
|
// Database attachments
|
|
//
|
|
#define DBB_read_seq_count 0
|
|
#define DBB_read_idx_count 1
|
|
#define DBB_update_count 2
|
|
#define DBB_insert_count 3
|
|
#define DBB_delete_count 4
|
|
#define DBB_backout_count 5
|
|
#define DBB_purge_count 6
|
|
#define DBB_expunge_count 7
|
|
#define DBB_max_count 8
|
|
|
|
//
|
|
// Database mutexes and read/write locks
|
|
//
|
|
#define DBB_MUTX_init_fini 0 // During startup and shutdown
|
|
#define DBB_MUTX_statistics 1 // Memory size and counts
|
|
#define DBB_MUTX_replay 2 // Replay logging
|
|
#define DBB_MUTX_dyn 3 // Dynamic ddl
|
|
#define DBB_MUTX_cache 4 // Process-private cache management
|
|
#define DBB_MUTX_clone 5 // Request cloning
|
|
#define DBB_MUTX_cmp_clone 6 // Compiled request cloning
|
|
#define DBB_MUTX_flush_count 7 // flush count/time
|
|
#define DBB_MUTX_max 8
|
|
#define DBB_WLCK_pools 0 // Pool manipulation
|
|
#define DBB_WLCK_files 1 // DB and shadow file manipulation
|
|
#define DBB_WLCK_max 2
|
|
|
|
//
|
|
// Flags to indicate normal internal requests vs. dyn internal requests
|
|
//
|
|
#define IRQ_REQUESTS 1
|
|
#define DYN_REQUESTS 2
|
|
|
|
|
|
//
|
|
// Errors during validation - will be returned on info calls
|
|
//
|
|
#define VAL_PAG_WRONG_TYPE 0
|
|
#define VAL_PAG_CHECKSUM_ERR 1
|
|
#define VAL_PAG_DOUBLE_ALLOC 2
|
|
#define VAL_PAG_IN_USE 3
|
|
#define VAL_PAG_ORPHAN 4
|
|
#define VAL_BLOB_INCONSISTENT 5
|
|
#define VAL_BLOB_CORRUPT 6
|
|
#define VAL_BLOB_TRUNCATED 7
|
|
#define VAL_REC_CHAIN_BROKEN 8
|
|
#define VAL_DATA_PAGE_CONFUSED 9
|
|
#define VAL_DATA_PAGE_LINE_ERR 10
|
|
#define VAL_INDEX_PAGE_CORRUPT 11
|
|
#define VAL_P_PAGE_LOST 12
|
|
#define VAL_P_PAGE_INCONSISTENT 13
|
|
#define VAL_REC_DAMAGED 14
|
|
#define VAL_REC_BAD_TID 15
|
|
#define VAL_REC_FRAGMENT_CORRUPT 16
|
|
#define VAL_REC_WRONG_LENGTH 17
|
|
#define VAL_INDEX_ROOT_MISSING 18
|
|
#define VAL_TIP_LOST 19
|
|
#define VAL_TIP_LOST_SEQUENCE 20
|
|
#define VAL_TIP_CONFUSED 21
|
|
#define VAL_REL_CHAIN_ORPHANS 22
|
|
#define VAL_INDEX_MISSING_ROWS 23
|
|
#define VAL_INDEX_ORPHAN_CHILD 24
|
|
#define VAL_MAX_ERROR 25
|
|
|
|
|
|
|
|
//
|
|
// the attachment block; one is created for each attachment to a database
|
|
//
|
|
class att : public pool_alloc<type_att>
|
|
{
|
|
public:
|
|
/* att()
|
|
: att_database(0),
|
|
att_next(0),
|
|
att_blocking(0),
|
|
att_user(0),
|
|
att_transactions(0),
|
|
att_dbkey_trans(0),
|
|
att_requests(0),
|
|
att_active_sorts(0),
|
|
att_id_lock(0),
|
|
att_attachment_id(0),
|
|
att_lock_owner_handle(0),
|
|
att_event_session(0),
|
|
att_security_class(0),
|
|
att_security_classes(0),
|
|
att_relation_locks(0),
|
|
att_bookmarks(0),
|
|
att_record_locks(0),
|
|
att_bkm_quick_ref(0),
|
|
att_lck_quick_ref(0),
|
|
att_flags(0),
|
|
att_charset(0),
|
|
att_lc_messages(0),
|
|
att_long_locks(0),
|
|
att_compatibility_table(0),
|
|
att_val_errors(0),
|
|
att_working_directory(0)
|
|
{
|
|
att_counts[0] = 0;
|
|
}*/
|
|
|
|
class dbb* att_database; // Parent databasea block
|
|
att* att_next; // Next attachment to database
|
|
att* att_blocking; // Blocking attachment, if any
|
|
class usr* att_user; // User identification
|
|
struct jrd_tra* att_transactions; // Transactions belonging to attachment
|
|
struct jrd_tra* att_dbkey_trans; // transaction to control db-key scope
|
|
struct jrd_req* att_requests; // Requests belonging to attachment
|
|
struct scb* att_active_sorts; // Active sorts
|
|
struct lck* att_id_lock; // Attachment lock (if any)
|
|
SLONG att_attachment_id; // Attachment ID
|
|
SLONG att_lock_owner_handle; // Handle for the lock manager
|
|
SLONG att_event_session; // Event session id, if any
|
|
class scl* att_security_class; // security class for database
|
|
class scl* att_security_classes; // security classes
|
|
class vcl* att_counts[DBB_max_count];
|
|
vec* att_relation_locks; // explicit persistent locks for relations
|
|
struct bkm* att_bookmarks; // list of bookmarks taken out using this attachment
|
|
struct lck* att_record_locks; // explicit or implicit record locks taken out during attachment
|
|
vec* att_bkm_quick_ref; // correspondence table of bookmarks
|
|
vec* att_lck_quick_ref; // correspondence table of locks
|
|
ULONG att_flags; // Flags describing the state of the attachment
|
|
SSHORT att_charset; // user's charset specified in dpb
|
|
class str* att_lc_messages; // attachment's preference for message natural language
|
|
struct lck* att_long_locks; // outstanding two phased locks
|
|
vec* att_compatibility_table; // hash table of compatible locks
|
|
class vcl* att_val_errors;
|
|
class str* att_working_directory; // Current working directory is cached
|
|
class str* att_filename; // alias used to attach the database
|
|
GDS_TIMESTAMP att_timestamp; // connection date and time
|
|
};
|
|
typedef att* ATT;
|
|
|
|
|
|
/* Attachment flags */
|
|
|
|
#define ATT_no_cleanup 1 // Don't expunge, purge, or garbage collect
|
|
#define ATT_shutdown 2 // attachment has been shutdown
|
|
#define ATT_shutdown_notify 4 // attachment has notified client of shutdown
|
|
#define ATT_shutdown_manager 8 // attachment requesting shutdown
|
|
#define ATT_lck_init_done 16 // LCK_init() called for the attachment
|
|
#define ATT_exclusive 32 // attachment wants exclusive database access
|
|
#define ATT_attach_pending 64 // Indicate attachment is only pending
|
|
#define ATT_exclusive_pending 128 // Indicate exclusive attachment pending
|
|
#define ATT_gbak_attachment 256 // Indicate GBAK attachment
|
|
#define ATT_security_db 512 // Indicates an implicit attachment to the security db
|
|
#ifdef GARBAGE_THREAD
|
|
#define ATT_notify_gc 1024 // Notify garbage collector to expunge, purge ..
|
|
#define ATT_disable_notify_gc 2048 // Temporarily perform own garbage collection
|
|
#define ATT_garbage_collector 4096 // I'm a garbage collector
|
|
|
|
#define ATT_NO_CLEANUP (ATT_no_cleanup | ATT_notify_gc)
|
|
#else
|
|
#define ATT_NO_CLEANUP ATT_no_cleanup
|
|
#endif
|
|
|
|
#ifdef CANCEL_OPERATION
|
|
#define ATT_cancel_raise 8192 // Cancel currently running operation
|
|
#define ATT_cancel_disable 16384 // Disable cancel operations
|
|
#endif
|
|
|
|
#define ATT_gfix_attachment 32768 // Indicate a GFIX attachment
|
|
#define ATT_gstat_attachment 65536 // Indicate a GSTAT attachment
|
|
|
|
|
|
/* Procedure block */
|
|
|
|
class jrd_prc : public pool_alloc_rpt<SCHAR, type_prc>
|
|
{
|
|
public:
|
|
USHORT prc_id; // Should be first field because MET_remove_procedure relies on that
|
|
USHORT prc_flags;
|
|
USHORT prc_inputs;
|
|
USHORT prc_outputs;
|
|
struct jrd_nod *prc_input_msg;
|
|
struct jrd_nod *prc_output_msg;
|
|
struct fmt *prc_input_fmt;
|
|
struct fmt *prc_output_fmt;
|
|
struct fmt *prc_format;
|
|
vec* prc_input_fields; /* vector of field blocks */
|
|
vec* prc_output_fields; /* vector of field blocks */
|
|
struct jrd_req *prc_request; /* compiled procedure request */
|
|
class str *prc_security_name; /* pointer to security class name for procedure */
|
|
USHORT prc_use_count; /* requests compiled with procedure */
|
|
SSHORT prc_int_use_count; /* number of procedures compiled with procedure, set and
|
|
used internally in the MET_clear_cache procedure
|
|
no code should rely on value of this field
|
|
(it will usually be 0)
|
|
*/
|
|
struct lck *prc_existence_lock; /* existence lock, if any */
|
|
class str *prc_name; /* pointer to ascic name */
|
|
USHORT prc_alter_count; /* No. of times the procedure was altered */
|
|
};
|
|
typedef jrd_prc* JRD_PRC;
|
|
|
|
#define PRC_scanned 1 /* Field expressions scanned */
|
|
#define PRC_system 2
|
|
#define PRC_obsolete 4 /* Procedure known gonzo */
|
|
#define PRC_being_scanned 8 /* New procedure needs dependencies during scan */
|
|
#define PRC_blocking 16 /* Blocking someone from dropping procedure */
|
|
#define PRC_create 32 /* Newly created */
|
|
#define PRC_being_altered 64 /* Procedure is getting altered */
|
|
#define PRC_check_existence 128 /* Existence lock released */
|
|
|
|
#define MAX_PROC_ALTER 64 /* No. of times an in-cache procedure can be altered */
|
|
|
|
|
|
|
|
/* Parameter block */
|
|
|
|
class prm : public pool_alloc_rpt<SCHAR, type_prm>
|
|
{
|
|
public:
|
|
USHORT prm_number;
|
|
struct dsc prm_desc;
|
|
TEXT *prm_name; /* pointer to asciiz name */
|
|
TEXT prm_string[2]; /* one byte for ALLOC and one for the terminating null */
|
|
};
|
|
typedef prm* PRM;
|
|
|
|
|
|
/* Primary dependencies from all foreign references to relation's
|
|
primary/unique keys */
|
|
|
|
typedef struct prim {
|
|
vec* prim_reference_ids;
|
|
vec* prim_relations;
|
|
vec* prim_indexes;
|
|
} *PRIM;
|
|
|
|
/* Foreign references to other relations' primary/unique keys */
|
|
|
|
typedef struct frgn {
|
|
vec* frgn_reference_ids;
|
|
vec* frgn_relations;
|
|
vec* frgn_indexes;
|
|
} *FRGN;
|
|
|
|
// Relation trigger definition
|
|
typedef struct trig {
|
|
class str* blr; // BLR code
|
|
jrd_req* request; // Compiled request. Gets filled on first invocation
|
|
BOOLEAN compile_in_progress;
|
|
BOOLEAN sys_trigger;
|
|
USHORT flags; // Flags as they are in RDB$TRIGGERS table
|
|
class jrd_rel* relation; // Trigger parent relation
|
|
class str* name; // Trigger name
|
|
void compile(tdbb* _tdbb); // Ensure that trigger is compiled
|
|
BOOLEAN release(tdbb* _tdbb); // Try to free trigger request
|
|
} *TRIG;
|
|
|
|
typedef Firebird::vector<trig> trig_vec;
|
|
|
|
typedef trig_vec* TRIG_VEC;
|
|
|
|
/* Relation block; one is created for each relation referenced
|
|
in the database, though it is not really filled out until
|
|
the relation is scanned */
|
|
|
|
class jrd_rel : public pool_alloc<type_rel>
|
|
{
|
|
public:
|
|
USHORT rel_id;
|
|
USHORT rel_flags;
|
|
USHORT rel_current_fmt; /* Current format number */
|
|
UCHAR rel_length; /* length of ascii relation name */
|
|
struct fmt *rel_current_format; /* Current record format */
|
|
TEXT* rel_name; /* pointer to ascii relation name */
|
|
vec* rel_formats; /* Known record formats */
|
|
TEXT *rel_owner_name; /* pointer to ascii owner */
|
|
class vcl *rel_pages; /* vector of pointer page numbers */
|
|
vec* rel_fields; /* vector of field blocks */
|
|
|
|
struct rse *rel_view_rse; /* view record select expression */
|
|
class vcx *rel_view_contexts; /* linked list of view contexts */
|
|
|
|
TEXT *rel_security_name; /* pointer to security class name for relation */
|
|
struct ext *rel_file; /* external file name */
|
|
SLONG rel_index_root; /* index root page number */
|
|
SLONG rel_data_pages; /* count of relation data pages */
|
|
|
|
vec* rel_gc_rec; /* vector of records for garbage collection */
|
|
#ifdef GARBAGE_THREAD
|
|
struct sbm *rel_gc_bitmap; /* garbage collect bitmap of data page sequences */
|
|
#endif
|
|
|
|
USHORT rel_slot_space; /* lowest pointer page with slot space */
|
|
USHORT rel_data_space; /* lowest pointer page with data page space */
|
|
USHORT rel_use_count; /* requests compiled with relation */
|
|
USHORT rel_sweep_count; /* sweep and/or garbage collector threads active */
|
|
SSHORT rel_scan_count; /* concurrent sequential scan count */
|
|
|
|
struct lck *rel_existence_lock; /* existence lock, if any */
|
|
struct lck *rel_interest_lock; /* interest lock to ensure compatibility of relation and record locks */
|
|
struct lck *rel_record_locking; /* lock to start record locking on relation */
|
|
|
|
ULONG rel_explicit_locks; /* count of records explicitly locked in relation */
|
|
ULONG rel_read_locks; /* count of records read locked in relation (implicit or explicit) */
|
|
ULONG rel_write_locks; /* count of records write locked in relation (implicit or explicit) */
|
|
ULONG rel_lock_total; /* count of records locked since database first attached */
|
|
|
|
struct idl *rel_index_locks; /* index existence locks */
|
|
struct idb *rel_index_blocks; /* index blocks for caching index info */
|
|
trig_vec *rel_pre_erase; /* Pre-operation erase trigger */
|
|
trig_vec *rel_post_erase; /* Post-operation erase trigger */
|
|
trig_vec *rel_pre_modify; /* Pre-operation modify trigger */
|
|
trig_vec *rel_post_modify; /* Post-operation modify trigger */
|
|
trig_vec *rel_pre_store; /* Pre-operation store trigger */
|
|
trig_vec *rel_post_store; /* Post-operation store trigger */
|
|
struct prim rel_primary_dpnds; /* foreign dependencies on this relation's primary key */
|
|
struct frgn rel_foreign_refs; /* foreign references to other relations' primary keys */
|
|
};
|
|
typedef jrd_rel* JRD_REL;
|
|
|
|
#define REL_scanned 1 /* Field expressions scanned (or being scanned) */
|
|
#define REL_system 2
|
|
#define REL_deleted 4 /* Relation known gonzo */
|
|
#define REL_get_dependencies 8 /* New relation needs dependencies during scan */
|
|
#define REL_force_scan 16 /* system relation has been updated since ODS change, force a scan */
|
|
#define REL_check_existence 32 /* Existence lock released pending drop of relation */
|
|
#define REL_blocking 64 /* Blocking someone from dropping relation */
|
|
#define REL_sys_triggers 128 /* The relation has system triggers to compile */
|
|
#define REL_sql_relation 256 /* Relation defined as sql table */
|
|
#define REL_check_partners 512 /* Rescan primary dependencies and foreign references */
|
|
#define REL_being_scanned 1024 /* relation scan in progress */
|
|
#define REL_sys_trigs_being_loaded 2048 /* System triggers being loaded */
|
|
#define REL_deleting 4096 /* relation delete in progress */
|
|
|
|
|
|
/* Field block, one for each field in a scanned relation */
|
|
|
|
class jrd_fld : public pool_alloc_rpt<SCHAR, type_fld>
|
|
{
|
|
public:
|
|
struct jrd_nod* fld_validation; /* validation clause, if any */
|
|
struct jrd_nod* fld_not_null; /* if field cannot be NULL */
|
|
struct jrd_nod* fld_missing_value; /* missing value, if any */
|
|
struct jrd_nod* fld_computation; /* computation for virtual field */
|
|
struct jrd_nod* fld_source; /* source for view fields */
|
|
struct jrd_nod* fld_default_value; /* default value, if any */
|
|
TEXT * fld_security_name; /* pointer to security class name for field */
|
|
struct arr* fld_array; /* array description, if array */
|
|
const TEXT* fld_name; /* Field name */
|
|
UCHAR fld_length; /* Field name length */
|
|
UCHAR fld_string[2]; /* one byte for ALLOC and one for the terminating null */
|
|
};
|
|
typedef jrd_fld *JRD_FLD;
|
|
|
|
|
|
|
|
/* Index block to cache index information */
|
|
|
|
class idb : public pool_alloc<type_idb>
|
|
{
|
|
public:
|
|
struct idb* idb_next;
|
|
struct jrd_nod* idb_expression; /* node tree for index expression */
|
|
struct jrd_req* idb_expression_request; /* request in which index expression is evaluated */
|
|
struct dsc idb_expression_desc; /* descriptor for expression result */
|
|
struct lck* idb_lock; /* lock to synchronize changes to index */
|
|
UCHAR idb_id;
|
|
};
|
|
typedef idb *IDB;
|
|
|
|
|
|
/* view context block to cache view aliases */
|
|
|
|
class vcx: public pool_alloc<type_vcx>
|
|
{
|
|
public:
|
|
class vcx *vcx_next;
|
|
class str *vcx_context_name;
|
|
class str *vcx_relation_name;
|
|
USHORT vcx_context;
|
|
};
|
|
typedef vcx *VCX;
|
|
|
|
|
|
/* general purpose vector */
|
|
template <class T, USHORT TYPE = type_vec>
|
|
class vec_base : protected pool_alloc<TYPE>
|
|
{
|
|
public:
|
|
typedef typename Firebird::vector<T>::iterator iterator;
|
|
|
|
static vec_base* newVector(MemoryPool& p, int len)
|
|
{ return FB_NEW(p) vec_base<T,TYPE>(p, len); }
|
|
static vec_base* newVector(MemoryPool& p, const vec_base& base)
|
|
{ return FB_NEW(p) vec_base<T,TYPE>(p, base); }
|
|
|
|
ULONG count() const { return vector.size(); }
|
|
T& operator[](size_t index) { return vector[index]; }
|
|
const T& operator[](size_t index) const { return vector[index]; }
|
|
|
|
iterator begin() { return vector.begin(); }
|
|
iterator end() { return vector.end(); }
|
|
|
|
void clear() { vector.clear(); }
|
|
void prepend(int n) { vector.insert(vector.begin(), n); }
|
|
|
|
// T* memPtr() { return &*(vector.begin()); }
|
|
T* memPtr() { return &vector[0]; }
|
|
|
|
void resize(size_t n, T val = T()) { vector.resize(n, val); }
|
|
|
|
void operator delete(void *mem) { MemoryPool::globalFree(mem); }
|
|
|
|
protected:
|
|
vec_base(MemoryPool& p, int len)
|
|
: vector(len, p, TYPE) {}
|
|
vec_base(MemoryPool& p, const vec_base& base)
|
|
: vector(p, TYPE) { vector = base.vector; }
|
|
|
|
private:
|
|
Firebird::vector<T> vector;
|
|
};
|
|
|
|
class vec : public vec_base<BlkPtr, type_vec>
|
|
{
|
|
public:
|
|
static vec* newVector(MemoryPool& p, int len)
|
|
{ return FB_NEW(p) vec(p, len); }
|
|
static vec* newVector(MemoryPool& p, const vec& base)
|
|
{ return FB_NEW(p) vec(p, base); }
|
|
static vec* newVector(MemoryPool& p, vec* base, int len)
|
|
{
|
|
if (!base)
|
|
base = FB_NEW(p) vec(p, len);
|
|
else if (len > (int) base->count())
|
|
base->resize(len);
|
|
return base;
|
|
}
|
|
|
|
private:
|
|
vec(MemoryPool& p, int len) : vec_base<BlkPtr, type_vec>(p, len) {}
|
|
vec(MemoryPool& p, const vec& base) : vec_base<BlkPtr, type_vec>(p, base) {}
|
|
};
|
|
typedef vec* VEC;
|
|
|
|
class vcl : public vec_base<SLONG, type_vcl>
|
|
{
|
|
public:
|
|
static vcl* newVector(MemoryPool& p, int len)
|
|
{ return FB_NEW(p) vcl(p, len); }
|
|
static vcl* newVector(MemoryPool& p, const vcl& base)
|
|
{ return FB_NEW(p) vcl(p, base); }
|
|
static vcl* newVector(MemoryPool& p, vcl* base, int len)
|
|
{
|
|
if (!base)
|
|
base = FB_NEW(p) vcl(p, len);
|
|
else if (len > (int) base->count())
|
|
base->resize(len);
|
|
return base;
|
|
}
|
|
|
|
private:
|
|
vcl(MemoryPool& p, int len) : vec_base<SLONG, type_vcl>(p, len) {}
|
|
vcl(MemoryPool& p, const vcl& base) : vec_base<SLONG, type_vcl>(p, base) {}
|
|
};
|
|
typedef vcl* VCL;
|
|
|
|
#define TEST_VECTOR(vector,number) ((vector && number < vector->vec_count) ? \
|
|
vector->vec_object [number] : NULL)
|
|
|
|
//
|
|
// general purpose queue
|
|
//
|
|
typedef struct que {
|
|
struct que* que_forward;
|
|
struct que* que_backward;
|
|
} *QUE;
|
|
|
|
|
|
|
|
/* symbol definitions */
|
|
|
|
typedef enum sym_t {
|
|
SYM_rel, /* relation block */
|
|
SYM_fld, /* field block */
|
|
SYM_fun, /* UDF function block */
|
|
SYM_prc, /* stored procedure block */
|
|
SYM_sql, /* SQL request cache block */
|
|
SYM_blr, /* BLR request cache block */
|
|
SYM_label /* CVC: I need to track labels if LEAVE is implemented. */
|
|
} SYM_T;
|
|
|
|
class sym : public pool_alloc<type_sym>
|
|
{
|
|
public:
|
|
TEXT *sym_string; /* address of asciz string */
|
|
/* USHORT sym_length; *//* length of asciz string */
|
|
SYM_T sym_type; /* symbol type */
|
|
BLK sym_object; /* general pointer to object */
|
|
sym *sym_collision; /* collision pointer */
|
|
sym *sym_homonym; /* homonym pointer */
|
|
};
|
|
typedef sym *SYM;
|
|
|
|
/* Random string block -- jack of all kludges */
|
|
|
|
class str : public pool_alloc_rpt<SCHAR, type_str>
|
|
{
|
|
public:
|
|
USHORT str_length;
|
|
UCHAR str_data[2]; /* one byte for ALLOC and one for the NULL */
|
|
|
|
static bool extend(str*& s, size_t new_len)
|
|
{
|
|
fb_assert(s);
|
|
MemoryPool* pPool = MemoryPool::blk_pool(s);
|
|
fb_assert(pPool);
|
|
if (!pPool) {
|
|
return false; // runtime safety
|
|
}
|
|
// TMN: Note that this violates "common sense" and should be fixed.
|
|
str* res = FB_NEW_RPT(*pPool, new_len+1) str;
|
|
res->str_length = new_len;
|
|
memcpy(res->str_data, s->str_data, s->str_length+1);
|
|
str* old = s;
|
|
s = res;
|
|
delete old;
|
|
return s != 0;
|
|
}
|
|
};
|
|
typedef str *STR;
|
|
|
|
|
|
//
|
|
// Transaction element block
|
|
//
|
|
typedef struct teb {
|
|
ATT *teb_database;
|
|
int teb_tpb_length;
|
|
UCHAR *teb_tpb;
|
|
} TEB;
|
|
|
|
/* Blocking Thread Block */
|
|
|
|
class btb : public pool_alloc<type_btb>
|
|
{
|
|
public:
|
|
btb *btb_next;
|
|
SLONG btb_thread_id;
|
|
};
|
|
typedef btb *BTB;
|
|
|
|
/* Lock levels */
|
|
|
|
#define LCK_none 0
|
|
#define LCK_null 1
|
|
#define LCK_SR 2
|
|
#define LCK_PR 3
|
|
#define LCK_SW 4
|
|
#define LCK_PW 5
|
|
#define LCK_EX 6
|
|
|
|
#define LCK_read LCK_PR
|
|
#define LCK_write LCK_EX
|
|
|
|
#define LCK_WAIT TRUE
|
|
#define LCK_NO_WAIT FALSE
|
|
|
|
/* Lock query data aggregates */
|
|
|
|
#define LCK_MIN 1
|
|
#define LCK_MAX 2
|
|
#define LCK_CNT 3
|
|
#define LCK_SUM 4
|
|
#define LCK_AVG 5
|
|
#define LCK_ANY 6
|
|
|
|
|
|
/* Window block for loading cached pages into */
|
|
|
|
typedef struct win {
|
|
SLONG win_page;
|
|
struct pag* win_buffer;
|
|
struct jrd_exp* win_expanded_buffer;
|
|
struct bdb* win_bdb;
|
|
SSHORT win_scans;
|
|
USHORT win_flags;
|
|
} WIN;
|
|
|
|
#define WIN_large_scan 1 /* large sequential scan */
|
|
#define WIN_secondary 2 /* secondary stream */
|
|
#define WIN_garbage_collector 4 /* garbage collector's window */
|
|
#define WIN_garbage_collect 8 /* scan left a page for garbage collector */
|
|
|
|
|
|
/* define used for journaling start transaction */
|
|
|
|
#define MOD_START_TRAN 100
|
|
|
|
|
|
/* Thread specific database block */
|
|
|
|
typedef struct tdbb
|
|
{
|
|
struct thdd tdbb_thd_data;
|
|
dbb* tdbb_database;
|
|
att* tdbb_attachment;
|
|
struct jrd_tra* tdbb_transaction;
|
|
struct jrd_req* tdbb_request;
|
|
JrdMemoryPool* tdbb_default;
|
|
ISC_STATUS* tdbb_status_vector;
|
|
void* tdbb_setjmp;
|
|
USHORT tdbb_inhibit; /* Inhibit context switch if non-zero */
|
|
SSHORT tdbb_quantum; /* Cycles remaining until voluntary schedule */
|
|
USHORT tdbb_flags;
|
|
struct iuo tdbb_mutexes;
|
|
struct iuo tdbb_rw_locks;
|
|
struct iuo tdbb_pages;
|
|
|
|
#if defined(UNIX) && defined(SUPERSERVER)
|
|
#if defined(FREEBSD)
|
|
sigjmp_buf tdbb_sigsetjmp;
|
|
#else
|
|
jmp_buf tdbb_sigsetjmp;
|
|
#endif
|
|
#endif
|
|
} *TDBB;
|
|
|
|
#define TDBB_sweeper 1 /* Thread sweeper or garbage collector */
|
|
#define TDBB_no_cache_unwind 2 /* Don't unwind page buffer cache */
|
|
#define TDBB_prc_being_dropped 4 /* Dropping a procedure */
|
|
#define TDBB_set_backup_state 8 /* Setting state for backup lock */
|
|
#define TDBB_backup_merge 16 /* Merging changes from difference file */
|
|
|
|
/* List of internal database handles */
|
|
|
|
typedef struct ihndl
|
|
{
|
|
struct ihndl* ihndl_next;
|
|
void* ihndl_object;
|
|
} *IHNDL;
|
|
|
|
|
|
/* Threading macros */
|
|
|
|
#ifdef GET_THREAD_DATA
|
|
#undef GET_THREAD_DATA
|
|
#endif
|
|
|
|
#ifdef V4_THREADING
|
|
#define PLATFORM_GET_THREAD_DATA ((TDBB) THD_get_specific())
|
|
#endif
|
|
|
|
/* RITTER - changed HP10 to HPUX in the expression below */
|
|
#ifdef MULTI_THREAD
|
|
#if (defined SOLARIS_MT || defined WIN_NT || \
|
|
defined HPUX || defined LINUX || defined DARWIN || defined FREEBSD )
|
|
#define PLATFORM_GET_THREAD_DATA ((TDBB) THD_get_specific())
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef PLATFORM_GET_THREAD_DATA
|
|
|
|
extern TDBB gdbb;
|
|
|
|
#define PLATFORM_GET_THREAD_DATA (gdbb)
|
|
#endif
|
|
|
|
/* Define GET_THREAD_DATA off the platform specific version.
|
|
* If we're in DEV mode, also do consistancy checks on the
|
|
* retrieved memory structure. This was originally done to
|
|
* track down cases of no "PUT_THREAD_DATA" on the NLM.
|
|
*
|
|
* This allows for NULL thread data (which might be an error by itself)
|
|
* If there is thread data,
|
|
* AND it is tagged as being a TDBB.
|
|
* AND it has a non-NULL tdbb_database field,
|
|
* THEN we validate that the structure there is a database block.
|
|
* Otherwise, we return what we got.
|
|
* We can't always validate the database field, as during initialization
|
|
* there is no tdbb_database set up.
|
|
*/
|
|
#ifdef DEV_BUILD
|
|
#define GET_THREAD_DATA (((PLATFORM_GET_THREAD_DATA) && \
|
|
(((THDD)(PLATFORM_GET_THREAD_DATA))->thdd_type == THDD_TYPE_TDBB) && \
|
|
(((TDBB)(PLATFORM_GET_THREAD_DATA))->tdbb_database)) \
|
|
? ((MemoryPool::blk_type(((TDBB)(PLATFORM_GET_THREAD_DATA))->tdbb_database) == type_dbb) \
|
|
? (PLATFORM_GET_THREAD_DATA) \
|
|
: (BUGCHECK (147), (PLATFORM_GET_THREAD_DATA))) \
|
|
: (PLATFORM_GET_THREAD_DATA))
|
|
#define CHECK_DBB(dbb) fb_assert ((dbb) && (MemoryPool::blk_type(dbb) == type_dbb) && ((dbb)->dbb_permanent->verify_pool()))
|
|
#define CHECK_TDBB(tdbb) fb_assert ((tdbb) && \
|
|
(((THDD)(tdbb))->thdd_type == THDD_TYPE_TDBB) && \
|
|
((!(tdbb)->tdbb_database)||MemoryPool::blk_type((tdbb)->tdbb_database) == type_dbb))
|
|
#else
|
|
/* PROD_BUILD */
|
|
#define GET_THREAD_DATA (PLATFORM_GET_THREAD_DATA)
|
|
#define CHECK_TDBB(tdbb) /* nothing */
|
|
#define CHECK_DBB(dbb) /* nothing */
|
|
#endif
|
|
|
|
#define GET_DBB (((TDBB) (GET_THREAD_DATA))->tdbb_database)
|
|
|
|
/*-------------------------------------------------------------------------*
|
|
* macros used to set tdbb and dbb pointers when there are not set already *
|
|
*-------------------------------------------------------------------------*/
|
|
|
|
#define SET_TDBB(tdbb) if ((tdbb) == NULL) { (tdbb) = GET_THREAD_DATA; }; CHECK_TDBB (tdbb)
|
|
#define SET_DBB(dbb) if ((dbb) == NULL) { (dbb) = GET_DBB; }; CHECK_DBB(dbb);
|
|
|
|
#ifdef V4_THREADING
|
|
#define V4_JRD_MUTEX_LOCK(mutx) JRD_mutex_lock (mutx)
|
|
#define V4_JRD_MUTEX_UNLOCK(mutx) JRD_mutex_unlock (mutx)
|
|
#define V4_JRD_RW_LOCK_LOCK(wlck,type) JRD_wlck_lock (wlck, type)
|
|
#define V4_JRD_RW_LOCK_UNLOCK(wlck) JRD_wlck_unlock (wlck)
|
|
// BRS. 03/23/2003
|
|
// Those empty defines was substituted with #ifdef V4_THREADING
|
|
//#else
|
|
//#define V4_JRD_MUTEX_LOCK(mutx)
|
|
//#define V4_JRD_MUTEX_UNLOCK(mutx)
|
|
//#define V4_JRD_RW_LOCK_LOCK(wlck,type)
|
|
//#define V4_JRD_RW_LOCK_UNLOCK(wlck)
|
|
#endif
|
|
|
|
#ifdef ANY_THREADING
|
|
#define THD_JRD_MUTEX_LOCK(mutx) JRD_mutex_lock (mutx)
|
|
#define THD_JRD_MUTEX_UNLOCK(mutx) JRD_mutex_unlock (mutx)
|
|
#else
|
|
#define THD_JRD_MUTEX_LOCK(mutx)
|
|
#define THD_JRD_MUTEX_UNLOCK(mutx)
|
|
#endif
|
|
|
|
|
|
/* global variables for engine */
|
|
|
|
|
|
#if !defined(REQUESTER)
|
|
|
|
extern int debug;
|
|
extern IHNDL internal_db_handles;
|
|
|
|
#endif /* REQUESTER */
|
|
|
|
|
|
/* Define the xxx_THREAD_DATA macros. These are needed in the whole
|
|
component, but they are defined differently for use in jrd.c (JRD_MAIN)
|
|
Here we have a function which sets some flags, and then calls THD_put_specific
|
|
so in this case we define the macro as calling that function. */
|
|
#ifndef JRD_MAIN
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#define SET_THREAD_DATA tdbb = &thd_context;\
|
|
MOVE_CLEAR (tdbb, sizeof (*tdbb));\
|
|
THD_put_specific (reinterpret_cast<struct thdd*>(tdbb));\
|
|
tdbb->tdbb_thd_data.thdd_type = THDD_TYPE_TDBB
|
|
|
|
#else
|
|
|
|
#define SET_THREAD_DATA tdbb = &thd_context;\
|
|
MOVE_CLEAR (tdbb, sizeof (*tdbb));\
|
|
THD_put_specific((struct thdd*)tdbb);\
|
|
tdbb->tdbb_thd_data.thdd_type = THDD_TYPE_TDBB
|
|
#endif /* __cplusplus */
|
|
|
|
#define RESTORE_THREAD_DATA THD_restore_specific()
|
|
|
|
#endif /* !JRD_MAIN */
|
|
|
|
|
|
|
|
#endif /* JRD_JRD_H */
|