/* * PROGRAM: Interactive SQL utility * MODULE: show.epp * DESCRIPTION: Display 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): ______________________________________. * $Id: show.epp,v 1.42 2004-04-26 07:54:16 brodsom Exp $ * Revision 1.2 2000/11/19 07:02:49 fsg * Change in show.e to use CHARACTER_LENGTH instead of FIELD_LENGTH in * SHOW PROCEDURE * * 19-May-2001 Claudio Valderrama. * Change to be in sync with extract.e: BLOB is not returned * by value but by descriptor. * 2001.09.21 Claudio Valderrama: Show correct mechanism for UDF parameters. * 2001.10.01 Claudio Valderrama: SHOW GRANTS works without any argument, too. * Metadata extraction is slightly faster if SHOW_grants() knows the obj_type. * Keyword USER is written when the grantee is a user and since the engine * now supports GRANT...to ROLE role_name, ROLE is written when the grantee is * indeed a role. When the grantee is a group, it's shown, too. * 2003.02.04 Dmitry Yemanov: support for universal triggers */ #include "firebird.h" #include "../jrd/ib_stdio.h" #include "../jrd/license.h" #include #include "../jrd/gds_proto.h" #include "../jrd/common.h" #include "../jrd/y_ref.h" #include "../jrd/ibase.h" #include "../isql/isql.h" #include "../jrd/constants.h" #include "../jrd/intl.h" #include "../isql/isql_proto.h" #include "../isql/show_proto.h" #include "../jrd/obj.h" #include "../jrd/ods.h" #include "../isql/extra_proto.h" #include "../common/utils_proto.h" #ifdef HAVE_CTYPE_H #include #endif DATABASE DB = EXTERN COMPILETIME "yachts.lnk"; extern USHORT major_ods; extern USHORT minor_ods; static void local_fprintf(void*, const char*); static void remove_delimited_double_quotes(TEXT*); static void make_priv_string(USHORT, char*); static processing_state show_all_tables(SSHORT); static void show_charsets(const SCHAR*, const SCHAR*, const bool, bool, bool, bool); static processing_state show_check(const SCHAR*); static void show_db(); static processing_state show_dialect(); static processing_state show_domains(const SCHAR*); static processing_state show_exceptions(const SCHAR*); static processing_state show_filters(const SCHAR*); static processing_state show_functions(const SCHAR*); static processing_state show_generators(const SCHAR*); static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT); static processing_state show_indices(const SCHAR* const*); static processing_state show_proc(const SCHAR*); static processing_state show_role(const SCHAR*); static processing_state show_table(const SCHAR*, bool); static processing_state show_trigger(const SCHAR*, bool, bool); const char* spaces = " "; static TEXT Print_buffer[512]; static TEXT SQL_identifier[BUFFER_LENGTH128]; static TEXT SQL_id_for_grant[BUFFER_LENGTH128]; // Initialize types static const SCHAR* Object_types[] = { "Table", "View", "Trigger", "Computed column", "Validation", "Procedure", "Expression index", "Exception", "User", "Domain", "Index", "Count [error if used]", "User group", "SQL role", "Generator", "User Defined Function" }; extern const sqltypes Column_types[] = { {SMALLINT, "SMALLINT"}, // NTX: keyword {INTEGER, "INTEGER"}, // NTX: keyword {QUAD, "QUAD"}, // NTX: keyword {T_FLOAT, "FLOAT"}, // NTX: keyword {T_CHAR, "CHAR"}, // NTX: keyword {DOUBLE_PRECISION, "DOUBLE PRECISION"}, // NTX: keyword {VARCHAR, "VARCHAR"}, // NTX: keyword {CSTRING, "CSTRING"}, // NTX: keyword {BLOB_ID, "BLOB_ID"}, // NTX: keyword {BLOB, "BLOB"}, // NTX: keyword {blr_sql_time, "TIME"}, // NTX: keyword {blr_sql_date, "DATE"}, // NTX: keyword {blr_timestamp, "TIMESTAMP"}, // NTX: keyword {blr_int64, "BIGINT"}, // NTX: keyword {0, ""} }; // Integral subtypes const int MAX_INTSUBTYPES = 2; const SCHAR* Integral_subtypes[] = { "UNKNOWN", // Defined type, NTX: keyword "NUMERIC", // NUMERIC, NTX: keyword "DECIMAL" // DECIMAL, NTX: keyword }; // Blob subtypes const int MAXSUBTYPES = 8; const SCHAR* Sub_types[] = { "UNKNOWN", // NTX: keyword "TEXT", // NTX: keyword "BLR", // NTX: keyword "ACL", // NTX: keyword "RANGES", // NTX: keyword "SUMMARY", // NTX: keyword "FORMAT", // NTX: keyword "TRANSACTION_DESCRIPTION", // NTX: keyword "EXTERNAL_FILE_DESCRIPTION" // NTX: keyword }; const SCHAR* Trigger_prefix_types[] = { "BEFORE", // NTX: keyword "AFTER" // NTX: keyword }; const SCHAR* Trigger_suffix_types[] = { "", "INSERT", // NTX: keyword "UPDATE", // NTX: keyword "DELETE" // NTX: keyword }; /* CVC: Notice that BY REFERENCE is the default for scalars and can't be specified explicitly; BY ISC_DESCRIPTOR is the default for BLOBs and can't be used explicitly; BY SCALAR_ARRAY_DESCRIPTOR should be supported in DSQL in the future, since the server has already the capability to deliver arrays to UDFs. */ const int MAX_UDFPARAM_TYPES = 4; const SCHAR* UDF_param_types[] = { " BY VALUE", // NTX: keyword "", // BY REFERENCE " BY DESCRIPTOR", // NTX: keyword in FB "", /* BY ISC_DESCRIPTOR => BLOB */ " BY SCALAR ARRAY DESCRIPTOR" // Should be NTX: keyword " ERROR-type-unknown" }; enum priv_flag { priv_UNKNOWN = 1, priv_SELECT = 2, priv_INSERT = 4, priv_UPDATE = 8, priv_DELETE = 16, priv_EXECUTE = 32, priv_REFERENCES = 64 }; static const struct { USHORT priv_flag; const char* priv_string; } privs[] = { { priv_DELETE, "DELETE"}, // NTX: keyword { priv_EXECUTE, "EXECUTE"}, // NTX: keyword { priv_INSERT, "INSERT"}, // NTX: keyword { priv_SELECT, "SELECT"}, // NTX: keyword { priv_UPDATE, "UPDATE"}, // NTX: keyword { priv_REFERENCES, "REFERENCES"}, // NTX: keyword { 0, NULL} }; /* strlen of each element above, + strlen(", ") for separators */ const int MAX_PRIV_LIST = (6 + 2 + 7 + 2 + 6 + 2 + 6 + 2 + 6 + 2 + 10 + 1); static const SCHAR db_dialect_info[] = { isc_info_db_sql_dialect, isc_info_end }; // Added support to display FORCED WRITES status. - PR 27-NOV-2001 // Added support to display transaction info when next_transaction id is fixed. static const SCHAR db_items[] = { isc_info_page_size, isc_info_db_size_in_pages, isc_info_sweep_interval, isc_info_limbo, isc_info_forced_writes, isc_info_oldest_transaction, isc_info_oldest_active, isc_info_oldest_snapshot, isc_info_next_transaction, isc_info_end }; /* BPB to force transliteration of any shown system blobs from * Database character set (CS_METADATA) to process character set * (CS_dynamic). * This same BPB is safe to use for both V3 & V4 db's - as * a V3 db will ignore the source_ & target_interp values. */ static const UCHAR metadata_text_bpb[] = { isc_bpb_version1, isc_bpb_source_type, 1, BLOB_text, isc_bpb_target_type, 1, BLOB_text, isc_bpb_source_interp, 1, CS_METADATA, isc_bpb_target_interp, 1, CS_dynamic }; // trigger action helpers #define TRIGGER_ACTION_PREFIX(value) \ ((value + 1) & 1) #define TRIGGER_ACTION_SUFFIX(value, slot) \ (((value + 1) >> (slot * 2 - 1)) & 3) const char* trigger_action(int type) { static char buffer[256]; int prefix = TRIGGER_ACTION_PREFIX(type); strcpy(buffer, Trigger_prefix_types[prefix]); int suffix = TRIGGER_ACTION_SUFFIX(type, 1); strcat(buffer, " "); strcat(buffer, Trigger_suffix_types[suffix]); if ( (suffix = TRIGGER_ACTION_SUFFIX(type, 2)) ) { strcat(buffer, " OR "); strcat(buffer, Trigger_suffix_types[suffix]); } if ( (suffix = TRIGGER_ACTION_SUFFIX(type, 3)) ) { strcat(buffer, " OR "); strcat(buffer, Trigger_suffix_types[suffix]); } return buffer; } bool SHOW_dbb_parameters(FRBRD* db_handle, SCHAR* info_buf, const SCHAR* db_items, USHORT item_length, bool translate) { /************************************** * * S H O W _ d b b _ p a r a m e t e r s * ************************************** * * Functional description * Show db_info on this database * * Arguments: * db_handle -- database handle * info_buf -- info_bufput file pointer * db_items -- list of db_info items to process * **************************************/ SCHAR* buffer = (SCHAR*) ISQL_ALLOC(BUFFER_LENGTH128); if (!buffer) { isc_status[0] = isc_arg_gds; isc_status[1] = isc_virmemexh; isc_status[2] = isc_arg_end; ISQL_errmsg(isc_status); return false; } TEXT* msg = (SCHAR*) ISQL_ALLOC(MSG_LENGTH); if (!msg) { isc_status[0] = isc_arg_gds; isc_status[1] = isc_virmemexh; isc_status[2] = isc_arg_end; ISQL_errmsg(isc_status); ISQL_FREE(buffer); return false; } ISC_STATUS_ARRAY status_vector; if (isc_database_info(status_vector, &db_handle, item_length, db_items, BUFFER_LENGTH128, buffer)) { ISQL_errmsg(status_vector); ISQL_FREE (buffer); ISQL_FREE (msg); return false; } *info_buf = '\0'; SCHAR* info = info_buf; for (const SCHAR* d = buffer; *d != isc_info_end;) { SLONG value_out = 0; const SCHAR item = *d++; const int length = isc_vax_integer(d, 2); d += 2; /* * This is not the best solution but it fixes the lack of characters * in Windows ISQL. This will need to remain until we modify the messages * to remove the '\n' (on the PC its '\n\r'). */ switch (item) { case isc_info_end: break; case isc_info_page_size: value_out = isc_vax_integer(d, length); sprintf(info, "PAGE_SIZE %ld %s", value_out, NEWLINE); break; case isc_info_db_size_in_pages: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(NUMBER_PAGES, msg, (TEXT*) (IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Number of DB pages allocated = %ld %s", value_out, NEWLINE); break; case isc_info_sweep_interval: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(SWEEP_INTERV, msg, (TEXT*)(IPTR) value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Sweep interval = %ld %s", value_out, NEWLINE); break; case isc_info_forced_writes: value_out = isc_vax_integer (d, length); sprintf (info, "Forced Writes are %s %s", (value_out==1 ? "ON" : "OFF"), NEWLINE); break; case isc_info_oldest_transaction : value_out = isc_vax_integer (d, length); sprintf (info, "Transaction - oldest = %ld %s", value_out, NEWLINE); break; case isc_info_oldest_active : value_out = isc_vax_integer (d, length); sprintf (info, "Transaction - oldest active = %ld %s", value_out, NEWLINE); break; case isc_info_oldest_snapshot : value_out = isc_vax_integer (d, length); sprintf (info, "Transaction - oldest snapshot = %ld %s", value_out, NEWLINE); break; case isc_info_next_transaction : value_out = isc_vax_integer (d, length); sprintf (info, "Transaction - Next = %ld %s", value_out, NEWLINE); break; #ifdef NOT_USED_OR_REPLACED // IGNORE WAL case isc_info_num_wal_buffers: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(NUM_WAL_BUFF, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Number of wal buffers = %ld %s", value_out, NEWLINE); break; case isc_info_wal_buffer_size: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(WAL_BUFF_SIZE, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Wal buffer size = %ld %s", value_out, NEWLINE); break; case isc_info_wal_ckpt_length: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(CKPT_LENGTH, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Check point length = %ld %s", value_out, NEWLINE); break; case isc_info_wal_cur_ckpt_interval: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(CKPT_INTERV, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Check point interval = %ld %s", value_out, NEWLINE); break; case isc_info_wal_grpc_wait_usecs: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(WAL_GRPC_WAIT, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Wal group commit wait = %ld %s", value_out, NEWLINE); break; #endif case isc_info_base_level: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(BASE_LEVEL, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Base level = %ld %s", value_out, NEWLINE); break; case isc_info_limbo: value_out = isc_vax_integer(d, length); if (translate) { ISQL_msg_get(LIMBO, msg, (TEXT*)(IPTR)value_out, NULL, NULL, NULL, NULL); sprintf(info, msg); } else sprintf(info, "Transaction in limbo = %ld %s", value_out, NEWLINE); break; } d += length; info += strlen(info); } ISQL_FREE(buffer); ISQL_FREE(msg); return true; } processing_state SHOW_grants(SCHAR* object, const SCHAR* terminator, USHORT obj_type) { /************************************** * * S H O W _ g r a n t s * ************************************** * * Functional description * Placeholder for SHOW_grants2 without additional message. * **************************************/ return SHOW_grants2 (object, terminator, obj_type, NULL); } processing_state SHOW_grants2 (SCHAR* object, const SCHAR* terminator, USHORT obj_type, const TEXT* optional_msg) { /************************************** * * S H O W _ g r a n t s 2 * ************************************** * * Functional description * Show grants for given object name * This function is also called by extract for privileges. * It must extract granted privileges on tables/views to users, * - these may be compound, so put them on the same line. * Grant execute privilege on procedures to users * Grant various privilegs to procedures. * All privileges may have the with_grant option set. * The optional msg is to display a customized message. When the * new feature of all grants is used, there's no way to print the * header message after this routine, so it should be printed here. * **************************************/ BASED_ON RDB$USER_PRIVILEGES.RDB$USER prev_user; BASED_ON RDB$USER_PRIVILEGES.RDB$GRANT_OPTION prev_option; BASED_ON RDB$USER_PRIVILEGES.RDB$FIELD_NAME prev_field; SCHAR user_string[44]; bool first = true; if (!*object) return ERR; // Query against user_privileges instead of looking at rdb$security_classes prev_option = -1; prev_user[0] = '\0'; prev_field[0] = '\0'; char priv_string[MAX_PRIV_LIST] = ""; char col_string[BUFFER_LENGTH128] = ""; char with_option[18] = ""; USHORT priv_flags = 0; SSHORT prev_field_null = -1; if (obj_type == obj_relation || obj_type == 255) { // Find the user specified relation and show its privileges FOR FIRST 1 R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ object; // This query only finds tables, eliminating owner privileges FOR PRV IN RDB$USER_PRIVILEGES CROSS REL IN RDB$RELATIONS WITH PRV.RDB$RELATION_NAME EQ object AND REL.RDB$RELATION_NAME EQ object AND PRV.RDB$PRIVILEGE NE 'M' AND REL.RDB$OWNER_NAME NE PRV.RDB$USER SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION; fb_utils::fb_exact_name(PRV.RDB$USER); // Sometimes grant options are null, sometimes 0. Both same if (PRV.RDB$GRANT_OPTION.NULL) PRV.RDB$GRANT_OPTION = 0; if (PRV.RDB$FIELD_NAME.NULL) PRV.RDB$FIELD_NAME[0] = '\0'; // Print a new grant statement for each new user or change of option if ((prev_user[0] && strcmp (prev_user, PRV.RDB$USER)) || (prev_field_null != -1 && prev_field_null != PRV.RDB$FIELD_NAME.NULL) || (!prev_field_null && strcmp (prev_field, PRV.RDB$FIELD_NAME)) || (prev_option != -1 && prev_option != PRV.RDB$GRANT_OPTION)) { make_priv_string (priv_flags, priv_string); if (first && optional_msg) ISQL_printf (Out, optional_msg); first = false; if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (object, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, object); sprintf (Print_buffer, "GRANT %s%s ON %s TO %s%s%s%s", priv_string, col_string, SQL_identifier, user_string, with_option, terminator, NEWLINE); ISQL_printf (Out, Print_buffer); // re-initialize strings priv_string[0] = '\0'; with_option[0] = '\0'; col_string[0] = '\0'; priv_flags = 0; } // At each row, store this value for the next compare of contol break strcpy (prev_user, PRV.RDB$USER); prev_option = PRV.RDB$GRANT_OPTION; prev_field_null = PRV.RDB$FIELD_NAME.NULL; strcpy (prev_field, PRV.RDB$FIELD_NAME); switch (PRV.RDB$USER_TYPE) { case obj_relation: case obj_view: case obj_trigger: case obj_procedure: case obj_sql_role: if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (PRV.RDB$USER, SQL_identifier, DBL_QUOTE); } else strcpy (SQL_identifier, PRV.RDB$USER); break; default: strcpy (SQL_identifier, PRV.RDB$USER); break; } switch (PRV.RDB$USER_TYPE) { case obj_view: sprintf (user_string, "VIEW %s", SQL_identifier); break; case obj_trigger: sprintf (user_string, "TRIGGER %s", SQL_identifier); break; case obj_procedure: sprintf (user_string, "PROCEDURE %s", SQL_identifier); break; case obj_user: if (strcmp(SQL_identifier, "PUBLIC")) sprintf (user_string, "USER %s", SQL_identifier); else strcpy (user_string, SQL_identifier); break; case obj_user_group: sprintf (user_string, "GROUP %s", SQL_identifier); break; case obj_sql_role: sprintf (user_string, "ROLE %s", SQL_identifier); break; default: strcpy (user_string, SQL_identifier); break; } // Only the first character is used for permissions const char c = PRV.RDB$PRIVILEGE[0]; switch (c) { case 'S': priv_flags |= priv_SELECT; break; case 'I': priv_flags |= priv_INSERT; break; case 'U': priv_flags |= priv_UPDATE; break; case 'D': priv_flags |= priv_DELETE; break; case 'R': priv_flags |= priv_REFERENCES; break; case 'X': // Execute should not be here -- special handling below break; default: priv_flags |= priv_UNKNOWN; } // Column level privileges for update and references only if (PRV.RDB$FIELD_NAME.NULL) { *col_string = '\0'; } else { fb_utils::fb_exact_name(PRV.RDB$FIELD_NAME); if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (PRV.RDB$FIELD_NAME, SQL_identifier, DBL_QUOTE); sprintf(col_string, " (%s)", SQL_identifier); } else { sprintf(col_string, " (%s)", PRV.RDB$FIELD_NAME); } } if (PRV.RDB$GRANT_OPTION) strcpy (with_option, " WITH GRANT OPTION"); END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; // Print last case if there was anything to print if (prev_option != -1) { make_priv_string (priv_flags, priv_string); if (first && optional_msg) ISQL_printf (Out, optional_msg); first = false; if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (object, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, object); sprintf (Print_buffer, "GRANT %s%s ON %s TO %s%s%s%s", priv_string, col_string, SQL_identifier, user_string, with_option, terminator, NEWLINE); ISQL_printf (Out, Print_buffer); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (!first) return (SKIP); } // No relation called "object" was found, try procedure "object" if (obj_type == obj_procedure || obj_type == 255) { FOR FIRST 1 P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_NAME EQ object // Part two is for stored procedures only FOR PRV IN RDB$USER_PRIVILEGES CROSS PRC IN RDB$PROCEDURES WITH PRV.RDB$OBJECT_TYPE = obj_procedure AND PRV.RDB$RELATION_NAME EQ object AND PRC.RDB$PROCEDURE_NAME EQ object AND PRV.RDB$PRIVILEGE EQ 'X' AND PRC.RDB$OWNER_NAME NE PRV.RDB$USER SORTED BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION; if (first && optional_msg) ISQL_printf (Out, optional_msg); first = false; fb_utils::fb_exact_name(PRV.RDB$USER); switch (PRV.RDB$USER_TYPE) { case obj_relation: case obj_view: case obj_trigger: case obj_procedure: case obj_sql_role: if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (PRV.RDB$USER, SQL_identifier, DBL_QUOTE); } else strcpy (SQL_identifier, PRV.RDB$USER); break; default: strcpy (SQL_identifier, PRV.RDB$USER); break; } switch (PRV.RDB$USER_TYPE) { case obj_view: sprintf (user_string, "VIEW %s", SQL_identifier); break; case obj_trigger: sprintf (user_string, "TRIGGER %s", SQL_identifier); break; case obj_procedure: sprintf (user_string, "PROCEDURE %s", SQL_identifier); break; case obj_user: if (strcmp(SQL_identifier, "PUBLIC")) sprintf (user_string, "USER %s", SQL_identifier); else strcpy (user_string, SQL_identifier); break; case obj_user_group: sprintf (user_string, "GROUP %s", SQL_identifier); break; case obj_sql_role: sprintf (user_string, "ROLE %s", SQL_identifier); break; default: strcpy (user_string, SQL_identifier); break; } if (PRV.RDB$GRANT_OPTION) strcpy (with_option, " WITH GRANT OPTION"); else with_option[0] = '\0'; if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (object, SQL_identifier, DBL_QUOTE); } else strcpy (SQL_identifier, object); sprintf (Print_buffer, "GRANT EXECUTE ON PROCEDURE %s TO %s%s%s%s", SQL_identifier, user_string, with_option, terminator, NEWLINE); first = false; ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return (ERR); END_ERROR END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; if (!first) return (SKIP); } // No procedure called "object" was found, try role "object" SCHAR role_name[BUFFER_LENGTH128]; if (obj_type == obj_sql_role || obj_type == 255) { // No procedure called "object" was found, try role "object" /* CVC: This code could be superseded by SHOW_grant_roles() below with the sole difference of the sort fields. */ FOR FIRST 1 R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ object FOR PRV IN RDB$USER_PRIVILEGES WITH PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND PRV.RDB$USER_TYPE EQ obj_user AND PRV.RDB$RELATION_NAME EQ object AND PRV.RDB$PRIVILEGE EQ 'M' SORTED BY PRV.RDB$USER fb_utils::fb_exact_name(PRV.RDB$RELATION_NAME); strcpy (role_name, PRV.RDB$RELATION_NAME); if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (role_name, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, role_name); fb_utils::fb_exact_name(PRV.RDB$USER); strcpy (user_string, PRV.RDB$USER); if (PRV.RDB$GRANT_OPTION) strcpy (with_option, " WITH ADMIN OPTION"); else with_option[0] = '\0'; sprintf (Print_buffer, "GRANT %s TO %s%s%s%s", SQL_identifier, user_string, with_option, terminator, NEWLINE); if (first && optional_msg) ISQL_printf (Out, optional_msg); first = false; ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return (ERR); END_ERROR; END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; if (!first) return (SKIP); } return OBJECT_NOT_FOUND; } void SHOW_grant_roles(const SCHAR* terminator, bool* first) { /************************************** * * S H O W _ g r a n t _ r o l e s * ************************************** * * Functional description * Placeholder for SHOW_grant_roles2 without additional message. * **************************************/ SHOW_grant_roles2 (terminator, first, 0); } void SHOW_grant_roles2 (const SCHAR* terminator, bool* first, const TEXT* optional_msg) { /************************************** * * S H O W _ g r a n t _ r o l e s * ************************************** * * Functional description * Show grants for given role name * This function is also called by extract for privileges. * All membership privilege may have the with_admin option set. * **************************************/ char with_option[18]; char user_string[44]; // process role "object" FOR PRV IN RDB$USER_PRIVILEGES WITH PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND PRV.RDB$USER_TYPE EQ obj_user AND PRV.RDB$PRIVILEGE EQ 'M' SORTED BY PRV.RDB$RELATION_NAME, PRV.RDB$USER if (first) { if (*first && optional_msg) { ISQL_printf (Out, optional_msg); } *first = false; } fb_utils::fb_exact_name(PRV.RDB$USER); strcpy (user_string, PRV.RDB$USER); if (PRV.RDB$GRANT_OPTION) strcpy (with_option, " WITH ADMIN OPTION"); else with_option[0] = '\0'; fb_utils::fb_exact_name(PRV.RDB$RELATION_NAME); if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { ISQL_copy_SQL_id (PRV.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE); sprintf (Print_buffer, "GRANT %s TO %s%s%s%s", SQL_identifier, user_string, with_option, terminator, NEWLINE); } else sprintf (Print_buffer, "GRANT %s TO %s%s%s%s", PRV.RDB$RELATION_NAME, user_string, with_option, terminator, NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg(isc_status); END_ERROR; } void SHOW_print_metadata_text_blob(IB_FILE* fp, ISC_QUAD* blobid) { /************************************** * * S H O W _ p r i n t _ m e t a d a t a _ t e x t _ b l o b * ************************************** * * Functional description * Print a Blob that is known to be metadata text. * **************************************/ // Don't bother with null blobs if (blobid->gds_quad_high == 0 && blobid->gds_quad_low == 0) return; isc_blob_handle blob_handle = NULL; if (isc_open_blob2(isc_status, &DB, &gds_trans, &blob_handle, blobid, sizeof(metadata_text_bpb), metadata_text_bpb)) { ISQL_errmsg(isc_status); return; } SCHAR* buffer = (SCHAR*) ISQL_ALLOC(BUFFER_LENGTH512); if (!buffer) { isc_status[0] = isc_arg_gds; isc_status[1] = isc_virmemexh; isc_status[2] = isc_arg_end; ISQL_errmsg(isc_status); return; } USHORT length = 0; while (!isc_get_segment(isc_status, &blob_handle, &length, (USHORT) (BUFFER_LENGTH512 - 1), buffer) || isc_status[1] == isc_segment) { /* * Need to step through the buffer until we hit a '\n' and then print the * line. This is because '\n' are included in blob text. */ buffer[length] = 0; ISQL_printf(fp, buffer); } if (isc_status[1] && isc_status[1] != isc_segstr_eof) ISQL_errmsg(isc_status); isc_close_blob(isc_status, &blob_handle); ISQL_FREE(buffer); } processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd) { /************************************** * * S H O W _ m e t a d a t a * ************************************** * * Functional description * If somebody presses the show ..., come here to * interpret the desired command. * Paramters: * cmd -- Array of words for the command * **************************************/ processing_state ret = SKIP; int key = 0; // Can't show nothing, return an error if (!cmd[1]) return (ERR); // Only show version works if there is no db attached if ((!strcmp(cmd[1], "VERSION")) || (!strcmp(cmd[1], "VER"))) { TEXT msg_string[MSG_LENGTH]; gds__msg_format(NULL, ISQL_MSG_FAC, VERSION, sizeof(msg_string), msg_string, FB_VERSION, NULL, NULL, NULL, NULL); sprintf(Print_buffer, "%s%s", msg_string, NEWLINE); ISQL_printf(Out, Print_buffer); isc_version(&DB, local_fprintf, NULL); } else if (!strcmp(cmd[1], "SQL")) { if (!strcmp(cmd[2], "DIALECT")) ret = show_dialect(); else ret = ERR; } else if (!ISQL_dbcheck()) { ; // Do nothing } else if ((!strcmp(cmd[1], "ROLE")) || (!strcmp(cmd[1], "ROLES"))) { if (major_ods >= ODS_VERSION9) { if (*cmd[2]) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_role(lcmd[2]); } else { ret = show_role(cmd[2]); } if (ret == NOT_FOUND) key = NO_ROLE; } else { ret = show_role(NULL); if (ret == NOT_FOUND) key = NO_ROLES; } } } else if ((!strcmp(cmd[1], "TABLE")) || (!strcmp(cmd[1], "TABLES"))) { if (*cmd[2]) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_table(lcmd[2], false); } else { ret = show_table(cmd[2], false); } if (ret == NOT_FOUND) key = NO_TABLE; } else { ret = show_all_tables(0); if (ret == NOT_FOUND) key = NO_TABLES; } } else if (!strcmp(cmd[1], "VIEW") || !strcmp(cmd[1], "VIEWS")) { if (*cmd[2]) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_table(lcmd[2], true); } else { ret = show_table(cmd[2], true); } if (ret == NOT_FOUND) key = NO_VIEW; } else { ret = show_all_tables(-1); if (ret == NOT_FOUND) key = NO_VIEWS; } } else if ((!strcmp(cmd[1], "SYSTEM")) || (!strcmp(cmd[1], "SYS"))) { show_all_tables(1); } else if ((!strcmp(cmd[1], "INDEX")) || (!strcmp(cmd[1], "IND")) || (!strcmp(cmd[1], "INDICES"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_indices(lcmd); } else { ret = show_indices(cmd); } if (ret == NOT_FOUND) { if (*cmd[2]) { FOR FIRST 1 R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ cmd[2]; key = NO_INDICES_ON_REL; END_FOR ON_ERROR // Ignore any error END_ERROR; if (!key) key = NO_REL_OR_INDEX; } else { key = NO_INDICES; } } } else if ((!strcmp(cmd[1], "DOMAIN")) || (!strcmp(cmd[1], "DOMAINS"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_domains(lcmd[2]); } else ret = show_domains(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) key = NO_DOMAIN; else key = NO_DOMAINS; } } else if ((!strcmp(cmd[1], "EXCEPTION")) || (!strcmp(cmd[1], "EXCEPTIONS"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_exceptions(lcmd[2]); } else ret = show_exceptions(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) key = NO_EXCEPTION; else key = NO_EXCEPTIONS; } } else if ((!strcmp(cmd[1], "FILTER")) || (!strcmp(cmd[1], "FILTERS"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_filters(lcmd[2]); } else ret = show_filters(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) key = NO_FILTER; else key = NO_FILTERS; } } else if ((!strcmp(cmd[1], "FUNCTION")) || (!strcmp(cmd[1], "FUNCTIONS"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_functions(lcmd[2]); } else ret = show_functions(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) key = NO_FUNCTION; else key = NO_FUNCTIONS; } } else if ((!strcmp(cmd[1], "GENERATOR")) || (!strcmp(cmd[1], "GENERATORS")) || (!strcmp(cmd[1], "GEN"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_generators(lcmd[2]); } else ret = show_generators(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) key = NO_GEN; else key = NO_GENS; } } else if ((!strcmp(cmd[1], "GRANT")) || (!strcmp(cmd[1], "GRANTS"))) { if (*cmd[2]) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); strcpy(SQL_id_for_grant, lcmd[2]); } else strcpy(SQL_id_for_grant, cmd[2]); ret = SHOW_grants (SQL_id_for_grant, "", 255); } else { strcpy(SQL_id_for_grant, cmd[2]); ret = EXTRACT_list_grants (""); } if (ret == NOT_FOUND) { if (*cmd[2]) { FOR FIRST 1 R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ SQL_id_for_grant; key = NO_GRANT_ON_REL; END_FOR ON_ERROR // Ignore any error END_ERROR; if (!key) { FOR FIRST 1 P IN RDB$PROCEDURES WITH P.RDB$PROCEDURE_NAME EQ SQL_id_for_grant; key = NO_GRANT_ON_PROC; END_FOR ON_ERROR // Ignore any error END_ERROR; } if (!key) { FOR FIRST 1 R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ SQL_id_for_grant; key = NO_GRANT_ON_ROL; END_FOR ON_ERROR // Ignore any error END_ERROR; } if (!key) key = NO_REL_OR_PROC_OR_ROLE; } else { key = NO_GRANT_ON_ANY; } } } else if ((!strcmp(cmd[1], "PROCEDURE")) || (!strcmp(cmd[1], "PROC")) || (!strcmp(cmd[1], "PROCEDURES"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_proc(lcmd[2]); } else ret = show_proc(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) key = NO_PROC; else key = NO_PROCS; } } else if ((!strcmp(cmd[1], "TRIGGER")) || (!strcmp(cmd[1], "TRIG")) || (!strcmp(cmd[1], "TRIGGERS"))) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_trigger(lcmd[2], true, true); } else ret = show_trigger(cmd[2], true, true); if (ret == NOT_FOUND) if (*cmd[2]) { FOR FIRST 1 R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ cmd[2]; key = NO_TRIGGERS_ON_REL; END_FOR ON_ERROR // Ignore any error END_ERROR; if (!key) key = NO_REL_OR_TRIGGER; } else key = NO_TRIGGERS; } else if (!strcmp(cmd[1], "CHECK")) { if (*cmd[2] == '"') { remove_delimited_double_quotes(lcmd[2]); ret = show_check(lcmd[2]); } else ret = show_check(cmd[2]); if (ret == NOT_FOUND) { if (*cmd[2]) { FOR FIRST 1 R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME EQ cmd[2]; key = NO_CHECKS_ON_REL; END_FOR ON_ERROR // Ignore any error END_ERROR; } if (!key) key = NO_TABLE; } } else if ((!strcmp(cmd[1], "DATABASE")) || (!strcmp(cmd[1], "DB"))) show_db(); else return (ERR); if (ret == NOT_FOUND) { TEXT key_string[MSG_LENGTH]; if (*cmd[2] == '"') gds__msg_format(NULL, ISQL_MSG_FAC, key, sizeof(key_string), key_string, lcmd[2], NULL, NULL, NULL, NULL); else gds__msg_format(NULL, ISQL_MSG_FAC, key, sizeof(key_string), key_string, cmd[2], NULL, NULL, NULL, NULL); STDERROUT(key_string, 1); } return (ret); } static void local_fprintf(void* format_ignored, const char* string) { /************************************** * * l o c a l _ p r i n t f * ************************************** * * Functional description * Used to make sure that local calls to print stuff go to Out * and not to ib_stdout if gds__version gets called. * **************************************/ ib_fprintf(Out, "%s", string); ib_fprintf(Out, "%s", NEWLINE); } static void remove_delimited_double_quotes(TEXT* string) { /************************************** * * r e m o v e _ d e l i m i t e d _ d o u b l e _ q u o t e s * ************************************** * * Functional description * Remove the delimited double quotes. Blanks could be part of * delimited SQL identifier. Unescape embedded double quotes. * **************************************/ ISQL_remove_and_unescape_quotes(string, DBL_QUOTE); } static void make_priv_string(USHORT flags, char* string) { /************************************** * * m a k e _ p r i v _ s t r i n g * ************************************** * * Functional description * Given a bit-vector of privileges, turn it into a * string list. * **************************************/ for (int i = 0; privs[i].priv_string; i++) { if (flags & privs[i].priv_flag) { if (*string) strcat(string, ", "); strcat(string, privs[i].priv_string); } } } static processing_state show_all_tables(SSHORT flag) { /************************************** * * s h o w _ a l l _ t a b l e s * ************************************** * * Print the names of all user tables from * rdb$relations. We use a dynamic query * * Parameters: flag -- 0, show user tables * 1, show system tables only; -1, show views only * **************************************/ bool odd = true; bool first = true; if (flag == -1) { // Views FOR REL IN RDB$RELATIONS WITH REL.RDB$VIEW_BLR NOT MISSING SORTED BY REL.RDB$RELATION_NAME first = false; sprintf (Print_buffer, "%38s%s", REL.RDB$RELATION_NAME, (odd ? " " : NEWLINE)); ISQL_printf (Out, Print_buffer); odd = !odd; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; } // 23-Apr-2004 (only tables) else { // The flag is not always set for non-system objects... this // query may potentially fail. FOR REL IN RDB$RELATIONS WITH REL.RDB$SYSTEM_FLAG EQ flag AND REL.RDB$VIEW_BLR MISSING SORTED BY REL.RDB$RELATION_NAME first = false; sprintf (Print_buffer, "%38s%s", REL.RDB$RELATION_NAME, (odd ? " " : NEWLINE)); ISQL_printf (Out, Print_buffer); odd = !odd; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; } if (!first) { ISQL_printf(Out, NEWLINE); return SKIP; } else return OBJECT_NOT_FOUND; } static void show_charsets( const SCHAR* relation_name, const SCHAR* field_name, bool show_charset, bool show_collation, bool doIndent, bool doReturn) { /************************************* * * s h o w _ c h a r s e t s * ************************************** * * Functional description * Show character set and collations * **************************************/ SSHORT collation, char_set_id; const SSHORT default_char_set_id = ISQL_get_default_char_set_id(); // If there is a relation_name, this is a real column, look up collation // in rdb$relation_fields if (relation_name) { FOR RRF IN RDB$RELATION_FIELDS CROSS FLD IN RDB$FIELDS WITH RRF.RDB$FIELD_NAME EQ field_name AND RRF.RDB$RELATION_NAME EQ relation_name AND RRF.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME char_set_id = 0; if (!FLD.RDB$CHARACTER_SET_ID.NULL) char_set_id = FLD.RDB$CHARACTER_SET_ID; collation = 0; if (!RRF.RDB$COLLATION_ID.NULL) collation = RRF.RDB$COLLATION_ID; else if (!FLD.RDB$COLLATION_ID.NULL) collation = FLD.RDB$COLLATION_ID; END_FOR ON_ERROR #ifdef DEV_BUILD ib_fprintf(ib_stderr, "show_charsets(%s %s) failed\n", relation_name, field_name); #endif END_ERROR; } else { FOR FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ field_name char_set_id = 0; collation = 0; if (!FLD.RDB$CHARACTER_SET_ID.NULL) char_set_id = FLD.RDB$CHARACTER_SET_ID; if (!FLD.RDB$COLLATION_ID.NULL) collation = FLD.RDB$COLLATION_ID; END_FOR ON_ERROR #ifdef DEV_BUILD ib_fprintf(ib_stderr, "show_charsets(NULL %s) failed\n", field_name); #endif END_ERROR; } TEXT char_sets[86]; /* CHARACTER SET COLLATE */ char_sets[0] = 0; if ((char_set_id != default_char_set_id) || collation){ if (show_charset && !show_collation) ISQL_get_character_sets(char_set_id, 0, false, char_sets); else if (!show_charset && show_collation) ISQL_get_character_sets(char_set_id, collation, true, char_sets); else ISQL_get_character_sets(char_set_id, collation, false, char_sets); } if (char_sets[0]){ if (doIndent) ISQL_printf(Out, spaces); ISQL_printf(Out, char_sets); if (doReturn) ISQL_printf(Out, NEWLINE); } } static processing_state show_check(const SCHAR* object) { /************************************** * * s h o w _ c h e c k * ************************************** * * Functional description * Show check constraints for the named object * **************************************/ bool first = true; if (!*object) return (ERR); // 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$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND CHK.RDB$TRIGGER_NAME STARTING WITH "CHECK" AND TRG.RDB$RELATION_NAME EQ object SORTED BY CHK.RDB$CONSTRAINT_NAME // Use print_blob to print the blob first = false; sprintf (Print_buffer, "CONSTRAINT %s:%s ", fb_utils::fb_exact_name(CHK.RDB$CONSTRAINT_NAME), NEWLINE); ISQL_printf (Out, Print_buffer); if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &TRG.RDB$TRIGGER_SOURCE); ISQL_printf (Out, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } static void show_db() { /************************************** * * s h o w _ d b * ************************************** * * Functional description * Show info on this database. cache, logfiles, etc * **************************************/ // First print the name of the database sprintf(Print_buffer, "Database: %s%s", global_Db_name, NEWLINE); ISQL_printf(Out, Print_buffer); // Get the owner name FOR REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME = "RDB$DATABASE" if (!REL.RDB$OWNER_NAME.NULL) { sprintf (Print_buffer, "%sOwner: %s%s", TAB_AS_SPACES, REL.RDB$OWNER_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return; END_ERROR; // Query for files FOR FIL IN RDB$FILES SORTED BY FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_SEQUENCE, FIL.RDB$FILE_SEQUENCE // 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; /* This line used to terminate the file name at the first space. This does not seem necessary, and creates problems since Windows 95 allows embeded spaces in file names. fb_utils::fb_exact_name(FIL.RDB$FILE_NAME); */ if (FIL.RDB$FILE_FLAGS == 0) { sprintf (Print_buffer, " File %d: \"%s\", length %ld, start %ld%s", FIL.RDB$FILE_SEQUENCE, FIL.RDB$FILE_NAME, FIL.RDB$FILE_LENGTH, FIL.RDB$FILE_START, NEWLINE); ISQL_printf (Out, Print_buffer); } if (FIL.RDB$FILE_FLAGS & FILE_cache) { sprintf (Print_buffer, " Cache: %s, length %ld%s", FIL.RDB$FILE_NAME, FIL.RDB$FILE_LENGTH, NEWLINE); ISQL_printf (Out, Print_buffer); } if (FIL.RDB$FILE_FLAGS & FILE_shadow) { if (FIL.RDB$FILE_SEQUENCE) { sprintf (Print_buffer, "%sfile %s ", TAB_AS_SPACES, FIL.RDB$FILE_NAME); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, " Shadow %d: \"%s\" ", FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_NAME); ISQL_printf (Out, Print_buffer); if (FIL.RDB$FILE_FLAGS & FILE_inactive) { sprintf (Print_buffer, "inactive "); ISQL_printf (Out, Print_buffer); } if (FIL.RDB$FILE_FLAGS & FILE_manual) { sprintf (Print_buffer, "manual "); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, "auto "); ISQL_printf (Out, Print_buffer); } if (FIL.RDB$FILE_FLAGS & FILE_conditional) { sprintf (Print_buffer, "conditional "); ISQL_printf (Out, Print_buffer); } } if (FIL.RDB$FILE_LENGTH) { sprintf (Print_buffer, "length %ld ", FIL.RDB$FILE_LENGTH); ISQL_printf (Out, Print_buffer); } if (FIL.RDB$FILE_START) { sprintf (Print_buffer, "starting %ld", FIL.RDB$FILE_START); ISQL_printf (Out, Print_buffer); } ISQL_printf (Out, NEWLINE); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return; END_ERROR; SCHAR* info_buf = (SCHAR*) ISQL_ALLOC(BUFFER_LENGTH400); if (!info_buf) { isc_status[0] = isc_arg_gds; isc_status[1] = isc_virmemexh; isc_status[2] = isc_arg_end; ISQL_errmsg(isc_status); return; } // First general database parameters bool translate = true; if (SHOW_dbb_parameters(DB, info_buf, db_items, sizeof(db_items), translate)) { ISQL_printf(Out, info_buf); } #ifdef NOT_USED_OR_REPLACED // IGNORE WAL bool is_wal = false; FOR LOG IN RDB$LOG_FILES SORTED BY LOG.RDB$FILE_FLAGS, LOG.RDB$FILE_SEQUENCE SORTED BY LOG.RDB$FILE_FLAGS, LOG.RDB$FILE_SEQUENCE // If there are log files, print Wal statistics is_wal = true; // reset nulls to zero if (LOG.RDB$FILE_FLAGS.NULL) LOG.RDB$FILE_FLAGS = 0; if (LOG.RDB$FILE_LENGTH.NULL) LOG.RDB$FILE_LENGTH = 0; if (LOG.RDB$FILE_SEQUENCE.NULL) LOG.RDB$FILE_SEQUENCE = 0; fb_utils::fb_exact_name(LOG.RDB$FILE_NAME); if (LOG.RDB$FILE_FLAGS & LOG_overflow) { sprintf (Print_buffer, "overflow: %s, ", LOG.RDB$FILE_NAME); ISQL_printf (Out, Print_buffer); } else if (LOG.RDB$FILE_FLAGS & LOG_serial) { sprintf (Print_buffer, "Logfile serial: %s, ", LOG.RDB$FILE_NAME); ISQL_printf (Out, Print_buffer); } else if (LOG.RDB$FILE_FLAGS & LOG_default) { sprintf (Print_buffer, "Logfile default, "); ISQL_printf (Out, Print_buffer); } else if (LOG.RDB$FILE_FLAGS & LOG_raw) { sprintf (Print_buffer, "Logfile raw: %s, %d partitions, ", LOG.RDB$FILE_NAME, LOG.RDB$FILE_PARTITIONS); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, "Logfile #%d: %s, ", LOG.RDB$FILE_SEQUENCE, LOG.RDB$FILE_NAME); ISQL_printf (Out, Print_buffer); } sprintf (Print_buffer, "length %ld%s", LOG.RDB$FILE_LENGTH, NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg(isc_status); if (info_buf) ISQL_FREE(info_buf); return; END_ERROR; // And now for Rich's show db parameters if (is_wal && SHOW_dbb_parameters(DB, info_buf, wal_items, sizeof(wal_items), translate)) { ISQL_printf(Out, info_buf); } #endif FOR DBB IN RDB$DATABASE WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING AND DBB.RDB$CHARACTER_SET_NAME NE " " sprintf (Print_buffer, "Default Character set: %s%s", DBB.RDB$CHARACTER_SET_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg(isc_status); if (info_buf) ISQL_FREE(info_buf); return; END_ERROR; ISQL_FREE(info_buf); } static processing_state show_dialect() { /************************************** * * s h o w _ d i a l e c t * ************************************** * * Print out the SQL dialect information * **************************************/ if (db_SQL_dialect > 0) { sprintf(Print_buffer, "%38s%d%s%d", "Client SQL dialect is set to: ", SQL_dialect, " and database SQL dialect is: ", db_SQL_dialect); } else if (SQL_dialect == 0) { sprintf(Print_buffer, "%38s%s", "Client SQL dialect has not been set", " and no database has been connected yet."); } else { sprintf(Print_buffer, "%38s%d%s", "Client SQL dialect is set to: ", SQL_dialect, ". No database has been connected."); } ISQL_printf(Out, Print_buffer); ISQL_printf(Out, NEWLINE); return SKIP; } static processing_state show_domains(const SCHAR* domain_name) { /************************************* * * s h o w _ d o m a i n s * ************************************** * * Functional description * Show all domains or the named domain ************************************/ bool odd = true; bool first = true; if (!*domain_name) { // List all domain names in columns 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 first = false; sprintf (Print_buffer, "%38s%s", FLD.RDB$FIELD_NAME, (odd ? " " : NEWLINE)); ISQL_printf (Out, Print_buffer); odd = !odd; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (!first) ISQL_printf(Out, NEWLINE); } else { // List named domain FOR FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ domain_name; first = false; // Print the name of the domain fb_utils::fb_exact_name(FLD.RDB$FIELD_NAME); sprintf (Print_buffer, "%-32s", FLD.RDB$FIELD_NAME); ISQL_printf (Out, Print_buffer); // Array dimensions if (!FLD.RDB$DIMENSIONS.NULL) { sprintf (Print_buffer, "ARRAY OF "); ISQL_printf (Out, Print_buffer); ISQL_array_dimensions (FLD.RDB$FIELD_NAME); sprintf (Print_buffer, "%s ", NEWLINE); ISQL_printf (Out, Print_buffer); } // 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 (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 == blr_int64)) { FOR FLD1 IN RDB$FIELDS WITH FLD1.RDB$FIELD_NAME EQ domain_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 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); } } ISQL_printf (Out, Print_buffer); break; } // Length for CHARs if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { sprintf (Print_buffer, "(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); ISQL_printf (Out, Print_buffer); } // Blob domains if (FLD.RDB$FIELD_TYPE == BLOB) { sprintf (Print_buffer, " segment %u, subtype ", (USHORT) FLD.RDB$SEGMENT_LENGTH); ISQL_printf (Out, Print_buffer); const SSHORT subtype = FLD.RDB$FIELD_SUB_TYPE; if (subtype >= 0 && subtype <= MAXSUBTYPES) { sprintf (Print_buffer, "%s", Sub_types[subtype]); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, "%d", subtype); ISQL_printf (Out, Print_buffer); } } // Show international character sets if (FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR || FLD.RDB$FIELD_TYPE == BLOB) { show_charsets(NULL, FLD.RDB$FIELD_NAME, true, false, false, false); } if (FLD.RDB$NULL_FLAG != 1) { sprintf (Print_buffer, " Nullable"); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, " Not Null"); ISQL_printf (Out, Print_buffer); } ISQL_printf (Out, NEWLINE); ISC_QUAD default_source; ISQL_get_default_source (NULL, FLD.RDB$FIELD_NAME, &default_source); if (default_source.gds_quad_high) { sprintf (Print_buffer, " "); ISQL_printf (Out, Print_buffer); SHOW_print_metadata_text_blob (Out, &default_source); ISQL_printf (Out, NEWLINE); } if (!FLD.RDB$VALIDATION_SOURCE.NULL) { sprintf (Print_buffer, " "); ISQL_printf (Out, Print_buffer); SHOW_print_metadata_text_blob (Out, &FLD.RDB$VALIDATION_SOURCE); ISQL_printf (Out, NEWLINE); } // Show collations if (FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR || FLD.RDB$FIELD_TYPE == BLOB) { show_charsets(NULL, FLD.RDB$FIELD_NAME, false, true, true, true); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; } if (first) return (OBJECT_NOT_FOUND); return (SKIP); } static processing_state show_exceptions(const SCHAR* object) { /************************************** * * s h o w _ e x c e p t i o n s * ************************************** * * Functional description * Show exceptions and their dependencies * This version fetches all the exceptions, and only prints the * one you asked for if you ask for one. It could be optimized * like other such functions. * **************************************/ bool first = true; SCHAR type[20]; //fb_utils::fb_exact_name(object); It already comes trimmed. FOR EXC IN RDB$EXCEPTIONS SORTED BY EXC.RDB$EXCEPTION_NAME fb_utils::fb_exact_name(EXC.RDB$EXCEPTION_NAME); // List all objects if none specified, or just the named exception if (!*object || !strcmp (EXC.RDB$EXCEPTION_NAME, object)) { if (first) { sprintf (Print_buffer, "Exception Name Used by, Type%s=============================== =============================================%s", NEWLINE, NEWLINE); ISQL_printf (Out, Print_buffer); } first = false; sprintf (Print_buffer, "%-31s ", EXC.RDB$EXCEPTION_NAME); ISQL_printf (Out, Print_buffer); // Look up dependent objects --procedures and triggers bool first_dep = true; FOR DEP IN RDB$DEPENDENCIES WITH DEP.RDB$DEPENDED_ON_TYPE = 7 AND DEP.RDB$DEPENDED_ON_NAME EQ EXC.RDB$EXCEPTION_NAME SORTED BY DEP.RDB$DEPENDENT_TYPE, DEP.RDB$DEPENDENT_NAME if (!first_dep) { sprintf (Print_buffer, " "); ISQL_printf (Out, Print_buffer); } first_dep = false; fb_utils::fb_exact_name(DEP.RDB$DEPENDENT_NAME); strcpy (type, "Unknown"); if (DEP.RDB$DEPENDENT_TYPE == 2) strcpy (type, "Trigger"); if (DEP.RDB$DEPENDENT_TYPE == 5) strcpy (type, "Stored procedure"); sprintf (Print_buffer, "%s, %s%s", DEP.RDB$DEPENDENT_NAME, type, NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; sprintf (Print_buffer, "%s %s%s", (first_dep ? NEWLINE : ""), EXC.RDB$MESSAGE, NEWLINE); ISQL_printf (Out, Print_buffer); } if (!first) ISQL_printf (Out, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } static processing_state show_filters(const SCHAR* object) { /************************************** * * s h o w _ f i l t e r s * ************************************** * * Functional description * Show blob filters in general or for the named filters * **************************************/ bool odd = true; bool first = true; // Show all functions if (!*object) { FOR FIL IN RDB$FILTERS SORTED BY FIL.RDB$FUNCTION_NAME first = false; fb_utils::fb_exact_name(FIL.RDB$FUNCTION_NAME); sprintf (Print_buffer, "%-38s%s", FIL.RDB$FUNCTION_NAME, (odd ? " " : NEWLINE)); ISQL_printf (Out, Print_buffer); odd = !odd; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (!first) { ISQL_printf(Out, NEWLINE); return (SKIP); } else return OBJECT_NOT_FOUND; } // We have a filter name, so expand on it FOR FIL IN RDB$FILTERS WITH FIL.RDB$FUNCTION_NAME EQ object first = false; fb_utils::fb_exact_name(FIL.RDB$FUNCTION_NAME); fb_utils::fb_exact_name(FIL.RDB$MODULE_NAME); fb_utils::fb_exact_name(FIL.RDB$ENTRYPOINT); sprintf (Print_buffer, "BLOB Filter: %s %s%sInput subtype: %d Output subtype: %d%s", FIL.RDB$FUNCTION_NAME, NEWLINE, TAB_AS_SPACES, FIL.RDB$INPUT_SUB_TYPE, FIL.RDB$OUTPUT_SUB_TYPE, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "%sFilter library is %s%s%sEntry point is %s%s%s", TAB_AS_SPACES, FIL.RDB$MODULE_NAME, NEWLINE, TAB_AS_SPACES, FIL.RDB$ENTRYPOINT, NEWLINE, NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } static processing_state show_functions(const SCHAR* object) { /************************************** * * s h o w _ f u n c t i o n s * ************************************** * * Functional description * Show external functions in general or for the named function * **************************************/ bool first = true; bool odd = true; // Show all functions if (!*object) { FOR FUN IN RDB$FUNCTIONS SORTED BY FUN.RDB$FUNCTION_NAME first = false; fb_utils::fb_exact_name(FUN.RDB$FUNCTION_NAME); sprintf (Print_buffer, "%-38s%s", FUN.RDB$FUNCTION_NAME, (odd ? " " : NEWLINE)); ISQL_printf (Out, Print_buffer); odd = !odd; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (!first) { ISQL_printf(Out, NEWLINE); return (SKIP); } else return OBJECT_NOT_FOUND; } FOR FUN IN RDB$FUNCTIONS CROSS FNA IN RDB$FUNCTION_ARGUMENTS WITH FUN.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME AND FUN.RDB$FUNCTION_NAME EQ object SORTED BY FNA.RDB$ARGUMENT_POSITION fb_utils::fb_exact_name(FUN.RDB$FUNCTION_NAME); fb_utils::fb_exact_name(FUN.RDB$MODULE_NAME); fb_utils::fb_exact_name(FUN.RDB$ENTRYPOINT); if (first) { sprintf (Print_buffer, "%sFunction %s:%s", NEWLINE, FUN.RDB$FUNCTION_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "Function library is %s%s", FUN.RDB$MODULE_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "Entry point is %s%s", FUN.RDB$ENTRYPOINT, NEWLINE); ISQL_printf (Out, Print_buffer); } SSHORT ptype = (SSHORT) abs (FNA.RDB$MECHANISM); if (ptype > MAX_UDFPARAM_TYPES + 1 || ptype < 0) { ptype = MAX_UDFPARAM_TYPES + 1; } first = false; if (FUN.RDB$RETURN_ARGUMENT == FNA.RDB$ARGUMENT_POSITION) { sprintf (Print_buffer, "Returns %s%s ", UDF_param_types[ptype], (FNA.RDB$MECHANISM < 0 ? "FREE_IT " : "")); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, "Argument %d:%s ", FNA.RDB$ARGUMENT_POSITION, UDF_param_types[ptype]); ISQL_printf (Out, Print_buffer); } for (int i = 0; Column_types[i].type; i++) { if (FNA.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; // Handle Integral subtypes NUMERIC and DECIMAL if ( (major_ods >= ODS_VERSION10) && ((FNA.RDB$FIELD_TYPE == SMALLINT) || (FNA.RDB$FIELD_TYPE == INTEGER) || (FNA.RDB$FIELD_TYPE == blr_int64)) ) { FOR FNA1 IN RDB$FUNCTION_ARGUMENTS WITH FNA1.RDB$FUNCTION_NAME = FNA.RDB$FUNCTION_NAME AND FNA1.RDB$ARGUMENT_POSITION = FNA.RDB$ARGUMENT_POSITION /* We are ODS >= 10 */ 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 (Print_buffer, "%s(%d, %d)", Integral_subtypes[FNA1.RDB$FIELD_SUB_TYPE], FNA1.RDB$FIELD_PRECISION, -FNA1.RDB$FIELD_SCALE); precision_known = true; } } END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; } if (!precision_known) { // Take a stab at numerics and decimals if ((FNA.RDB$FIELD_TYPE == SMALLINT) && (FNA.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(4, %d)", -FNA.RDB$FIELD_SCALE); } else if ((FNA.RDB$FIELD_TYPE == INTEGER) && (FNA.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(9, %d)", -FNA.RDB$FIELD_SCALE); } else if ((FNA.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FNA.RDB$FIELD_SCALE < 0)) { sprintf (Print_buffer, "NUMERIC(15, %d)", -FNA.RDB$FIELD_SCALE); } else { sprintf (Print_buffer, "%s", Column_types[i].type_name); } } ISQL_printf (Out, Print_buffer); break; } } // Print length where appropriate if ((FNA.RDB$FIELD_TYPE == T_CHAR) || (FNA.RDB$FIELD_TYPE == VARCHAR) || (FNA.RDB$FIELD_TYPE == CSTRING)) { FOR V4FNA IN RDB$FUNCTION_ARGUMENTS CROSS CHARSET IN RDB$CHARACTER_SETS OVER RDB$CHARACTER_SET_ID WITH V4FNA.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME AND V4FNA.RDB$ARGUMENT_POSITION EQ FNA.RDB$ARGUMENT_POSITION fb_utils::fb_exact_name(CHARSET.RDB$CHARACTER_SET_NAME); sprintf (Print_buffer, "(%d) CHARACTER SET %s", (FNA.RDB$FIELD_LENGTH / MAX (1, CHARSET.RDB$BYTES_PER_CHARACTER)), CHARSET.RDB$CHARACTER_SET_NAME); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; } ISQL_printf (Out, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } static processing_state show_generators(const SCHAR* object) { /************************************** * * s h o w _ g e n e r a t o r s * ************************************** * * Functional description * Show generators including the next number they return * We do this by selecting the GEN_ID of each one, * incrementing by 0 to not change the current value. * **************************************/ SSHORT indicator; bool found = false; XSQLDA sqlda; SINT64 genid64 = 0; SLONG genid = 0; TEXT query[100], gen_name[WORDLENGTH * 2]; // Show all generators or named generator FOR GEN IN RDB$GENERATORS SORTED BY GEN.RDB$GENERATOR_NAME fb_utils::fb_exact_name(GEN.RDB$GENERATOR_NAME); if ((!*object && GEN.RDB$SYSTEM_FLAG.NULL) || (!strcmp (GEN.RDB$GENERATOR_NAME, object))) { // Get the current id for each generator const bool delimited_yes = strchr(GEN.RDB$GENERATOR_NAME, DBL_QUOTE) != 0; if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION && delimited_yes) { ISQL_copy_SQL_id (GEN.RDB$GENERATOR_NAME, gen_name, DBL_QUOTE); } else { // If we are extracting in dialect 1, identifiers may cause failures. strcpy(gen_name, GEN.RDB$GENERATOR_NAME); } sprintf (query, "SELECT GEN_ID(%s, 0) FROM RDB$DATABASE", gen_name); isc_stmt_handle stmt = 0; isc_dsql_allocate_statement (isc_status, &DB, &stmt); sqlda.sqln = 1; sqlda.version = 1; /* If the user has set his client dialect to 1, we take that to mean that he wants to see just the lower 32 bits of the generator, as in V5. Otherwise, we show him the whole 64-bit value. */ if (isc_dsql_prepare (isc_status, &gds_trans, &stmt, 0, query, SQL_dialect, &sqlda)) { ISQL_errmsg (isc_status); continue; }; if (SQL_dialect >= SQL_DIALECT_V6_TRANSITION) sqlda.sqlvar[0].sqldata = (SCHAR*) &genid64; else sqlda.sqlvar[0].sqldata = (SCHAR*) &genid; sqlda.sqlvar[0].sqlind = &indicator; // Singleton select needs no fetch if (isc_dsql_execute2 (isc_status, &gds_trans, &stmt, SQL_dialect, NULL, &sqlda)) { ISQL_errmsg (isc_status); } else { found = true; if (SQL_dialect >= SQL_DIALECT_V6_TRANSITION) { sprintf (Print_buffer, "Generator %s, current value is %" QUADFORMAT "d%s", GEN.RDB$GENERATOR_NAME, genid64, NEWLINE); } else { sprintf (Print_buffer, "Generator %s, current value is %ld%s", GEN.RDB$GENERATOR_NAME, genid, NEWLINE); } ISQL_printf (Out, Print_buffer); } if (isc_dsql_free_statement (isc_status, &stmt, DSQL_drop)) ISQL_errmsg (isc_status); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (!found) return (OBJECT_NOT_FOUND); return SKIP; } static void show_index(SCHAR* relation_name, SCHAR* index_name, const SSHORT unique_flag, const SSHORT index_type, const SSHORT inactive) { /************************************** * * s h o w _ i n d e x * ************************************** * * Functional description * Show an index. * * relation_name -- Name of table to investigate * **************************************/ // Strip trailing blanks fb_utils::fb_exact_name(relation_name); fb_utils::fb_exact_name(index_name); sprintf(Print_buffer, "%s%s%s INDEX ON %s", index_name, (unique_flag ? " UNIQUE" : ""), (index_type == 1 ? " DESCENDING" : ""), relation_name); ISQL_printf(Out, Print_buffer); // Get column names SCHAR* collist = (SCHAR*) ISQL_ALLOC(BUFFER_LENGTH512); if (!collist) { isc_status[0] = isc_arg_gds; isc_status[1] = isc_virmemexh; isc_status[2] = isc_arg_end; ISQL_errmsg(isc_status); return; } if (ISQL_get_index_segments(collist, index_name, false)) { sprintf(Print_buffer, "(%s) %s%s", collist, (inactive ? "(inactive)" : ""), NEWLINE); ISQL_printf(Out, Print_buffer); } ISQL_FREE(collist); } static processing_state show_indices(const SCHAR* const* cmd) { /************************************** * * s h o w _ i n d i c e s * ************************************** * * Functional description * shows indices for a given table name or index name or all tables * * Use a static SQL query to get the info and print it. * * relation_name -- Name of table to investigate * **************************************/ bool first = true; // The names stored in the database are all upper case const SCHAR* name = cmd[2]; if (*name) { FOR IDX1 IN RDB$INDICES WITH IDX1.RDB$RELATION_NAME EQ name OR IDX1.RDB$INDEX_NAME EQ name SORTED BY IDX1.RDB$INDEX_NAME if (IDX1.RDB$INDEX_INACTIVE.NULL) IDX1.RDB$INDEX_INACTIVE = 0; show_index (IDX1.RDB$RELATION_NAME, IDX1.RDB$INDEX_NAME, IDX1.RDB$UNIQUE_FLAG, IDX1.RDB$INDEX_TYPE, IDX1.RDB$INDEX_INACTIVE); #ifdef EXPRESSION_INDICES if (!IDX1.RDB$EXPRESSION_BLR.NULL) { sprintf (Print_buffer, " COMPUTED BY "); ISQL_printf (Out, Print_buffer); if (!IDX1.RDB$EXPRESSION_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &IDX1.RDB$EXPRESSION_SOURCE); ISQL_printf (Out, NEWLINE); } #endif first = false; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } else { FOR IDX2 IN RDB$INDICES CROSS REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING SORTED BY IDX2.RDB$RELATION_NAME, IDX2.RDB$INDEX_NAME first = false; show_index (IDX2.RDB$RELATION_NAME, IDX2.RDB$INDEX_NAME, IDX2.RDB$UNIQUE_FLAG, IDX2.RDB$INDEX_TYPE, IDX2.RDB$INDEX_INACTIVE); #ifdef EXPRESSION_INDICES if (!IDX2.RDB$EXPRESSION_BLR.NULL) { sprintf (Print_buffer, " COMPUTED BY "); ISQL_printf (Out, Print_buffer); if (!IDX2.RDB$EXPRESSION_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &IDX2.RDB$EXPRESSION_SOURCE); ISQL_printf (Out, NEWLINE); } #endif END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } } static processing_state show_proc(const SCHAR* procname) { /************************************** * * s h o w _ p r o c * ************************************** * * Functional description * shows text of a stored procedure given a name. * or lists procedures if no argument. * * procname -- Name of procedure to investigate * **************************************/ // If no procedure name was given, just list the procedures if (!procname || !strlen(procname)) { /* This query gets the procedure name the next query ** gets all the dependencies if any */ bool first_proc = true; FOR PRC IN RDB$PROCEDURES SORTED BY PRC.RDB$PROCEDURE_NAME if (first_proc) { sprintf (Print_buffer, "Procedure Name Dependency, Type%s", NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "================================= ======================================%s", NEWLINE); ISQL_printf (Out, Print_buffer); first_proc = false; } // Strip trailing blanks fb_utils::fb_exact_name(PRC.RDB$PROCEDURE_NAME); sprintf (Print_buffer, "%-34s", PRC.RDB$PROCEDURE_NAME); ISQL_printf (Out, Print_buffer); bool first_dep = true; FOR DEP IN RDB$DEPENDENCIES WITH PRC.RDB$PROCEDURE_NAME EQ DEP.RDB$DEPENDENT_NAME REDUCED TO DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME SORTED BY DEP.RDB$DEPENDED_ON_TYPE, DEP.RDB$DEPENDED_ON_NAME fb_utils::fb_exact_name(DEP.RDB$DEPENDED_ON_NAME); // Get column type name to print if (!first_dep) { sprintf (Print_buffer, "%s%34s", NEWLINE, ""); ISQL_printf (Out, Print_buffer); } first_dep = false; sprintf (Print_buffer, "%s, %s", DEP.RDB$DEPENDED_ON_NAME, Object_types[DEP.RDB$DEPENDED_ON_TYPE]); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return (ERR); END_ERROR; ISQL_printf (Out, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; if (first_proc) return OBJECT_NOT_FOUND; return (SKIP); } // A procedure was named, so print all the info on that procedure SCHAR type_name[33]; SCHAR lenstring[33] = ""; bool first = true; FOR PRC IN RDB$PROCEDURES WITH PRC.RDB$PROCEDURE_NAME EQ procname first = false; sprintf (Print_buffer, "Procedure text:%s", NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "=============================================================================%s", NEWLINE); ISQL_printf (Out, Print_buffer); if (!PRC.RDB$PROCEDURE_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &PRC.RDB$PROCEDURE_SOURCE); sprintf (Print_buffer, "%s=============================================================================%s", NEWLINE, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "Parameters:%s", NEWLINE); ISQL_printf (Out, Print_buffer); FOR PRM IN RDB$PROCEDURE_PARAMETERS CROSS FLD IN RDB$FIELDS WITH PRC.RDB$PROCEDURE_NAME EQ PRM.RDB$PROCEDURE_NAME AND PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME SORTED BY PRM.RDB$PARAMETER_TYPE, PRM.RDB$PARAMETER_NUMBER fb_utils::fb_exact_name(PRM.RDB$PARAMETER_NAME); // Get column type name to print // Look through types array for (SSHORT i = 0; Column_types[i].type; i++) if (FLD.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; if (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 == blr_int64)) { 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 (type_name, "%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 ERR; END_ERROR; } // if field_type ... } // if major_ods ... if (!precision_known) { // Take a stab at numerics and decimals if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (type_name, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (type_name, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE); } else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) && (FLD.RDB$FIELD_SCALE < 0)) { sprintf (type_name, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE); } else { strcpy(type_name, Column_types[i].type_name); } } break; } /* Use RDB$CHARACTER_LENGTH instead of RDB$FIELD_LENGTH FSG 19.Nov.2000 */ if (((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) && !FLD.RDB$CHARACTER_LENGTH.NULL) { sprintf (lenstring, "(%d)", FLD.RDB$CHARACTER_LENGTH); } else { // CVC: the original programmer initialized it only once, // outside the loop, so it may contain garbage from previous iteration. strcpy(lenstring, ""); } sprintf (Print_buffer, "%-33s %s %s%s ", PRM.RDB$PARAMETER_NAME, (PRM.RDB$PARAMETER_TYPE ? "OUTPUT" : "INPUT"), type_name, lenstring); ISQL_printf (Out, Print_buffer); // Show international character sets and collations if (FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR || FLD.RDB$FIELD_TYPE == BLOB) { show_charsets(NULL, FLD.RDB$FIELD_NAME, true, true, false, false); } ISQL_printf (Out, NEWLINE); END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } static processing_state show_role(const SCHAR* object) { if (object == NULL) { // show role with no parameters, show all roles /************************************** * Print the names of all roles from * RDB$ROLES. We use a dynamic query * If there is any roles, then returns SKIP. * Otherwise returns NOT_FOUND. **************************************/ bool first = true; bool odd = true; FOR X IN RDB$ROLES WITH X.RDB$ROLE_NAME NOT MISSING SORTED BY X.RDB$ROLE_NAME first = false; sprintf (Print_buffer, "%38s%s", X.RDB$ROLE_NAME, (odd ? " " : NEWLINE)); ISQL_printf (Out, Print_buffer); odd = !odd; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (!first) { ISQL_printf(Out, NEWLINE); return SKIP; } else { return OBJECT_NOT_FOUND; } } else { // show role with role supplied, display users granted this role SCHAR role_name[BUFFER_LENGTH128]; bool first = true; FOR FIRST 1 R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ object first = false; FOR PRV IN RDB$USER_PRIVILEGES WITH PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND PRV.RDB$USER_TYPE EQ obj_user AND PRV.RDB$RELATION_NAME EQ object AND PRV.RDB$PRIVILEGE EQ 'M' SORTED BY PRV.RDB$USER fb_utils::fb_exact_name(PRV.RDB$RELATION_NAME); strcpy (role_name, PRV.RDB$RELATION_NAME); if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) ISQL_copy_SQL_id (role_name, SQL_identifier, DBL_QUOTE); else strcpy (SQL_identifier, role_name); fb_utils::fb_exact_name(PRV.RDB$USER); sprintf(Print_buffer, "%s\n", PRV.RDB$USER); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return (ERR); END_ERROR; END_FOR ON_ERROR ISQL_errmsg(isc_status); return (ERR); END_ERROR; if (first) return (OBJECT_NOT_FOUND); return (SKIP); } } static processing_state show_table( const SCHAR* relation_name, bool isView) { /************************************** * * s h o w _ t a b l e * ************************************** * * Functional description * shows columns, types, info for a given table name * and text of views. * Use a SQL query to get the info and print it. * This also shows integrity constraints and triggers * * relation_name -- Name of table to investigate * **************************************/ bool first = true; // Query to obtain relation information // REL.RDB$VIEW_BLR NOT MISSING FOR REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ relation_name if (first) { if (!REL.RDB$EXTERNAL_FILE.NULL) { sprintf (Print_buffer, "External file: %s\n", REL.RDB$EXTERNAL_FILE); ISQL_printf (Out, Print_buffer); } } first = false; if (isView && REL.RDB$VIEW_BLR.NULL || !isView && !REL.RDB$VIEW_BLR.NULL) first = true; END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return (OBJECT_NOT_FOUND); /* *FOR RFR IN RDB$RELATION_FIELDS CROSS REL IN RDB$RELATIONS CROSS FLD IN RDB$FIELDS WITH RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND RFR.RDB$RELATION_NAME EQ relation_name AND REL.RDB$RELATION_NAME EQ RFR.RDB$RELATION_NAME SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME */ FOR 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 relation_name SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME // Get length of colname to align columns for printing fb_utils::fb_exact_name(RFR.RDB$FIELD_NAME); // Print the column name in first column sprintf (Print_buffer, "%-32s", RFR.RDB$FIELD_NAME); ISQL_printf (Out, Print_buffer); // Decide if this is a user-created domain if (!((strncmp (FLD.RDB$FIELD_NAME, "RDB$", 4) == 0) && isdigit (FLD.RDB$FIELD_NAME[4]) && FLD.RDB$SYSTEM_FLAG != 1)) { fb_utils::fb_exact_name(FLD.RDB$FIELD_NAME); sprintf (Print_buffer, "(%s) ", FLD.RDB$FIELD_NAME); ISQL_printf (Out, Print_buffer); } // Detect the existence of arrays if (!FLD.RDB$DIMENSIONS.NULL) { sprintf (Print_buffer, "ARRAY OF "); ISQL_printf (Out, Print_buffer); ISQL_array_dimensions (FLD.RDB$FIELD_NAME); sprintf (Print_buffer, "%s ", NEWLINE); ISQL_printf (Out, Print_buffer); } // If a computed field, show the source and exit // Note that view columns which are computed are dealt with later. if (!FLD.RDB$COMPUTED_BLR.NULL) { sprintf (Print_buffer, "Computed by: "); ISQL_printf (Out, Print_buffer); if (!FLD.RDB$COMPUTED_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &FLD.RDB$COMPUTED_SOURCE); ISQL_printf (Out, NEWLINE); continue; } // Look through types array for (SSHORT i = 0; Column_types[i].type; i++) if (FLD.RDB$FIELD_TYPE == Column_types[i].type) { bool precision_known = false; if (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 == blr_int64)) { 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 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); } } ISQL_printf (Out, Print_buffer); break; } if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { sprintf (Print_buffer, "(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); ISQL_printf (Out, Print_buffer); // Show international character sets and collations show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false); } if (FLD.RDB$FIELD_TYPE == BLOB) { sprintf (Print_buffer, " segment %u, subtype ", (USHORT) FLD.RDB$SEGMENT_LENGTH); ISQL_printf (Out, Print_buffer); const SSHORT subtype = FLD.RDB$FIELD_SUB_TYPE; if (subtype >= 0 && subtype <= MAXSUBTYPES) { sprintf (Print_buffer, "%s", Sub_types[subtype]); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, "%d", subtype); ISQL_printf (Out, Print_buffer); } // Show international character sets and collations show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false); } if (!FLD.RDB$COMPUTED_BLR.NULL) { // A view expression. Other computed fields will not reach this point. sprintf (Print_buffer, " Expression%s", NEWLINE); ISQL_printf (Out, Print_buffer); continue; } // The null flag is either 1 or null (for nullable) if (RFR.RDB$NULL_FLAG == 1 || FLD.RDB$NULL_FLAG == 1 || (!RFR.RDB$BASE_FIELD.NULL && !ISQL_get_null_flag (relation_name, RFR.RDB$FIELD_NAME))) { sprintf (Print_buffer, " Not Null "); ISQL_printf (Out, Print_buffer); } else { sprintf (Print_buffer, " Nullable "); ISQL_printf (Out, Print_buffer); } // Handle defaults for columns if (!RFR.RDB$DEFAULT_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &RFR.RDB$DEFAULT_SOURCE); else if (!FLD.RDB$DEFAULT_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &FLD.RDB$DEFAULT_SOURCE); ISQL_printf (Out, NEWLINE); // Validation clause for domains if (!FLD.RDB$VALIDATION_SOURCE.NULL) { sprintf (Print_buffer, " "); ISQL_printf (Out, Print_buffer); SHOW_print_metadata_text_blob (Out, &FLD.RDB$VALIDATION_SOURCE); ISQL_printf (Out, NEWLINE); } // Handle collations if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR) || (FLD.RDB$FIELD_TYPE == BLOB)) { show_charsets(relation_name, RFR.RDB$FIELD_NAME, false, true, true, true); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; // If this is a view and there were columns, print the view text if (!first) { FOR REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ relation_name AND REL.RDB$VIEW_BLR NOT MISSING sprintf (Print_buffer, "View Source:%s==== ======%s", NEWLINE, NEWLINE); ISQL_printf (Out, Print_buffer); if (!REL.RDB$VIEW_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &REL.RDB$VIEW_SOURCE); ISQL_printf (Out, NEWLINE); END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; } // Handle any referential or primary constraint on this table SCHAR* collist = (SCHAR*) ISQL_ALLOC(BUFFER_LENGTH512); if (!collist) { isc_status[0] = isc_arg_gds; isc_status[1] = isc_virmemexh; isc_status[2] = isc_arg_end; ISQL_errmsg(isc_status); return ERR; } // Static queries for obtaining referential constraints FOR RELC1 IN RDB$RELATION_CONSTRAINTS WITH RELC1.RDB$RELATION_NAME EQ relation_name SORTED BY RELC1.RDB$CONSTRAINT_TYPE, RELC1.RDB$CONSTRAINT_NAME ISQL_get_index_segments (collist, RELC1.RDB$INDEX_NAME, false); if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "PRIMARY", 7)) { fb_utils::fb_exact_name(RELC1.RDB$CONSTRAINT_NAME); sprintf (Print_buffer, "CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, " Primary key (%s)%s", collist, NEWLINE); ISQL_printf (Out, Print_buffer); } else if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "UNIQUE", 6)) { fb_utils::fb_exact_name(RELC1.RDB$CONSTRAINT_NAME); sprintf (Print_buffer, "CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, " Unique key (%s)%s", collist, NEWLINE); ISQL_printf (Out, Print_buffer); } else if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "FOREIGN", 7)) { fb_utils::fb_exact_name(RELC1.RDB$CONSTRAINT_NAME); sprintf (Print_buffer, "CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); ISQL_get_index_segments (collist, RELC1.RDB$INDEX_NAME, false); sprintf (Print_buffer, " Foreign key (%s)", collist); ISQL_printf (Out, Print_buffer); FOR RELC2 IN RDB$RELATION_CONSTRAINTS CROSS REFC IN RDB$REF_CONSTRAINTS WITH RELC2.RDB$CONSTRAINT_NAME EQ REFC.RDB$CONST_NAME_UQ AND REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME ISQL_get_index_segments (collist, RELC2.RDB$INDEX_NAME, false); fb_utils::fb_exact_name(RELC2.RDB$RELATION_NAME); sprintf (Print_buffer, " References %s (%s)", RELC2.RDB$RELATION_NAME, collist); ISQL_printf (Out, Print_buffer); if (!REFC.RDB$UPDATE_RULE.NULL) { ISQL_truncate_term (REFC.RDB$UPDATE_RULE, sizeof(REFC.RDB$UPDATE_RULE)); ISQL_ri_action_print (REFC.RDB$UPDATE_RULE, " On Update", false); } if (!REFC.RDB$DELETE_RULE.NULL) { ISQL_truncate_term (REFC.RDB$DELETE_RULE, sizeof(REFC.RDB$DELETE_RULE)); ISQL_ri_action_print (REFC.RDB$DELETE_RULE, " On Delete", false); } sprintf (Print_buffer, "%s", NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; } END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; FOR R_C IN RDB$RELATION_CONSTRAINTS CROSS C_C IN RDB$CHECK_CONSTRAINTS WITH R_C.RDB$RELATION_NAME EQ relation_name AND R_C.RDB$CONSTRAINT_TYPE EQ 'NOT NULL' AND R_C.RDB$CONSTRAINT_NAME EQ C_C.RDB$CONSTRAINT_NAME if (strncmp (R_C.RDB$CONSTRAINT_NAME, "INTEG_", 6)) { fb_utils::fb_exact_name(C_C.RDB$TRIGGER_NAME); fb_utils::fb_exact_name(R_C.RDB$CONSTRAINT_NAME); sprintf (Print_buffer, "CONSTRAINT %s:%s", R_C.RDB$CONSTRAINT_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, " Not Null Column (%s)%s", C_C.RDB$TRIGGER_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); } END_FOR ON_ERROR ISQL_errmsg(isc_status); ISQL_FREE(collist); return ERR; END_ERROR; if (collist) ISQL_FREE(collist); // Do check constraints show_check(relation_name); // Do triggers show_trigger(relation_name, false, false); if (first) return (OBJECT_NOT_FOUND); return SKIP; } static processing_state show_trigger( const SCHAR* object, bool show_source, bool isTriggerName) { /************************************** * * s h o w _ t r i g g e r * ************************************** * * Functional description * Show triggers in general or for the named object or trigger * **************************************/ bool first = true; bool skip = false; // Show all triggers if (!*object) { FOR TRG IN RDB$TRIGGERS CROSS REL IN RDB$RELATIONS WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME AND NOT (ANY CHK IN RDB$CHECK_CONSTRAINTS WITH TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME) SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_NAME if (first) { sprintf (Print_buffer, "Table name Trigger name%s", NEWLINE); ISQL_printf (Out, Print_buffer); sprintf (Print_buffer, "=========== ============%s", NEWLINE); ISQL_printf (Out, Print_buffer); first = false; } fb_utils::fb_exact_name(TRG.RDB$TRIGGER_NAME); fb_utils::fb_exact_name(TRG.RDB$RELATION_NAME); sprintf (Print_buffer, "%-32s %s%s%s", TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_NAME, (TRG.RDB$SYSTEM_FLAG == 1 ? "(system)" : ""), NEWLINE); ISQL_printf (Out, Print_buffer); END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return OBJECT_NOT_FOUND; else return (SKIP); } // Show triggers for the named object // and avoid check constraints char triggerName[32]; char relationName[32]; if (isTriggerName){ sprintf(triggerName,"%s",object); relationName[0] = '\0'; } else { sprintf(relationName,"%s",object); triggerName[0] = '\0'; } FOR TRG IN RDB$TRIGGERS WITH (TRG.RDB$RELATION_NAME EQ relationName OR TRG.RDB$TRIGGER_NAME EQ triggerName) SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME; skip = false; // Skip triggers for check constraints FOR FIRST 1 CHK IN RDB$CHECK_CONSTRAINTS WITH TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME skip = true; END_FOR ON_ERROR ISQL_errmsg (isc_status); return ERR; END_ERROR; if (skip) continue; fb_utils::fb_exact_name(TRG.RDB$TRIGGER_NAME); fb_utils::fb_exact_name(TRG.RDB$RELATION_NAME); if (first) { sprintf (Print_buffer, "%sTriggers on Table %s:%s", NEWLINE, TRG.RDB$RELATION_NAME, NEWLINE); ISQL_printf (Out, Print_buffer); first = false; } sprintf (Print_buffer, "%s, Sequence: %d, Type: %s, %s%s", TRG.RDB$TRIGGER_NAME, TRG.RDB$TRIGGER_SEQUENCE, trigger_action (TRG.RDB$TRIGGER_TYPE), (TRG.RDB$TRIGGER_INACTIVE ? "Inactive" : "Active"), NEWLINE); ISQL_printf (Out, Print_buffer); if (show_source) { // Use print_blob to print the blob if (!TRG.RDB$TRIGGER_SOURCE.NULL) SHOW_print_metadata_text_blob (Out, &TRG.RDB$TRIGGER_SOURCE); sprintf (Print_buffer, "%s+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%s", NEWLINE, NEWLINE); ISQL_printf (Out, Print_buffer); } END_FOR ON_ERROR ISQL_errmsg(isc_status); return ERR; END_ERROR; if (first) return OBJECT_NOT_FOUND; return SKIP; }