/* * PROGRAM: JRD Command Oriented Query Language * MODULE: show.epp * DESCRIPTION: Show environment commands * * 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): ______________________________________. */ #include "firebird.h" #include #include #include "../jrd/ibase.h" #include "../qli/dtr.h" #include "../qli/parse.h" #include "../qli/compile.h" #include "../jrd/license.h" #include "../qli/reqs.h" #include "../jrd/flags.h" #include "../qli/all_proto.h" #include "../qli/comma_proto.h" #include "../qli/err_proto.h" #include "../qli/meta_proto.h" #include "../qli/proc_proto.h" #include "../qli/show_proto.h" #include "../jrd/gds_proto.h" #include "../common/utils_proto.h" #include "../common/classes/UserBlob.h" using MsgFormat::SafeArg; static void array_dimensions(qli_dbb*, const TEXT*); static void display_acl(qli_dbb*, ISC_QUAD&); static void display_blob(qli_dbb*, ISC_QUAD&, const TEXT*, USHORT, const UCHAR*, bool); static void display_blr(qli_dbb*, ISC_QUAD&); static void display_text(qli_dbb*, ISC_QUAD&, const TEXT*, bool); static void display_procedure(qli_dbb*, const UCHAR*, FB_API_HANDLE); static USHORT get_window_size(int); static void show_blob_info(ISC_QUAD&, ISC_QUAD&, USHORT, USHORT, qli_dbb*, const TEXT*); static void show_blr(qli_dbb*, USHORT, ISC_QUAD&, USHORT, ISC_QUAD&); static void show_datatype(qli_dbb*, USHORT, USHORT, SSHORT, SSHORT, USHORT, USHORT); static void show_dbb(qli_dbb*); static void show_dbb_parameters(qli_dbb*); static int show_field_detail(qli_dbb*, const TEXT*, const TEXT*, qli_syntax*); static int show_field_instances(qli_dbb*, const TEXT*); static void show_fields(qli_rel*, qli_fld*); static void show_filt(qli_filter*); static int show_filter_detail(qli_dbb*, const TEXT*); static void show_filts(qli_dbb*); static int show_filters_detail(qli_dbb*); static void show_fld(qli_syntax*); static void show_func(qli_func*); static int show_func_detail(qli_dbb*, const TEXT*); static void show_funcs(qli_dbb*); static int show_funcs_detail(qli_dbb*); static int show_insecure_fields(qli_dbb*, const TEXT*, const TEXT*); //static void show_forms_db(qli_dbb*); static void show_gbl_field(qli_syntax*); static int show_gbl_field_detail(qli_dbb*, const TEXT*); static void show_gbl_fields(qli_dbb*); static int show_gbl_fields_detail(qli_dbb*); static int show_indices_detail(qli_rel*); static void show_matching(); static void show_names(const TEXT*, USHORT, TEXT*); static void show_proc(qli_proc*); static void show_procs(qli_dbb*); static void show_rel(qli_rel*); static void show_rel_detail(qli_rel*); static void show_rels(qli_dbb*, enum show_t, SSHORT); static USHORT show_security_class_detail(qli_dbb*, const TEXT*); static USHORT show_security_classes_detail(qli_dbb*); static void show_string(USHORT, TEXT*, USHORT, TEXT*); static void show_sys_trigs(qli_dbb*); static void show_text_blob(qli_dbb*, const TEXT*, USHORT, ISC_QUAD*, USHORT, ISC_QUAD*, bool); static void show_trig(qli_rel*); static int show_trigger_detail(qli_dbb*, const TEXT*); static void show_trigger_header(TEXT*, USHORT, USHORT, USHORT, ISC_QUAD&, qli_dbb*); // const TEXT*); static void show_trigger_messages(qli_dbb*, const TEXT*); static void show_trigger_status(TEXT*, USHORT, USHORT, USHORT); static void show_trigs(qli_dbb*); static int show_triggers_detail(qli_dbb*); static void show_var(const qli_name*); static void show_vars(); static void show_versions(); static void show_view(qli_rel*); static int show_views_detail(qli_dbb*); static void view_info(qli_dbb*, const TEXT*, const TEXT*, SSHORT, SSHORT); static const SCHAR db_items[] = { isc_info_page_size, isc_info_db_size_in_pages, isc_info_end }; static const UCHAR acl_bpb[] = { isc_bpb_version1, isc_bpb_source_type, 1, 3, isc_bpb_target_type, 1, 1 }; static const UCHAR blr_bpb[] = { isc_bpb_version1, isc_bpb_source_type, 1, 2, isc_bpb_target_type, 1, 1 }; DATABASE DB = EXTERN FILENAME "yachts.lnk"; /* values for rdb$trigger_type, based from types.h ** Some better way should be found to pick this up dynamically (?) ** until then, this must be kept in sync with jrd/types.h manually. */ const USHORT PRE_STORE = 1; const USHORT POST_STORE = 2; const USHORT PRE_MODIFY = 3; const USHORT POST_MODIFY = 4; const USHORT PRE_ERASE = 5; const USHORT POST_ERASE = 6; const int buf_len = 256; typedef TEXT buf_type[buf_len]; void SHOW_stuff( qli_syntax* node) { /************************************** * * S H O W _ s t u f f * ************************************** * * Functional description * Show various stuffs. * **************************************/ qli_rel* relation; qli_dbb* dbb; USHORT count; qli_name* name; SSHORT width; QLI_skip_line = true; qli_syntax** ptr = node->syn_arg; for (USHORT i = 0; i < node->syn_count; i++) { const show_t sw = (enum show_t)(IPTR)*ptr++; qli_syntax* value = *ptr++; if (sw != show_matching_language && sw != show_version && sw != show_variable && sw != show_variables && CMD_check_ready()) { return; } switch (sw) { case show_all: for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) { show_dbb(dbb); for (relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (!(relation->rel_flags & REL_system)) { show_rel(relation); show_fields(relation, NULL); } if (QLI_abort) return; } printf("\n"); } if (QLI_variables) show_vars(); break; case show_databases: for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) { show_dbb(dbb); show_dbb_parameters(dbb); } break; case show_database: if (!(dbb = (qli_dbb*) value)) dbb = QLI_databases; show_dbb(dbb); show_dbb_parameters(dbb); for (relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (!(relation->rel_flags & REL_system)) { show_rel(relation); show_fields(relation, NULL); } } printf("\n"); break; case show_relations: case show_system_relations: // No need to define a buffer here; we are interested in its length. width = get_window_size(buf_len - 1); if (dbb = (qli_dbb*) value) show_rels(dbb, sw, width); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) show_rels(dbb, sw, width); } break; case show_db_fields: dbb = (qli_dbb*) value; for (relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (!(relation->rel_flags & REL_system)) { show_rel(relation); show_fields(relation, NULL); } if (QLI_abort) return; } break; case show_security_classes: count = 0; if (value) count += show_security_classes_detail((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) count += show_security_classes_detail(dbb); } if (!count) { ERRQ_msg_put(90); // Msg90 No security classes defined } break; case show_security_class: count = 0; name = (qli_name*) value; for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) count += show_security_class_detail(dbb, name->nam_string); if (!count) { ERRQ_msg_put(91, name->nam_string); // Msg91 Security class %s is not defined } break; case show_views: count = 0; if (value) count += show_views_detail((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) count += show_views_detail(dbb); } if (!count) { ERRQ_msg_put(92); // Msg92 No views defined } break; case show_relation: show_rel((qli_rel*) value); show_fields((qli_rel*) value, NULL); show_view((qli_rel*) value); show_rel_detail((qli_rel*) value); break; case show_indices: if (value) { show_rel((qli_rel*) value); if (!show_indices_detail((qli_rel*) value)) { ERRQ_msg_put(93); // Msg93 No indices defined } break; } for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) { show_dbb(dbb); for (relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (!(relation->rel_flags & (REL_system | REL_view))) { show_rel(relation); if (!show_indices_detail(relation)) { ERRQ_msg_put(94); // Msg94 No indices defined } } } } break; case show_db_indices: dbb = (qli_dbb*) value; show_dbb(dbb); for (relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (!(relation->rel_flags & (REL_system | REL_view))) { show_rel(relation); if (!show_indices_detail(relation)) { ERRQ_msg_put(94); // Msg94 No indices defined } } } break; case show_field: show_fld(value); break; case show_filter: show_filt((qli_filter*) value); break; case show_filters: if (value) show_filts((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) show_filts(dbb); } break; /* case show_forms: if (value) show_forms_db((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) show_forms_db(dbb); } break; */ case show_function: show_func((qli_func*) value); break; case show_functions: if (value) show_funcs((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) show_funcs(dbb); } break; case show_matching_language: show_matching(); break; case show_procedures: if (value) show_procs((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) show_procs(dbb); } break; case show_procedure: show_proc((qli_proc*) value); break; case show_version: show_versions(); break; case show_variable: show_var((qli_name*) value); break; case show_variables: show_vars(); break; case show_global_field: show_gbl_field(value); break; case show_global_fields: show_gbl_fields((qli_dbb*) value); break; case show_trigger: show_trig((qli_rel*) value); break; case show_triggers: show_trigs((qli_dbb*) value); break; case show_system_triggers: if (value) show_sys_trigs((qli_dbb*) value); else { for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next) show_sys_trigs(dbb); } break; default: ERRQ_bugcheck(7); // Msg7 show option not implemented } } } static void array_dimensions( qli_dbb* database, const TEXT* field_name) { /************************************** * * a r r a y _ d i m e n s i o n s * ************************************** * * Functional description * Display the dimensions of an array * **************************************/ MET_meta_transaction(database, false); TEXT s[128], *p = s; s[0] = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_dimensions]) D IN RDB$FIELD_DIMENSIONS WITH D.RDB$FIELD_NAME = field_name SORTED BY D.RDB$DIMENSION if (D.RDB$LOWER_BOUND != 1) { sprintf(p, "%"SLONGFORMAT":", D.RDB$LOWER_BOUND); while (*++p); } sprintf(p, "%"SLONGFORMAT", ", D.RDB$UPPER_BOUND); while (*++p); END_FOR; --p; *--p = 0; ERRQ_msg_partial(479, SafeArg() << s); // Msg479 (%s) } static void display_acl( qli_dbb* dbb, ISC_QUAD& blob_id) { /************************************** * * d i s p l a y _ a c l * ************************************** * * Functional description * Display the contents of a security class * **************************************/ display_blob(dbb, blob_id, "\t ", sizeof(acl_bpb), acl_bpb, true); } static void display_blob(qli_dbb* dbb, ISC_QUAD& blob_id, const TEXT* prefix, USHORT bpb_length, const UCHAR* bpb, bool strip_line) { /************************************** * * d i s p l a y _ b l o b * ************************************** * * Functional description * Display the contents of a security class * **************************************/ ISC_STATUS_ARRAY status_vector; UserBlob blob(status_vector); if (!blob.open(dbb->dbb_handle, dbb->dbb_meta_trans, blob_id, bpb_length, bpb)) { ERRQ_database_error(dbb, status_vector); } buf_type buffer; const USHORT buffer_length = sizeof(buffer) - 1; for (;;) { size_t length; if (!blob.getSegment(buffer_length, buffer, length)) break; buffer[length--] = 0; if (strip_line) { for (TEXT* b = buffer + length; b >= buffer;) { if (*b == '\n' || *b == '\t' || *b == ' ') *b-- = 0; else break; } } else { if (buffer[length] == '\n') buffer[length] = 0; } if (buffer[0]) printf("%s%s\n", prefix, buffer); } blob.close(); } static void display_blr( qli_dbb* dbb, ISC_QUAD& blob_id) { /************************************** * * d i s p l a y _ b l r * ************************************** * * Functional description * Display the contents of a security class * **************************************/ display_blob(dbb, blob_id, "\t ", sizeof(blr_bpb), blr_bpb, true); } static void display_text( qli_dbb* dbb, ISC_QUAD& blob_id, const TEXT* prefix, bool strip) { /************************************** * * d i s p l a y _ t e x t * ************************************** * * Functional description * Display a text blob. * **************************************/ display_blob(dbb, blob_id, prefix, 0, NULL, strip); } static void display_procedure( qli_dbb* database, const UCHAR* name, FB_API_HANDLE blob) { /************************************** * * d i s p l a y _ p r o c e d u r e * ************************************** * * Functional description * Show definition of procedure. Somebody * else has already figured out what database * it's in, and so forth. * **************************************/ ERRQ_msg_put(96, SafeArg() << name << database->dbb_filename << database->dbb_symbol->sym_string); // Msg96 Procedure %s in database %s (%s) TEXT buffer[256]; while (PRO_get_line(blob, buffer, sizeof(buffer))) { printf(" %s", buffer); } PRO_close(database, blob); printf("\n"); } static USHORT get_window_size( int max_width) { /************************************** * * g e t _ w i n d o w _ s i z e * ************************************** * * Functional description * Get the display window size. * **************************************/ SSHORT result = QLI_columns; if (max_width < result) result = max_width; return result; } static void show_blob_info(ISC_QUAD& blob_blr, ISC_QUAD& blob_src, USHORT msg_blr, USHORT msg_src, qli_dbb* database, const TEXT* relation_name) { /***************************************************** * * s h o w _ b l o b _ i n f o * ***************************************************** * * Functional description * Display source if possible or blr. * *****************************************************/ if (UserBlob::blobIsNull(blob_src)) { ERRQ_msg_put(msg_blr); display_blr(database, blob_blr); } else { ERRQ_msg_put(msg_src, relation_name); show_text_blob(database, "\t", 0, &blob_src, 0, NULL, true); } } static void show_blr(qli_dbb* database, USHORT source_msg, ISC_QUAD& source, USHORT blr_msg, ISC_QUAD& blr) { /************************************** * * s h o w _ b l r * ************************************** * * Functional description * Show either source or blr for a blr item along with * appopriate messages. * **************************************/ if (!UserBlob::blobIsNull(source)) show_text_blob(database, "\t", source_msg, &source, 0, NULL, false); else if (!UserBlob::blobIsNull(blr)) { if (blr_msg) ERRQ_msg_put(blr_msg); display_blr(database, blr); } } static void show_datatype(qli_dbb* database, USHORT dtype, USHORT length, SSHORT scale, SSHORT sub_type, USHORT segment_length, USHORT dimensions) { /************************************** * * s h o w _ d a t a t y p e * ************************************** * * Functional description * Display datatype information. * **************************************/ TEXT subtype[32]; SSHORT msg = 0; switch (dtype) { case dtype_text: msg = 97; break; case dtype_varying: msg = 98; break; case dtype_cstring: length -= 1; msg = 99; break; case dtype_short: msg = 100; break; case dtype_long: msg = 101; break; case dtype_quad: msg = 102; break; case dtype_real: msg = 103; break; case dtype_double: msg = 104; break; case dtype_int64: msg = 329; break; case dtype_blob: ERRQ_msg_partial(105); // Msg105 blob if (segment_length) { ERRQ_msg_partial(106, SafeArg() << segment_length); // Msg106 , segment length %d } if (sub_type) { // Only the number in case there's no text name for the type. sprintf(subtype, "%d", sub_type); if (database && (database->dbb_capabilities & DBB_cap_types)) { FOR(REQUEST_HANDLE database->dbb_requests[REQ_fld_subtype]) TYPE IN RDB$TYPES WITH TYPE.RDB$FIELD_NAME EQ "RDB$FIELD_SUB_TYPE" AND TYPE.RDB$TYPE EQ sub_type TEXT* p = subtype; for (const TEXT* q = TYPE.RDB$TYPE_NAME; *q && *q != ' ';) { *p++ = *q++; } *p = 0; END_FOR; } ERRQ_msg_partial(107, SafeArg() << subtype); } return; case dtype_sql_date: ERRQ_msg_partial(110, SafeArg() << length); ERRQ_msg_partial(107, SafeArg() << "SQL DATE"); return; case dtype_sql_time: ERRQ_msg_partial(110, SafeArg() << length); ERRQ_msg_partial(107, SafeArg() << "SQL TIME"); return; case dtype_timestamp: msg = 110; break; default: ERRQ_bugcheck(8); // Msg8 show_fields: dtype not done } ERRQ_msg_partial(msg, SafeArg() << length); if (dimensions) { ERRQ_msg_partial(433); // Msg433 array } switch (dtype) { case dtype_short: case dtype_long: case dtype_quad: case dtype_int64: if (scale) { ERRQ_msg_partial(111, SafeArg() << scale); // Msg111 , scale %d } break; case dtype_text: case dtype_varying: case dtype_cstring: if (sub_type == 1) ERRQ_msg_partial(112); // Msg112 , subtype fixed else if (sub_type != 0) { sprintf(subtype, "%d", sub_type); ERRQ_msg_partial(107, SafeArg() << subtype); } break; } } static void show_dbb( qli_dbb* database) { /************************************** * * s h o w _ d b b * ************************************** * * Functional description * Print a database name and some * functional stuff about it. * **************************************/ if (database) { const qli_symbol* symbol = database->dbb_symbol; if (symbol) { ERRQ_msg_put(113, SafeArg() << database->dbb_filename << symbol->sym_string); // Msg113 Database %s readied as %s } else ERRQ_msg_put(114, database->dbb_filename); // Msg114 Database %s } else ERRQ_msg_put(115); // Msg115 No databases are currently ready } static void show_dbb_parameters( qli_dbb* database) { /************************************** * * s h o w _ d b b _ p a r a m e t e r s * ************************************** * * Functional description * Print stuff about a database. * **************************************/ UCHAR buffer[127]; ISC_STATUS_ARRAY status_vector; if (!database) return; if (isc_database_info(status_vector, &database->dbb_handle, sizeof(db_items), db_items, sizeof(buffer), (char*) buffer)) { ERRQ_database_error(database, status_vector); } SLONG page_size = 0, allocation = 0; for (const UCHAR* d = buffer; *d != isc_info_end;) { const UCHAR item = *d++; const SLONG length = gds__vax_integer(d, 2); d += 2; switch (item) { case isc_info_db_size_in_pages: allocation = gds__vax_integer(d, length); break; case isc_info_page_size: page_size = gds__vax_integer(d, length); break; case isc_info_error: break; } d += length; } ERRQ_msg_put(116, SafeArg() << page_size << allocation); // Msg116 Page size is %d bytes. Current allocation is %d pages. MET_meta_transaction(database, false); if (database->dbb_capabilities & DBB_cap_security) { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_dbb]) D IN RDB$DATABASE show_string(260, D.RDB$SECURITY_CLASS, 0, NULL); show_text_blob(database, "\t", 261, &D.RDB$DESCRIPTION, 0, NULL, false); END_FOR; } else { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_dbb]) D IN RDB$DATABASE show_text_blob(database, "\t", 262, &D.RDB$DESCRIPTION, 0, NULL, false); END_FOR; } if (database->dbb_capabilities & DBB_cap_files) { if (database->dbb_capabilities & DBB_cap_shadowing) { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_files]) F IN DB.RDB$FILES SORTED BY F.RDB$SHADOW_NUMBER, F.RDB$FILE_START if (F.RDB$SHADOW_NUMBER) { if (!(F.RDB$FILE_FLAGS & FILE_conditional)) { ERRQ_msg_put(385, SafeArg() << F.RDB$SHADOW_NUMBER << F.RDB$FILE_NAME << F.RDB$FILE_START); // Msg385 Shadow %d, File:%s starting at page %d } } else { ERRQ_msg_put(263, SafeArg() << F.RDB$FILE_NAME << F.RDB$FILE_START); // Msg263 File:%s starting at page %d } END_FOR; } else { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_files]) F IN DB.RDB$FILES SORTED BY F.RDB$FILE_START ERRQ_msg_put(263, SafeArg() << F.RDB$FILE_NAME << F.RDB$FILE_START); // Msg263 File:%s starting at page %d END_FOR; } } } static int show_field_detail(qli_dbb* database, const TEXT* relation_name, const TEXT* field_name, qli_syntax* idx_node) { /************************************** * * s h o w _ f i e l d _ d e t a i l * ************************************** * * Functional description * Show everything we know about local * fields with the specified name in a particular * database. * **************************************/ MET_meta_transaction(database, false); USHORT count = 0; if (!(database->dbb_capabilities & DBB_cap_security)) count += show_insecure_fields(database, relation_name, field_name); FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_field]) RFR IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS CROSS R IN RDB$RELATIONS WITH RFR.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME AND R.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND (RFR.RDB$FIELD_NAME = field_name OR RFR.RDB$QUERY_NAME = field_name OR (RFR.RDB$QUERY_NAME MISSING AND F.RDB$QUERY_NAME = field_name)) fb_utils::exact_name(RFR.RDB$RELATION_NAME); if (relation_name && (strcmp(RFR.RDB$RELATION_NAME, relation_name))) continue; const USHORT dimensions = MET_dimensions(database, F.RDB$FIELD_NAME); if (dimensions && idx_node && dimensions != idx_node->syn_arg[s_idx_count]->syn_count) { continue; } if (count++) printf("\n"); fb_utils::exact_name(RFR.RDB$FIELD_NAME); fb_utils::exact_name(F.RDB$FIELD_NAME); if (!R.RDB$VIEW_BLR.NULL) { ERRQ_msg_put(495, SafeArg() << RFR.RDB$FIELD_NAME << RFR.RDB$RELATION_NAME << database->dbb_symbol->sym_string); // Msg495 Field %s in view %s of database %s } else { ERRQ_msg_put(496, SafeArg() << RFR.RDB$FIELD_NAME << RFR.RDB$RELATION_NAME << database->dbb_symbol->sym_string); // Msg495 Field %s in relation %s of database %s } ERRQ_msg_put(265, F.RDB$FIELD_NAME); // Msg265 Global field %s if (!RFR.RDB$BASE_FIELD.NULL) { fb_utils::exact_name(RFR.RDB$BASE_FIELD); view_info(database, RFR.RDB$RELATION_NAME, RFR.RDB$BASE_FIELD, RFR.RDB$VIEW_CONTEXT, 0); } show_text_blob(database, "\t", 266, &RFR.RDB$DESCRIPTION, 339, &F.RDB$DESCRIPTION, false); ERRQ_msg_put(267); // Msg267 Datatype information: printf("\t"); show_datatype(database, MET_get_datatype(F.RDB$FIELD_TYPE), F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_SUB_TYPE, F.RDB$SEGMENT_LENGTH, dimensions); if (dimensions && !idx_node) array_dimensions(database, F.RDB$FIELD_NAME); printf("\n"); show_blr(database, 341, F.RDB$COMPUTED_SOURCE, 341, F.RDB$COMPUTED_BLR); show_blr(database, 342, F.RDB$VALIDATION_SOURCE, 342, F.RDB$VALIDATION_BLR); show_string(270, RFR.RDB$SECURITY_CLASS, 0, NULL); show_string(271, RFR.RDB$QUERY_NAME, 271, F.RDB$QUERY_NAME); show_string(273, RFR.RDB$EDIT_STRING, 273, F.RDB$EDIT_STRING); show_text_blob(database, "\t", 275, &RFR.RDB$QUERY_HEADER, 275, &F.RDB$QUERY_HEADER, false); END_FOR; return count; } static int show_field_instances( qli_dbb* database, const TEXT* field_name) { /************************************** * * s h o w _ f i e l d _ i n s t a n c e s * ************************************** * * Functional description * Print a list of places where a global field * is used. * **************************************/ int count = 0; MET_meta_transaction(database, false); FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_field_instance]) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$FIELD_SOURCE = field_name SORTED BY RFR.RDB$RELATION_NAME if (!count++) { ERRQ_msg_put(335, SafeArg() << field_name << database->dbb_symbol->sym_string); // Msg335 Global field %s is used database %s as: } fb_utils::exact_name(RFR.RDB$FIELD_NAME); fb_utils::exact_name(RFR.RDB$RELATION_NAME); ERRQ_msg_put(336, SafeArg() << RFR.RDB$FIELD_NAME << RFR.RDB$RELATION_NAME); // Msg336 %s in relation %s END_FOR; return count; } static void show_fields( qli_rel* relation, qli_fld* fields) { /************************************** * * s h o w _ f i e l d s * ************************************** * * Functional description * Show the fields for a relation. * **************************************/ qli_dbb* database; // Find the long field name (including query name) if (relation) { if (!(relation->rel_flags & REL_fields)) MET_fields(relation); fields = relation->rel_fields; database = relation->rel_database; MET_meta_transaction(database, false); } else database = NULL; USHORT max_name = 0; const qli_fld* field; for (field = fields; field; field = field->fld_next) { USHORT l = field->fld_name->sym_length; const qli_symbol* symbol = field->fld_query_name; if (symbol) l += symbol->sym_length + 3; max_name = MAX(max_name, l); } // Now print the fields for (field = fields; field; field = field->fld_next) { if (QLI_abort) return; const qli_symbol* symbol = field->fld_name; USHORT l = symbol->sym_length; printf(" %s", symbol->sym_string); if (symbol = field->fld_query_name) { l += symbol->sym_length + 3; printf(" (%s)", symbol->sym_string); } for (l = max_name + 12 - l; l; --l) putchar(' '); show_datatype(database, field->fld_dtype, (field->fld_dtype == dtype_varying) ? field->fld_length - 2 : field->fld_length, field->fld_scale, field->fld_sub_type, field->fld_segment_length, (field->fld_flags & FLD_array) ? 1 : 0); if (database && field->fld_flags & FLD_array) array_dimensions(database, field->fld_name->sym_string); if (field->fld_flags & FLD_computed) ERRQ_msg_put(119); // Msg119 (computed expression) else printf("\n"); } } static void show_filt( qli_filter* filter) { /************************************** * * s h o w _ f i l t * ************************************** * * Functional description * Show definition of filter. If a particular database * was specified, look there, otherwise, print all filters * with that name. * **************************************/ int count = 0; const qli_name* name = filter->qfl_name; qli_dbb* database = filter->qfl_database; if (database) { if (!(database->dbb_capabilities & DBB_cap_filters)) { // Msg439 Filters are not supported in database %s. ERRQ_msg_put(439, database->dbb_symbol->sym_string); return; } count = show_filter_detail(database, name->nam_string); if (!count) { // Msg440 Filter %s is not defined in database %s. ERRQ_msg_put(440, SafeArg() << name->nam_string << database->dbb_symbol->sym_string); } } else { bool any_supported = false; for (database = QLI_databases; database; database = database->dbb_next) { if (database->dbb_capabilities & DBB_cap_filters) { any_supported = true; count += show_filter_detail(database, name->nam_string); } } if (!count) { if (any_supported) { // Msg441 Filter %s is not defined in any open database ERRQ_msg_put(441, name->nam_string); } else { // Msg442 Filters are not supported in any open database. ERRQ_msg_put(442); } } } } static int show_filter_detail( qli_dbb* database, const TEXT* filter_name) { /************************************** * * s h o w _ f i l t e r _ d e t a i l * ************************************** * * Functional description * Display the following information about a * filter with the specified name in a particular * database: Filter name, filter library, input and * output sub-types, and description. * **************************************/ MET_meta_transaction(database, false); int count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_filter_detail]) F IN RDB$FILTERS WITH F.RDB$FUNCTION_NAME = filter_name count++; fb_utils::exact_name(F.RDB$FUNCTION_NAME); ERRQ_msg_put(444, // Msg444 Filter %s in database \"%s\" (%s): SafeArg() << F.RDB$FUNCTION_NAME << database->dbb_filename << database->dbb_symbol->sym_string); ERRQ_msg_put(445, F.RDB$MODULE_NAME); // Msg445 Filter library is %s ERRQ_msg_put(446, SafeArg() << F.RDB$INPUT_SUB_TYPE); // Msg446 Input sub-type is %d ERRQ_msg_put(447, SafeArg() << F.RDB$OUTPUT_SUB_TYPE); // Msg447 Output sub-type is %d show_text_blob(database, "\t", 448, &F.RDB$DESCRIPTION, 0, NULL, false); END_FOR; return count; } static void show_filts( qli_dbb* database) { /************************************** * * s h o w _ f i l t s * * Functional description * Show filter names in a database. * **************************************/ if (!(database->dbb_capabilities & DBB_cap_filters)) { // Msg463 Filters are not supported for database %s. ERRQ_msg_put(463, database->dbb_symbol->sym_string); } else if (!(show_filters_detail(database))) { // Msg464 no filters defined for database %s. ERRQ_msg_put(464, database->dbb_symbol->sym_string); } } static int show_filters_detail( qli_dbb* database) { /************************************** * * s h o w _ f i l t e r s _ d e t a i l * ************************************** * * Functional description * Show filter names in a database. * **************************************/ buf_type buffer; SSHORT width = get_window_size(sizeof(buffer) - 1); buffer[0] = 0; MET_meta_transaction(database, false); int count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_filters]) F IN RDB$FILTERS SORTED BY F.RDB$FUNCTION_NAME if (!count++) { ERRQ_msg_put(449, SafeArg() << database->dbb_filename << database->dbb_symbol->sym_string); // Msg449 Filters in database %s (%s): } show_names(F.RDB$FUNCTION_NAME, width, buffer); END_FOR; if (buffer[0]) printf("%s\n", buffer); return count; } static void show_fld( qli_syntax* field_node) { /************************************** * * s h o w _ f l d * ************************************** * * Functional description * Show all details about a particular * field. What we've got coming in * is a list of 1, 2, or 3 name blocks, * contain the [[database.]relation.]field * specification. Figure out what we've * got and let somebody else do all the work. * **************************************/ qli_syntax* idx_node = NULL; if (field_node->syn_type == nod_index) { idx_node = field_node; field_node = idx_node->syn_arg[s_idx_field]; } qli_dbb* database = NULL; qli_name* field_name = NULL; qli_name* relation_name = NULL; for (qli_syntax** ptr = field_node->syn_arg + field_node->syn_count; --ptr >= field_node->syn_arg;) { if (!field_name) field_name = (qli_name*) * ptr; else if (!relation_name) relation_name = (qli_name*) * ptr; else for (qli_symbol* symbol = ((qli_name*) *ptr)->nam_symbol; symbol; symbol = symbol->sym_homonym) { if (symbol->sym_type == SYM_database) { database = (qli_dbb*) symbol->sym_object; break; } } } const TEXT* string = relation_name ? relation_name->nam_string : NULL; TEXT s[65]; if (string) sprintf(s, "%s.%s", string, field_name->nam_string); else sprintf(s, "%s", field_name->nam_string); int count = 0; if (database) { count += show_field_detail(database, string, field_name->nam_string, NULL); if (!count) { ERRQ_msg_put(117, SafeArg() << s << database->dbb_symbol->sym_string); // Msg117 Field %s does not exist in database %s } } else { for (database = QLI_databases; database; database = database->dbb_next) { count += show_field_detail(database, string, field_name->nam_string, idx_node); } if (!count) { ERRQ_msg_put(118, s); // Msg118 Field %s does not exist in any open database } } } static void show_func( qli_func* func) { /************************************** * * s h o w _ f u n c * ************************************** * * Functional description * Show definition of function. If a particular database * was specified, look there, otherwise, print all functions * with that name. * **************************************/ int count = 0; const qli_name* name = func->qfn_name; qli_dbb* database = func->qfn_database; if (database) { if (!(database->dbb_capabilities & DBB_cap_functions)) { // Msg417 Functions are not supported in database %s. ERRQ_msg_put(417, database->dbb_symbol->sym_string); return; } count = show_func_detail(database, name->nam_string); if (!count) { // Msg422 Function %s is not defined in database %s. ERRQ_msg_put(422, SafeArg() << name->nam_string << database->dbb_symbol->sym_string); } } else { bool any_supported = false; for (database = QLI_databases; database; database = database->dbb_next) { if (database->dbb_capabilities & DBB_cap_functions) { any_supported = true; count += show_func_detail(database, name->nam_string); } } if (!count) { if (any_supported) { // Msg423 Function is %s not defined in any open database ERRQ_msg_put(423, name->nam_string); } else { // Msg420 Functions are not supported in any open database. ERRQ_msg_put(420); } } } } static int show_func_detail( qli_dbb* database, const TEXT* func_name) { /************************************** * * s h o w _ f u n c _ d e t a i l * ************************************** * * Functional description * Display the following information about a * function with the specified name in a particular * database: Function name, query name, function * library, input and output argument datatypes, and * description. * **************************************/ MET_meta_transaction(database, false); int count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_func_detail]) F IN RDB$FUNCTIONS WITH (F.RDB$FUNCTION_NAME = func_name OR F.RDB$QUERY_NAME = func_name) count++; fb_utils::exact_name(F.RDB$QUERY_NAME); fb_utils::exact_name(F.RDB$FUNCTION_NAME); BASED ON RDB$FUNCTIONS.RDB$QUERY_NAME fq_name; strcpy(fq_name, F.RDB$FUNCTION_NAME); if (F.RDB$QUERY_NAME[0]) { ERRQ_msg_put(424, // Msg424 Function %s (%s) in database \"%s\" (%s): SafeArg() << F.RDB$FUNCTION_NAME << F.RDB$QUERY_NAME << database->dbb_filename << database->dbb_symbol->sym_string); } else { ERRQ_msg_put(425, // Msg425 Function %s in database \"%s\" (%s): SafeArg() << F.RDB$FUNCTION_NAME << database->dbb_filename << database->dbb_symbol->sym_string); } ERRQ_msg_put(426, F.RDB$MODULE_NAME); // Msg426 Function library is %s FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_func_args]) FA IN RDB$FUNCTION_ARGUMENTS WITH FA.RDB$FUNCTION_NAME = fq_name SORTED BY FA.RDB$ARGUMENT_POSITION if (FA.RDB$ARGUMENT_POSITION == 0) { ERRQ_msg_partial(427); // Msg427 Return argument is } else { ERRQ_msg_partial(428, SafeArg() << FA.RDB$ARGUMENT_POSITION); // Msg428 Argument %d is } const USHORT array = (FA.RDB$MECHANISM == 2); // funct below wants USHORT show_datatype(database, MET_get_datatype(FA.RDB$FIELD_TYPE), FA.RDB$FIELD_LENGTH, FA.RDB$FIELD_SCALE, FA.RDB$FIELD_SUB_TYPE, 0, array); printf("\n"); END_FOR; show_text_blob(database, "\t", 421, &F.RDB$DESCRIPTION, 0, NULL, false); END_FOR; return count; } static void show_funcs( qli_dbb* database) { /************************************** * * s h o w _ f u n c s * ************************************** * * Functional description * Show function names in all ready databases, * or a specific database. * **************************************/ if (!(database->dbb_capabilities & DBB_cap_functions)) { ERRQ_msg_put(461, database->dbb_symbol->sym_string); // 461 - functions aren't supported in this database } if (!(show_funcs_detail(database))) { ERRQ_msg_put(462, database->dbb_symbol->sym_string); // 462 - no functions are defined in this database } } static int show_funcs_detail( qli_dbb* database) { /************************************** * * s h o w _ f u n c s _ d e t a i l * ************************************** * * Functional description * Show function names in a database. * **************************************/ buf_type buffer; SSHORT width = get_window_size(sizeof(buffer) - 1); buffer[0] = 0; MET_meta_transaction(database, false); int count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_functions]) F IN RDB$FUNCTIONS SORTED BY F.RDB$FUNCTION_NAME if (!count++) { // Msg416 Functions in database %s (%s): ERRQ_msg_put(416, SafeArg() << database->dbb_filename << database->dbb_symbol->sym_string); } show_names(F.RDB$FUNCTION_NAME, width, buffer); END_FOR; if (buffer[0]) printf("%s\n", buffer); return count; } static int show_insecure_fields(qli_dbb* database, const TEXT* relation_name, const TEXT* field_name) { /************************************** * * s h o w _ i n s e c u r e _ f i e l d s * ************************************** * * Functional description * Show everything we know about local * fields with the specified name in a particular * database, that doesn't have security classes * defined. * **************************************/ int count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_field]) RFR IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS CROSS R IN RDB$RELATIONS WITH RFR.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME AND R.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND (RFR.RDB$FIELD_NAME = field_name OR RFR.RDB$QUERY_NAME = field_name OR (RFR.RDB$QUERY_NAME MISSING AND F.RDB$QUERY_NAME = field_name)) fb_utils::exact_name(RFR.RDB$RELATION_NAME); if (relation_name && (strcmp(RFR.RDB$RELATION_NAME, relation_name))) continue; if (count++) printf("\n"); fb_utils::exact_name(RFR.RDB$FIELD_NAME); fb_utils::exact_name(F.RDB$FIELD_NAME); if (R.RDB$VIEW_BLR.NULL) { ERRQ_msg_put(496, SafeArg() << RFR.RDB$FIELD_NAME << RFR.RDB$RELATION_NAME << database->dbb_symbol->sym_string); // Msg495 Field %s in relation %s of database %s } else { ERRQ_msg_put(495, SafeArg() << RFR.RDB$FIELD_NAME << RFR.RDB$RELATION_NAME << database->dbb_symbol->sym_string); // Msg495 Field %s in view %s of database %s } ERRQ_msg_put(338, F.RDB$FIELD_NAME); // Msg338 Global field %s if (!RFR.RDB$BASE_FIELD.NULL) { fb_utils::exact_name(RFR.RDB$BASE_FIELD); view_info(database, RFR.RDB$RELATION_NAME, RFR.RDB$BASE_FIELD, RFR.RDB$VIEW_CONTEXT, 0); } show_text_blob(database, "\t", 339, &RFR.RDB$DESCRIPTION, 339, &F.RDB$DESCRIPTION, false); ERRQ_msg_partial(340); // Msg340 Datatype information: printf("\t"); show_datatype(database, MET_get_datatype(F.RDB$FIELD_TYPE), F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_SUB_TYPE, F.RDB$SEGMENT_LENGTH, MET_dimensions(database, F.RDB$FIELD_NAME)); printf("\n"); show_blr(database, 341, F.RDB$COMPUTED_SOURCE, 341, F.RDB$COMPUTED_BLR); show_blr(database, 342, F.RDB$VALIDATION_SOURCE, 342, F.RDB$VALIDATION_BLR); show_string(343, RFR.RDB$QUERY_NAME, 343, F.RDB$QUERY_NAME); show_string(346, RFR.RDB$EDIT_STRING, 346, F.RDB$EDIT_STRING); show_text_blob(database, "\t", 345, &RFR.RDB$QUERY_HEADER, 345, &F.RDB$QUERY_HEADER, false); END_FOR; return count; } #ifdef NOT_USED_OR_REPLACED static void show_forms_db( qli_dbb* database) { /************************************** * * s h o w _ f o r m s _ d b * ************************************** * * Functional description * Show what we know about forms * for one database. * **************************************/ ERRQ_msg_put(120, database->dbb_symbol->sym_string); // Msg120 There are no forms defined for database %s } #endif // NOT_USED_OR_REPLACED static void show_gbl_field( qli_syntax* field_node) { /************************************** * * s h o w _ g b l _ f i e l d * ************************************** * * Functional description * Show what we know about a global * field. It may be qualified with a * database handle, in which case, show only * the one global field in that database, * otherwise show them all. * **************************************/ qli_name* field_name = NULL; qli_dbb* database = NULL; for (qli_syntax** ptr = field_node->syn_arg + field_node->syn_count - 1; ptr >= field_node->syn_arg; ptr--) { if (!field_name) { field_name = (qli_name*) * ptr; } else { qli_name* name = (qli_name*) *ptr; for (qli_symbol* symbol = name->nam_symbol; symbol; symbol = symbol->sym_homonym) { if (symbol->sym_type == SYM_database) { database = (qli_dbb*) symbol->sym_object; break; } } } } int count = 0; if (database) { count += show_gbl_field_detail(database, field_name->nam_string); if (!count) { ERRQ_msg_put(122, // Msg122 Global field %s does not exist in database %s SafeArg() << field_name->nam_string << database->dbb_symbol->sym_string); } } else { for (database = QLI_databases; database; database = database->dbb_next) count += show_gbl_field_detail(database, field_name->nam_string); if (!count) { ERRQ_msg_put(123, field_name->nam_string); // Msg123 Global field %s does not exist in any open database } } } static int show_gbl_field_detail( qli_dbb* database, const TEXT* field_name) { /************************************** * * s h o w _ g b l _ f i e l d _ d e t a i l * ************************************** * * Functional description * Show everything we know about a global * field with the specified name in a particular * database. * **************************************/ int count = 0; MET_meta_transaction(database, false); FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_global_field]) F IN RDB$FIELDS WITH F.RDB$FIELD_NAME = field_name if (count++) printf("\n"); fb_utils::exact_name(F.RDB$FIELD_NAME); ERRQ_msg_put(276, SafeArg() << F.RDB$FIELD_NAME << database->dbb_symbol->sym_string); // Msg276 Global field %s in database %s show_text_blob(database, "\t", 277, &F.RDB$DESCRIPTION, 0, NULL, false); ERRQ_msg_put(278); // Msg278 Datatype information: printf("\t"); show_datatype(database, MET_get_datatype(F.RDB$FIELD_TYPE), F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_SUB_TYPE, F.RDB$SEGMENT_LENGTH, MET_dimensions(database, F.RDB$FIELD_NAME)); printf("\n"); show_blr(database, 279, F.RDB$COMPUTED_SOURCE, 341, F.RDB$COMPUTED_BLR); show_blr(database, 280, F.RDB$VALIDATION_SOURCE, 342, F.RDB$VALIDATION_BLR); show_string(281, F.RDB$QUERY_NAME, 0, NULL); show_string(282, F.RDB$EDIT_STRING, 0, NULL); show_text_blob(database, "\t", 283, &F.RDB$QUERY_HEADER, 0, NULL, false); END_FOR; if (count && !(show_field_instances(database, field_name))) { ERRQ_msg_put(284, SafeArg() << field_name << database->dbb_symbol->sym_string); // Msg284 %s is not used in any relations in database %s } return count; } static void show_gbl_fields( qli_dbb* database) { /************************************** * * s h o w _ g b l _ f i e l d s * ************************************** * * Functional description * Show what we know about a global * field. It may be qualified with a * database handle, in which case, show only * the global fields in that database, * otherwise show them all. * **************************************/ int count = 0; if (database) { count += show_gbl_fields_detail(database); if (!count) { ERRQ_msg_put(124, database->dbb_symbol->sym_string); // Msg124 There are no fields defined for database %s } } else { for (database = QLI_databases; database; database = database->dbb_next) { count += show_gbl_fields_detail(database); } if (!count) { ERRQ_msg_put(125); // Msg125 There are no fields defined in any open database } } } static int show_gbl_fields_detail( qli_dbb* database) { /************************************** * * s h o w _ g b l _ f i e l d s _ d e t a i l * ************************************** * * Functional description * Show everything we know about * global fields in a particular * database. * **************************************/ int count = 0; MET_meta_transaction(database, false); FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_global_fields]) F IN RDB$FIELDS WITH F.RDB$SYSTEM_FLAG MISSING OR F.RDB$SYSTEM_FLAG = 0 SORTED BY F.RDB$FIELD_NAME if (!count++) { ERRQ_msg_put(286, SafeArg() << database->dbb_symbol->sym_string); // Msg286 Global fields for database %s: } if (!F.RDB$COMPUTED_BLR.NULL) continue; printf(" %s", F.RDB$FIELD_NAME); show_datatype(database, MET_get_datatype(F.RDB$FIELD_TYPE), F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, F.RDB$FIELD_SUB_TYPE, F.RDB$SEGMENT_LENGTH, MET_dimensions(database, F.RDB$FIELD_NAME)); show_text_blob(database, "\t", 262, &F.RDB$DESCRIPTION, 0, NULL, false); printf("\n"); END_FOR; return count; } static int show_indices_detail( qli_rel* relation) { /************************************** * * s h o w _ i n d i c e s _ d e t a i l * ************************************** * * Functional description * Show indices for a relation. If none, return 0. * **************************************/ USHORT count = 0; qli_dbb* database = relation->rel_database; MET_meta_transaction(database, false); if (database->dbb_capabilities & DBB_cap_idx_inactive) { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_indices]) X IN RDB$INDICES CROSS Z IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string AND Z.RDB$RELATION_NAME EQ X.RDB$RELATION_NAME AND Z.RDB$VIEW_BLR MISSING SORTED BY X.RDB$INDEX_NAME ++count; USHORT type = 0; // this wasn't reset for each index! if (database->dbb_capabilities & DBB_cap_index_type) { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_index_type]) Y IN RDB$INDICES WITH Y.RDB$INDEX_NAME = X.RDB$INDEX_NAME type = Y.RDB$INDEX_TYPE; END_FOR; } // Index name can have spaces, we need something like MET_exact_name() // to replace the custom loops that get rid of trailing spaces. // I found truncate_string(). But later replaced it by fb_utils::exact_name(). fb_utils::exact_name(X.RDB$INDEX_NAME); ERRQ_msg_put(450, SafeArg() << X.RDB$INDEX_NAME << ((X.RDB$UNIQUE_FLAG) ? " (unique)" : "") << ((type == 1) ? " (descending)" : "") << ((X.RDB$INDEX_INACTIVE) ? " (inactive)" : "")); // Msg450 Index %s%s%s%s FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_index]) Y IN RDB$INDEX_SEGMENTS WITH Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME SORTED BY Y.RDB$FIELD_POSITION fb_utils::exact_name(Y.RDB$FIELD_NAME); printf(" %s\n", Y.RDB$FIELD_NAME); END_FOR; if (!X.RDB$EXPRESSION_SOURCE.NULL) show_text_blob(database, "\t ", 0, &X.RDB$EXPRESSION_SOURCE, 0, NULL, true); else if (!X.RDB$EXPRESSION_BLR.NULL) { ERRQ_msg_put (485); display_blr(database, X.RDB$EXPRESSION_BLR); } END_FOR; } else { FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_indices]) X IN RDB$INDICES CROSS Z IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string AND Z.RDB$RELATION_NAME EQ X.RDB$RELATION_NAME AND Z.RDB$VIEW_BLR MISSING SORTED BY X.RDB$INDEX_NAME ++count; fb_utils::exact_name(X.RDB$INDEX_NAME); ERRQ_msg_put(290, SafeArg() << X.RDB$INDEX_NAME << ((X.RDB$UNIQUE_FLAG) ? " (unique)" : "")); // Msg290 Index %s%s FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_index]) Y IN RDB$INDEX_SEGMENTS WITH Y.RDB$INDEX_NAME EQ X.RDB$INDEX_NAME SORTED BY Y.RDB$FIELD_POSITION fb_utils::exact_name(Y.RDB$FIELD_NAME); printf(" %s\n", Y.RDB$FIELD_NAME); END_FOR; END_FOR; } return count; } static void show_matching() { /************************************** * * s h o w _ m a t c h i n g * ************************************** * * Functional description * Just print the QLI matching language string. * **************************************/ if (QLI_abort) return; if (QLI_matching_language) { buf_type buffer; strncpy(buffer, (char*) QLI_matching_language->con_data, QLI_matching_language->con_desc.dsc_length); buffer[QLI_matching_language->con_desc.dsc_length] = 0; printf("\n\t%s\n", buffer); } } static void show_names( const TEXT* name, USHORT width, TEXT* buffer) { /************************************** * * s h o w _ n a m e s * ************************************** * * Functional description * **************************************/ BASED ON QLI$PROCEDURES.QLI$PROCEDURE_NAME padded_name; TEXT* s = buffer + strlen(buffer); SSHORT len = sizeof(padded_name) - 1; const SSHORT l1 = s - buffer; if ((s != buffer) && ((l1 + len + 4) > width)) { printf("%s\n", buffer); buffer[0] = 0; s = buffer; } *s++ = ' '; *s++ = ' '; *s++ = ' '; *s++ = ' '; strcpy(s, name); while (*s) { s++; len--; } while (len--) { *s++ = ' '; } *s = 0; } static void show_proc( qli_proc* proc) { /************************************** * * s h o w _ p r o c * ************************************** * * Functional description * Show definition of procedure. If a particular database * was specified, look there, otherwise, print all procedures * with that name. * **************************************/ const qli_name* name = proc->qpr_name; qli_dbb* database = proc->qpr_database; if (database) { FB_API_HANDLE blob = PRO_fetch_procedure(database, (TEXT*) name->nam_string); if (blob) display_procedure(database, (const UCHAR*) name->nam_string, blob); else { ERRQ_msg_put(126, // Msg126 Procedure %s not found in database %s SafeArg() << name->nam_string << database->dbb_symbol->sym_string); } return; } int count = 0; for (database = QLI_databases; database; database = database->dbb_next) { FB_API_HANDLE blob = PRO_fetch_procedure(database, (TEXT*) name->nam_string); if (blob) { display_procedure(database, (const UCHAR*) name->nam_string, blob); count++; } } if (!count) { ERRQ_msg_put(127, name->nam_string); // Msg127 Procedure %s not found return; } } static void show_procs( qli_dbb* database) { /************************************** * * s h o w _ p r o c s * ************************************** * * Functional description * Show procedures in a database * **************************************/ buf_type buffer; const SSHORT width = get_window_size(sizeof(buffer) - 1); PRO_setup(database); ERRQ_msg_put(128, SafeArg() << database->dbb_filename << // Msg128 Procedures in database %s (%s): database->dbb_symbol->sym_string); buffer[0] = 0; FOR(REQUEST_HANDLE database->dbb_scan_blobs) X IN DB.QLI$PROCEDURES SORTED BY X.QLI$PROCEDURE_NAME show_names(X.QLI$PROCEDURE_NAME, width, buffer); END_FOR; if (buffer[0]) printf("%s\n", buffer); } static void show_rel( qli_rel* relation) { /************************************** * * s h o w _ r e l * ************************************** * * Functional description * Just print a relation name. Almost mindless. * **************************************/ if (QLI_abort) return; printf(" %s\n", relation->rel_symbol->sym_string); } static void show_rel_detail( qli_rel* relation) { /************************************** * * s h o w _ r e l _ d e t a i l * ************************************** * * Functional description * Ask META to print description, * security class, etc. * **************************************/ const TEXT* relation_name = relation->rel_symbol->sym_string; qli_dbb* database = relation->rel_database; MET_meta_transaction(database, false); FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_rel_detail]) R IN RDB$RELATIONS WITH R.RDB$RELATION_NAME = relation_name show_text_blob(database, "\t", 291, &R.RDB$DESCRIPTION, 0, NULL, false); if (database->dbb_capabilities & DBB_cap_security) FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_rel_secur]) S IN RDB$RELATIONS WITH S.RDB$RELATION_NAME = R.RDB$RELATION_NAME AND S.RDB$SECURITY_CLASS NOT MISSING show_string(292, S.RDB$SECURITY_CLASS, 0, NULL); END_FOR; if (database->dbb_capabilities & DBB_cap_extern_file) FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_rel_extern]) E IN RDB$RELATIONS WITH E.RDB$RELATION_NAME = R.RDB$RELATION_NAME AND E.RDB$EXTERNAL_FILE NOT MISSING ERRQ_msg_put(293, E.RDB$EXTERNAL_FILE); // Msg293 Stored in external file %s END_FOR; // OBSOLETE - Handling of DBB_cap_triggers (old V2 style triggers) // OBSOLETE - Msg294 An erase trigger is defined for %s // OBSOLETE - Msg295 A modify trigger is defined for %s // OBSOLETE - Msg296 A store trigger is defined for %s if (database->dbb_capabilities & DBB_cap_new_triggers) { USHORT msg = 380; FOR(REQUEST_HANDLE database->dbb_requests[REQ_new_trig_exists]) X IN RDB$TRIGGERS WITH X.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string if (!X.RDB$TRIGGER_BLR.NULL) { if (msg) { ERRQ_msg_put(msg); // Msg380 Trigger defined for this relation msg = 0; } printf("\t"); show_trigger_status(X.RDB$TRIGGER_NAME, X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_INACTIVE, X.RDB$TRIGGER_SEQUENCE); } END_FOR; } END_FOR; } static void show_rels( qli_dbb* dbb, enum show_t sw, SSHORT width) { /************************************** * * s h o w _ r e l s * ************************************** * * Functional description * Display information about a relations * or system_relations for a specific database. * **************************************/ buf_type buffer; switch (sw) { case show_relations: { show_dbb(dbb); buffer[0] = 0; for (const qli_rel* relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (!(relation->rel_flags & REL_system)) show_names(relation->rel_symbol->sym_string, width, buffer); } if (buffer[0]) printf("%s\n", buffer); printf("\n"); break; } case show_system_relations: { show_dbb(dbb); buffer[0] = 0; for (const qli_rel* relation = dbb->dbb_relations; relation; relation = relation->rel_next) { if (relation->rel_flags & REL_system) show_names(relation->rel_symbol->sym_string, width, buffer); } if (buffer[0]) printf("%s\n", buffer); printf("\n"); } } } static USHORT show_security_class_detail( qli_dbb* database, const TEXT* name) { /************************************** * * s h o w _ s e c u r i t y _ c l a s s _ d e t a i l * ************************************** * * Functional description * Show security classes for a databases. * **************************************/ MET_meta_transaction(database, false); if (!(database->dbb_capabilities & DBB_cap_security)) return 0; USHORT count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_secur_class]) S IN RDB$SECURITY_CLASSES WITH S.RDB$SECURITY_CLASS = name if (fb_utils::exact_name(S.RDB$SECURITY_CLASS)[0]) { printf("\t%s:\n", S.RDB$SECURITY_CLASS); display_acl(database, S.RDB$ACL); } count++; END_FOR; return count; } static USHORT show_security_classes_detail( qli_dbb* database) { /************************************** * * s h o w _ s e c u r i t y _ c l a s s e s _ d e t a i l * ************************************** * * Functional description * Show security classes for a databases. * **************************************/ MET_meta_transaction(database, false); if (!(database->dbb_capabilities & DBB_cap_security)) return 0; USHORT count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_secur]) S IN RDB$SECURITY_CLASSES if (!count) { ERRQ_msg_put(297, database->dbb_symbol->sym_string); // Msg297 Security classes for database %s } if (fb_utils::exact_name(S.RDB$SECURITY_CLASS)[0]) { printf("\t%s:\n", S.RDB$SECURITY_CLASS); display_acl(database, S.RDB$ACL); } count++; END_FOR; return count; } static void show_string(USHORT msg1, TEXT* string1, USHORT msg2, TEXT* string2) { /************************************** * * s h o w _ s t r i n g * ************************************** * * Functional description * Show one of two strings and maybe a message, too. * **************************************/ if (string2 && (!*string1 || *string1 == ' ')) { msg1 = msg2; string1 = string2; } if (!*string1 || *string1 == ' ') return; fb_utils::exact_name(string1); ERRQ_msg_put(msg1, string1); } static void show_sys_trigs( qli_dbb* database) { /************************************** * * s h o w _ s y s _ t r i g s * ************************************** * * Functional description * Ask META to print trigger information * for the system. Since parse * has already swallowed a possible database * qualifier, just assume that the database * is the right one. * **************************************/ MET_meta_transaction(database, false); USHORT count = 0; if (database->dbb_capabilities & DBB_cap_new_triggers) FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_sys_triggers]) X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG EQ 1 SORTED BY X.RDB$RELATION_NAME, X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_SEQUENCE, X.RDB$TRIGGER_NAME if (!X.RDB$TRIGGER_BLR.NULL) { ERRQ_msg_put(379, X.RDB$RELATION_NAME); // Msg379 System Triggers show_trigger_header(X.RDB$TRIGGER_NAME, X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_SEQUENCE, X.RDB$TRIGGER_INACTIVE, X.RDB$DESCRIPTION, database); //, X.RDB$RELATION_NAME); show_blob_info(X.RDB$TRIGGER_BLR, X.RDB$TRIGGER_SOURCE, 377, // Msg377 Source for the trigger is not available. Trigger BLR: 376, // Msg376 Source for the trigger database, X.RDB$RELATION_NAME); show_trigger_messages(database, X.RDB$TRIGGER_NAME); count++; } END_FOR; if (!count) ERRQ_msg_put(378); // Msg378 No system triggers } static void show_text_blob(qli_dbb* database, const TEXT* column, USHORT msg1, ISC_QUAD* blob1, USHORT msg2, ISC_QUAD* blob2, bool strip) { /************************************** * * s h o w _ t e x t _ b l o b * ************************************** * * Functional description * Display a text blob. * **************************************/ if (blob2 && UserBlob::blobIsNull(*blob1)) { blob1 = blob2; msg1 = msg2; } if (UserBlob::blobIsNull(*blob1)) return; if (msg1) ERRQ_msg_put(msg1); display_text(database, *blob1, column, strip); } static void show_trig( qli_rel* relation) { /************************************** * * s h o w _ t r i g * ************************************** * * Functional description * Ask META to print trigger information * for a particular relation. Since parse * has already swallowed a possible database * qualifier, just assume that the database * is the right one. * **************************************/ if (!(show_trigger_detail(relation->rel_database, relation->rel_symbol->sym_string))) { ERRQ_msg_put(129, relation->rel_symbol->sym_string); // Msg129 No triggers are defined for relation %s } } static int show_trigger_detail( qli_dbb* database, const TEXT* relation_name) { /************************************** * * s h o w _ t r i g g e r _ d e t a i l * ************************************** * * Functional description * Show trigger definitions for a particular * relation. * **************************************/ if (!(database->dbb_capabilities & DBB_cap_new_triggers)) return 0; MET_meta_transaction(database, false); int count = 0; // New style triggers if (database->dbb_capabilities & DBB_cap_new_triggers) { ERRQ_msg_put(365, relation_name); // Msg365 Triggers for relation %s FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_new_trigger]) X IN RDB$TRIGGERS WITH X.RDB$RELATION_NAME EQ relation_name AND(X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG EQ 0) SORTED BY X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_SEQUENCE, X.RDB$TRIGGER_NAME if (!X.RDB$TRIGGER_BLR.NULL) { show_trigger_header(X.RDB$TRIGGER_NAME, X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_SEQUENCE, X.RDB$TRIGGER_INACTIVE, X.RDB$DESCRIPTION, database); //relation_name); show_blob_info(X.RDB$TRIGGER_BLR, X.RDB$TRIGGER_SOURCE, 377, // Msg377 Source for the trigger is not available. Trigger BLR: 376, // Msg376 Source for the trigger database, relation_name); show_trigger_messages(database, X.RDB$TRIGGER_NAME); count++; } END_FOR; return count; } // Old style triggers // OBSOLETE - 1996-Aug-06 David Schnepper // OBSOLETE - Msg298 Triggers for relation %s: // OBSOLETE - Msg299 Source for the erase trigger is not available. Trigger BLR: // OBSOLETE - Msg300 Erase trigger for relation %s: // OBSOLETE - Msg301 Source for the modify trigger is not available. Trigger BLR: // OBSOLETE - Msg302 Modify trigger for relation %s: // OBSOLETE - Msg303 Source for the store trigger is not available. Trigger BLR: // OBSOLETE - Msg304 Store trigger for relation %s: return count; } static void show_trigger_header(TEXT* name, USHORT type, USHORT sequence, USHORT inactive, ISC_QUAD& description, qli_dbb* database) //const TEXT* relation_name) // unused param { /***************************************************** * * s h o w _ t r i g g e r _ h e a d e r * ***************************************************** * * Functional description * Display header information for a new style * trigger only. * *****************************************************/ show_trigger_status(name, type, inactive, sequence); show_text_blob(database, "\t ", 375, &description, 0, NULL, true); } static void show_trigger_messages( qli_dbb* database, const TEXT* name) { /***************************************************** * * s h o w _ t r i g g e r _ m e s s a g e s * ***************************************************** * * Display error messages associated with * a new style (V3) trigger * *****************************************************/ bool first = true; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_trig_message]) M IN RDB$TRIGGER_MESSAGES WITH M.RDB$TRIGGER_NAME = name SORTED BY M.RDB$MESSAGE_NUMBER if (first) { ERRQ_msg_put(456, name); // msg 456: Messages associated with %s:\n first = false; } ERRQ_msg_put(457, SafeArg() << M.RDB$MESSAGE_NUMBER << M.RDB$MESSAGE); // msg 457: message %ld: %s\n END_FOR; if (!first) printf("\n"); } static void show_trigger_status(TEXT* name, USHORT type, USHORT status, USHORT sequence) { /***************************************************** * * s h o w _ t r i g g e r _ s t a t u s * ***************************************************** * * Display type and active status of a new style (V3) trigger * *****************************************************/ SCHAR trigger_type[16], trigger_active[9]; int msg_num; switch (type) { case PRE_STORE: msg_num = 367; break; // Msg367 pre-store case POST_STORE: msg_num = 368; break; // Msg368 post-store case PRE_MODIFY: msg_num = 369; break; // Msg369 pre-modify case POST_MODIFY: msg_num = 370; break; // Msg370 post-modify case PRE_ERASE: msg_num = 371; break; // Msg371 pre-erase case POST_ERASE: msg_num = 372; break; // Msg372 post-erase default: msg_num = 372; break; // Should never happen, not worth an error } ERRQ_msg_format(msg_num, sizeof(trigger_type), trigger_type); msg_num = status ? 374 : 373; ERRQ_msg_format(msg_num, sizeof(trigger_active), trigger_active); fb_utils::exact_name(name); ERRQ_msg_put(366, SafeArg() << name << trigger_type << sequence << trigger_active); // Msg366 Name: %s, Type: %s, Sequence: %d, Active: %s } static void show_trigs( qli_dbb* database) { /************************************** * * s h o w _ t r i g s * ************************************** * * Functional description * Ask META to print all trigger information * for a particular database or all databases. * **************************************/ if (database) { if (!show_triggers_detail(database)) { ERRQ_msg_put(130, database->dbb_symbol->sym_string); // Msg130 No triggers are defined in database %s } } else { for (database = QLI_databases; database; database = database->dbb_next) if (!show_triggers_detail(database)) { ERRQ_msg_put(131, database->dbb_symbol->sym_string); // Msg131 No triggers are defined in database %s } } } static int show_triggers_detail( qli_dbb* database) { /************************************** * * s h o w _ t r i g g e r s _ d e t a i l * ************************************** * * Functional description * Show trigger definitions for a particular * database * **************************************/ MET_meta_transaction(database, false); int count = 0; if (!(database->dbb_capabilities & DBB_cap_new_triggers)) return count; if (database->dbb_capabilities & DBB_cap_new_triggers) { // New style triggers FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_new_triggers]) X IN RDB$TRIGGERS WITH X.RDB$SYSTEM_FLAG MISSING OR X.RDB$SYSTEM_FLAG EQ 0 SORTED BY X.RDB$RELATION_NAME, X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_SEQUENCE, X.RDB$TRIGGER_NAME if (!X.RDB$TRIGGER_BLR.NULL) { fb_utils::exact_name(X.RDB$RELATION_NAME); ERRQ_msg_put(381, X.RDB$RELATION_NAME); // Msg365 Triggers for relation %s show_trigger_header(X.RDB$TRIGGER_NAME, X.RDB$TRIGGER_TYPE, X.RDB$TRIGGER_SEQUENCE, X.RDB$TRIGGER_INACTIVE, X.RDB$DESCRIPTION, database); //X.RDB$RELATION_NAME); show_blob_info(X.RDB$TRIGGER_BLR, X.RDB$TRIGGER_SOURCE, 377, // Msg377 Source for the trigger is not available. Trigger BLR: 376, // Msg376 Source for the trigger database, X.RDB$RELATION_NAME); show_trigger_messages(database, X.RDB$TRIGGER_NAME); count++; } END_FOR; } else { // Old style triggers // OBSOLETE - 1996-Aug-06 David Schnepper // OBSOLETE - Msg305 Triggers for relation %s: // OBSOLETE - Msg306 Source for the erase trigger is not available. Trigger BLR: // OBSOLETE - Msg307 Erase trigger for relation %s: // OBSOLETE - Msg308 Source for the modify trigger is not available. Trigger BLR: // OBSOLETE - Msg309 Modify trigger for relation %s: // OBSOLETE - Msg310 Source for the store trigger is not available. Trigger BLR: // OBSOLETE - Msg311 Store trigger for relation %s: } return count; } static void show_var( const qli_name* var_name) { /************************************** * * s h o w _ v a r * ************************************** * * Functional description * Display a global variables. * **************************************/ const qli_fld* variable; for (variable = QLI_variables; variable; variable = variable->fld_next) { if (!strcmp(var_name->nam_string, variable->fld_name->sym_string)) break; } if (!variable) { ERRQ_msg_put(474, var_name->nam_string); // Msg474 Variable %s has not been declared return; } ERRQ_msg_put(471, variable->fld_name->sym_string); // Msg471 Variable %s ERRQ_msg_put(475); printf("\t"); show_datatype(NULL, variable->fld_dtype, (variable->fld_dtype == dtype_varying) ? variable->fld_length - 2 : variable->fld_length, variable->fld_scale, variable->fld_sub_type, variable->fld_segment_length, (variable->fld_flags & FLD_array) ? 1 : 0); printf("\n"); if (variable->fld_query_name) { ERRQ_msg_put(472, variable->fld_query_name->sym_string); } if (variable->fld_edit_string) ERRQ_msg_put(473, variable->fld_edit_string); } static void show_vars() { /************************************** * * s h o w _ v a r s * ************************************** * * Functional description * Display global variables. If there aren't any, don't * display any. * **************************************/ ERRQ_msg_put(132); // Msg132 Variables: show_fields(NULL, QLI_variables); } static void show_versions() { /************************************** * * s h o w _ v e r s i o n s * ************************************** * * Functional description * Show the version for QLI and all databases. * **************************************/ ERRQ_msg_put(133, GDS_VERSION); // Msg133 QLI, version %s for (qli_dbb* dbb = QLI_databases; dbb; dbb = dbb->dbb_next) { ERRQ_msg_put(134, dbb->dbb_filename); // Msg134 Version(s) for database %s isc_version(&dbb->dbb_handle, NULL, NULL); } } static void show_view( qli_rel* relation) { /************************************** * * s h o w _ v i e w * ************************************** * * Functional description * Call MET to show the view definition * if there is one. * **************************************/ qli_dbb* database = relation->rel_database; MET_meta_transaction(database, false); FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_view]) X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ relation->rel_symbol->sym_string AND X.RDB$VIEW_BLR NOT MISSING if (X.RDB$VIEW_SOURCE.NULL) { ERRQ_msg_put(312, relation->rel_symbol->sym_string); // Msg312 View source for relation %s is not available. View BLR: display_blr(database, X.RDB$VIEW_BLR); } else { ERRQ_msg_put(313, relation->rel_symbol->sym_string); // Msg313 Relation %s is a view defined as: show_text_blob(database, "\t", 0, &X.RDB$VIEW_SOURCE, 0, NULL, false); } END_FOR; } static int show_views_detail( qli_dbb* database) { /************************************** * * s h o w _ v i e w s _ d e t a i l * ************************************** * * Functional description * Show the view definitions. If none, return 0. * **************************************/ MET_meta_transaction(database, false); int count = 0; FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_views]) X IN RDB$RELATIONS WITH X.RDB$VIEW_BLR NOT MISSING SORTED BY X.RDB$RELATION_NAME if (!count++) { ERRQ_msg_put(316, database->dbb_symbol->sym_string); // Msg316 Views in database %s: } fb_utils::exact_name(X.RDB$RELATION_NAME); ERRQ_msg_put(317, X.RDB$RELATION_NAME); // Msg317 %s comprised of: FOR(REQUEST_HANDLE database->dbb_requests[REQ_show_view_rel]) V IN RDB$VIEW_RELATIONS WITH V.RDB$VIEW_NAME = X.RDB$RELATION_NAME SORTED BY V.RDB$RELATION_NAME printf(" %s\n", V.RDB$RELATION_NAME); END_FOR; END_FOR; return count; } static void view_info(qli_dbb* dbb, const TEXT* view, const TEXT* base_field, SSHORT context, SSHORT level) { /************************************** * * v i e w _ i n f o * ************************************** * * Functional description * * field came from another relation. * expand on this phenomenon. * **************************************/ TEXT spaces[64]; FOR(REQUEST_HANDLE dbb->dbb_requests[REQ_show_view_field] LEVEL level) RFR IN RDB$RELATION_FIELDS CROSS VR IN RDB$VIEW_RELATIONS WITH RFR.RDB$FIELD_NAME = base_field AND RFR.RDB$RELATION_NAME = VR.RDB$RELATION_NAME AND VR.RDB$VIEW_NAME = view AND VR.RDB$VIEW_CONTEXT = context fb_utils::exact_name(RFR.RDB$RELATION_NAME); // create some space according to how many levels deep we are; // this is to avoid using %*s in the printf, which doesn't work for OS/2 TEXT* p = spaces; for (const TEXT* const end = spaces + MIN((level + 2) * 4, static_cast(sizeof(spaces) - 1)); p < end;) { *p++ = ' '; } *p = '\0'; if (RFR.RDB$BASE_FIELD.NULL) { ERRQ_msg_put(507, SafeArg() << spaces << base_field << RFR.RDB$RELATION_NAME); // Msg507 %s Based on field %s of relation %s } else { ERRQ_msg_put(508, SafeArg() << spaces << base_field << RFR.RDB$RELATION_NAME); // Msg508 %s Based on field %s of view %s } show_text_blob(dbb, "\t", 349, &RFR.RDB$DESCRIPTION, 0, NULL, false); if (!RFR.RDB$DESCRIPTION.NULL) { ERRQ_msg_put(349, SafeArg() << spaces << base_field); // Msg349 %sBase field description for %s: show_text_blob(dbb, "\t\t", 0, &RFR.RDB$DESCRIPTION, 0, NULL, false); } if (!RFR.RDB$BASE_FIELD.NULL && (dbb->dbb_capabilities & DBB_cap_multi_trans)) { fb_utils::exact_name(RFR.RDB$BASE_FIELD); view_info(dbb, RFR.RDB$RELATION_NAME, RFR.RDB$BASE_FIELD, RFR.RDB$VIEW_CONTEXT, level + 1); } END_FOR; }