/* * PROGRAM: Dynamic SQL runtime support * MODULE: dsql.h * DESCRIPTION: General Definitions for V4 DSQL module * * * 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): ______________________________________. * * 2001.11.26 Claudio Valderrama: include udf_arguments and udf_flags * in the udf struct, so we can load the arguments and check for * collisions between dropping and redefining the udf concurrently. * This closes SF Bug# 409769. * 2002.10.29 Nickolay Samofatov: Added support for savepoints * 2004.01.16 Vlad Horsun: added support for default parameters and * EXECUTE BLOCK statement */ #ifndef DSQL_DSQL_H #define DSQL_DSQL_H #include "../jrd/common.h" #include "../dsql/all.h" #include "../common/classes/array.h" #include "../common/classes/stack.h" #define REQUESTER #include "../jrd/val.h" // Get rid of duplicated FUN_T enum. #undef REQUESTER #ifdef DEV_BUILD // This macro enables DSQL tracing code #define DSQL_DEBUG #endif #ifdef DSQL_DEBUG DEFINE_TRACE_ROUTINE(dsql_trace); #endif //! Dynamic SQL Error Status Block struct dsql_err_stblock { ISC_STATUS* dsql_status; ISC_STATUS* dsql_user_status; }; // this table is used in data allocation to determine // whether a block has a variable length tail #include "../dsql/blk.h" // generic block used as header to all allocated structures #include "../include/fb_blk.h" #include "../dsql/sym.h" //! generic data type used to store strings class dsql_str : public pool_alloc_rpt { public: const char* str_charset; //!< ASCIIZ Character set identifier for string USHORT str_flags; ULONG str_length; //!< length of string in BYTES char str_data[2]; //!< one for ALLOC and one for the NULL }; // values used in str_flags const long STR_delimited_id = 0x1L; // Context aliases used in triggers const char* const OLD_CONTEXT = "OLD"; const char* const NEW_CONTEXT = "NEW"; const char* const TEMP_CONTEXT = "TEMP"; //! macros and block used to implement a generic stack mechanism #ifdef NOT_USED_OR_REPLACED class dsql_lls : public pool_alloc { public: blk* lls_object; dsql_lls* lls_next; }; inline void LLS_PUSH(blk* object, dsql_lls** stack) { DsqlMemoryPool::ALLD_push(object, stack); } inline blk* LLS_POP(dsql_lls** stack) { return DsqlMemoryPool::ALLD_pop(stack); } #endif class dsql_ctx; class dsql_str; class dsql_nod; class dsql_intlsym; typedef Firebird::Stack DsqlContextStack; typedef Firebird::Stack DsqlStrStack; typedef Firebird::Stack DsqlNodStack; //====================================================================== // remaining node definitions for local processing // /// Include definition of descriptor #include "../jrd/dsc.h" //! internal DSQL requests enum irq_type_t { irq_relation = 0, //!< lookup a relation irq_fields = 1, //!< lookup a relation's fields irq_dimensions = 2, //!< lookup a field's dimensions irq_primary_key = 3, //!< lookup a primary key irq_view = 4, //!< lookup a view's base relations irq_function = 5, //!< lookup a user defined function irq_func_return = 6, //!< lookup a function's return argument irq_procedure = 7, //!< lookup a stored procedure irq_parameters = 8, //!< lookup a procedure's parameters irq_collation = 9, //!< lookup a collation name irq_charset = 10, //!< lookup a character set irq_trigger = 11, //!< lookup a trigger irq_domain = 12, //!< lookup a domain irq_type = 13, //!< lookup a symbolic name in RDB$TYPES irq_col_default = 14, //!< lookup default for a column irq_domain_2 = 15, //!< lookup a domain irq_exception = 16, //!< lookup an exception irq_cs_name = 17, //!< lookup a charset name irq_default_cs = 18, //!< lookup the default charset irq_rel_ids = 19, //!< check relation/field ids irq_MAX = 20 }; // dsql_nod definition #include "../dsql/node.h" // blocks used to cache metadata //! Database Block typedef Firebird::SortedArray < dsql_intlsym*, Firebird::EmptyStorage, SSHORT, dsql_intlsym, Firebird::DefaultComparator > IntlSymArray; class dsql_dbb : public pool_alloc { public: dsql_dbb* dbb_next; class dsql_rel* dbb_relations; //!< known relations in database class dsql_prc* dbb_procedures; //!< known procedures in database class dsql_udf* dbb_functions; //!< known functions in database DsqlMemoryPool* dbb_pool; //!< The current pool for the dbb FB_API_HANDLE dbb_database_handle; FB_API_HANDLE dbb_requests[irq_MAX]; dsql_str* dbb_dfl_charset; USHORT dbb_base_level; //!< indicates the version of the engine code itself USHORT dbb_flags; USHORT dbb_db_SQL_dialect; SSHORT dbb_att_charset; //!< characterset at time of attachment IntlSymArray dbb_charsets_by_id; // charsets sorted by charset_id dsql_dbb(DsqlMemoryPool& p) : dbb_charsets_by_id(p, 16) {}; }; //! values used in dbb_flags enum dbb_flags_vals { DBB_no_arrays = 0x1, DBB_no_charset = 0x2, DBB_read_only = 0x4 }; //! Relation block class dsql_rel : public pool_alloc_rpt { public: dsql_rel* rel_next; //!< Next relation in database dsql_sym* rel_symbol; //!< Hash symbol for relation class dsql_fld* rel_fields; //!< Field block dsql_rel* rel_base_relation; //!< base relation for an updatable view TEXT* rel_name; //!< Name of relation TEXT* rel_owner; //!< Owner of relation USHORT rel_id; //!< Relation id USHORT rel_dbkey_length; USHORT rel_flags; TEXT rel_data[3]; }; // rel_flags bits enum rel_flags_vals { REL_new_relation = 1, //!< relation exists in sys tables, not committed yet REL_dropped = 2, //!< relation has been dropped REL_view = 4, //!< relation is a view REL_external = 8, //!< relation is an external table REL_creating = 16 //!< we are creating the bare relation in memory }; class dsql_fld : public pool_alloc_rpt { public: dsql_fld* fld_next; //!< Next field in relation dsql_rel* fld_relation; //!< Parent relation class dsql_prc* fld_procedure; //!< Parent procedure dsql_nod* fld_ranges; //!< ranges for multi dimension array dsql_nod* fld_character_set; //!< null means not specified dsql_nod* fld_sub_type_name; //!< Subtype name for later resolution USHORT fld_flags; USHORT fld_id; //!< Field in in database USHORT fld_dtype; //!< Data type of field FLD_LENGTH fld_length; //!< Length of field USHORT fld_element_dtype; //!< Data type of array element USHORT fld_element_length; //!< Length of array element SSHORT fld_scale; //!< Scale factor of field SSHORT fld_sub_type; //!< Subtype for text & blob fields USHORT fld_precision; //!< Precision for exact numeric types USHORT fld_character_length; //!< length of field in characters USHORT fld_seg_length; //!< Segment length for blobs SSHORT fld_dimensions; //!< Non-zero means array SSHORT fld_character_set_id; //!< ID of field's character set SSHORT fld_collation_id; //!< ID of field's collation SSHORT fld_ttype; //!< ID of field's language_driver TEXT fld_name[2]; }; // values used in fld_flags enum fld_flags_vals { FLD_computed = 1, FLD_national = 2, //!< field uses NATIONAL character set FLD_nullable = 4, FLD_system = 8 }; const int MAX_ARRAY_DIMENSIONS = 16; //!< max array dimensions //! database/log/cache file block class dsql_fil : public pool_alloc { public: SLONG fil_length; //!< File length in pages SLONG fil_start; //!< Starting page dsql_str* fil_name; //!< File name dsql_fil* fil_next; //!< next file SSHORT fil_shadow_number; //!< shadow number if part of shadow SSHORT fil_manual; //!< flag to indicate manual shadow SSHORT fil_partitions; //!< number of log file partitions USHORT fil_flags; }; //! Stored Procedure block class dsql_prc : public pool_alloc_rpt { public: dsql_prc* prc_next; //!< Next relation in database dsql_sym* prc_symbol; //!< Hash symbol for procedure dsql_fld* prc_inputs; //!< Input parameters dsql_fld* prc_outputs; //!< Output parameters TEXT* prc_name; //!< Name of procedure TEXT* prc_owner; //!< Owner of procedure SSHORT prc_in_count; SSHORT prc_def_count; //!< number of inputs with default values SSHORT prc_out_count; USHORT prc_id; //!< Procedure id USHORT prc_flags; TEXT prc_data[3]; }; // prc_flags bits enum prc_flags_vals { PRC_new_procedure = 1, //!< procedure is newly defined, not committed yet PRC_dropped = 2 //!< procedure has been dropped }; //! User defined function block class dsql_udf : public pool_alloc_rpt { public: dsql_udf* udf_next; dsql_sym* udf_symbol; //!< Hash symbol for udf USHORT udf_dtype; SSHORT udf_scale; SSHORT udf_sub_type; USHORT udf_length; SSHORT udf_character_set_id; USHORT udf_character_length; dsql_nod* udf_arguments; USHORT udf_flags; TEXT udf_name[2]; }; // udf_flags bits enum udf_flags_vals { UDF_new_udf = 1, //!< udf is newly declared, not committed yet UDF_dropped = 2 //!< udf has been dropped }; // Variables - input, output & local //! Variable block class dsql_var : public pool_alloc_rpt { public: dsql_fld* var_field; //!< Field on which variable is based USHORT var_flags; USHORT var_msg_number; //!< Message number containing variable USHORT var_msg_item; //!< Item number in message USHORT var_variable_number; //!< Local variable number TEXT var_name[2]; }; // values used in var_flags enum var_flags_vals { VAR_input = 1, VAR_output = 2, VAR_local = 4 }; // Symbolic names for international text types // (either collation or character set name) //! International symbol class dsql_intlsym : public pool_alloc_rpt { public: dsql_sym* intlsym_symbol; //!< Hash symbol for intlsym USHORT intlsym_type; //!< what type of name USHORT intlsym_flags; SSHORT intlsym_ttype; //!< id of implementation SSHORT intlsym_charset_id; SSHORT intlsym_collate_id; USHORT intlsym_bytes_per_char; TEXT intlsym_name[2]; static SSHORT generate(const void*, const dsql_intlsym* Item) { return Item->intlsym_charset_id; } }; // values used in intlsym_type enum dsql_intlsym_type_vals { DSQL_INTLSYM_collation = 1, DSQL_INTLSYM_charset = 2 }; // values used in intlsym_flags // Forward declaration. class dsql_par; class dsql_opn; //! Request information enum REQ_TYPE { REQ_SELECT, REQ_SELECT_UPD, REQ_INSERT, REQ_DELETE, REQ_UPDATE, REQ_UPDATE_CURSOR, REQ_DELETE_CURSOR, REQ_COMMIT, REQ_ROLLBACK, REQ_DDL, REQ_EMBED_SELECT, REQ_START_TRANS, REQ_GET_SEGMENT, REQ_PUT_SEGMENT, REQ_EXEC_PROCEDURE, REQ_COMMIT_RETAIN, REQ_ROLLBACK_RETAIN, REQ_SET_GENERATOR, REQ_SAVEPOINT, REQ_EXEC_BLOCK, REQ_SELECT_BLOCK }; class dsql_req : public pool_alloc { public: // begin - member functions that should be private inline void append_uchar(UCHAR byte); inline void append_ushort(USHORT val); inline void append_ulong(ULONG val); void append_cstring(UCHAR verb, const char* string); void append_string(UCHAR verb, const char* string, USHORT len); void append_number(UCHAR verb, SSHORT number); void begin_blr(UCHAR verb); void end_blr(); void append_uchars(UCHAR byte, UCHAR count); void append_ushort_with_length(USHORT val); void append_ulong_with_length(ULONG val); void append_file_length(ULONG length); void append_file_start(ULONG start); void generate_unnamed_trigger_beginning( bool on_update_trigger, const char* prim_rel_name, const dsql_nod* prim_columns, const char* for_rel_name, const dsql_nod* for_columns); // end - member functions that should be private dsql_req(DsqlMemoryPool& p) : req_pool(p), req_main_context(p), req_context(&req_main_context), req_union_context(p), req_dt_context(p), req_blr_data(p), req_labels(p), req_cursors(p) { } dsql_req* req_parent; //!< Source request, if cursor update dsql_req* req_sibling; //!< Next sibling request, if cursor update dsql_req* req_offspring; //!< Cursor update requests DsqlMemoryPool& req_pool; DsqlContextStack req_main_context; DsqlContextStack* req_context; DsqlContextStack req_union_context; //!< Save contexts for views of unions DsqlContextStack req_dt_context; //!< Save contexts for views of derived tables dsql_sym* req_name; //!< Name of request dsql_sym* req_cursor; //!< Cursor symbol, if any dsql_dbb* req_dbb; //!< Database handle FB_API_HANDLE req_trans; //!< Database transaction handle dsql_opn* req_open_cursor; dsql_nod* req_ddl_node; //!< Store metadata request dsql_nod* req_blk_node; //!< exec_block node class dsql_blb* req_blob; //!< Blob info for blob requests FB_API_HANDLE req_handle; //!< OSRI request handle //dsql_str* req_blr_string; //!< String block during BLR generation Firebird::HalfStaticArray req_blr_data; class dsql_msg* req_send; //!< Message to be sent to start request class dsql_msg* req_receive; //!< Per record message to be received class dsql_msg* req_async; //!< Message for sending scrolling information dsql_par* req_eof; //!< End of file parameter dsql_par* req_dbkey; //!< Database key for current of dsql_par* req_rec_version; //!< Record Version for current of dsql_par* req_parent_rec_version; //!< parent record version dsql_par* req_parent_dbkey; //!< Parent database key for current of dsql_rel* req_relation; //!< relation created by this request (for DDL) dsql_prc* req_procedure; //!< procedure created by this request (for DDL) class dsql_ctx* req_outer_agg_context; //!< agg context for outer ref //BLOB_PTR* req_blr; //!< Running blr address //BLOB_PTR* req_blr_yellow; //!< Threshold for upping blr buffer size ULONG req_inserts; //!< records processed in request ULONG req_deletes; ULONG req_updates; ULONG req_selects; REQ_TYPE req_type; //!< Type of request ULONG req_base_offset; //!< place to go back and stuff in blr length USHORT req_context_number; //!< Next available context number USHORT req_scope_level; //!< Scope level for parsing aliases in subqueries USHORT req_message_number; //!< Next available message number USHORT req_loop_level; //!< Loop level DsqlStrStack req_labels; //!< Loop labels USHORT req_cursor_number; //!< Cursor number DsqlNodStack req_cursors; //!< Cursors USHORT req_in_select_list; //!< now processing "select list" USHORT req_in_where_clause; //!< processing "where clause" USHORT req_in_group_by_clause; //!< processing "group by clause" USHORT req_in_having_clause; //!< processing "having clause" USHORT req_in_order_by_clause; //!< processing "order by clause" USHORT req_error_handlers; //!< count of active error handlers USHORT req_flags; //!< generic flag USHORT req_client_dialect; //!< dialect passed into the API call USHORT req_in_outer_join; //!< processing inside outer-join part dsql_str* req_alias_relation_prefix; //!< prefix for every relation-alias. private: // Request should never be destroyed using delete. // It dies together with it's pool in release_request(). ~dsql_req(); // To avoid posix warning about missing public destructor declare // MemoryPool as friend class. In fact IT releases request memory! friend class MemoryPool; }; // values used in req_flags enum req_flags_vals { REQ_cursor_open = 1, REQ_save_metadata = 2, REQ_prepared = 4, REQ_embedded_sql_cursor = 8, REQ_procedure = 16, REQ_trigger = 32, REQ_orphan = 64, REQ_enforce_scope = 128, REQ_no_batch = 256, REQ_backwards = 512, REQ_blr_version4 = 1024, REQ_blr_version5 = 2048, REQ_block = 4096 }; //! Blob class dsql_blb : public pool_alloc { public: dsql_nod* blb_field; //!< Related blob field dsql_par* blb_blob_id; //!< Parameter to hold blob id dsql_par* blb_segment; //!< Parameter for segments dsql_nod* blb_from; dsql_nod* blb_to; class dsql_msg* blb_open_in_msg; //!< Input message to open cursor class dsql_msg* blb_open_out_msg; //!< Output message from open cursor class dsql_msg* blb_segment_msg; //!< Segment message }; //! List of open cursors class dsql_opn : public pool_alloc { public: dsql_opn* opn_next; //!< Next open cursor dsql_req* opn_request; //!< Request owning the cursor FB_API_HANDLE opn_transaction; //!< Transaction executing request }; //! Transaction block class dsql_tra : public pool_alloc { public: dsql_tra* tra_next; //!< Next open transaction }; //! Context block used to create an instance of a relation reference class dsql_ctx : public pool_alloc { public: dsql_ctx(MemoryPool &p) : ctx_childs_derived_table(p) {} dsql_req* ctx_request; //!< Parent request dsql_rel* ctx_relation; //!< Relation for context dsql_prc* ctx_procedure; //!< Procedure for context dsql_nod* ctx_proc_inputs; //!< Procedure input parameters class dsql_map* ctx_map; //!< Map for aggregates dsql_nod* ctx_rse; //!< Sub-rse for aggregates dsql_ctx* ctx_parent; //!< Parent context for aggregates TEXT* ctx_alias; //!< Context alias (can include concatenated derived table alias) TEXT* ctx_internal_alias; //!< Alias as specified in query USHORT ctx_context; //!< Context id USHORT ctx_scope_level; //!< Subquery level within this request USHORT ctx_flags; //!< Various flag values DsqlContextStack ctx_childs_derived_table; //!< Childs derived table context dsql_ctx& operator=(dsql_ctx& v) { ctx_request = v.ctx_request; ctx_relation = v.ctx_relation; ctx_procedure = v.ctx_procedure; ctx_proc_inputs = v.ctx_proc_inputs; ctx_map = v.ctx_map; ctx_rse = v.ctx_rse; ctx_parent = v.ctx_parent; ctx_alias = v.ctx_alias; ctx_context = v.ctx_context; ctx_scope_level = v.ctx_scope_level; ctx_flags = v.ctx_flags; ctx_childs_derived_table.assign(v.ctx_childs_derived_table); return *this; } }; // Flag values for ctx_flags const USHORT CTX_outer_join = 0x01; // reference is part of an outer join const USHORT CTX_system = 0x02; // Context generated by system (NEW/OLD in triggers,check-constraint) //! Aggregate/union map block to map virtual fields to their base //! TMN: NOTE! This datatype should definitely be renamed! class dsql_map : public pool_alloc { public: dsql_map* map_next; //!< Next map in item dsql_nod* map_node; //!< Value for map item USHORT map_position; //!< Position in map }; //! Message block used in communicating with a running request class dsql_msg : public pool_alloc { public: dsql_par* msg_parameters; //!< Parameter list dsql_par* msg_par_ordered; //!< Ordered parameter list UCHAR* msg_buffer; //!< Message buffer USHORT msg_number; //!< Message number USHORT msg_length; //!< Message length USHORT msg_parameter; //!< Next parameter number USHORT msg_index; //!< Next index into SQLDA }; //! Parameter block used to describe a parameter of a message class dsql_par : public pool_alloc { public: dsql_msg* par_message; //!< Parent message dsql_par* par_next; //!< Next parameter in linked list dsql_par* par_ordered; //!< Next parameter in order of index dsql_par* par_null; //!< Null parameter, if used dsql_nod* par_node; //!< Associated value node, if any dsql_ctx* par_dbkey_ctx; //!< Context of internally requested dbkey dsql_ctx* par_rec_version_ctx; //!< Context of internally requested record version const TEXT* par_name; //!< Parameter name, if any const TEXT* par_rel_name; //!< Relation name, if any const TEXT* par_owner_name; //!< Owner name, if any const TEXT* par_rel_alias; //!< Relation alias, if any const TEXT* par_alias; //!< Alias, if any DSC par_desc; //!< Field data type DSC par_user_desc; //!< SQLDA data type USHORT par_parameter; //!< BLR parameter number USHORT par_index; //!< Index into SQLDA, if appropriate }; #include "../jrd/thd.h" // DSQL threading declarations class tsql : public ThreadData { private: DsqlMemoryPool* tsql_default; friend class Firebird::SubsystemContextPoolHolder ; void setDefaultPool(DsqlMemoryPool* p) { tsql_default = p; } public: typedef tsql* Pointer; tsql(ISC_STATUS* status, Pointer& ptr) : ThreadData(tddSQL), tsql_default(0), tsql_status(status) { ptr = this; putSpecific(); } ~tsql() { restoreSpecific(); } ISC_STATUS* tsql_status; DsqlMemoryPool* getDefaultPool() { return tsql_default; } }; typedef Firebird::SubsystemContextPoolHolder DsqlContextPoolHolder; inline tsql* DSQL_get_thread_data() { return (tsql*) ThreadData::getSpecific(); } /*! \var unsigned DSQL_debug \brief Debug level 0 No output 1 Display output tree in PASS1_statment 2 Display input tree in PASS1_statment 4 Display ddl BLR 8 Display BLR 16 Display PASS1_rse input tree 32 Display SQL input string 64 Display BLR in dsql/prepare > 256 Display yacc parser output level = DSQL_level>>8 */ // macros for error generation #define BLKCHK(blk, type) if (MemoryPool::blk_type(blk) != (SSHORT) type) ERRD_bugcheck("expected type") #ifdef DSQL_DEBUG extern unsigned DSQL_debug; #endif #ifdef DEV_BUILD // Verifies that a pointed to block matches the expected type. // Useful to find coding errors & memory globbers. #define DEV_BLKCHK(blk, typ) { \ if ((blk) && MemoryPool::blk_type(blk) != (SSHORT)typ) { \ ERRD_assert_msg("Unexpected memory block type", \ (char*) __FILE__, \ (ULONG) __LINE__); \ } \ } #undef fb_assert void ERRD_assert_msg(const char*, const char*, ULONG); #define fb_assert(ex) {if (!(ex)) {ERRD_assert_msg (NULL, (char*)__FILE__, __LINE__);}} #else // PROD_BUILD #define DEV_BLKCHK(blk, typ) #undef fb_assert #define fb_assert(ex) #endif // DEV_BUILD // CVC: Enumeration used for the COMMENT command. enum { ddl_database, ddl_domain, ddl_relation, ddl_view, ddl_procedure, ddl_trigger, ddl_udf, ddl_blob_filter, ddl_exception, ddl_generator, ddl_index, ddl_role, ddl_charset, ddl_collation//, ddl_sec_class }; #endif // DSQL_DSQL_H