/* * PROGRAM: JRD Data Definition Utility * MODULE: dyn_util.epp * DESCRIPTION: Dynamic data definition - utility functions * * 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-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY) * */ #include "firebird.h" #include #include #include "../jrd/common.h" #include "../jrd/jrd.h" #include "../jrd/tra.h" #include "../jrd/scl.h" #include "../jrd/drq.h" #include "../jrd/flags.h" #include "../jrd/ibase.h" #include "../jrd/lls.h" #include "../jrd/met.h" #include "../jrd/btr.h" #include "../jrd/intl.h" #include "../jrd/dyn.h" #include "../jrd/ods.h" #include "../jrd/blb_proto.h" #include "../jrd/cmp_proto.h" #include "../jrd/dyn_proto.h" #include "../jrd/dyn_md_proto.h" #include "../jrd/dyn_ut_proto.h" #include "../jrd/err_proto.h" #include "../jrd/exe_proto.h" #include "../jrd/gds_proto.h" #include "../jrd/inf_proto.h" #include "../jrd/intl_proto.h" #include "../jrd/isc_f_proto.h" #include "../jrd/vio_proto.h" #include "../common/utils_proto.h" using MsgFormat::SafeArg; using namespace Jrd; DATABASE DB = STATIC "ODS.RDB"; static const SCHAR gen_id_blr1[] = { blr_version5, blr_begin, blr_message, 0, 1, 0, blr_int64, 0, blr_begin, blr_send, 0, blr_begin, blr_assignment, blr_gen_id }; static const SCHAR gen_id_blr2[] = { blr_literal, blr_long, 0, 1, 0, 0, 0, blr_parameter, 0, 0, 0, blr_end, blr_end, blr_end, blr_eoc }; static const UCHAR prot_blr[] = { blr_version5, blr_begin, blr_message, 1, 1, 0, blr_short, 0, blr_message, 0, 2, 0, blr_cstring, 32, 0, blr_cstring, 32, 0, blr_receive, 0, blr_begin, blr_send, 1, blr_begin, blr_assignment, blr_prot_mask, blr_parameter, 0, 0, 0, blr_parameter, 0, 1, 0, blr_parameter, 1, 0, 0, blr_end, blr_end, blr_end, blr_eoc }; SINT64 DYN_UTIL_gen_unique_id(thread_db* tdbb, Global* gbl, SSHORT id, const char* generator_name) { /************************************** * * D Y N _ U T I L _ g e n _ u n i q u e _ i d * ************************************** * * Functional description * Generate a unique id using a generator. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = CMP_find_request(tdbb, id, DYN_REQUESTS); SINT64 value = 0; try { if (!request) { const size_t name_length = strlen(generator_name); fb_assert(name_length < MAX_SQL_IDENTIFIER_SIZE); const size_t blr_size = sizeof(gen_id_blr1) + sizeof(gen_id_blr2) + 1 + name_length; Firebird::UCharBuffer blr; UCHAR* p = blr.getBuffer(blr_size); memcpy(p, gen_id_blr1, sizeof(gen_id_blr1)); p += sizeof(gen_id_blr1); *p++ = name_length; memcpy(p, generator_name, name_length); p += name_length; memcpy(p, gen_id_blr2, sizeof(gen_id_blr2)); p += sizeof(gen_id_blr2); request = CMP_compile2(tdbb, blr.begin(), TRUE); } EXE_start(tdbb, request, dbb->dbb_sys_trans); EXE_receive(tdbb, request, 0, sizeof(value), (UCHAR*) &value); EXE_unwind(tdbb, request); } catch (const Firebird::Exception&) { DYN_rundown_request(request, id); throw; } if (!DYN_REQUEST(id)) { DYN_REQUEST(id) = request; } return value; } void DYN_UTIL_generate_constraint_name( thread_db* tdbb, Global* gbl, Firebird::MetaName& buffer) { /************************************** * * D Y N _ U T I L _ g e n e r a t e _ c o n s t r a i n t _ n a m e * ************************************** * * Functional description * Generate a name unique to RDB$RELATION_CONSTRAINTS. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; SSHORT id = -1; try { bool found = false; do { buffer.printf("INTEG_%" SQUADFORMAT, (SINT64) DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_con, "RDB$CONSTRAINT_NAME")); request = CMP_find_request(tdbb, drq_f_nxt_con, DYN_REQUESTS); id = drq_f_nxt_con; found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$RELATION_CONSTRAINTS WITH X.RDB$CONSTRAINT_NAME EQ buffer.c_str() if (!DYN_REQUEST(drq_f_nxt_con)) DYN_REQUEST(drq_f_nxt_con) = request; found = true; END_FOR; if (!DYN_REQUEST(drq_f_nxt_con)) DYN_REQUEST(drq_f_nxt_con) = request; request = NULL; } while (found); } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, id); DYN_error_punt(true, 131); /* msg 131: "Generation of constraint name failed" */ } } void DYN_UTIL_generate_field_name( thread_db* tdbb, Global* gbl, TEXT* buffer) { /************************************** * * D Y N _ U T I L _ g e n e r a t e _ f i e l d _ n a m e * ************************************** * * Functional description * Stub to make it work with char* too. * **************************************/ Firebird::MetaName temp; DYN_UTIL_generate_field_name(tdbb, gbl, temp); strcpy(buffer, temp.c_str()); } void DYN_UTIL_generate_field_name( thread_db* tdbb, Global* gbl, Firebird::MetaName& buffer) { /************************************** * * D Y N _ U T I L _ g e n e r a t e _ f i e l d _ n a m e * ************************************** * * Functional description * Generate a name unique to RDB$FIELDS. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; SSHORT id = -1; try { bool found = false; do { buffer.printf("RDB$%" SQUADFORMAT, (SINT64) DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_fld, "RDB$FIELD_NAME")); request = CMP_find_request(tdbb, drq_f_nxt_fld, DYN_REQUESTS); id = drq_f_nxt_fld; found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ buffer.c_str() if (!DYN_REQUEST(drq_f_nxt_fld)) DYN_REQUEST(drq_f_nxt_fld) = request; found = true; END_FOR; if (!DYN_REQUEST(drq_f_nxt_fld)) DYN_REQUEST(drq_f_nxt_fld) = request; request = NULL; } while (found); } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, id); DYN_error_punt(true, 81); /* msg 81: "Generation of field name failed" */ } } void DYN_UTIL_generate_field_position(thread_db* tdbb, Global* gbl, const Firebird::MetaName& relation_name, SLONG* field_pos) { /************************************** * * D Y N _ U T I L _ g e n e r a t e _ f i e l d _ p o s i t i o n * ************************************** * * Functional description * Generate a field position if not specified * **************************************/ SLONG field_position = -1; SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; try { request = CMP_find_request(tdbb, drq_l_fld_pos, DYN_REQUESTS); FOR(REQUEST_HANDLE request) X IN RDB$RELATION_FIELDS WITH X.RDB$RELATION_NAME EQ relation_name.c_str() if (!DYN_REQUEST(drq_l_fld_pos)) DYN_REQUEST(drq_l_fld_pos) = request; if (X.RDB$FIELD_POSITION.NULL) continue; field_position = MAX(X.RDB$FIELD_POSITION, field_position); END_FOR; *field_pos = field_position; } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, -1); DYN_error_punt(true, 162); /* msg 162: "Looking up field position failed" */ } } void DYN_UTIL_generate_index_name(thread_db* tdbb, Global* gbl, Firebird::MetaName& buffer, UCHAR verb) { /************************************** * * D Y N _ U T I L _ g e n e r a t e _ i n d e x _ n a m e * ************************************** * * Functional description * Generate a name unique to RDB$INDICES. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; SSHORT id = -1; try { bool found = false; do { const SCHAR* format; switch (verb) { case isc_dyn_def_primary_key: format = "RDB$PRIMARY%" SQUADFORMAT; break; case isc_dyn_def_foreign_key: format = "RDB$FOREIGN%" SQUADFORMAT; break; default: format = "RDB$%" SQUADFORMAT; } buffer.printf(format, (SINT64) DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_idx, "RDB$INDEX_NAME")); request = CMP_find_request(tdbb, drq_f_nxt_idx, DYN_REQUESTS); id = drq_f_nxt_idx; found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$INDICES WITH X.RDB$INDEX_NAME EQ buffer.c_str() if (!DYN_REQUEST(drq_f_nxt_idx)) DYN_REQUEST(drq_f_nxt_idx) = request; found = true; END_FOR; if (!DYN_REQUEST(drq_f_nxt_idx)) DYN_REQUEST(drq_f_nxt_idx) = request; request = NULL; } while (found); } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, id); DYN_error_punt(true, 82); /* msg 82: "Generation of index name failed" */ } } void DYN_UTIL_generate_trigger_name( thread_db* tdbb, Global* gbl, Firebird::MetaName& buffer) { /************************************** * * D Y N _ U T I L _ g e n e r a t e _ t r i g g e r _ n a m e * ************************************** * * Functional description * Generate a name unique to RDB$TRIGGERS. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; SSHORT id = -1; try { bool found = false; do { buffer.printf("CHECK_%" SQUADFORMAT, (SINT64) DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_trg, "RDB$TRIGGER_NAME")); request = CMP_find_request(tdbb, drq_f_nxt_trg, DYN_REQUESTS); id = drq_f_nxt_trg; found = false; FOR(REQUEST_HANDLE request) FIRST 1 X IN RDB$TRIGGERS WITH X.RDB$TRIGGER_NAME EQ buffer.c_str() if (!DYN_REQUEST(drq_f_nxt_trg)) DYN_REQUEST(drq_f_nxt_trg) = request; found = true; END_FOR; if (!DYN_REQUEST(drq_f_nxt_trg)) DYN_REQUEST(drq_f_nxt_trg) = request; request = NULL; } while (found); } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, id); DYN_error_punt(true, 83); /* msg 83: "Generation of trigger name failed" */ } } bool DYN_UTIL_find_field_source(thread_db* tdbb, Global* gbl, const Firebird::MetaName& view_name, USHORT context, const TEXT* local_name, TEXT* output_field_name) { /************************************** * * D Y N _U T I L _ f i n d _ f i e l d _ s o u r c e * ************************************** * * Functional description * Find the original source for a view field. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; /* CVC: It seems the logic of this function was changed over time. It's unlikely it will cause a failure that leads to call DYN_error_punt(), unless the request finds problems due to database corruption or unexpected ODS changes. Under normal circumstances, it will return either true or false. When true, we found a field source for the view's name/context/field and are loading this value in the last parameter, that can be used against rdb$fields' rdb$field_name. */ bool found = false; try { request = CMP_find_request(tdbb, drq_l_fld_src2, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) VRL IN RDB$VIEW_RELATIONS CROSS RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME WITH VRL.RDB$VIEW_NAME EQ view_name.c_str() AND VRL.RDB$VIEW_CONTEXT EQ context AND RFR.RDB$FIELD_NAME EQ local_name if (!DYN_REQUEST(drq_l_fld_src2)) { DYN_REQUEST(drq_l_fld_src2) = request; } found = true; fb_utils::exact_name_limit(RFR.RDB$FIELD_SOURCE, sizeof(RFR.RDB$FIELD_SOURCE)); strcpy(output_field_name, RFR.RDB$FIELD_SOURCE); END_FOR; if (!DYN_REQUEST(drq_l_fld_src2)) { DYN_REQUEST(drq_l_fld_src2) = request; } if (!found) { request = CMP_find_request(tdbb, drq_l_fld_src3, DYN_REQUESTS); FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) VRL IN RDB$VIEW_RELATIONS CROSS PPR IN RDB$PROCEDURE_PARAMETERS WITH VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND VRL.RDB$VIEW_NAME EQ view_name.c_str() AND VRL.RDB$VIEW_CONTEXT EQ context AND PPR.RDB$PARAMETER_NAME EQ local_name if (!DYN_REQUEST(drq_l_fld_src3)) { DYN_REQUEST(drq_l_fld_src3) = request; } found = true; fb_utils::exact_name_limit(PPR.RDB$FIELD_SOURCE, sizeof(PPR.RDB$FIELD_SOURCE)); strcpy(output_field_name, PPR.RDB$FIELD_SOURCE); END_FOR; if (!DYN_REQUEST(drq_l_fld_src3)) { DYN_REQUEST(drq_l_fld_src3) = request; } } } catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, -1); DYN_error_punt(true, 80); /* msg 80: "Specified domain or source field does not exist" */ } return found; } bool DYN_UTIL_get_prot(thread_db* tdbb, Global* gbl, const SCHAR* rname, const SCHAR* fname, SecurityClass::flags_t* prot_mask) { /************************************** * * D Y N _ U T I L _ g e t _ p r o t * ************************************** * * Functional description * Get protection mask for relation or relation_field * **************************************/ struct { SqlIdentifier relation_name; SqlIdentifier field_name; } in_msg; SET_TDBB(tdbb); jrd_req* request = CMP_find_request(tdbb, drq_l_prot_mask, DYN_REQUESTS); try { if (!request) { request = CMP_compile2(tdbb, prot_blr, TRUE); } gds__vtov(rname, in_msg.relation_name, sizeof(in_msg.relation_name)); gds__vtov(fname, in_msg.field_name, sizeof(in_msg.field_name)); EXE_start(tdbb, request, gbl->gbl_transaction); EXE_send(tdbb, request, 0, sizeof(in_msg), (UCHAR*)&in_msg); EXE_receive(tdbb, request, 1, sizeof(SecurityClass::flags_t), (UCHAR*)prot_mask); DYN_rundown_request(request, drq_l_prot_mask); } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, drq_l_prot_mask); return false; } return true; } void DYN_UTIL_store_check_constraints(thread_db* tdbb, Global* gbl, const Firebird::MetaName& constraint_name, const Firebird::MetaName& trigger_name) { /************************************** * * D Y N _ U T I L _s t o r e _ c h e c k _ c o n s t r a i n t s * ************************************** * * Functional description * Fill in rdb$check_constraints the association between a check name and the * system defined trigger that implements that check. * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = CMP_find_request(tdbb, drq_s_chk_con, DYN_REQUESTS); try { STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) CHK IN RDB$CHECK_CONSTRAINTS strcpy(CHK.RDB$CONSTRAINT_NAME, constraint_name.c_str()); strcpy(CHK.RDB$TRIGGER_NAME, trigger_name.c_str()); END_STORE; if (!DYN_REQUEST(drq_s_chk_con)) { DYN_REQUEST(drq_s_chk_con) = request; } } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, drq_s_chk_con); DYN_error_punt(true, 122); /* msg 122: "STORE RDB$CHECK_CONSTRAINTS failed" */ } } //*************************************** // // D Y N _ U T I L _ i s _ a r r a y // //************************************** // // Functional description // Discover if a given domain (either automatic or explicit) has dimensions. // //*************************************** bool DYN_UTIL_is_array(thread_db* tdbb, Global* gbl, const Firebird::MetaName& domain_name) { SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); jrd_req* request = CMP_find_request(tdbb, drq_dom_is_array, DYN_REQUESTS); try { bool rc = false; FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ domain_name.c_str() if (!DYN_REQUEST(drq_dom_is_array)) DYN_REQUEST(drq_dom_is_array) = request; rc = !X.RDB$DIMENSIONS.NULL && X.RDB$DIMENSIONS > 0; END_FOR if (!DYN_REQUEST(drq_dom_is_array)) DYN_REQUEST(drq_dom_is_array) = request; return rc; } catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, drq_dom_is_array); DYN_error_punt(true, 227, domain_name.c_str()); // msg 227: "DYN_UTIL_is_array failed for domain %s" return false; // Keep compiler happy. } } //*************************************** // // D Y N _ U T I L _ c o p y _ d o m a i n // //************************************** // // Functional description // Copy a domain in another. More reliable than using dyn_fld as intermediate. // The source cannot be an array domain. // We don't copy the default, it may be useless work. // //*************************************** void DYN_UTIL_copy_domain(thread_db* tdbb, Global* gbl, const Firebird::MetaName& org_name, const Firebird::MetaName& new_name) { SET_TDBB(tdbb); //Database* dbb = tdbb->getDatabase(); jrd_req* request = NULL; //CMP_find_request(tdbb, drq_dom_copy, DYN_REQUESTS); jrd_req* req2 = NULL; try { FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) X IN RDB$FIELDS WITH X.RDB$FIELD_NAME EQ org_name.c_str() //if (!DYN_REQUEST(drq_dom_copy)) // DYN_REQUEST(drq_dom_copy) = request; if (!X.RDB$DIMENSIONS.NULL && X.RDB$DIMENSIONS > 0) ERR_punt(); STORE(REQUEST_HANDLE req2 TRANSACTION_HANDLE gbl->gbl_transaction) X2 IN RDB$FIELDS X2.RDB$FIELD_NAME.NULL = FALSE; strcpy(X2.RDB$FIELD_NAME, new_name.c_str()); X2.RDB$QUERY_NAME.NULL = X.RDB$QUERY_NAME.NULL; if (!X.RDB$QUERY_NAME.NULL) strcpy(X2.RDB$QUERY_NAME, X.RDB$QUERY_NAME); // The following fields may require blob copying: // rdb$validation_blr, rdb$validation_source, // rdb$computed_blr, rdb$computed_source, // rdb$default_value, rdb$default_source, // rdb$missing_value, rdb$missing_source, // rdb$description and rdb$query_header. X2.RDB$VALIDATION_BLR.NULL = X.RDB$VALIDATION_BLR.NULL; X2.RDB$VALIDATION_BLR = X.RDB$VALIDATION_BLR; X2.RDB$VALIDATION_SOURCE.NULL = X.RDB$VALIDATION_SOURCE.NULL; X2.RDB$VALIDATION_SOURCE = X.RDB$VALIDATION_SOURCE; X2.RDB$COMPUTED_BLR.NULL = X.RDB$COMPUTED_BLR.NULL; X2.RDB$COMPUTED_BLR = X.RDB$COMPUTED_BLR; X2.RDB$COMPUTED_SOURCE.NULL = X.RDB$COMPUTED_SOURCE.NULL; X2.RDB$COMPUTED_SOURCE = X.RDB$COMPUTED_SOURCE; //X2.RDB$DEFAULT_VALUE.NULL = X.RDB$DEFAULT_VALUE.NULL; //X2.RDB$DEFAULT_VALUE = X.RDB$DEFAULT_VALUE; //X2.RDB$DEFAULT_SOURCE.NULL = X.RDB$DEFAULT_SOURCE.NULL; //X2.RDB$DEFAULT_SOURCE = X.RDB$DEFAULT_SOURCE; X2.RDB$FIELD_LENGTH.NULL = X.RDB$FIELD_LENGTH.NULL; X2.RDB$FIELD_LENGTH = X.RDB$FIELD_LENGTH; X2.RDB$FIELD_SCALE.NULL = X.RDB$FIELD_SCALE.NULL; X2.RDB$FIELD_SCALE = X.RDB$FIELD_SCALE; X2.RDB$FIELD_TYPE.NULL = X.RDB$FIELD_TYPE.NULL; X2.RDB$FIELD_TYPE = X.RDB$FIELD_TYPE; X2.RDB$FIELD_SUB_TYPE.NULL = X.RDB$FIELD_SUB_TYPE.NULL; X2.RDB$FIELD_SUB_TYPE = X.RDB$FIELD_SUB_TYPE; X2.RDB$MISSING_VALUE.NULL = X.RDB$MISSING_VALUE.NULL; X2.RDB$MISSING_VALUE = X.RDB$MISSING_VALUE; X2.RDB$MISSING_SOURCE.NULL = X.RDB$MISSING_SOURCE.NULL; X2.RDB$MISSING_SOURCE = X.RDB$MISSING_SOURCE; X2.RDB$DESCRIPTION.NULL = X.RDB$DESCRIPTION.NULL; X2.RDB$DESCRIPTION = X.RDB$DESCRIPTION; X2.RDB$SYSTEM_FLAG.NULL = X.RDB$SYSTEM_FLAG.NULL; X2.RDB$SYSTEM_FLAG = X.RDB$SYSTEM_FLAG; X2.RDB$QUERY_HEADER.NULL = X.RDB$QUERY_HEADER.NULL; X2.RDB$QUERY_HEADER = X.RDB$QUERY_HEADER; X2.RDB$SEGMENT_LENGTH.NULL = X.RDB$SEGMENT_LENGTH.NULL; X2.RDB$SEGMENT_LENGTH = X.RDB$SEGMENT_LENGTH; X2.RDB$EDIT_STRING.NULL = X.RDB$EDIT_STRING.NULL; if (!X.RDB$EDIT_STRING.NULL) strcpy(X2.RDB$EDIT_STRING, X.RDB$EDIT_STRING); X2.RDB$EXTERNAL_LENGTH.NULL = X.RDB$EXTERNAL_LENGTH.NULL; X2.RDB$EXTERNAL_LENGTH = X.RDB$EXTERNAL_LENGTH; X2.RDB$EXTERNAL_SCALE.NULL = X.RDB$EXTERNAL_SCALE.NULL; X2.RDB$EXTERNAL_SCALE = X.RDB$EXTERNAL_SCALE; X2.RDB$EXTERNAL_TYPE.NULL = X.RDB$EXTERNAL_TYPE.NULL; X2.RDB$EXTERNAL_TYPE = X.RDB$EXTERNAL_TYPE; X2.RDB$DIMENSIONS.NULL = X.RDB$DIMENSIONS.NULL; X2.RDB$DIMENSIONS = X.RDB$DIMENSIONS; X2.RDB$NULL_FLAG.NULL = X.RDB$NULL_FLAG.NULL; X2.RDB$NULL_FLAG = X.RDB$NULL_FLAG; X2.RDB$CHARACTER_LENGTH.NULL = X.RDB$CHARACTER_LENGTH.NULL; X2.RDB$CHARACTER_LENGTH = X.RDB$CHARACTER_LENGTH; X2.RDB$COLLATION_ID.NULL = X.RDB$COLLATION_ID.NULL; X2.RDB$COLLATION_ID = X.RDB$COLLATION_ID; X2.RDB$CHARACTER_SET_ID.NULL = X.RDB$CHARACTER_SET_ID.NULL; X2.RDB$CHARACTER_SET_ID = X.RDB$CHARACTER_SET_ID; X2.RDB$FIELD_PRECISION.NULL = X.RDB$FIELD_PRECISION.NULL; X2.RDB$FIELD_PRECISION = X.RDB$FIELD_PRECISION; END_STORE CMP_release(tdbb, req2); req2 = NULL; END_FOR CMP_release(tdbb, request); request = NULL; // For now, CMP_release used instead of this: //if (!DYN_REQUEST(drq_dom_copy)) // DYN_REQUEST(drq_dom_copy) = request; } catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); DYN_rundown_request(request, -1); //drq_dom_copy); DYN_error_punt(true, 228, org_name.c_str()); // msg 228: "DYN_UTIL_copy_domain failed for domain %s" } }