/* * PROGRAM: Interactive SQL utility * MODULE: extract.epp * DESCRIPTION: Definition extract routines * * 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): ______________________________________. * Revision 1.3 2000/11/22 17:07:25 patrickgriffin * In get_procedure_args change comment style from // to c style * * ...pat * * 2001.09.09 Claudio Valderrama: procedure's parameter names may need * double quotes if they are in dialect 3 and have special characters. * 2001.09.21 Claudio Valderrama: Show correct mechanism for UDF parameters * and support the RETURNS PARAMETER syntax. * 2001.10.01 Claudio Valderrama: list_all_grants2() and EXTRACT_list_grants() * to better organize the code that should be called to handle SHOW GRANTS. * * Revision 1.2 2000/11/18 16:49:24 fsg * Increased PRINT_BUFFER_LENGTH to 2048 to show larger plans * Fixed Bug #122563 in extract.e get_procedure_args * Apparently this has to be done in show.e also, * but that is for another day :-) * * 2003.02.04 Dmitry Yemanov: support for universal triggers */ #include "firebird.h" #include #include #include #include // isdigit #include "../jrd/common.h" #include "../jrd/constants.h" #include "../jrd/ibase.h" #include "../jrd/gds_proto.h" #include "../jrd/intlobj_new.h" #include "../isql/isql.h" #include "../isql/extra_proto.h" #include "../isql/isql_proto.h" #include "../isql/show_proto.h" #include "../jrd/ini.h" #include "../jrd/obj.h" #include "../jrd/ods.h" #include "../common/utils_proto.h" #include "../jrd/constants.h" using MsgFormat::SafeArg; DATABASE DB = EXTERN COMPILETIME "yachts.lnk"; static void list_all_grants(); static processing_state list_all_grants2(bool, const SCHAR*); static void list_all_procs(); static void list_all_tables(LegacyTables flag, SSHORT); static void list_all_triggers(); static void list_check(); static void list_collations(); static void list_create_db(); static void list_domain_table(const SCHAR*, SSHORT); static void list_domains(SSHORT); static void list_exception(); static void list_filters(); static void list_foreign(); static void list_functions(); static void list_generators(); static void list_index(); static void list_views(); static void get_procedure_args(const char*); extern const char* trigger_action(int); static const char* Procterm = "^"; // TXNN: script use only /* Maybe 512 would be really enough as Print_buffer size, but as we have PRINT_BUFFER_LENGTH in isql.h, we should use it FSG 17.Nov.2000 */ static TEXT Print_buffer[PRINT_BUFFER_LENGTH]; static TEXT SQL_identifier[BUFFER_LENGTH128]; static TEXT SQL_identifier2[BUFFER_LENGTH128]; int EXTRACT_ddl(LegacyTables flag, const SCHAR* tabname) { /************************************** * * E X T R A C T _ d d l * ************************************** * * Functional description * Extract all sql information * 0 flag means SQL only tables. 1 flag means all tables * **************************************/ bool did_attach = false; if (!DB) { if (isc_attach_database(gds_status, 0, isqlGlob.global_Db_name, &DB, 0, NULL)) { ISQL_errmsg(gds_status); return FINI_ERROR; } did_attach = true; } ISQL_get_version(false); if (isqlGlob.SQL_dialect != isqlGlob.db_SQL_dialect) { isqlGlob.printf( "/*=========================================================*/%s", NEWLINE); isqlGlob.printf( "/*= ==*/%s", NEWLINE); isqlGlob.printf( "/*= Command Line -sqldialect %d is overwritten by ==*/%s", isqlGlob.SQL_dialect, NEWLINE); isqlGlob.printf( "/*= Database SQL Dialect %d. ==*/%s", isqlGlob.db_SQL_dialect, NEWLINE); isqlGlob.printf( "/*= ==*/%s", NEWLINE); isqlGlob.printf( "/*=========================================================*/%s", NEWLINE); } isqlGlob.printf(NEWLINE); isqlGlob.printf("SET SQL DIALECT %d; %s", isqlGlob.db_SQL_dialect, NEWLINE); isqlGlob.printf(NEWLINE); bool did_start = false; if (!gds_trans) { if (isc_start_transaction(gds_status, &gds_trans, 1, &DB, 0, NULL)) { ISQL_errmsg(gds_status); return FINI_ERROR; } did_start = true; } const SSHORT default_char_set_id = ISQL_get_default_char_set_id(); int ret_code = FINI_OK; // If a table name was passed, extract only that table and domains if (*tabname) { if (EXTRACT_list_table(tabname, NULL, true, default_char_set_id)) { SCHAR errbuf[MSG_LENGTH]; ISQL_msg_get(NOT_FOUND_MSG, errbuf, SafeArg() << tabname); STDERROUT(errbuf); ret_code = FINI_ERROR; } } else { list_create_db(); list_filters(); list_collations(); list_functions(); list_generators(); list_domains(default_char_set_id); list_all_tables(flag, default_char_set_id); list_index(); list_foreign(); list_views(); list_check(); list_exception(); list_all_procs(); list_all_triggers(); list_all_grants(); SHOW_comments(false); // Let's make this an option later. } if (gds_trans && did_start) if (isc_commit_transaction(gds_status, &gds_trans)) { ISQL_errmsg(gds_status); return FINI_ERROR; } if (DB && did_attach) { if (isc_detach_database(gds_status, &DB)) { ISQL_errmsg(gds_status); return FINI_ERROR; } DB = 0; } return ret_code; } processing_state EXTRACT_list_grants(const SCHAR* terminator) { /************************************** * * E X T R A C T _ l i s t _ g r a n t s * ************************************** * * Functional description * Print the permissions on all user tables, views and procedures. * **************************************/ return list_all_grants2(false, terminator); } int EXTRACT_list_table(const SCHAR* relation_name, const SCHAR* new_name, bool domain_flag, SSHORT default_char_set_id) { /************************************** * * E X T R A C T _ l i s t _ t a b l e * ************************************** * * Functional description * Shows columns, types, info for a given table name * and text of views. * Use a GDML query to get the info and print it. * If a new_name is passed, substitute it for relation_name * * relation_name -- Name of table to investigate * new_name -- Name of a new name for a replacement table * domain_flag -- extract needed domains before the table * default_char_set_id -- character set def to supress * **************************************/ /************************************** * default_char_set_id warrents special * consideration. If the metadata for a * table is being extracted when there is * really no need to redundantly and repeatedly * list the databases default character set * for every field. * * At the same time there is a need to list * the character set NONE when it is not * the default character set for the database. * * EXCEPT! If the metadata is being extracted * with the intention of coping that tables structure * into another database, and it is not possible * to know the default character set for the * target database, then list every fields * character set. This includes the character * set NONE. * * Fields with no character set definition will * not have any character set listed. * * Use -1 as the default_char_set_id * in this case. * * POTENTIAL TRAP! Consider the following: * When copying a table from one database * to another how should fields using the * default character set be handled? * * If both databases have the same default * character set, then there is no problem * or confusion. * * If the databases have different default * character sets then should fields using * the default is the source database use * the default of the target database? * **************************************/ bool first = true; SCHAR char_sets[86]; USHORT rel_flags = 0; //bool intchar = false; // CVC: shouldn't this var be initialized inside the FOR statement instead? // CVC: 2004.12.03: I discovered someone made this variable obsolete; // it's set but never used. Hope the change was right. I commented it. rel_t rel_type = rel_persistent; if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_11_1) { FOR RT IN RDB$RELATIONS WITH RT.RDB$RELATION_NAME EQ relation_name AND RT.RDB$RELATION_TYPE NOT MISSING rel_type = (rel_t) RT.RDB$RELATION_TYPE; END_FOR ON_ERROR ISQL_errmsg(gds_status); return FINI_ERROR; END_ERROR; } // Query to obtain relation detail information FOR REL IN RDB$RELATIONS CROSS RFR IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS WITH RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND RFR.RDB$RELATION_NAME EQ REL.RDB$RELATION_NAME AND REL.RDB$RELATION_NAME EQ relation_name SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME SSHORT collation = 0; SSHORT char_set_id = 0; if (first) { first = false; // Do we need to print domains if (domain_flag) list_domain_table (relation_name, default_char_set_id); fb_utils::exact_name(REL.RDB$OWNER_NAME); isqlGlob.printf("%s/* Table: %s, Owner: %s */%s", NEWLINE, relation_name, REL.RDB$OWNER_NAME, NEWLINE); if (rel_type == rel_global_temp_preserve || rel_type == rel_global_temp_delete) { isqlGlob.printf("CREATE GLOBAL TEMPORARY TABLE "); } else { isqlGlob.printf("CREATE TABLE "); } if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { if (new_name) ISQL_copy_SQL_id (new_name, SQL_identifier, DBL_QUOTE); else ISQL_copy_SQL_id (relation_name, SQL_identifier, DBL_QUOTE); isqlGlob.printf("%s ", SQL_identifier); } else { isqlGlob.printf("%s ", new_name ? new_name : relation_name); } if (!REL.RDB$EXTERNAL_FILE.NULL) { ISQL_copy_SQL_id (REL.RDB$EXTERNAL_FILE, SQL_identifier2, SINGLE_QUOTE); isqlGlob.printf("EXTERNAL FILE %s ", SQL_identifier2); } isqlGlob.printf("("); } else { isqlGlob.printf(",%s%s", NEWLINE, TAB_AS_SPACES); } if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (fb_utils::exact_name(RFR.RDB$FIELD_NAME), SQL_identifier, DBL_QUOTE); isqlGlob.printf("%s ", SQL_identifier); } else isqlGlob.printf("%s ", fb_utils::exact_name(RFR.RDB$FIELD_NAME)); /* ** Check first for computed fields, then domains. ** If this is a known domain, then just print the domain rather than type ** Domains won't have length, array, or blob definitions, but they ** may have not null, default and check overriding their definitions */ if (!FLD.RDB$COMPUTED_BLR.NULL) { isqlGlob.printf("COMPUTED BY "); if (!FLD.RDB$COMPUTED_SOURCE.NULL) ISQL_print_validation (isqlGlob.Out, &FLD.RDB$COMPUTED_SOURCE, true, gds_trans); } else if (!(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && FLD.RDB$SYSTEM_FLAG != 1)) { fb_utils::exact_name(FLD.RDB$FIELD_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.prints(SQL_identifier); } else isqlGlob.prints(FLD.RDB$FIELD_NAME); // International character sets // Print only the character set if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR) && !RFR.RDB$COLLATION_ID.NULL && RFR.RDB$COLLATION_ID) { char_sets[0] = '\0'; collation = RFR.RDB$COLLATION_ID; char_set_id = FLD.RDB$CHARACTER_SET_ID; ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, 0, true, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); } } else { // Look through types array for (int i = 0; Column_types[i].type; i++) { if (FLD.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; if (isqlGlob.major_ods >= ODS_VERSION10) { // Handle Integral subtypes NUMERIC and DECIMAL if ((FLD.RDB$FIELD_TYPE == SMALLINT) || (FLD.RDB$FIELD_TYPE == INTEGER) || (FLD.RDB$FIELD_TYPE == BIGINT)) { FOR FLD1 IN RDB$FIELDS WITH FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME /* We are ODS >= 10 and could be any Dialect */ if (!FLD1.RDB$FIELD_PRECISION.NULL) { /* We are Dialect >=3 since FIELD_PRECISION is non-NULL */ if (FLD1.RDB$FIELD_SUB_TYPE > 0 && FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) { sprintf (Print_buffer, "%s(%d, %d)", Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE], FLD1.RDB$FIELD_PRECISION, -FLD1.RDB$FIELD_SCALE); precision_known = true; } } END_FOR ON_ERROR ISQL_errmsg (isc_status); return ps_ERR; END_ERROR; } } if (!precision_known) { // Take a stab at numerics and decimals if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE); } else sprintf (Print_buffer, "%s", Column_types[i].type_name); } isqlGlob.prints(Print_buffer); break; } } if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { if (FLD.RDB$CHARACTER_LENGTH.NULL) { isqlGlob.printf("(%d)", FLD.RDB$FIELD_LENGTH); } else { isqlGlob.printf("(%d)", FLD.RDB$CHARACTER_LENGTH); } } // Catch arrays after printing the type if (!FLD.RDB$DIMENSIONS.NULL) ISQL_array_dimensions (FLD.RDB$FIELD_NAME); if (FLD.RDB$FIELD_TYPE == BLOB) { const int subtype = FLD.RDB$FIELD_SUB_TYPE; isqlGlob.printf(" SUB_TYPE "); if ((subtype > 0) && (subtype <= MAX_BLOBSUBTYPES)) isqlGlob.prints(Sub_types[subtype]); else { isqlGlob.printf("%d", subtype); } isqlGlob.printf(" SEGMENT SIZE %u", (USHORT) FLD.RDB$SEGMENT_LENGTH); } // International character sets if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR || FLD.RDB$FIELD_TYPE == BLOB) && !FLD.RDB$CHARACTER_SET_ID.NULL) { char_sets[0] = '\0'; // Override rdb$fields id with relation_fields if present if (!RFR.RDB$COLLATION_ID.NULL) collation = RFR.RDB$COLLATION_ID; else if (!FLD.RDB$COLLATION_ID.NULL) collation = FLD.RDB$COLLATION_ID; if (!FLD.RDB$CHARACTER_SET_ID.NULL) char_set_id = FLD.RDB$CHARACTER_SET_ID; if ((char_set_id != default_char_set_id) || collation) ISQL_get_character_sets (char_set_id, 0, false, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); // CVC: Someone deleted the code that checks intchar when handling collations // several lines below, so it didn't have any effect. Commented it. //if (!char_set_id) // intchar = true; } } // Handle defaults for columns if (!RFR.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf(" "); SHOW_print_metadata_text_blob (isqlGlob.Out, &RFR.RDB$DEFAULT_SOURCE); } /* The null flag is either 1 or null (for nullable) . if there is ** a constraint name, print that too. Domains cannot have named ** constraints. The column name is in rdb$trigger_name in ** rdb$check_constraints. We hope we get at most one row back. */ if (RFR.RDB$NULL_FLAG == 1) { FOR RCO IN RDB$RELATION_CONSTRAINTS CROSS CON IN RDB$CHECK_CONSTRAINTS WITH CON.RDB$TRIGGER_NAME = RFR.RDB$FIELD_NAME AND CON.RDB$CONSTRAINT_NAME = RCO.RDB$CONSTRAINT_NAME AND RCO.RDB$CONSTRAINT_TYPE EQ "NOT NULL" AND RCO.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME if (strncmp(CON.RDB$CONSTRAINT_NAME, "INTEG", 5)) { fb_utils::exact_name(CON.RDB$CONSTRAINT_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (CON.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); sprintf (Print_buffer, " CONSTRAINT %s", SQL_identifier); } else isqlGlob.printf(" CONSTRAINT %s", CON.RDB$CONSTRAINT_NAME); } END_FOR ON_ERROR ISQL_errmsg (gds_status); return FINI_ERROR; END_ERROR; isqlGlob.printf(" NOT NULL"); } // Handle collations after defaults if (collation) { char_sets[0] = '\0'; ISQL_get_character_sets (char_set_id, collation, true, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); } END_FOR ON_ERROR ISQL_errmsg(gds_status); return FINI_ERROR; END_ERROR; // Do primary and unique keys only. references come later SCHAR collist[BUFFER_LENGTH512 * 2]; FOR RELC IN RDB$RELATION_CONSTRAINTS WITH (RELC.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY" OR RELC.RDB$CONSTRAINT_TYPE EQ "UNIQUE") AND RELC.RDB$RELATION_NAME EQ relation_name SORTED BY RELC.RDB$CONSTRAINT_NAME isqlGlob.printf(",%s", NEWLINE); // If the name of the constraint is not INTEG..., print it if (strncmp(RELC.RDB$CONSTRAINT_NAME, "INTEG", 5)) { fb_utils::exact_name(RELC.RDB$CONSTRAINT_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (RELC.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("CONSTRAINT %s ", SQL_identifier); } else isqlGlob.printf("CONSTRAINT %s ", RELC.RDB$CONSTRAINT_NAME); } if (!strncmp (RELC.RDB$CONSTRAINT_TYPE, "PRIMARY", 7)) { ISQL_get_index_segments (collist, sizeof(collist), RELC.RDB$INDEX_NAME, true); isqlGlob.printf("PRIMARY KEY (%s)", collist); } else if (!strncmp (RELC.RDB$CONSTRAINT_TYPE, "UNIQUE", 6)) { ISQL_get_index_segments (collist, sizeof(collist), RELC.RDB$INDEX_NAME, true); isqlGlob.printf("UNIQUE (%s)", collist); } END_FOR ON_ERROR ISQL_errmsg(gds_status); return FINI_ERROR; END_ERROR; // Check constaints are now deferred if (first) // we extracted nothing return FINI_ERROR; if (rel_type == rel_global_temp_preserve) { isqlGlob.printf(")%sON COMMIT PRESERVE ROWS", NEWLINE); } else if (rel_type == rel_global_temp_delete) { isqlGlob.printf(")%sON COMMIT DELETE ROWS", NEWLINE); } else { isqlGlob.printf(")"); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); return FINI_OK; } static void get_procedure_args(const char* proc_name) { /************************************** * * g e t _ p r o c e d u r e _ a r g s * ************************************** * * Functional description * This function extract the procedure parameters and adds it to the * extract file * **************************************/ SCHAR char_sets[86]; // query to retrieve the parameters. /* placed the two identical code blocks into one for loop as suggested by Ann H. and Claudio V. FSG 18.Nov.2000 */ // Parameter types 0 = input // Parameter types 1 = return for (SSHORT ptype = 0; ptype < 2; ptype++) { bool first_time = true; FOR PRM IN RDB$PROCEDURE_PARAMETERS CROSS FLD IN RDB$FIELDS WITH PRM.RDB$PROCEDURE_NAME = proc_name AND PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND PRM.RDB$PARAMETER_TYPE = ptype SORTED BY PRM.RDB$PARAMETER_NUMBER bool prm_collation_id_null = true; SSHORT prm_collation_id = 0; bool prm_default_source_null = true; ISC_QUAD prm_default_source; bool prm_null_flag_null = true; bool prm_null_flag; prm_mech_t prm_mech = prm_mech_normal; if (ENCODE_ODS(isqlGlob.major_ods, isqlGlob.minor_ods) >= ODS_11_1) { FOR PRM2 IN RDB$PROCEDURE_PARAMETERS WITH PRM2.RDB$PROCEDURE_NAME EQ PRM.RDB$PROCEDURE_NAME AND PRM2.RDB$PARAMETER_NAME EQ PRM.RDB$PARAMETER_NAME prm_collation_id_null = PRM2.RDB$COLLATION_ID.NULL; prm_collation_id = PRM2.RDB$COLLATION_ID; prm_default_source_null = PRM2.RDB$DEFAULT_SOURCE.NULL; prm_default_source = PRM2.RDB$DEFAULT_SOURCE; prm_null_flag_null = PRM2.RDB$NULL_FLAG.NULL; prm_null_flag = PRM2.RDB$NULL_FLAG; if (!PRM2.RDB$PARAMETER_MECHANISM.NULL) prm_mech = (prm_mech_t) PRM2.RDB$PARAMETER_MECHANISM; END_FOR } if (first_time) { first_time = false; if (ptype == 0) { // this is the input part isqlGlob.printf("("); } else { // we are in the output part isqlGlob.printf("RETURNS ("); } } else { isqlGlob.printf(",%s", NEWLINE); } fb_utils::exact_name(PRM.RDB$PARAMETER_NAME); // CVC: Parameter names need check for dialect 3, too. if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (PRM.RDB$PARAMETER_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, PRM.RDB$PARAMETER_NAME); isqlGlob.printf("%s ", SQL_identifier); if (!(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && FLD.RDB$SYSTEM_FLAG != 1)) { if (prm_mech == prm_mech_type_of) isqlGlob.printf("TYPE OF "); fb_utils::exact_name(FLD.RDB$FIELD_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.prints(SQL_identifier); } else isqlGlob.prints(FLD.RDB$FIELD_NAME); // International character sets // Print only the collation if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR) && !prm_collation_id_null && prm_collation_id) { char_sets[0] = '\0'; ISQL_get_character_sets(FLD.RDB$CHARACTER_SET_ID, prm_collation_id, true, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); } if (ptype == 0) // input, try to extract default and make Vlad happy. { if (!prm_default_source_null) { isqlGlob.printf(" "); SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); } } } else { // Get column type name to print for (int i = 0; Column_types[i].type; i++) { if (FLD.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; if (isqlGlob.major_ods >= ODS_VERSION10) { // Handle Integral subtypes NUMERIC and DECIMAL if ((FLD.RDB$FIELD_TYPE == SMALLINT) || (FLD.RDB$FIELD_TYPE == INTEGER) || (FLD.RDB$FIELD_TYPE == BIGINT)) { /* We are ODS >= 10 and could be any Dialect */ FOR FLD1 IN RDB$FIELDS WITH FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME if (!FLD1.RDB$FIELD_PRECISION.NULL) { /* We are Dialect >=3 since FIELD_PRECISION is non-NULL */ if (FLD1.RDB$FIELD_SUB_TYPE > 0 && FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) { sprintf (Print_buffer, "%s(%d, %d)", Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE], FLD1.RDB$FIELD_PRECISION, -FLD1.RDB$FIELD_SCALE); precision_known = true; } } END_FOR ON_ERROR ISQL_errmsg (isc_status); return; END_ERROR; } } if (!precision_known) { // Take a stab at numerics and decimals if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE); } else { sprintf (Print_buffer, "%s", Column_types[i].type_name); } } isqlGlob.prints(Print_buffer); break; } } /* Changed this to return RDB$CHARACTER_LENGTH if available Fix for Bug #122563 FSG 18.Nov.2000 */ if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { if (FLD.RDB$CHARACTER_LENGTH.NULL) { isqlGlob.printf("(%d)", FLD.RDB$FIELD_LENGTH); } else { isqlGlob.printf("(%d)", FLD.RDB$CHARACTER_LENGTH); } } // Show international character sets and collations if (!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) { char_sets[0] = 0; SSHORT collation = 0; if (!prm_collation_id_null) collation = prm_collation_id; else if (!FLD.RDB$COLLATION_ID.NULL) collation = FLD.RDB$COLLATION_ID; if (FLD.RDB$CHARACTER_SET_ID.NULL) FLD.RDB$CHARACTER_SET_ID = 0; ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, collation, false, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); } if (ptype == 0) // input, try to extract default and make Vlad happy. { if (!prm_default_source_null) { isqlGlob.printf(" "); SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); } else if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf(" "); SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); } } } if (!prm_null_flag_null && prm_null_flag) isqlGlob.printf(" NOT NULL"); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; // If there was at least one param, close parens if (!first_time) { isqlGlob.printf(")%s", NEWLINE); } } // end for ptype isqlGlob.printf("AS %s", NEWLINE); } static void list_all_grants() { /************************************** * * l i s t _ a l l _ g r a n t s * ************************************** * * Functional description * Print the permissions on all user tables, views and procedures. * * Wrapper around list_all_grants2(). * **************************************/ list_all_grants2(true, isqlGlob.global_Term); } static processing_state list_all_grants2(bool show_role_list, const SCHAR* terminator) { /************************************** * * l i s t _ a l l _ g r a n t s * ************************************** * * Functional description * Print the permissions on all user tables. * * Get separate permissions on table/views and then procedures. * **************************************/ bool first_role = true; TEXT prev_owner[44]; // Process GRANT roles if (isqlGlob.major_ods >= ODS_VERSION9 && show_role_list) { prev_owner[0] = '\0'; FOR XX IN RDB$ROLES SORTED BY XX.RDB$ROLE_NAME if (first_role) { isqlGlob.printf("%s/* Grant roles for this database */%s", NEWLINE, NEWLINE); first_role = false; } // Null terminate name string fb_utils::exact_name(XX.RDB$ROLE_NAME); fb_utils::exact_name(XX.RDB$OWNER_NAME); if (strcmp (prev_owner, XX.RDB$OWNER_NAME) != 0) { isqlGlob.printf("%s/* Role: %s, Owner: %s */%s", NEWLINE, XX.RDB$ROLE_NAME, XX.RDB$OWNER_NAME, NEWLINE); strcpy (prev_owner, XX.RDB$OWNER_NAME); } if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (XX.RDB$ROLE_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("CREATE ROLE %s;%s", SQL_identifier, NEWLINE); } else isqlGlob.printf("CREATE ROLE %s;%s", XX.RDB$ROLE_NAME, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return OBJECT_NOT_FOUND; END_ERROR; } // This version of cursor gets only sql tables identified by security class // and misses views, getting only null view_source char banner[100]; sprintf(banner, "%s/* Grant permissions for this database */%s", NEWLINE, NEWLINE); bool first = true; FOR REL IN RDB$RELATIONS WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND REL.RDB$SECURITY_CLASS STARTING "SQL$" SORTED BY REL.RDB$RELATION_NAME // Null terminate name string fb_utils::exact_name(REL.RDB$RELATION_NAME); const processing_state rc = SHOW_grants2(REL.RDB$RELATION_NAME, terminator, obj_relation, first ? banner : 0); if (rc == SKIP) { first = false; } END_FOR ON_ERROR ISQL_errmsg(gds_status); return OBJECT_NOT_FOUND; END_ERROR; if (first) SHOW_grant_roles2(terminator, &first, banner); else SHOW_grant_roles(terminator, 0); // Again for stored procedures FOR PRC IN RDB$PROCEDURES SORTED BY PRC.RDB$PROCEDURE_NAME // Null terminate name string fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME); const processing_state rc = SHOW_grants2(PRC.RDB$PROCEDURE_NAME, terminator, obj_procedure, first ? banner: 0); if (rc == SKIP) first = false; END_FOR ON_ERROR ISQL_errmsg(gds_status); return OBJECT_NOT_FOUND; END_ERROR; return first_role && first ? OBJECT_NOT_FOUND : SKIP; } static void list_all_procs() { /************************************** * * l i s t _ a l l _ p r o c s * ************************************** * * Functional description * Shows text of a stored procedure given a name. * or lists procedures if no argument. * Since procedures may reference each other, we will create all * dummy procedures of the correct name, then alter these to their * correct form. * Add the parameter names when these procedures are created. * * procname -- Name of procedure to investigate * **************************************/ bool header = true; static const SCHAR* create_procedure_str1 = "CREATE PROCEDURE %s "; static const SCHAR* create_procedure_str2 = "BEGIN EXIT; END %s%s"; // First the dummy procedures // create the procedures with their parameters FOR PRC IN RDB$PROCEDURES SORTED BY PRC.RDB$PROCEDURE_NAME if (header) { isqlGlob.printf("COMMIT WORK;%s", NEWLINE); isqlGlob.printf("SET AUTODDL OFF;%s", NEWLINE); isqlGlob.printf("SET TERM %s %s%s", Procterm, isqlGlob.global_Term, NEWLINE); isqlGlob.printf("%s/* Stored procedures */%s", NEWLINE, NEWLINE); header = false; } fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (PRC.RDB$PROCEDURE_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf(create_procedure_str1, SQL_identifier); } else { isqlGlob.printf(create_procedure_str1, PRC.RDB$PROCEDURE_NAME); } get_procedure_args (PRC.RDB$PROCEDURE_NAME); isqlGlob.printf(create_procedure_str2, Procterm, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; // This query gets the procedure name and the source. We then nest a query // to retrieve the parameters. Alter is used, because the procedures are already there TEXT msg[MSG_LENGTH]; FOR PRC IN RDB$PROCEDURES SORTED BY PRC.RDB$PROCEDURE_NAME fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (PRC.RDB$PROCEDURE_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("%sALTER PROCEDURE %s ", NEWLINE, SQL_identifier); } else isqlGlob.printf("%sALTER PROCEDURE %s ", NEWLINE, PRC.RDB$PROCEDURE_NAME); get_procedure_args (PRC.RDB$PROCEDURE_NAME); // Print the procedure body if (!PRC.RDB$PROCEDURE_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &PRC.RDB$PROCEDURE_SOURCE); isqlGlob.printf(" %s%s", Procterm, NEWLINE); END_FOR ON_ERROR ISQL_msg_get(GEN_ERR, msg, SafeArg() << isc_sqlcode(gds_status)); STDERROUT(msg); // Statement failed, SQLCODE = %d\n\n ISQL_errmsg(gds_status); return; END_ERROR; // Only reset the terminators is there were procs to print if (!header) { isqlGlob.printf("SET TERM %s %s%s", isqlGlob.global_Term, Procterm, NEWLINE); isqlGlob.printf("COMMIT WORK %s%s", isqlGlob.global_Term, NEWLINE); isqlGlob.printf("SET AUTODDL ON;%s", NEWLINE); } } static void list_all_tables(LegacyTables flag, SSHORT default_char_set_id) { /************************************** * * l i s t _ a l l _ t a b l e s * ************************************** * * Functional description * Extract the names of all user tables from * rdb$relations. Filter SQL tables by * security class after we fetch them * Parameters: flag -- 0, get all tables * **************************************/ /* This version of cursor gets only sql tables identified by security class and misses views, getting only null view_source */ FOR REL IN RDB$RELATIONS WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND REL.RDB$VIEW_BLR MISSING SORTED BY REL.RDB$RELATION_NAME // If this is not an SQL table and we aren't doing ALL objects if ((REL.RDB$FLAGS.NULL || !(REL.RDB$FLAGS & REL_sql)) && (flag != ALL_objects) ) continue; // Null terminate name string fb_utils::exact_name(REL.RDB$RELATION_NAME); if (flag || !strncmp (REL.RDB$SECURITY_CLASS, "SQL$", 4)) EXTRACT_list_table (REL.RDB$RELATION_NAME, NULL, false, default_char_set_id); END_FOR ON_ERROR ISQL_errmsg(gds_status); ROLLBACK; return; END_ERROR; } static void list_all_triggers() { /************************************** * * l i s t _ a l l _ t r i g g e r s * ************************************** * * Functional description * Lists triggers in general on non-system * tables with sql source only. * **************************************/ bool header = true; // Query gets the trigger info for non-system triggers with // source that are not part of an SQL constraint. FOR TRG IN RDB$TRIGGERS WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) AND TRG.RDB$RELATION_NAME MISSING SORTED BY TRG.RDB$TRIGGER_TYPE, TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME if (header) { isqlGlob.printf("SET TERM %s %s%s", Procterm, isqlGlob.global_Term, NEWLINE); isqlGlob.printf( "%s/* Triggers only will work for SQL triggers */%s", NEWLINE, NEWLINE); header = false; } fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); if (TRG.RDB$TRIGGER_INACTIVE.NULL) TRG.RDB$TRIGGER_INACTIVE = 0; // If trigger is not SQL put it in comments if (!(TRG.RDB$FLAGS & TRG_sql)) isqlGlob.printf("/* "); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (TRG.RDB$TRIGGER_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, TRG.RDB$TRIGGER_NAME); isqlGlob.printf("CREATE TRIGGER %s %s%s %s POSITION %d %s", SQL_identifier, NEWLINE, (TRG.RDB$TRIGGER_INACTIVE ? "INACTIVE" : "ACTIVE"), trigger_action (TRG.RDB$TRIGGER_TYPE), TRG.RDB$TRIGGER_SEQUENCE, NEWLINE); if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE); isqlGlob.printf(" %s%s", Procterm, NEWLINE); isqlGlob.printf(NEWLINE); if (!(TRG.RDB$FLAGS & TRG_sql)) { isqlGlob.printf("*/%s", NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; FOR TRG IN RDB$TRIGGERS CROSS REL IN RDB$RELATIONS OVER RDB$RELATION_NAME //WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND //NOT (ANY CHK IN RDB$CHECK_CONSTRAINTS WITH //TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME) WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME if (header) { isqlGlob.printf("SET TERM %s %s%s", Procterm, isqlGlob.global_Term, NEWLINE); isqlGlob.printf( "%s/* Triggers only will work for SQL triggers */%s", NEWLINE, NEWLINE); header = false; } fb_utils::exact_name(TRG.RDB$TRIGGER_NAME); fb_utils::exact_name(TRG.RDB$RELATION_NAME); if (TRG.RDB$TRIGGER_INACTIVE.NULL) TRG.RDB$TRIGGER_INACTIVE = 0; // If trigger is not SQL put it in comments if (!(TRG.RDB$FLAGS & TRG_sql)) isqlGlob.printf("/* "); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (TRG.RDB$TRIGGER_NAME, SQL_identifier, DBL_QUOTE); ISQL_copy_SQL_id (TRG.RDB$RELATION_NAME, SQL_identifier2, DBL_QUOTE); } else { strcpy (SQL_identifier, TRG.RDB$TRIGGER_NAME); strcpy (SQL_identifier2, TRG.RDB$RELATION_NAME); } isqlGlob.printf("CREATE TRIGGER %s FOR %s %s%s %s POSITION %d %s", SQL_identifier, SQL_identifier2, NEWLINE, (TRG.RDB$TRIGGER_INACTIVE ? "INACTIVE" : "ACTIVE"), trigger_action (TRG.RDB$TRIGGER_TYPE), TRG.RDB$TRIGGER_SEQUENCE, NEWLINE); if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE); isqlGlob.printf(" %s%s", Procterm, NEWLINE); isqlGlob.printf(NEWLINE); if (!(TRG.RDB$FLAGS & TRG_sql)) { isqlGlob.printf("*/%s", NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; if (!header) { isqlGlob.printf("COMMIT WORK %s%s", Procterm, NEWLINE); isqlGlob.printf("SET TERM %s %s%s", isqlGlob.global_Term, Procterm, NEWLINE); } } static void list_check() { /************************************** * * l i s t _ c h e c k * ************************************** * * Functional description * List check constraints for all objects to allow forward references * **************************************/ // Query gets the check clauses for triggers stored for check constraints FOR TRG IN RDB$TRIGGERS CROSS CHK IN RDB$CHECK_CONSTRAINTS WITH TRG.RDB$TRIGGER_TYPE EQ 1 AND TRG.RDB$SYSTEM_FLAG EQ int(fb_sysflag_check_constraint) AND TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND (ANY RELC IN RDB$RELATION_CONSTRAINTS WITH CHK.RDB$CONSTRAINT_NAME EQ RELC.RDB$CONSTRAINT_NAME AND RELC.RDB$CONSTRAINT_TYPE EQ "CHECK") REDUCED TO CHK.RDB$CONSTRAINT_NAME SORTED BY CHK.RDB$CONSTRAINT_NAME fb_utils::exact_name(TRG.RDB$RELATION_NAME); isqlGlob.printf(NEWLINE); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (TRG.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("ALTER TABLE %s ADD %s%s", SQL_identifier, NEWLINE, TAB_AS_SPACES); } else isqlGlob.printf("ALTER TABLE %s ADD %s%s", TRG.RDB$RELATION_NAME, NEWLINE, TAB_AS_SPACES); // If the name of the constraint is not INTEG..., print it if (strncmp(CHK.RDB$CONSTRAINT_NAME, "INTEG", 5)) { fb_utils::exact_name(CHK.RDB$CONSTRAINT_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (CHK.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("CONSTRAINT %s ", SQL_identifier); } else isqlGlob.printf("CONSTRAINT %s ", CHK.RDB$CONSTRAINT_NAME); } if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_collations() { /************************************** * * l i s t _ c o l l a t i o n s * ************************************** * * Functional description * Re create all non-system collations * **************************************/ if (isqlGlob.major_ods < ODS_VERSION11) return; bool first = true; FOR CL IN RDB$COLLATIONS CROSS CS IN RDB$CHARACTER_SETS WITH CS.RDB$CHARACTER_SET_ID EQ CL.RDB$CHARACTER_SET_ID AND (CL.RDB$SYSTEM_FLAG MISSING OR CL.RDB$SYSTEM_FLAG NE 1) SORTED BY CS.RDB$CHARACTER_SET_NAME, CL.RDB$COLLATION_NAME if (first) { isqlGlob.printf( "%s/* Collations */%s", NEWLINE, NEWLINE); first = false; } isqlGlob.printf("CREATE COLLATION "); fb_utils::exact_name(CL.RDB$COLLATION_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (CL.RDB$COLLATION_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, CL.RDB$COLLATION_NAME); isqlGlob.printf("%s", SQL_identifier); fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (CS.RDB$CHARACTER_SET_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, CS.RDB$CHARACTER_SET_NAME); isqlGlob.printf(" FOR %s", SQL_identifier); if (!CL.RDB$BASE_COLLATION_NAME.NULL) { fb_utils::exact_name(CL.RDB$BASE_COLLATION_NAME); ISQL_copy_SQL_id (CL.RDB$BASE_COLLATION_NAME, SQL_identifier, SINGLE_QUOTE); isqlGlob.printf(" FROM EXTERNAL (%s)", SQL_identifier); } if (!CL.RDB$COLLATION_ATTRIBUTES.NULL) { if (CL.RDB$COLLATION_ATTRIBUTES & TEXTTYPE_ATTR_PAD_SPACE) isqlGlob.printf(" PAD SPACE"); if (CL.RDB$COLLATION_ATTRIBUTES & TEXTTYPE_ATTR_CASE_INSENSITIVE) isqlGlob.printf(" CASE INSENSITIVE"); if (CL.RDB$COLLATION_ATTRIBUTES & TEXTTYPE_ATTR_ACCENT_INSENSITIVE) isqlGlob.printf(" ACCENT INSENSITIVE"); } if (!CL.RDB$SPECIFIC_ATTRIBUTES.NULL) { isqlGlob.printf(" '"); SHOW_print_metadata_text_blob (isqlGlob.Out, &CL.RDB$SPECIFIC_ATTRIBUTES); isqlGlob.printf("'"); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; isqlGlob.printf(NEWLINE); } #ifdef NOT_USED_OR_REPLACED static void print_set(bool* set_used) { /************************************** * * p r i n t _ s e t * ************************************** * * Functional description * print the word "SET" * in the first line of the ALTER DATABASE * settings options. Also, add trailing * comma for end of prior line if needed. * * uses Print_buffer, a global * **************************************/ if (!*set_used) { isqlGlob.printf(" SET "); *set_used = true; } else { isqlGlob.printf(", %s ", NEWLINE); } } #endif static void list_create_db() { /************************************** * * l i s t _ c r e a t e _ d b * ************************************** * * Functional description * Print the create database command if requested. At least put * the page size in a comment with the extracted db name * **************************************/ static const SCHAR page_items[] = { isc_info_page_size, isc_info_end }; // Comment out the create database if no db param was specified bool nodb = false; if (!*isqlGlob.global_Target_db) { isqlGlob.printf("/* "); strcpy(isqlGlob.global_Target_db, isqlGlob.global_Db_name); nodb = true; } isqlGlob.printf("CREATE DATABASE '%s'", isqlGlob.global_Target_db); // Get the page size from db_info call SCHAR info_buf[20]; // CVC: Finally I got the idea: translate is associated with WISQL that // no longer exists. Localizing the messages means also not printing // any CRLF and therefore the output looks ugly. const bool translate = true; if (!SHOW_dbb_parameters(DB, info_buf, page_items, sizeof(page_items), translate)) { isqlGlob.printf(" %s", info_buf); } FOR DBP IN RDB$DATABASE WITH DBP.RDB$CHARACTER_SET_NAME NOT MISSING AND DBP.RDB$CHARACTER_SET_NAME != " "; isqlGlob.printf(" DEFAULT CHARACTER SET %s", fb_utils::exact_name(DBP.RDB$CHARACTER_SET_NAME)); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; if (nodb) { isqlGlob.printf(" */%s", NEWLINE); } else { isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); } // List secondary files and shadows as alter db and create shadow in comment bool first = true; FOR FIL IN RDB$FILES SORTED BY FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_SEQUENCE if (first) { isqlGlob.printf("%s/* Add secondary files in comments %s", NEWLINE, NEWLINE); } first = false; // reset nulls to zero if (FIL.RDB$FILE_FLAGS.NULL) FIL.RDB$FILE_FLAGS = 0; if (FIL.RDB$FILE_LENGTH.NULL) FIL.RDB$FILE_LENGTH = 0; if (FIL.RDB$FILE_SEQUENCE.NULL) FIL.RDB$FILE_SEQUENCE = 0; if (FIL.RDB$FILE_START.NULL) FIL.RDB$FILE_START = 0; fb_utils::exact_name(FIL.RDB$FILE_NAME); // Pure secondary files if (FIL.RDB$FILE_FLAGS == 0) { isqlGlob.printf("%sALTER DATABASE ADD FILE '%s'", NEWLINE, FIL.RDB$FILE_NAME); if (FIL.RDB$FILE_START) { isqlGlob.printf(" STARTING %ld", FIL.RDB$FILE_START); } if (FIL.RDB$FILE_LENGTH) { isqlGlob.printf(" LENGTH %ld", FIL.RDB$FILE_LENGTH); } isqlGlob.printf(NEWLINE); } if (FIL.RDB$FILE_FLAGS & FILE_shadow) { if (FIL.RDB$FILE_SEQUENCE) { isqlGlob.printf("%sFILE '%s' ", TAB_AS_SPACES, FIL.RDB$FILE_NAME); } else { isqlGlob.printf("%sCREATE SHADOW %d '%s' ", NEWLINE, FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_NAME); if (FIL.RDB$FILE_FLAGS & FILE_inactive) isqlGlob.printf("INACTIVE "); if (FIL.RDB$FILE_FLAGS & FILE_manual) isqlGlob.printf("MANUAL "); else isqlGlob.printf("AUTO "); if (FIL.RDB$FILE_FLAGS & FILE_conditional) isqlGlob.printf("CONDITIONAL "); } if (FIL.RDB$FILE_LENGTH) { isqlGlob.printf("LENGTH %ld ", FIL.RDB$FILE_LENGTH); } if (FIL.RDB$FILE_START) { isqlGlob.printf("STARTING %ld ", FIL.RDB$FILE_START); } isqlGlob.printf(NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; if (!first) { if (nodb) { isqlGlob.printf("%s */%s", NEWLINE, NEWLINE); } else { isqlGlob.printf("%s%s%s", isqlGlob.global_Term, NEWLINE, NEWLINE); } } } static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_id) { /************************************** * * l i s t _ d o m a i n _ t a b l e * ************************************** * * Functional description * List domains as identified by fields with any constraints on them * for the named table * * Parameters: table_name == only extract domains for this table * default_char_set_id -- character set def to supress * **************************************/ bool first = true; SCHAR char_sets[86]; FOR FLD IN RDB$FIELDS CROSS RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND RFR.RDB$RELATION_NAME EQ table_name SORTED BY FLD.RDB$FIELD_NAME // Skip over artificial domains if (fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && (FLD.RDB$SYSTEM_FLAG.NULL || FLD.RDB$SYSTEM_FLAG != 1)) { continue; } if (first) { isqlGlob.printf("/* Domain definitions */%s", NEWLINE); first = false; } fb_utils::exact_name(FLD.RDB$FIELD_NAME); isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME); for (int i = 0; Column_types[i].type; i++) if (FLD.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; if (isqlGlob.major_ods >= ODS_VERSION10) { // Handle Integral subtypes NUMERIC and DECIMAL if ((FLD.RDB$FIELD_TYPE == SMALLINT) || (FLD.RDB$FIELD_TYPE == INTEGER) || (FLD.RDB$FIELD_TYPE == BIGINT)) { /* We are ODS >= 10 and could be any Dialect */ FOR FLD1 IN RDB$FIELDS WITH FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME if (!FLD1.RDB$FIELD_PRECISION.NULL) { /* We are Dialect >=3 since FIELD_PRECISION is non-NULL */ if (FLD1.RDB$FIELD_SUB_TYPE > 0 && FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) { sprintf (Print_buffer, "%s(%d, %d)", Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE], FLD1.RDB$FIELD_PRECISION, -FLD1.RDB$FIELD_SCALE); precision_known = true; } } END_FOR ON_ERROR ISQL_errmsg (isc_status); return; END_ERROR; } } if (!precision_known) { // Take a stab at numerics and decimals if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE); } else { sprintf (Print_buffer, "%s", Column_types[i].type_name); } } isqlGlob.prints(Print_buffer); break; } if (FLD.RDB$FIELD_TYPE == BLOB) { const int subtype = FLD.RDB$FIELD_SUB_TYPE; isqlGlob.printf(" SUB_TYPE "); if ((subtype > 0) && (subtype <= MAX_BLOBSUBTYPES)) { isqlGlob.prints(Sub_types[subtype]); } else { isqlGlob.printf("%d", subtype); } isqlGlob.printf(" SEGMENT SIZE %u", (USHORT) FLD.RDB$SEGMENT_LENGTH); } else if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { // Length for chars isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); } /* Bug 8261: do not show the collation information just yet! If you do, then the domain syntax when printed is not correct */ /* since the character set is part of the field type, display that information now. */ if (!FLD.RDB$CHARACTER_SET_ID.NULL) { char_sets[0] = 0; if ((FLD.RDB$CHARACTER_SET_ID != default_char_set_id) || (!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0)) { ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, 0, false, char_sets); } if (char_sets[0]) isqlGlob.prints(char_sets); } if (!FLD.RDB$DIMENSIONS.NULL) ISQL_array_dimensions (FLD.RDB$FIELD_NAME); if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); } if (!FLD.RDB$VALIDATION_SOURCE.NULL) { isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); ISQL_print_validation (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE, false, gds_trans); } if (FLD.RDB$NULL_FLAG == 1) isqlGlob.printf(" NOT NULL"); // Bug 8261: Now show the collation order information /* Show the collation order if one has been specified. If the collation order is the default for the character set being used, then no collation order will be shown ( because it isn't needed ). If the collation id is 0, then the default for the character set is being used so there is no need to retrieve the collation information.*/ if (!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0) { char_sets[0] = 0; ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, true, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_domains(SSHORT default_char_set_id) { /************************************** * * l i s t _ d o m a i n s * ************************************** * * Functional description * List domains * * Parameters: * default_char_set_id -- character set def to supress * **************************************/ bool first = true; SCHAR char_sets[86]; FOR FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND FLD.RDB$SYSTEM_FLAG NE 1 SORTED BY FLD.RDB$FIELD_NAME if (first) { isqlGlob.printf("/* Domain definitions */%s", NEWLINE); first = false; } fb_utils::exact_name(FLD.RDB$FIELD_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id(FLD.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("CREATE DOMAIN %s AS ", SQL_identifier); } else isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME); // Get domain type for (int i = 0; Column_types[i].type; i++) if (FLD.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; if (isqlGlob.major_ods >= ODS_VERSION10) { // Handle Integral subtypes NUMERIC and DECIMAL if ((FLD.RDB$FIELD_TYPE == SMALLINT) || (FLD.RDB$FIELD_TYPE == INTEGER) || (FLD.RDB$FIELD_TYPE == BIGINT)) { /* We are ODS >= 10 and could be any Dialect */ FOR FLD1 IN RDB$FIELDS WITH FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME if (!FLD1.RDB$FIELD_PRECISION.NULL) { /* We are Dialect >=3 since FIELD_PRECISION is non-NULL */ if (FLD1.RDB$FIELD_SUB_TYPE > 0 && FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) { sprintf (Print_buffer, "%s(%d, %d)", Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE], FLD1.RDB$FIELD_PRECISION, -FLD1.RDB$FIELD_SCALE); precision_known = true; } } END_FOR ON_ERROR ISQL_errmsg (isc_status); return; END_ERROR; } } if (!precision_known) { // Take a stab at numerics and decimals if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE); } else { sprintf (Print_buffer, "%s", Column_types[i].type_name); } } isqlGlob.prints(Print_buffer); break; } if (FLD.RDB$FIELD_TYPE == BLOB) { const int subtype = FLD.RDB$FIELD_SUB_TYPE; isqlGlob.printf(" SUB_TYPE "); if ((subtype > 0) && (subtype <= MAX_BLOBSUBTYPES)) { isqlGlob.prints(Sub_types[subtype]); } else { isqlGlob.printf("%d", subtype); } isqlGlob.printf(" SEGMENT SIZE %u", (USHORT) FLD.RDB$SEGMENT_LENGTH); } else if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { // Length for chars isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); } /* Bug 8261: do not show the collation information just yet! If you do, then the domain syntax when printed is not correct */ /* since the character set is part of the field type, display that information now. */ if (!FLD.RDB$CHARACTER_SET_ID.NULL) { char_sets[0] = 0; if ((FLD.RDB$CHARACTER_SET_ID != default_char_set_id) || (!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0)) { ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, 0, false, char_sets); } if (char_sets[0]) isqlGlob.prints(char_sets); } if (!FLD.RDB$DIMENSIONS.NULL) ISQL_array_dimensions (FLD.RDB$FIELD_NAME); if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); } if (!FLD.RDB$VALIDATION_SOURCE.NULL) { isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); ISQL_print_validation (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE, false, gds_trans); } if (FLD.RDB$NULL_FLAG == 1) isqlGlob.printf(" NOT NULL"); // Bug 8261: Now show the collation order information /* Show the collation order if one has been specified. If the collation order is the default for the character set being used, then no collation order will be shown ( because it isn't needed If the collation id is 0, then the default for the character set is being used so there is no need to retrieve the collation information.*/ if (!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0) { char_sets[0] = 0; ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, true, char_sets); if (char_sets[0]) isqlGlob.prints(char_sets); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_exception() { /************************************** * * l i s t _ e x c e p t i o n * ************************************** * * Functional description * List all exceptions defined in the database * * Parameters: none * **************************************/ bool first = true; FOR EXC IN RDB$EXCEPTIONS SORTED BY EXC.RDB$EXCEPTION_NAME if (first) { isqlGlob.printf("%s/* Exceptions */%s", NEWLINE, NEWLINE); } first = false; fb_utils::exact_name(EXC.RDB$EXCEPTION_NAME); ISQL_copy_SQL_id (EXC.RDB$MESSAGE, SQL_identifier2, SINGLE_QUOTE); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (EXC.RDB$EXCEPTION_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("CREATE EXCEPTION %s %s%s%s", SQL_identifier, SQL_identifier2, isqlGlob.global_Term, NEWLINE); } else isqlGlob.printf("CREATE EXCEPTION %s %s%s%s", EXC.RDB$EXCEPTION_NAME, SQL_identifier2, isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_filters() { /************************************** * * l i s t _ f i l t e r s * ************************************** * * Functional description * List all blob filters * * Parameters: none * Results in * DECLARE FILTER INPUT_TYPE OUTPUT_TYPE * ENTRY_POINT MODULE_NAME **************************************/ bool first = true; FOR FIL IN RDB$FILTERS SORTED BY FIL.RDB$FUNCTION_NAME fb_utils::exact_name(FIL.RDB$FUNCTION_NAME); fb_utils::exact_name(FIL.RDB$MODULE_NAME); fb_utils::exact_name(FIL.RDB$ENTRYPOINT); if (first) { isqlGlob.printf("%s/* BLOB Filter declarations */%s", NEWLINE, NEWLINE); } first = false; isqlGlob.printf("DECLARE FILTER %s INPUT_TYPE %d OUTPUT_TYPE %d%s%sENTRY_POINT '%s' MODULE_NAME '%s'%s%s%s", FIL.RDB$FUNCTION_NAME, FIL.RDB$INPUT_SUB_TYPE, FIL.RDB$OUTPUT_SUB_TYPE, NEWLINE, TAB_AS_SPACES, FIL.RDB$ENTRYPOINT, FIL.RDB$MODULE_NAME, isqlGlob.global_Term, NEWLINE, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_foreign() { /************************************** * * l i s t _ f o r e i g n * ************************************** * * Functional description * List all foreign key constraints and alter the tables * **************************************/ SCHAR collist[BUFFER_LENGTH512 * 2]; /* Static queries for obtaining foreign constraints, where RELC1 is the foreign key constraints, RELC2 is the primary key lookup and REFC is the join table */ FOR RELC1 IN RDB$RELATION_CONSTRAINTS CROSS RELC2 IN RDB$RELATION_CONSTRAINTS CROSS REFC IN RDB$REF_CONSTRAINTS WITH RELC1.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY" AND REFC.RDB$CONST_NAME_UQ EQ RELC2.RDB$CONSTRAINT_NAME AND REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME AND (RELC2.RDB$CONSTRAINT_TYPE EQ "UNIQUE" OR RELC2.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY") SORTED BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME fb_utils::exact_name(RELC1.RDB$RELATION_NAME); fb_utils::exact_name(RELC2.RDB$RELATION_NAME); ISQL_get_index_segments (collist, sizeof(collist), RELC1.RDB$INDEX_NAME, true); isqlGlob.printf(NEWLINE); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (RELC1.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("ALTER TABLE %s ADD ", SQL_identifier); } else isqlGlob.printf("ALTER TABLE %s ADD ", RELC1.RDB$RELATION_NAME); /* If the name of the constraint is not INTEG..., print it. INTEG... are internally generated names. */ if (!RELC1.RDB$CONSTRAINT_NAME.NULL && strncmp(RELC1.RDB$CONSTRAINT_NAME, "INTEG", 5)) { ISQL_truncate_term (RELC1.RDB$CONSTRAINT_NAME, strlen(RELC1.RDB$CONSTRAINT_NAME)); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (RELC1.RDB$CONSTRAINT_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("CONSTRAINT %s ", SQL_identifier); } else isqlGlob.printf("CONSTRAINT %s ", RELC1.RDB$CONSTRAINT_NAME); } if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (RELC2.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); isqlGlob.printf("FOREIGN KEY (%s) REFERENCES %s ", collist, SQL_identifier); } else isqlGlob.printf("FOREIGN KEY (%s) REFERENCES %s ", collist, RELC2.RDB$RELATION_NAME); // Get the column list for the primary key ISQL_get_index_segments (collist, sizeof(collist), RELC2.RDB$INDEX_NAME, true); isqlGlob.printf("(%s)", collist); // Add the referential actions, if any if (!REFC.RDB$UPDATE_RULE.NULL) { ISQL_truncate_term (REFC.RDB$UPDATE_RULE, strlen(REFC.RDB$UPDATE_RULE)); ISQL_ri_action_print (REFC.RDB$UPDATE_RULE, " ON UPDATE", true); } if (!REFC.RDB$DELETE_RULE.NULL) { ISQL_truncate_term (REFC.RDB$DELETE_RULE, strlen(REFC.RDB$DELETE_RULE)); ISQL_ri_action_print (REFC.RDB$DELETE_RULE, " ON DELETE", true); } isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_functions() { /************************************** * * l i s t _ f u n c t i o n s * ************************************** * * Functional description * List all external functions * * Parameters: none * Results in * DECLARE EXTERNAL FUNCTION function_name * CHAR(256) , INTEGER, .... * RETURNS INTEGER BY VALUE * ENTRY_POINT entrypoint MODULE_NAME module; **************************************/ char type_buffer[BUFFER_LENGTH128]; char return_buffer[BUFFER_LENGTH128]; bool first = true; FOR FUN IN RDB$FUNCTIONS WITH FUN.RDB$SYSTEM_FLAG NE 1 OR FUN.RDB$SYSTEM_FLAG MISSING SORTED BY FUN.RDB$FUNCTION_NAME fb_utils::exact_name(FUN.RDB$FUNCTION_NAME); fb_utils::exact_name(FUN.RDB$MODULE_NAME); fb_utils::exact_name(FUN.RDB$ENTRYPOINT); if (first) { isqlGlob.printf("%s/* External Function declarations */%s", NEWLINE, NEWLINE); first = false; } if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id(FUN.RDB$FUNCTION_NAME, SQL_identifier, DBL_QUOTE); else strcpy(SQL_identifier, FUN.RDB$FUNCTION_NAME); // Start new function declaration isqlGlob.printf("DECLARE EXTERNAL FUNCTION %s %s", SQL_identifier, NEWLINE); bool firstarg = true; FOR FNA IN RDB$FUNCTION_ARGUMENTS WITH FUN.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME SORTED BY FNA.RDB$ARGUMENT_POSITION // Find parameter type int i = 0; while (FNA.RDB$FIELD_TYPE != Column_types[i].type) i++; // Print length where appropriate if ((FNA.RDB$FIELD_TYPE == T_CHAR) || (FNA.RDB$FIELD_TYPE == VARCHAR) || (FNA.RDB$FIELD_TYPE == CSTRING)) { bool did_charset = false; FOR CHARSET IN RDB$CHARACTER_SETS WITH CHARSET.RDB$CHARACTER_SET_ID = FNA.RDB$CHARACTER_SET_ID did_charset = true; fb_utils::exact_name(CHARSET.RDB$CHARACTER_SET_NAME); sprintf (type_buffer, "%s(%d) CHARACTER SET %s", Column_types[i].type_name, (FNA.RDB$FIELD_LENGTH / MAX (1, CHARSET.RDB$BYTES_PER_CHARACTER)), CHARSET.RDB$CHARACTER_SET_NAME); END_FOR ON_ERROR ISQL_errmsg (gds_status); return; END_ERROR; if (!did_charset) sprintf (type_buffer, "%s(%d)", Column_types[i].type_name, FNA.RDB$FIELD_LENGTH); } else { bool precision_known = false; if ( (isqlGlob.major_ods >= ODS_VERSION10) && ((FNA.RDB$FIELD_TYPE == SMALLINT) || (FNA.RDB$FIELD_TYPE == INTEGER) || (FNA.RDB$FIELD_TYPE == BIGINT))) { FOR FNA1 IN RDB$FUNCTION_ARGUMENTS WITH FNA1.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME AND FNA1.RDB$ARGUMENT_POSITION EQ FNA.RDB$ARGUMENT_POSITION /* We are ODS >= 10 and could be any Dialect */ if (!FNA1.RDB$FIELD_PRECISION.NULL) { /* We are Dialect >=3 since FIELD_PRECISION is non-NULL */ if (FNA1.RDB$FIELD_SUB_TYPE > 0 && FNA1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) { sprintf (type_buffer, "%s(%d, %d)", Integral_subtypes[FNA1.RDB$FIELD_SUB_TYPE], FNA1.RDB$FIELD_PRECISION, -FNA1.RDB$FIELD_SCALE); precision_known = true; } } // if field_precision is not null END_FOR ON_ERROR ISQL_errmsg (isc_status); return; END_ERROR; } /* if isqlGlob.major_ods >= ods_version10 && */ if (!precision_known) { // Take a stab at numerics and decimals if ((FNA.RDB$FIELD_TYPE == SMALLINT) && (FNA.RDB$FIELD_SCALE < 0)) { sprintf (type_buffer, "NUMERIC(4, %d)", -FNA.RDB$FIELD_SCALE); } else if ((FNA.RDB$FIELD_TYPE == INTEGER) && (FNA.RDB$FIELD_SCALE < 0)) { sprintf (type_buffer, "NUMERIC(9, %d)", -FNA.RDB$FIELD_SCALE); } else if ((FNA.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FNA.RDB$FIELD_SCALE < 0)) { sprintf (type_buffer, "NUMERIC(15, %d)", -FNA.RDB$FIELD_SCALE); } else sprintf (type_buffer, "%s", Column_types[i].type_name); } // if !precision_known } // if T_CHAR or VARCHAR or CSTRING ... else // If a return argument, save it for the end, otherwise print /* * Changed the following to not return a BLOB by value. * To be sincere, this code doesn't cater for the RETURNS PARAMETER syntax but * it would require more surgery than I'm willing to do, since I'm sick of isql * so I started my own metadata extraction utility based on IBO that does this * trick and others. * Claudio Valderrama (by way of) MOD 23-Apr-2001 CVC: Finally enhanced the UDF metadata extraction. */ int ptype = (int) abs(FNA.RDB$MECHANISM); if (ptype > MAX_UDFPARAM_TYPES) ptype = MAX_UDFPARAM_TYPES; bool printarg = true; if (FUN.RDB$RETURN_ARGUMENT == FNA.RDB$ARGUMENT_POSITION) { if (FUN.RDB$RETURN_ARGUMENT) { sprintf (return_buffer, "RETURNS PARAMETER %d", FUN.RDB$RETURN_ARGUMENT); } else { sprintf (return_buffer, "RETURNS %s%s %s", type_buffer, UDF_param_types[ptype], (FNA.RDB$MECHANISM < 0 ? "FREE_IT" : "")); printarg = false; } } if (printarg) { // First arg needs no comma isqlGlob.printf("%s%s%s", (firstarg ? "" : ", "), type_buffer, UDF_param_types[ptype]); firstarg = false; } END_FOR ON_ERROR ISQL_errmsg (gds_status); return; END_ERROR; // Print the return type -- All functions return a type isqlGlob.printf("%s%s%s", NEWLINE, return_buffer, NEWLINE); // Print out entrypoint information isqlGlob.printf("ENTRY_POINT '%s' MODULE_NAME '%s'%s%s%s", FUN.RDB$ENTRYPOINT, FUN.RDB$MODULE_NAME, isqlGlob.global_Term, NEWLINE, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_generators() { /************************************** * * l i s t _ g e n e r a t o r s * ************************************** * * Functional description * Re create all non-system generators * **************************************/ bool first = true; FOR GEN IN RDB$GENERATORS WITH GEN.RDB$GENERATOR_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND GEN.RDB$GENERATOR_NAME NOT MATCHING "SQL$+" USING "+=[0-9][0-9]* *" AND (GEN.RDB$SYSTEM_FLAG MISSING OR GEN.RDB$SYSTEM_FLAG NE 1) SORTED BY GEN.RDB$GENERATOR_NAME if (first) { isqlGlob.printf( "%s/* Generators or sequences */%s", NEWLINE, NEWLINE); first = false; } fb_utils::exact_name(GEN.RDB$GENERATOR_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (GEN.RDB$GENERATOR_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, GEN.RDB$GENERATOR_NAME); isqlGlob.printf("CREATE GENERATOR %s%s%s", SQL_identifier, isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; isqlGlob.printf(NEWLINE); } static void list_index() { /************************************** * * l i s t _ i n d e x * ************************************** * * Functional description * Define all non-constraint indices * Use a static SQL query to get the info and print it. * * Uses get_index_segment to provide a key list for each index * **************************************/ char collist[BUFFER_LENGTH512 * 2]; bool first = true; FOR IDX IN RDB$INDICES CROSS RELC IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH (RELC.RDB$SYSTEM_FLAG NE 1 OR RELC.RDB$SYSTEM_FLAG MISSING) AND NOT (ANY RC IN RDB$RELATION_CONSTRAINTS WITH RC.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME) SORTED BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME if (first) { isqlGlob.printf( "%s/* Index definitions for all user tables */%s", NEWLINE, NEWLINE); first = false; } // Strip trailing blanks fb_utils::exact_name(IDX.RDB$RELATION_NAME); fb_utils::exact_name(IDX.RDB$INDEX_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (IDX.RDB$INDEX_NAME, SQL_identifier, DBL_QUOTE); ISQL_copy_SQL_id (IDX.RDB$RELATION_NAME, SQL_identifier2, DBL_QUOTE); isqlGlob.printf("CREATE%s%s INDEX %s ON %s", (IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""), (IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""), SQL_identifier, SQL_identifier2); } else isqlGlob.printf("CREATE%s%s INDEX %s ON %s", (IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""), (IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""), IDX.RDB$INDEX_NAME, IDX.RDB$RELATION_NAME); // Get index expression or column names if (!IDX.RDB$EXPRESSION_BLR.NULL) { isqlGlob.printf(" COMPUTED BY "); if (!IDX.RDB$EXPRESSION_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &IDX.RDB$EXPRESSION_SOURCE); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); } else if (ISQL_get_index_segments (collist, sizeof(collist), IDX.RDB$INDEX_NAME, true)) { isqlGlob.printf(" (%s)%s%s", collist, isqlGlob.global_Term, NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; } static void list_views() { /************************************** * * l i s t _ v i e w s * ************************************** * * Functional description * Show text of views. * Use a SQL query to get the info and print it. * Note: This should also contain check option * **************************************/ // If this is a view, use print_blob to print the view text FOR REL IN RDB$RELATIONS WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND REL.RDB$VIEW_BLR NOT MISSING AND REL.RDB$FLAGS = REL_sql SORTED BY REL.RDB$RELATION_ID bool first = true; fb_utils::exact_name(REL.RDB$RELATION_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (REL.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, REL.RDB$RELATION_NAME); fb_utils::exact_name(REL.RDB$OWNER_NAME); isqlGlob.printf("%s/* View: %s, Owner: %s */%s", NEWLINE, REL.RDB$RELATION_NAME, REL.RDB$OWNER_NAME, NEWLINE); isqlGlob.printf("CREATE VIEW %s (", SQL_identifier); // Get column list FOR RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME SORTED BY RFR.RDB$FIELD_POSITION fb_utils::exact_name(RFR.RDB$FIELD_NAME); if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (RFR.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, RFR.RDB$FIELD_NAME); isqlGlob.printf("%s%s", (first ? "" : ", "), SQL_identifier); first = false; END_FOR ON_ERROR ISQL_errmsg (gds_status); return; END_ERROR; isqlGlob.printf(") AS%s", NEWLINE); if (!REL.RDB$VIEW_SOURCE.NULL) SHOW_print_metadata_text_blob (isqlGlob.Out, &REL.RDB$VIEW_SOURCE); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(gds_status); return; END_ERROR; }