8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 11:23:02 +01:00
firebird-mirror/src/isql/show.epp

3700 lines
93 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Interactive SQL utility
* MODULE: show.epp
2001-05-23 15:26:42 +02:00
* 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): ______________________________________.
* Revision 1.2 2000/11/19 07:02:49 fsg
2004-11-30 07:08:56 +01:00
* Change in show.epp to use CHARACTER_LENGTH instead of FIELD_LENGTH in
2001-05-23 15:26:42 +02:00
* SHOW PROCEDURE
*
* 19-May-2001 Claudio Valderrama.
* Change to be in sync with extract.e: BLOB is not returned
* by value but by descriptor.
2002-06-29 15:39:11 +02:00
* 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
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2002-06-29 15:39:11 +02:00
#include "../jrd/license.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../jrd/gds_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/common.h"
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../isql/isql.h"
#include "../jrd/intl.h"
#include "../isql/isql_proto.h"
#include "../isql/show_proto.h"
#include "../jrd/obj.h"
#include "../jrd/ods.h"
2002-06-29 15:39:11 +02:00
#include "../isql/extra_proto.h"
2003-12-31 06:36:12 +01:00
#include "../common/utils_proto.h"
#include "../jrd/constants.h"
2001-05-23 15:26:42 +02:00
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
2001-05-23 15:26:42 +02:00
DATABASE DB = EXTERN COMPILETIME "yachts.lnk";
// This enumeration tell comment-related routines how to behave: for SHOW,
// we present names and text as they are. For EXTRACT, we need to make a valid
// script and escape double quotes in identifiers and single quotes in strings.
enum commentMode {cmmShow, cmmExtract};
2003-12-22 11:00:59 +01:00
static void local_fprintf(void*, const char*);
static void remove_delimited_double_quotes(TEXT*);
static void make_priv_string(USHORT, char*);
2003-12-03 09:19:24 +01:00
static processing_state show_all_tables(SSHORT);
static void show_charsets(const SCHAR*, const SCHAR*, const bool, bool, bool, bool);
2003-12-03 09:19:24 +01:00
static processing_state show_check(const SCHAR*);
static void show_comment(const char* objtype, char* name1, char* name2,
ISC_QUAD* blobfld, const commentMode showextract, const char* banner);
static processing_state show_comments(const commentMode showextract, const char* banner);
static void show_db();
2003-12-03 09:19:24 +01:00
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*, const SSHORT = 0);
2003-12-03 09:19:24 +01:00
static processing_state show_generators(const SCHAR*);
static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT);
2003-12-03 09:19:24 +01:00
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 = " ";
2001-05-23 15:26:42 +02:00
static TEXT Print_buffer[512];
static TEXT SQL_identifier[BUFFER_LENGTH128];
// Initialize types
2001-05-23 15:26:42 +02:00
static const SCHAR* Object_types[] = {
2001-05-23 15:26:42 +02:00
"Table",
"View",
"Trigger",
"Computed column",
"Validation",
"Procedure",
"Expression index",
"Exception",
"User",
"Domain",
2002-06-29 15:39:11 +02:00
"Index",
"Count [error if used]",
"User group",
"SQL role",
"Generator",
"User Defined Function"
2001-05-23 15:26:42 +02:00
};
const SCHAR* Trigger_prefix_types[] = {
"BEFORE", // NTX: keyword
"AFTER" // NTX: keyword
};
const SCHAR* Trigger_suffix_types[] = {
2001-05-23 15:26:42 +02:00
"",
"INSERT", // NTX: keyword
"UPDATE", // NTX: keyword
"DELETE" // NTX: keyword
2001-05-23 15:26:42 +02:00
};
2002-06-29 15:39:11 +02:00
enum priv_flag {
priv_UNKNOWN = 1,
priv_SELECT = 2,
priv_INSERT = 4,
priv_UPDATE = 8,
priv_DELETE = 16,
priv_EXECUTE = 32,
priv_REFERENCES = 64
};
2001-05-23 15:26:42 +02:00
2003-02-13 10:42:18 +01:00
static const struct {
2001-05-23 15:26:42 +02:00
USHORT priv_flag;
const char* priv_string;
2001-05-23 15:26:42 +02:00
} 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
2001-05-23 15:26:42 +02:00
{ 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);
2001-05-23 15:26:42 +02:00
2003-02-13 10:42:18 +01:00
static const SCHAR db_dialect_info[] = {
2001-05-23 15:26:42 +02:00
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.
// Added support to display ODS version. CVC 26-Aug-2004.
2003-02-13 10:42:18 +01:00
static const SCHAR db_items[] = {
2001-05-23 15:26:42 +02:00
isc_info_page_size,
isc_info_db_size_in_pages,
isc_info_sweep_interval,
isc_info_limbo,
2002-06-29 15:39:11 +02:00
isc_info_forced_writes,
isc_info_oldest_transaction,
isc_info_oldest_active,
isc_info_oldest_snapshot,
isc_info_next_transaction,
isc_info_ods_version,
isc_info_ods_minor_version,
2001-05-23 15:26:42 +02:00
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.
*/
2003-02-13 10:42:18 +01:00
static const UCHAR metadata_text_bpb[] = {
2001-05-23 15:26:42 +02:00
isc_bpb_version1,
isc_bpb_source_type, 1, isc_blob_text,
isc_bpb_target_type, 1, isc_blob_text,
2001-05-23 15:26:42 +02:00
isc_bpb_source_interp, 1, CS_METADATA,
isc_bpb_target_interp, 1, CS_dynamic
};
// trigger action helpers
2004-05-29 06:55:23 +02:00
inline int TRIGGER_ACTION_PREFIX(int value) {
return (value + 1) & 1;
}
2004-05-29 06:55:23 +02:00
inline int TRIGGER_ACTION_SUFFIX(int value, int slot) {
return ((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;
}
inline bool blobIsNull(const ISC_QUAD* blobid)
{
return blobid->gds_quad_high == 0 && blobid->gds_quad_low == 0;
}
// There was too much string comparison inside SHOW_metadata.
// Handle all cases except VERSION and SQL DIALECT inside this class.
class ShowOptions
{
public:
enum show_commands
{
role, table, view, system, index, domain, exception,
filter, function, generator, grant, procedure, trigger,
check, database, comment, wrong
};
static show_commands getCommand(const char* cmd);
private:
struct map
{
show_commands kw;
const char* text;
};
static const map options[];
};
const ShowOptions::map ShowOptions::options[] =
{
{role, "ROLE"},
{role, "ROLES"},
{table, "TABLE"},
{table, "TABLES"},
{view, "VIEW"},
{view, "VIEWS"},
{system, "SYSTEM"},
{system, "SYS"},
{index, "IND"},
{index, "INDEX"},
{index, "INDICES"},
{domain, "DOMAIN"},
{domain, "DOMAINS"},
{exception, "EXCEPTION"},
{exception, "EXCEPTIONS"},
{filter, "FILTER"},
{filter, "FILTERS"},
{function, "FUNCTION"},
{function, "FUNCTIONS"},
{generator, "GEN"},
{generator, "GENERATOR"},
{generator, "GENERATORS"},
{generator, "SEQ"},
{generator, "SEQUENCE"},
{generator, "SEQUENCES"},
{grant, "GRANT"},
{grant, "GRANTS"},
{procedure, "PROC"},
{procedure, "PROCEDURE"},
{procedure, "PROCEDURES"},
{trigger, "TRIG"},
{trigger, "TRIGGER"},
{trigger, "TRIGGERS"},
{check, "CHECK"},
{check, "CHECKS"},
{database, "DB"},
{database, "DATABASE"},
{comment, "COMMENT"},
{comment, "COMMENTS"}
};
// Return the keyword associated with the string. There may be several strings
// for the same keyword (see table above). Return last (unused) keyword on error.
// Assume the command string is uppercased already.
ShowOptions::show_commands ShowOptions::getCommand(const char* cmd)
{
for (int i = 0; i < FB_NELEM(options); ++i)
{
if (!strcmp(cmd, options[i].text))
return options[i].kw;
}
return wrong;
}
// *************************
// S H O W _ c o m m e n t s
// *************************
// Extract database comments. Since it's called by the script extraction
// routine, it does nothing for ODS < 11, unless the force option is true.
void SHOW_comments(bool force)
{
if (isqlGlob.major_ods >= ODS_VERSION11 || force)
{
char banner[BUFFER_LENGTH128];
sprintf(banner, "%s/* Comments for database objects. */%s",
NEWLINE, NEWLINE);
show_comments(cmmExtract, banner);
}
}
2001-05-23 15:26:42 +02:00
2004-05-03 01:06:37 +02:00
bool SHOW_dbb_parameters(FB_API_HANDLE db_handle,
SCHAR* info_buf,
2004-05-12 21:39:17 +02:00
const SCHAR* db_itemsL,
USHORT item_length,
bool translate)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S H O W _ d b b _ p a r a m e t e r s
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Show db_info on this database
*
* Arguments:
2001-05-23 15:26:42 +02:00
* db_handle -- database handle
* info_buf -- info_bufput file pointer
2004-05-12 21:39:17 +02:00
* db_itemsL -- list of db_info items to process
2001-05-23 15:26:42 +02:00
*
**************************************/
SCHAR buffer[BUFFER_LENGTH128];
TEXT msg[MSG_LENGTH];
2001-05-23 15:26:42 +02:00
ISC_STATUS_ARRAY status_vector;
if (isc_database_info(status_vector, &db_handle, item_length,
2004-05-12 21:39:17 +02:00
db_itemsL, BUFFER_LENGTH128, buffer))
{
ISQL_errmsg(status_vector);
return false;
}
2001-05-23 15:26:42 +02:00
*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);
2001-05-23 15:26:42 +02:00
d += 2;
/*
* This is not the best solution but it fixes the lack of <LF> characters
* in Windows ISQL. This will need to remain until we modify the messages
* to remove the '\n' (on the PC its '\n\r').
2004-09-22 03:55:37 +02:00
* CVC: WISQL is dead. I've restored the the missing newlines for isql.
2001-05-23 15:26:42 +02:00
*/
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);
2004-09-22 03:55:37 +02:00
sprintf(info, "%s%s", msg, NEWLINE);
2001-05-23 15:26:42 +02:00
}
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);
2004-09-22 03:55:37 +02:00
sprintf(info, "%s%s", msg, NEWLINE);
2001-05-23 15:26:42 +02:00
}
else
sprintf(info, "Sweep interval = %ld %s", value_out, NEWLINE);
break;
case isc_info_forced_writes:
value_out = isc_vax_integer (d, length);
2004-11-30 07:08:56 +01:00
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;
2002-06-29 15:39:11 +02:00
2001-05-23 15:26:42 +02:00
case isc_info_base_level:
value_out = isc_vax_integer(d, length);
if (translate) {
ISQL_msg_get(BASE_LEVEL, msg, (TEXT*)(IPTR)value_out);
2004-09-22 03:55:37 +02:00
sprintf(info, "%s%s", msg, NEWLINE);
2001-05-23 15:26:42 +02:00
}
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);
2004-09-22 03:55:37 +02:00
sprintf(info, "%s%s", msg, NEWLINE);
2001-05-23 15:26:42 +02:00
}
else
sprintf(info, "Transaction in limbo = %ld %s",
value_out, NEWLINE);
break;
case isc_info_ods_version:
isqlGlob.major_ods = isc_vax_integer(d, length);
break;
case isc_info_ods_minor_version:
value_out = isc_vax_integer(d, length);
sprintf(info, "ODS = %ld.%ld%s", (SLONG) isqlGlob.major_ods, value_out, NEWLINE);
break;
}
2001-05-23 15:26:42 +02:00
d += length;
info += strlen(info);
}
2002-06-29 15:39:11 +02:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-11-23 12:03:48 +01:00
processing_state SHOW_grants(const SCHAR* object,
2003-09-09 13:03:37 +02:00
const SCHAR* terminator,
USHORT obj_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S H O W _ g r a n t s
*
**************************************
*
* Functional description
2002-06-29 15:39:11 +02:00
* Placeholder for SHOW_grants2 without additional message.
*
**************************************/
return SHOW_grants2 (object, terminator, obj_type, NULL);
2002-06-29 15:39:11 +02:00
}
2004-11-23 12:03:48 +01:00
processing_state SHOW_grants2 (const SCHAR* object,
2003-09-09 13:03:37 +02:00
const SCHAR* terminator,
USHORT obj_type,
const TEXT* optional_msg)
2002-06-29 15:39:11 +02:00
{
/**************************************
*
* S H O W _ g r a n t s 2
*
**************************************
*
* Functional description
2001-05-23 15:26:42 +02:00
* 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.
2002-06-29 15:39:11 +02:00
* 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.
2001-05-23 15:26:42 +02:00
*
**************************************/
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;
BASED_ON RDB$USER_PRIVILEGES.RDB$USER_TYPE prev_user_type;
SCHAR user_string[QUOTEDLENGTH + 20];
bool first = true;
2001-05-23 15:26:42 +02:00
if (!*object)
return ps_ERR;
2001-05-23 15:26:42 +02:00
// Query against user_privileges instead of looking at rdb$security_classes
2001-05-23 15:26:42 +02:00
prev_option = -1;
prev_user[0] = '\0';
prev_field[0] = '\0';
prev_user_type = -1;
char priv_string[MAX_PRIV_LIST] = "";
char col_string[BUFFER_LENGTH128] = "";
2005-12-27 10:42:40 +01:00
char with_option[19] = "";
USHORT priv_flags = 0;
SSHORT prev_field_null = -1;
2001-05-23 15:26:42 +02:00
if (obj_type == obj_relation || obj_type == 255)
{
2001-05-23 15:26:42 +02:00
// 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
2002-06-29 15:39:11 +02:00
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::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) ||
(prev_user_type != -1 && prev_user_type != PRV.RDB$USER_TYPE))
{
make_priv_string (priv_flags, priv_string);
if (first && optional_msg)
isqlGlob.prints(optional_msg);
first = false;
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
ISQL_copy_SQL_id (object, SQL_identifier, DBL_QUOTE);
else
strcpy (SQL_identifier, object);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("GRANT %s%s ON %s TO %s%s%s%s", priv_string,
col_string, SQL_identifier, user_string,
with_option, terminator, NEWLINE);
// 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);
prev_user_type = PRV.RDB$USER_TYPE;
switch (PRV.RDB$USER_TYPE) {
case obj_relation:
case obj_view:
case obj_trigger:
case obj_procedure:
case obj_sql_role:
if (isqlGlob.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::exact_name(PRV.RDB$FIELD_NAME);
if (isqlGlob.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 ps_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)
isqlGlob.prints(optional_msg);
first = false;
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
ISQL_copy_SQL_id (object, SQL_identifier, DBL_QUOTE);
else
strcpy (SQL_identifier, object);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("GRANT %s%s ON %s TO %s%s%s%s",
priv_string, col_string,
SQL_identifier, user_string, with_option, terminator, NEWLINE);
}
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
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
2001-05-23 15:26:42 +02:00
// Part two is for stored procedures only
2001-05-23 15:26:42 +02:00
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)
isqlGlob.prints(optional_msg);
first = false;
fb_utils::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 (isqlGlob.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 (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) {
ISQL_copy_SQL_id (object, SQL_identifier, DBL_QUOTE);
}
else
strcpy (SQL_identifier, object);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("GRANT EXECUTE ON PROCEDURE %s TO %s%s%s%s",
SQL_identifier, user_string, with_option, terminator, NEWLINE);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
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.
// This part is only used by SHOW GRANT <object> command
// Metadata extraction and SHOW GRANT with no param uses SHOW_grant_roles.
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::exact_name(PRV.RDB$RELATION_NAME);
strcpy (role_name, PRV.RDB$RELATION_NAME);
if (isqlGlob.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::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)
isqlGlob.prints(optional_msg);
first = false;
isqlGlob.prints(Print_buffer);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
if (!first)
return (SKIP);
}
2002-06-29 15:39:11 +02:00
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
}
2003-09-09 13:03:37 +02:00
void SHOW_grant_roles(const SCHAR* terminator,
bool* first)
2002-06-29 15:39:11 +02:00
{
/**************************************
*
* 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);
2002-06-29 15:39:11 +02:00
}
2003-09-09 13:03:37 +02:00
void SHOW_grant_roles2 (const SCHAR* terminator,
bool* first,
const TEXT* optional_msg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S H O W _ g r a n t _ r o l e s
*
**************************************
*
* Functional description
* Show grants for each role name
2001-05-23 15:26:42 +02:00
* This function is also called by extract for privileges.
* All membership privilege may have the with_admin option set.
*
**************************************/
2005-12-27 10:42:40 +01:00
char with_option[19];
2001-12-24 03:51:06 +01:00
char user_string[44];
2001-05-23 15:26:42 +02:00
// process role "object"
2001-05-23 15:26:42 +02:00
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
2002-06-29 15:39:11 +02:00
if (first) {
if (*first && optional_msg) {
isqlGlob.prints(optional_msg);
}
*first = false;
}
fb_utils::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';
const char* role = fb_utils::exact_name(PRV.RDB$RELATION_NAME);
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
{
ISQL_copy_SQL_id (PRV.RDB$RELATION_NAME, SQL_identifier, DBL_QUOTE);
role = SQL_identifier;
}
2005-05-24 06:42:01 +02:00
isqlGlob.printf("GRANT %s TO %s%s%s%s", role,
user_string, with_option, terminator, NEWLINE);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
2001-05-23 15:26:42 +02:00
END_ERROR;
}
2004-04-29 00:36:29 +02:00
void SHOW_print_metadata_text_blob(FILE* fp,
ISC_QUAD* blobid,
bool escape_squote)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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.
* The last param says whether single quotes should be escaped (duplicating them).
2001-05-23 15:26:42 +02:00
*
**************************************/
// Don't bother with null blobs
if (blobIsNull(blobid))
2001-05-23 15:26:42 +02:00
return;
2004-05-03 01:06:37 +02:00
isc_blob_handle blob_handle = 0;
if (isc_open_blob2(isc_status, &DB, &gds_trans, &blob_handle, blobid,
sizeof(metadata_text_bpb), metadata_text_bpb))
{
2001-05-23 15:26:42 +02:00
ISQL_errmsg(isc_status);
return;
}
SCHAR buffer[BUFFER_LENGTH512];
2001-05-23 15:26:42 +02:00
USHORT length = 0;
2001-05-23 15:26:42 +02:00
while (!isc_get_segment(isc_status, &blob_handle, &length,
2003-04-08 12:38:59 +02:00
(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.
// CVC: The above comment and the code do not match.
2001-05-23 15:26:42 +02:00
buffer[length] = 0;
if (escape_squote)
{
for (const UCHAR* p = (UCHAR*) buffer; *p; ++p)
{
if (*p == '\'')
fputc(*p, fp);
fputc(*p, fp);
}
fflush(fp);
}
else
ISQL_printf(fp, buffer);
2001-05-23 15:26:42 +02:00
}
if (isc_status[1] && isc_status[1] != isc_segstr_eof)
ISQL_errmsg(isc_status);
isc_close_blob(isc_status, &blob_handle);
}
2003-12-03 09:19:24 +01:00
processing_state SHOW_metadata(const SCHAR* const* cmd,
SCHAR** lcmd)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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
*
**************************************/
2003-12-03 09:19:24 +01:00
processing_state ret = SKIP;
2001-05-23 15:26:42 +02:00
int key = 0;
// Can't show nothing, return an error
2001-05-23 15:26:42 +02:00
if (!cmd[1])
return ps_ERR;
// Only show version and show sql dialect work if there is no db attached
bool handled = true;
if ((!strcmp(cmd[1], "VERSION")) || (!strcmp(cmd[1], "VER")))
{
TEXT msg_string[MSG_LENGTH];
ISQL_msg_get(VERSION, msg_string, FB_VERSION);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s%s", msg_string, NEWLINE);
2003-12-22 11:00:59 +01:00
isc_version(&DB, local_fprintf, NULL);
2001-05-23 15:26:42 +02:00
}
else if (!strcmp(cmd[1], "SQL"))
{
2001-05-23 15:26:42 +02:00
if (!strcmp(cmd[2], "DIALECT"))
ret = show_dialect();
else
ret = ps_ERR;
2001-05-23 15:26:42 +02:00
}
else
{
handled = false;
if (!ISQL_dbcheck())
ret = ps_ERR;
}
if (ret == ps_ERR || handled)
return ret;
TEXT SQL_id_for_grant[BUFFER_LENGTH128];
switch (ShowOptions::getCommand(cmd[1]))
2001-05-23 15:26:42 +02:00
{
case ShowOptions::role:
if (isqlGlob.major_ods >= ODS_VERSION9)
{
2001-05-23 15:26:42 +02:00
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 == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
key = NO_ROLE;
}
else
{
ret = show_role(NULL);
if (ret == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
key = NO_ROLES;
}
}
else
{
ret = OBJECT_NOT_FOUND;
key = NO_ROLES;
}
break;
case ShowOptions::table:
2001-05-23 15:26:42 +02:00
if (*cmd[2])
{
if (*cmd[2] == '"')
{
remove_delimited_double_quotes(lcmd[2]);
ret = show_table(lcmd[2], false);
2001-05-23 15:26:42 +02:00
}
else
{
ret = show_table(cmd[2], false);
2001-05-23 15:26:42 +02:00
}
if (ret == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
key = NO_TABLE;
}
else
{
ret = show_all_tables(0);
if (ret == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
key = NO_TABLES;
}
break;
case ShowOptions::view:
2001-05-23 15:26:42 +02:00
if (*cmd[2])
{
if (*cmd[2] == '"')
{
remove_delimited_double_quotes(lcmd[2]);
ret = show_table(lcmd[2], true);
2001-05-23 15:26:42 +02:00
}
else
{
ret = show_table(cmd[2], true);
2001-05-23 15:26:42 +02:00
}
if (ret == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
key = NO_VIEW;
}
else
{
ret = show_all_tables(-1);
if (ret == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
key = NO_VIEWS;
}
break;
case ShowOptions::system:
{
TEXT msg[MSG_LENGTH];
ISQL_msg_get(MSG_TABLES, msg, NULL);
isqlGlob.printf("%s%s", msg, NEWLINE);
show_all_tables(1);
ISQL_msg_get(MSG_FUNCTIONS, msg, NULL);
isqlGlob.printf("%s%s", msg, NEWLINE);
show_functions("", 1);
}
break;
case ShowOptions::index:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"')
{
remove_delimited_double_quotes(lcmd[2]);
ret = show_indices(lcmd);
}
else
{
ret = show_indices(cmd);
}
if (ret == OBJECT_NOT_FOUND)
2001-05-23 15:26:42 +02:00
{
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
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!key)
key = NO_REL_OR_INDEX;
}
else
{
key = NO_INDICES;
}
}
break;
case ShowOptions::domain:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"')
{
remove_delimited_double_quotes(lcmd[2]);
ret = show_domains(lcmd[2]);
}
else
ret = show_domains(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
if (*cmd[2])
key = NO_DOMAIN;
else
key = NO_DOMAINS;
}
break;
case ShowOptions::exception:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_exceptions(lcmd[2]);
}
else
ret = show_exceptions(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
if (*cmd[2])
key = NO_EXCEPTION;
else
key = NO_EXCEPTIONS;
}
break;
case ShowOptions::filter:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_filters(lcmd[2]);
}
else
ret = show_filters(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
if (*cmd[2])
key = NO_FILTER;
else
key = NO_FILTERS;
}
break;
case ShowOptions::function:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_functions(lcmd[2]);
}
else
ret = show_functions(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
if (*cmd[2])
key = NO_FUNCTION;
else
key = NO_FUNCTIONS;
}
break;
case ShowOptions::generator:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_generators(lcmd[2]);
}
else
ret = show_generators(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
if (*cmd[2])
key = NO_GEN;
else
key = NO_GENS;
}
break;
case ShowOptions::grant:
2001-05-23 15:26:42 +02:00
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);
2001-05-23 15:26:42 +02:00
}
2002-06-29 15:39:11 +02:00
else {
2001-05-23 15:26:42 +02:00
strcpy(SQL_id_for_grant, cmd[2]);
ret = EXTRACT_list_grants ("");
}
2001-05-23 15:26:42 +02:00
if (ret == OBJECT_NOT_FOUND) {
if (*cmd[2]) {
FOR FIRST 1 R IN RDB$RELATIONS
WITH R.RDB$RELATION_NAME EQ SQL_id_for_grant;
2002-06-29 15:39:11 +02:00
key = NO_GRANT_ON_REL;
END_FOR
ON_ERROR
// Ignore any error
2001-05-23 15:26:42 +02:00
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;
}
}
break;
case ShowOptions::procedure:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_proc(lcmd[2]);
}
else
ret = show_proc(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
if (*cmd[2])
key = NO_PROC;
else
key = NO_PROCS;
}
break;
case ShowOptions::trigger:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_trigger(lcmd[2], true, true);
2001-05-23 15:26:42 +02:00
}
else
ret = show_trigger(cmd[2], true, true);
2001-05-23 15:26:42 +02:00
if (ret == OBJECT_NOT_FOUND)
{
2001-05-23 15:26:42 +02:00
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
2001-05-23 15:26:42 +02:00
ON_ERROR
// Ignore any error
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!key)
key = NO_REL_OR_TRIGGER;
}
else
key = NO_TRIGGERS;
}
break;
case ShowOptions::check:
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"') {
remove_delimited_double_quotes(lcmd[2]);
ret = show_check(lcmd[2]);
}
else
ret = show_check(cmd[2]);
if (ret == OBJECT_NOT_FOUND) {
2001-05-23 15:26:42 +02:00
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
2001-05-23 15:26:42 +02:00
ON_ERROR
// Ignore any error
2001-05-23 15:26:42 +02:00
END_ERROR;
}
if (!key)
key = NO_TABLE;
}
break;
case ShowOptions::database:
2001-05-23 15:26:42 +02:00
show_db();
break;
case ShowOptions::comment:
ret = show_comments(cmmShow, 0);
if (ret == OBJECT_NOT_FOUND)
key = NO_COMMENTS;
break;
default:
return ps_ERR;
} // switch
2001-05-23 15:26:42 +02:00
if (ret == OBJECT_NOT_FOUND) {
TEXT key_string[MSG_LENGTH];
2001-05-23 15:26:42 +02:00
if (*cmd[2] == '"')
ISQL_msg_get(key, key_string, lcmd[2]);
2001-05-23 15:26:42 +02:00
else
ISQL_msg_get(key, key_string, cmd[2]);
STDERROUT(key_string);
2001-05-23 15:26:42 +02:00
}
return ret;
2001-05-23 15:26:42 +02:00
}
2003-12-22 11:00:59 +01:00
static void local_fprintf(void* format_ignored,
const char* string)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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 isqlGlob.Out
* and not to stdout if isc_version gets called.
2001-05-23 15:26:42 +02:00
*
**************************************/
isqlGlob.printf("%s%s", string, NEWLINE);
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
static void remove_delimited_double_quotes(TEXT* string)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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.
2001-05-23 15:26:42 +02:00
*
**************************************/
ISQL_remove_and_unescape_quotes(string, DBL_QUOTE);
2001-05-23 15:26:42 +02:00
}
static void make_priv_string(USHORT flags,
char* string)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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
2001-05-23 15:26:42 +02:00
* string list.
*
**************************************/
for (int i = 0; privs[i].priv_string; i++) {
2001-05-23 15:26:42 +02:00
if (flags & privs[i].priv_flag) {
if (*string)
strcat(string, ", ");
strcat(string, privs[i].priv_string);
2001-05-23 15:26:42 +02:00
}
}
}
static processing_state show_all_tables(SSHORT sys_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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
2001-05-23 15:26:42 +02:00
*
* Parameters: sys_flag -- 0, show user tables
2003-09-09 13:03:37 +02:00
* 1, show system tables only; -1, show views only
2001-05-23 15:26:42 +02:00
*
**************************************/
2003-09-09 13:03:37 +02:00
bool odd = true;
bool first = true;
2001-05-23 15:26:42 +02:00
if (sys_flag == -1) {
// Views
FOR REL IN RDB$RELATIONS WITH
REL.RDB$VIEW_BLR NOT MISSING
SORTED BY REL.RDB$RELATION_NAME
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", REL.RDB$RELATION_NAME, (odd ? " " : NEWLINE));
odd = !odd;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
}
// 23-Apr-2004 (only tables)
2001-05-23 15:26:42 +02:00
else {
// The rdb$system_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 sys_flag
/*OR (sys_flag == 0 AND REL.RDB$SYSTEM_FLAG MISSING)*/)
AND REL.RDB$VIEW_BLR MISSING
SORTED BY REL.RDB$RELATION_NAME
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", REL.RDB$RELATION_NAME, (odd ? " " : NEWLINE));
odd = !odd;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
}
if (!first) {
isqlGlob.printf(NEWLINE);
2001-05-23 15:26:42 +02:00
return SKIP;
}
else
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
}
static void show_charsets(
const SCHAR* relation_name,
const SCHAR* field_name,
bool show_charset,
bool show_collation,
bool doIndent,
bool doReturn)
2001-05-23 15:26:42 +02:00
{
/*************************************
2001-05-23 15:26:42 +02:00
*
* s h o w _ c h a r s e t s
*
**************************************
*
* Functional description
* Show character set and collations
2001-05-23 15:26:42 +02:00
*
**************************************/
SSHORT collation, char_set_id;
const SSHORT default_char_set_id = ISQL_get_default_char_set_id();
2001-05-23 15:26:42 +02:00
// If there is a relation_name, this is a real column, look up collation
2004-03-07 08:58:55 +01:00
// in rdb$relation_fields
2001-05-23 15:26:42 +02:00
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
2001-05-23 15:26:42 +02:00
ON_ERROR
#ifdef DEV_BUILD
2004-04-29 00:36:29 +02:00
fprintf(stderr, "show_charsets(%s %s) failed\n",
2001-05-23 15:26:42 +02:00
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
2001-05-23 15:26:42 +02:00
ON_ERROR
#ifdef DEV_BUILD
2004-04-29 00:36:29 +02:00
fprintf(stderr, "show_charsets(NULL %s) failed\n",
2001-05-23 15:26:42 +02:00
field_name);
#endif
END_ERROR;
}
TEXT char_sets[86]; /* CHARACTER SET <name31> COLLATE <name31> */
2001-05-23 15:26:42 +02:00
char_sets[0] = 0;
2004-05-09 07:48:33 +02:00
if ((char_set_id != default_char_set_id) || collation) {
if (show_charset && !show_collation)
2004-04-24 16:38:27 +02:00
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);
}
2004-05-09 07:48:33 +02:00
if (char_sets[0]) {
if (doIndent)
isqlGlob.printf(spaces);
isqlGlob.prints(char_sets);
if (doReturn)
isqlGlob.printf(NEWLINE);
}
2001-05-23 15:26:42 +02:00
}
2003-12-03 09:19:24 +01:00
static processing_state show_check(const SCHAR* object)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s h o w _ c h e c k
*
**************************************
*
* Functional description
* Show check constraints for the named object
*
**************************************/
bool first = true;
2001-05-23 15:26:42 +02:00
if (!*object)
return ps_ERR;
// Query gets the check clauses for triggers stored for check constraints
2001-05-23 15:26:42 +02:00
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$SYSTEM_FLAG EQ int(fb_sysflag_check_constraint) AND
TRG.RDB$RELATION_NAME EQ object
SORTED BY CHK.RDB$CONSTRAINT_NAME
// Use print_blob to print the blob
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("CONSTRAINT %s:%s ",
fb_utils::exact_name(CHK.RDB$CONSTRAINT_NAME), NEWLINE);
if (!TRG.RDB$TRIGGER_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE);
isqlGlob.printf(NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
// ***********************
// s h o w _ c o m m e n t
// ***********************
// Helper that displays in correct syntax the COMMENT ON command for each object.
// It escapes identifiers with embedded double quotes and escapes the comment
// itself if it contains single quotes when we are honoring script extraction.
static void show_comment(const char* objtype, char* name1, char* name2,
ISC_QUAD* blobfld, const commentMode showextract, const char* banner)
{
const bool escape_quotes = showextract == cmmExtract;
if (escape_quotes && banner)
isqlGlob.prints(banner);
if (name1)
fb_utils::exact_name(name1);
if (name2)
fb_utils::exact_name(name2);
char SQL_identifier2[BUFFER_LENGTH128];
if (escape_quotes && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
{
if (name1)
{
ISQL_copy_SQL_id (name1, SQL_identifier, DBL_QUOTE);
name1 = SQL_identifier;
}
if (name2)
{
ISQL_copy_SQL_id (name2, SQL_identifier2, DBL_QUOTE);
name2 = SQL_identifier2;
}
}
const char* quot = escape_quotes ? "'" : "";
if (!name1)
isqlGlob.printf("COMMENT ON %-12s IS %s", objtype, quot);
else if (!name2)
isqlGlob.printf("COMMENT ON %-12s %s IS %s", objtype, name1, quot);
else
isqlGlob.printf("COMMENT ON %-12s %s.%s IS %s", objtype, name1, name2, quot);
SHOW_print_metadata_text_blob(isqlGlob.Out, blobfld, escape_quotes);
isqlGlob.printf("%s%s%s", quot, isqlGlob.global_Term, NEWLINE);
}
// *************************
// s h o w _ c o m m e n t s
// *************************
// Will extract and show descriptions (comments) for all supported db objects.
// This function does its task even if the server version doesn't support
// the COMMENT ON command. It will however skip generators and roles that
// didn't have description fields before ODS11.
// It will extract the main objects by category and inside each category,
// in alphabetical order. For tables and views, their fields are printed
// immediately after the table/field in rdb$field_position order, that's
// the order the users sees when doing a select * from tbl/view. For procedures,
// their parameters are printed immediately after the procedure, first the input
// params by position, the the output params by position. All system objects
// as well as implicit domains and implicit triggers are skipped. For ODS < 11,
// we skip generators and roles because those system tables didn't have a
// rdb$description field.
// When showing comments, we don't escape quotes in neither names nor strings.
// When extracting comments, we do the usual escaping to make the script valid.
static processing_state show_comments(const commentMode showextract, const char* banner)
{
// From dsql.h:
// ddl_database, ddl_domain, ddl_relation, ddl_view, ddl_procedure, ddl_trigger,
// ddl_udf, ddl_blob_filter, ddl_exception, ddl_generator, ddl_index, ddl_role,
// ddl_charset, ddl_collation//, ddl_sec_class
bool first = true;
FOR FIRST 1 DT IN RDB$DATABASE
WITH DT.RDB$DESCRIPTION NOT MISSING
show_comment("DATABASE", 0, 0, &DT.RDB$DESCRIPTION, showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR DM IN RDB$FIELDS
WITH DM.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *"
AND (DM.RDB$SYSTEM_FLAG EQ 0 OR DM.RDB$SYSTEM_FLAG MISSING)
AND DM.RDB$DESCRIPTION NOT MISSING
SORTED BY DM.RDB$FIELD_NAME
show_comment("DOMAIN", DM.RDB$FIELD_NAME, 0, &DM.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR RL IN RDB$RELATIONS
WITH RL.RDB$VIEW_BLR MISSING
AND (RL.RDB$SYSTEM_FLAG EQ 0 OR RL.RDB$SYSTEM_FLAG MISSING)
SORTED BY RL.RDB$RELATION_NAME
if (!RL.RDB$DESCRIPTION.NULL && !blobIsNull(&RL.RDB$DESCRIPTION))
{
show_comment("TABLE", RL.RDB$RELATION_NAME, 0, &RL.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
}
FOR RF IN RDB$RELATION_FIELDS
WITH RF.RDB$RELATION_NAME = RL.RDB$RELATION_NAME
AND RF.RDB$DESCRIPTION NOT MISSING
SORTED BY RF.RDB$FIELD_POSITION
show_comment(" COLUMN", RL.RDB$RELATION_NAME, RF.RDB$FIELD_NAME,
&RF.RDB$DESCRIPTION, showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR VW IN RDB$RELATIONS
WITH VW.RDB$VIEW_BLR NOT MISSING
AND (VW.RDB$SYSTEM_FLAG EQ 0 OR VW.RDB$SYSTEM_FLAG MISSING)
SORTED BY VW.RDB$RELATION_NAME
if (!VW.RDB$DESCRIPTION.NULL && !blobIsNull(&VW.RDB$DESCRIPTION))
{
show_comment("VIEW", VW.RDB$RELATION_NAME, 0 , &VW.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
}
FOR RF IN RDB$RELATION_FIELDS
WITH RF.RDB$RELATION_NAME = VW.RDB$RELATION_NAME
AND RF.RDB$DESCRIPTION NOT MISSING
SORTED BY RF.RDB$FIELD_POSITION
show_comment(" COLUMN", VW.RDB$RELATION_NAME, RF.RDB$FIELD_NAME,
&RF.RDB$DESCRIPTION, showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR PR IN RDB$PROCEDURES
WITH (PR.RDB$SYSTEM_FLAG EQ 0 OR PR.RDB$SYSTEM_FLAG MISSING)
SORTED BY PR.RDB$PROCEDURE_NAME
if (!PR.RDB$DESCRIPTION.NULL && !blobIsNull(&PR.RDB$DESCRIPTION))
{
show_comment("PROCEDURE", PR.RDB$PROCEDURE_NAME, 0, &PR.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
}
FOR PA IN RDB$PROCEDURE_PARAMETERS
WITH PA.RDB$PROCEDURE_NAME = PR.RDB$PROCEDURE_NAME
AND PA.RDB$DESCRIPTION NOT MISSING
SORTED BY PA.RDB$PARAMETER_TYPE, PA.RDB$PARAMETER_NUMBER
show_comment(" PARAMETER", PR.RDB$PROCEDURE_NAME, PA.RDB$PARAMETER_NAME,
&PA.RDB$DESCRIPTION, showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR TR IN RDB$TRIGGERS
WITH TR.RDB$DESCRIPTION NOT MISSING
AND (TR.RDB$SYSTEM_FLAG EQ 0 OR TR.RDB$SYSTEM_FLAG MISSING)
SORTED BY TR.RDB$TRIGGER_NAME
show_comment("TRIGGER", TR.RDB$TRIGGER_NAME, 0, &TR.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR UD IN RDB$FUNCTIONS
WITH UD.RDB$DESCRIPTION NOT MISSING
AND (UD.RDB$SYSTEM_FLAG EQ 0 OR UD.RDB$SYSTEM_FLAG MISSING)
SORTED BY UD.RDB$FUNCTION_NAME
show_comment("EXTERNAL FUNCTION", UD.RDB$FUNCTION_NAME, 0,
&UD.RDB$DESCRIPTION, showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR BF IN RDB$FILTERS
WITH BF.RDB$DESCRIPTION NOT MISSING
AND (BF.RDB$SYSTEM_FLAG EQ 0 OR BF.RDB$SYSTEM_FLAG MISSING)
SORTED BY BF.RDB$FUNCTION_NAME
show_comment("FILTER", BF.RDB$FUNCTION_NAME, 0, &BF.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR XC IN RDB$EXCEPTIONS
WITH XC.RDB$DESCRIPTION NOT MISSING
AND (XC.RDB$SYSTEM_FLAG EQ 0 OR XC.RDB$SYSTEM_FLAG MISSING)
SORTED BY XC.RDB$EXCEPTION_NAME
show_comment("EXCEPTION", XC.RDB$EXCEPTION_NAME, 0, &XC.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
if (isqlGlob.major_ods >= ODS_VERSION11)
{
FOR GR IN RDB$GENERATORS
WITH GR.RDB$DESCRIPTION NOT MISSING
AND (GR.RDB$SYSTEM_FLAG EQ 0 OR GR.RDB$SYSTEM_FLAG MISSING)
SORTED BY GR.RDB$GENERATOR_NAME
show_comment("GENERATOR", GR.RDB$GENERATOR_NAME, 0, &GR.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
}
FOR IX IN RDB$INDICES
WITH IX.RDB$DESCRIPTION NOT MISSING
AND (IX.RDB$SYSTEM_FLAG EQ 0 OR IX.RDB$SYSTEM_FLAG MISSING)
SORTED BY IX.RDB$INDEX_NAME
show_comment("INDEX", IX.RDB$INDEX_NAME, 0, &IX.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
if (isqlGlob.major_ods >= ODS_VERSION11)
{
FOR RO IN RDB$ROLES
WITH RO.RDB$DESCRIPTION NOT MISSING
AND (RO.RDB$SYSTEM_FLAG EQ 0 OR RO.RDB$SYSTEM_FLAG MISSING)
SORTED BY RO.RDB$ROLE_NAME
show_comment("ROLE", RO.RDB$ROLE_NAME, 0, &RO.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
}
FOR CH IN RDB$CHARACTER_SETS
WITH CH.RDB$DESCRIPTION NOT MISSING
AND (CH.RDB$SYSTEM_FLAG EQ 0 OR CH.RDB$SYSTEM_FLAG MISSING)
SORTED BY CH.RDB$CHARACTER_SET_NAME
show_comment("CHARACTER SET", CH.RDB$CHARACTER_SET_NAME, 0,
&CH.RDB$DESCRIPTION, showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
FOR CL IN RDB$COLLATIONS
WITH CL.RDB$DESCRIPTION NOT MISSING
AND (CL.RDB$SYSTEM_FLAG EQ 0 OR CL.RDB$SYSTEM_FLAG MISSING)
SORTED BY CL.RDB$COLLATION_NAME
show_comment("COLLATION", CL.RDB$COLLATION_NAME, 0, &CL.RDB$DESCRIPTION,
showextract, first ? banner : 0);
first = false;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
return first ? OBJECT_NOT_FOUND : SKIP;
}
static void show_db()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s h o w _ d b
*
**************************************
*
* Functional description
* Show info on this database. cache, logfiles, etc
*
**************************************/
// First print the name of the database
2001-05-23 15:26:42 +02:00
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Database: %s%s", isqlGlob.global_Db_name, NEWLINE);
// Get the owner name
2001-05-23 15:26:42 +02:00
FOR REL IN RDB$RELATIONS WITH
REL.RDB$RELATION_NAME = "RDB$DATABASE"
if (!REL.RDB$OWNER_NAME.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%sOwner: %s%s", TAB_AS_SPACES, REL.RDB$OWNER_NAME, NEWLINE);
}
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return;
2001-05-23 15:26:42 +02:00
END_ERROR;
// Query for files
2001-05-23 15:26:42 +02:00
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;
fb_utils::exact_name(FIL.RDB$FILE_NAME);
if (FIL.RDB$FILE_FLAGS == 0) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" 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);
}
if (FIL.RDB$FILE_FLAGS & FILE_shadow) {
if (FIL.RDB$FILE_SEQUENCE) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%sfile %s ", TAB_AS_SPACES, FIL.RDB$FILE_NAME);
}
else {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Shadow %d: \"%s\" ",
FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_NAME);
if (FIL.RDB$FILE_FLAGS & FILE_inactive) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("inactive ");
}
if (FIL.RDB$FILE_FLAGS & FILE_manual) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("manual ");
}
else {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("auto ");
}
if (FIL.RDB$FILE_FLAGS & FILE_conditional) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("conditional ");
}
}
if (FIL.RDB$FILE_LENGTH) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("length %ld ", FIL.RDB$FILE_LENGTH);
}
if (FIL.RDB$FILE_START) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("starting %ld", FIL.RDB$FILE_START);
}
isqlGlob.printf(NEWLINE);
}
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return;
2001-05-23 15:26:42 +02:00
END_ERROR;
SCHAR info_buf[BUFFER_LENGTH400];
2001-05-23 15:26:42 +02:00
// First general database parameters
2001-05-23 15:26:42 +02:00
bool translate = true;
if (SHOW_dbb_parameters(DB, info_buf, db_items, sizeof(db_items), translate)) {
isqlGlob.prints(info_buf);
}
2001-05-23 15:26:42 +02:00
FOR DBB IN RDB$DATABASE
WITH DBB.RDB$CHARACTER_SET_NAME NOT MISSING
AND DBB.RDB$CHARACTER_SET_NAME NE " "
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Default Character set: %s%s",
DBB.RDB$CHARACTER_SET_NAME,
NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return;
END_ERROR;
2001-05-23 15:26:42 +02:00
}
2003-12-03 09:19:24 +01:00
static processing_state show_dialect()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s h o w _ d i a l e c t
*
**************************************
*
* Print out the SQL dialect information
2001-05-23 15:26:42 +02:00
*
**************************************/
if (isqlGlob.db_SQL_dialect > 0) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%d%s%d",
"Client SQL dialect is set to: ", isqlGlob.SQL_dialect,
" and database SQL dialect is: ", isqlGlob.db_SQL_dialect);
}
else if (isqlGlob.SQL_dialect == 0) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s",
2001-05-23 15:26:42 +02:00
"Client SQL dialect has not been set",
" and no database has been connected yet.");
}
else {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%d%s",
"Client SQL dialect is set to: ", isqlGlob.SQL_dialect,
2001-05-23 15:26:42 +02:00
". No database has been connected.");
}
isqlGlob.printf(NEWLINE);
2001-05-23 15:26:42 +02:00
return SKIP;
}
2003-12-03 09:19:24 +01:00
static processing_state show_domains(const SCHAR* domain_name)
2001-05-23 15:26:42 +02:00
{
/*************************************
2001-05-23 15:26:42 +02:00
*
* s h o w _ d o m a i n s
*
**************************************
*
* Functional description
* Show all domains or the named domain
************************************/
bool first = true;
2001-05-23 15:26:42 +02:00
if (!*domain_name) {
bool odd = true;
// 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;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", FLD.RDB$FIELD_NAME, (odd ? " " : NEWLINE));
odd = !odd;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
if (!first)
isqlGlob.printf(NEWLINE);
2001-05-23 15:26:42 +02:00
}
else { // List named domain
2001-05-23 15:26:42 +02:00
FOR FLD IN RDB$FIELDS WITH
FLD.RDB$FIELD_NAME EQ domain_name;
first = false;
// Print the name of the domain
fb_utils::exact_name(FLD.RDB$FIELD_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%-32s", FLD.RDB$FIELD_NAME);
// Array dimensions
if (!FLD.RDB$DIMENSIONS.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("ARRAY OF ");
ISQL_array_dimensions (FLD.RDB$FIELD_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s ",
NEWLINE);
}
// Look through types array
for (int i = 0; Column_types[i].type; i++)
if (FLD.RDB$FIELD_TYPE == Column_types[i].type) {
bool precision_known = false;
if (isqlGlob.major_ods >= ODS_VERSION10) {
// Handle Integral subtypes NUMERIC and DECIMAL
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
(FLD.RDB$FIELD_TYPE == INTEGER) ||
2004-09-22 03:55:37 +02:00
(FLD.RDB$FIELD_TYPE == BIGINT))
{
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 ps_ERR;
END_ERROR;
}
}
if (!precision_known) {
// Take a stab at numerics and decimals
if ((FLD.RDB$FIELD_TYPE == SMALLINT) &&
(FLD.RDB$FIELD_SCALE < 0))
{
sprintf (Print_buffer,
"NUMERIC(4, %d)",
-FLD.RDB$FIELD_SCALE);
}
else if ((FLD.RDB$FIELD_TYPE == INTEGER) &&
(FLD.RDB$FIELD_SCALE < 0))
{
sprintf (Print_buffer,
"NUMERIC(9, %d)",
-FLD.RDB$FIELD_SCALE);
}
else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
(FLD.RDB$FIELD_SCALE < 0))
{
sprintf (Print_buffer,
"NUMERIC(15, %d)",
-FLD.RDB$FIELD_SCALE);
}
else {
sprintf (Print_buffer, "%s", Column_types[i].type_name);
}
}
isqlGlob.prints(Print_buffer);
break;
}
// Length for CHARs
2004-04-24 16:38:27 +02:00
if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME));
}
// Blob domains
if (FLD.RDB$FIELD_TYPE == BLOB) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" segment %u, subtype ", (USHORT) FLD.RDB$SEGMENT_LENGTH);
2004-12-07 01:33:16 +01:00
const int subtype = FLD.RDB$FIELD_SUB_TYPE;
2004-05-09 07:48:33 +02:00
if (subtype >= 0 && subtype <= MAX_BLOBSUBTYPES) {
isqlGlob.prints(Sub_types[subtype]);
}
else {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%d", subtype);
}
}
// Show international character sets
2004-04-24 16:38:27 +02:00
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) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Nullable");
}
else {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Not Null");
}
isqlGlob.printf(NEWLINE);
ISC_QUAD default_source;
ISQL_get_default_source (NULL, FLD.RDB$FIELD_NAME,
&default_source);
if (default_source.gds_quad_high) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" ");
SHOW_print_metadata_text_blob (isqlGlob.Out, &default_source);
isqlGlob.printf(NEWLINE);
}
if (!FLD.RDB$VALIDATION_SOURCE.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" ");
SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE);
isqlGlob.printf(NEWLINE);
}
// Show collations
2004-04-24 16:38:27 +02:00
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 ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
}
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
2003-12-03 09:19:24 +01:00
static processing_state show_exceptions(const SCHAR* object)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
SCHAR type[20];
//fb_utils::exact_name(object); It already comes trimmed.
FOR EXC IN RDB$EXCEPTIONS
SORTED BY EXC.RDB$EXCEPTION_NAME
fb_utils::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) {
isqlGlob.printf("Exception Name Used by, Type%s%s%s",
NEWLINE,
"=============================== =============================================",
NEWLINE);
}
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%-31s ", EXC.RDB$EXCEPTION_NAME);
// Look up dependent objects --procedures and triggers
bool first_dep = true;
FOR DEP IN RDB$DEPENDENCIES WITH
DEP.RDB$DEPENDED_ON_TYPE = obj_exception AND
DEP.RDB$DEPENDED_ON_NAME EQ EXC.RDB$EXCEPTION_NAME
SORTED BY DEP.RDB$DEPENDENT_TYPE, DEP.RDB$DEPENDENT_NAME
if (!first_dep) {
isqlGlob.printf("%31s ", "");
}
first_dep = false;
fb_utils::exact_name(DEP.RDB$DEPENDENT_NAME);
switch (DEP.RDB$DEPENDENT_TYPE)
{
case obj_trigger:
strcpy (type, "Trigger");
break;
case obj_procedure:
strcpy (type, "Stored procedure");
break;
default:
strcpy (type, "Unknown");
break;
}
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s, %s%s",
DEP.RDB$DEPENDENT_NAME,
type,
NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
if (first_dep)
printf(NEWLINE);
if (!EXC.RDB$MESSAGE.NULL && strlen(EXC.RDB$MESSAGE))
isqlGlob.printf("Msg: %s%s", EXC.RDB$MESSAGE, NEWLINE);
}
if (!first)
isqlGlob.printf(NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
2003-12-03 09:19:24 +01:00
static processing_state show_filters(const SCHAR* object)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s h o w _ f i l t e r s
*
**************************************
*
* Functional description
* Show blob filters in general or for the named filters
*
**************************************/
bool first = true;
2001-05-23 15:26:42 +02:00
// Show all functions
2001-05-23 15:26:42 +02:00
if (!*object) {
bool odd = true;
2003-09-09 13:03:37 +02:00
FOR FIL IN RDB$FILTERS
SORTED BY FIL.RDB$FUNCTION_NAME
first = false;
2005-04-03 08:58:40 +02:00
//fb_utils::exact_name(FIL.RDB$FUNCTION_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", FIL.RDB$FUNCTION_NAME, (odd ? " " : NEWLINE));
odd = !odd;
2003-09-09 13:03:37 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!first) {
isqlGlob.printf(NEWLINE);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
else
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
}
// We have a filter name, so expand on it
2001-05-23 15:26:42 +02:00
FOR FIL IN RDB$FILTERS WITH
FIL.RDB$FUNCTION_NAME EQ object
first = false;
fb_utils::exact_name(FIL.RDB$FUNCTION_NAME);
fb_utils::exact_name(FIL.RDB$MODULE_NAME);
fb_utils::exact_name(FIL.RDB$ENTRYPOINT);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("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);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%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);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
static processing_state show_functions(const SCHAR* object, const SSHORT sys_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
// Show all functions
2001-05-23 15:26:42 +02:00
if (!*object)
{
bool odd = true;
if (!sys_flag)
{
FOR FUN IN RDB$FUNCTIONS
WITH FUN.RDB$SYSTEM_FLAG EQ 0
OR FUN.RDB$SYSTEM_FLAG MISSING
SORTED BY FUN.RDB$FUNCTION_NAME
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", FUN.RDB$FUNCTION_NAME, (odd ? " " : NEWLINE));
odd = !odd;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
}
else
{
FOR FUN IN RDB$FUNCTIONS
WITH FUN.RDB$SYSTEM_FLAG EQ sys_flag
SORTED BY FUN.RDB$FUNCTION_NAME
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", FUN.RDB$FUNCTION_NAME, (odd ? " " : NEWLINE));
odd = !odd;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
}
2001-05-23 15:26:42 +02:00
if (!first)
{
isqlGlob.printf(NEWLINE);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
else
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
}
2001-05-23 15:26:42 +02:00
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::exact_name(FUN.RDB$FUNCTION_NAME);
fb_utils::exact_name(FUN.RDB$MODULE_NAME);
fb_utils::exact_name(FUN.RDB$ENTRYPOINT);
if (first) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%sFunction %s:%s",
NEWLINE,
FUN.RDB$FUNCTION_NAME,
NEWLINE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Function library is %s%s",
FUN.RDB$MODULE_NAME,
NEWLINE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Entry point is %s%s",
FUN.RDB$ENTRYPOINT,
NEWLINE);
}
SSHORT ptype = (SSHORT) abs (FNA.RDB$MECHANISM);
2004-09-22 03:55:37 +02:00
if (ptype > MAX_UDFPARAM_TYPES) {
ptype = MAX_UDFPARAM_TYPES;
}
first = false;
if (FUN.RDB$RETURN_ARGUMENT == FNA.RDB$ARGUMENT_POSITION) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Returns %s%s",
UDF_param_types[ptype],
2004-09-22 03:55:37 +02:00
(FNA.RDB$MECHANISM < 0 ? " FREE_IT " : " "));
}
else {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Argument %d:%s ", FNA.RDB$ARGUMENT_POSITION,
UDF_param_types[ptype]);
}
for (int i = 0; Column_types[i].type; i++)
2001-05-23 15:26:42 +02:00
{
if (FNA.RDB$FIELD_TYPE == Column_types[i].type)
2001-05-23 15:26:42 +02:00
{
bool precision_known = false;
// Handle Integral subtypes NUMERIC and DECIMAL
if ( (isqlGlob.major_ods >= ODS_VERSION10) &&
((FNA.RDB$FIELD_TYPE == SMALLINT) ||
(FNA.RDB$FIELD_TYPE == INTEGER) ||
2004-09-22 03:55:37 +02:00
(FNA.RDB$FIELD_TYPE == BIGINT)) )
2001-05-23 15:26:42 +02:00
{
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)
2001-05-23 15:26:42 +02:00
{
/* We are Dialect >=3 since FIELD_PRECISION is
non-NULL */
if (FNA1.RDB$FIELD_SUB_TYPE > 0 &&
FNA1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
2001-05-23 15:26:42 +02:00
{
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 ps_ERR;
END_ERROR;
}
if (!precision_known)
2001-05-23 15:26:42 +02:00
{
// Take a stab at numerics and decimals
if ((FNA.RDB$FIELD_TYPE == SMALLINT) && (FNA.RDB$FIELD_SCALE < 0))
2001-05-23 15:26:42 +02:00
{
sprintf (Print_buffer, "NUMERIC(4, %d)", -FNA.RDB$FIELD_SCALE);
}
else if ((FNA.RDB$FIELD_TYPE == INTEGER) && (FNA.RDB$FIELD_SCALE < 0))
2001-05-23 15:26:42 +02:00
{
sprintf (Print_buffer, "NUMERIC(9, %d)", -FNA.RDB$FIELD_SCALE);
}
else if ((FNA.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
(FNA.RDB$FIELD_SCALE < 0))
2001-05-23 15:26:42 +02:00
{
sprintf (Print_buffer, "NUMERIC(15, %d)", -FNA.RDB$FIELD_SCALE);
}
else
2001-05-23 15:26:42 +02:00
{
sprintf (Print_buffer, "%s", Column_types[i].type_name);
}
}
isqlGlob.prints(Print_buffer);
break;
}
}
// Print length where appropriate
2004-04-24 16:38:27 +02:00
if ((FNA.RDB$FIELD_TYPE == T_CHAR) || (FNA.RDB$FIELD_TYPE == VARCHAR)
|| (FNA.RDB$FIELD_TYPE == CSTRING))
2001-05-23 15:26:42 +02:00
{
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::exact_name(CHARSET.RDB$CHARACTER_SET_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("(%d) CHARACTER SET %s",
(FNA.RDB$FIELD_LENGTH / MAX (1, CHARSET.RDB$BYTES_PER_CHARACTER)),
CHARSET.RDB$CHARACTER_SET_NAME);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
}
isqlGlob.printf(NEWLINE);
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
2003-12-03 09:19:24 +01:00
static processing_state show_generators(const SCHAR* object)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
XSQLDA sqlda;
SINT64 genid64 = 0;
SLONG genid = 0;
const char genIdStr[] = "SELECT GEN_ID(%s, 0) FROM RDB$DATABASE";
TEXT query[sizeof(genIdStr) + QUOTEDLENGTH], gen_name[QUOTEDLENGTH];
2001-05-23 15:26:42 +02:00
// Show all generators or named generator
FOR GEN IN RDB$GENERATORS
SORTED BY GEN.RDB$GENERATOR_NAME
fb_utils::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
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) {
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, genIdStr, gen_name);
isc_stmt_handle stmt = 0;
isc_dsql_allocate_statement (isc_status, &DB, &stmt);
sqlda.sqln = 1;
sqlda.version = SQLDA_VERSION1;
/* 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,
isqlGlob.SQL_dialect, &sqlda))
2001-05-23 15:26:42 +02:00
{
ISQL_errmsg (isc_status);
continue;
}
if (isqlGlob.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,
isqlGlob.SQL_dialect, NULL, &sqlda))
{
ISQL_errmsg (isc_status);
}
else
2001-05-23 15:26:42 +02:00
{
found = true;
if (isqlGlob.SQL_dialect >= SQL_DIALECT_V6_TRANSITION)
2001-05-23 15:26:42 +02:00
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf(
"Generator %s, current value is %" QUADFORMAT "d%s",
GEN.RDB$GENERATOR_NAME,
genid64,
NEWLINE);
2001-05-23 15:26:42 +02:00
}
else
2001-05-23 15:26:42 +02:00
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Generator %s, current value is %ld%s",
GEN.RDB$GENERATOR_NAME,
genid,
NEWLINE);
2001-05-23 15:26:42 +02:00
}
}
if (isc_dsql_free_statement (isc_status, &stmt, DSQL_drop))
ISQL_errmsg (isc_status);
}
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (!found)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return SKIP;
}
static void show_index(SCHAR* relation_name,
SCHAR* index_name,
const SSHORT unique_flag,
const SSHORT index_type,
const SSHORT inactive)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s h o w _ i n d e x
*
**************************************
*
* Functional description
* Show an index.
*
* relation_name -- Name of table to investigate
*
**************************************/
2005-05-24 06:42:01 +02:00
// Strip trailing blanks
2001-05-23 15:26:42 +02:00
fb_utils::exact_name(relation_name);
fb_utils::exact_name(index_name);
2001-05-23 15:26:42 +02:00
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s%s%s INDEX ON %s", index_name,
2001-05-23 15:26:42 +02:00
(unique_flag ? " UNIQUE" : ""),
(index_type == 1 ? " DESCENDING" : ""), relation_name);
2005-05-24 06:42:01 +02:00
// Get column names
2001-05-23 15:26:42 +02:00
SCHAR collist[BUFFER_LENGTH512];
2001-05-23 15:26:42 +02:00
2005-05-24 06:42:01 +02:00
if (ISQL_get_index_segments(collist, sizeof(collist), index_name, false))
{
isqlGlob.printf("(%s) %s%s", collist,
2001-05-23 15:26:42 +02:00
(inactive ? "(inactive)" : ""), NEWLINE);
}
}
2003-12-03 09:19:24 +01:00
static processing_state show_indices(const SCHAR* const* cmd)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
// The names stored in the database are all upper case
2001-05-23 15:26:42 +02:00
const SCHAR* name = cmd[2];
2001-05-23 15:26:42 +02:00
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);
2001-05-23 15:26:42 +02:00
#ifdef EXPRESSION_INDICES
if (!IDX1.RDB$EXPRESSION_BLR.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" COMPUTED BY ");
if (!IDX1.RDB$EXPRESSION_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &IDX1.RDB$EXPRESSION_SOURCE);
isqlGlob.printf(NEWLINE);
}
2001-05-23 15:26:42 +02:00
#endif
first = false;
END_FOR
ON_ERROR ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
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);
2001-05-23 15:26:42 +02:00
#ifdef EXPRESSION_INDICES
if (!IDX2.RDB$EXPRESSION_BLR.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" COMPUTED BY ");
if (!IDX2.RDB$EXPRESSION_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &IDX2.RDB$EXPRESSION_SOURCE);
isqlGlob.printf(NEWLINE);
}
2001-05-23 15:26:42 +02:00
#endif
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
}
2003-12-03 09:19:24 +01:00
static processing_state show_proc(const SCHAR* procname)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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
2001-05-23 15:26:42 +02:00
if (!procname || !strlen(procname)) {
2001-05-23 15:26:42 +02:00
/* This query gets the procedure name the next query
** gets all the dependencies if any
2001-05-23 15:26:42 +02:00
*/
bool first_proc = true;
2001-05-23 15:26:42 +02:00
FOR PRC IN RDB$PROCEDURES
SORTED BY PRC.RDB$PROCEDURE_NAME
if (first_proc) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(
"Procedure Name Dependency, Type%s", NEWLINE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf(
"================================= ======================================%s", NEWLINE);
first_proc = false;
}
// Strip trailing blanks
fb_utils::exact_name(PRC.RDB$PROCEDURE_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%-34s", PRC.RDB$PROCEDURE_NAME);
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::exact_name(DEP.RDB$DEPENDED_ON_NAME);
// Get column type name to print
if (!first_dep) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s%34s", NEWLINE, "");
}
first_dep = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s, %s", DEP.RDB$DEPENDED_ON_NAME,
Object_types[DEP.RDB$DEPENDED_ON_TYPE]);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
isqlGlob.printf(NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first_proc)
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
return (SKIP);
}
// A procedure was named, so print all the info on that procedure
2001-05-23 15:26:42 +02:00
SCHAR type_name[33];
SCHAR lenstring[33] = "";
bool first = true;
2001-05-23 15:26:42 +02:00
FOR PRC IN RDB$PROCEDURES WITH
PRC.RDB$PROCEDURE_NAME EQ procname
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Procedure text:%s", NEWLINE);
isqlGlob.printf("=============================================================================%s", NEWLINE);
if (!PRC.RDB$PROCEDURE_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &PRC.RDB$PROCEDURE_SOURCE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s=============================================================================%s", NEWLINE, NEWLINE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Parameters:%s", NEWLINE);
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::exact_name(PRM.RDB$PARAMETER_NAME);
// Get column type name to print
// Look through types array
for (int i = 0; Column_types[i].type; i++)
if (FLD.RDB$FIELD_TYPE == Column_types[i].type) {
bool precision_known = false;
if (isqlGlob.major_ods >= ODS_VERSION10) {
// Handle Integral subtypes NUMERIC and DECIMAL
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
(FLD.RDB$FIELD_TYPE == INTEGER) ||
2004-09-22 03:55:37 +02:00
(FLD.RDB$FIELD_TYPE == BIGINT))
{
FOR FLD1 IN RDB$FIELDS
WITH FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
/* We are ODS >= 10 and could be any Dialect */
if (!FLD1.RDB$FIELD_PRECISION.NULL) {
/* We are Dialect >=3 since FIELD_PRECISION is
non-NULL */
if (FLD1.RDB$FIELD_SUB_TYPE > 0 &&
FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
{
sprintf (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 ps_ERR;
END_ERROR;
} // if field_type ...
} // if isqlGlob.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
*/
2004-04-24 16:38:27 +02:00
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, "");
}
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%-33s %s %s%s ", PRM.RDB$PARAMETER_NAME,
(PRM.RDB$PARAMETER_TYPE ? "OUTPUT" : "INPUT"),
type_name, lenstring);
// Show international character sets and collations
2004-04-24 16:38:27 +02:00
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);
}
if (PRM.RDB$PARAMETER_TYPE == 0) // input, try to show default and make Vlad happy.
{
if (!FLD.RDB$DEFAULT_SOURCE.NULL)
{
isqlGlob.printf(" ");
SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE);
}
}
isqlGlob.printf(NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
2003-12-03 09:19:24 +01:00
static processing_state show_role(const SCHAR* object)
2001-05-23 15:26:42 +02:00
{
if (object == NULL) { // show role with no parameters, show all roles
2001-05-23 15:26:42 +02:00
/**************************************
* Print the names of all roles from
* RDB$ROLES. We use a dynamic query
2001-05-23 15:26:42 +02:00
* If there is any roles, then returns SKIP.
* Otherwise returns OBJECT_NOT_FOUND.
2001-05-23 15:26:42 +02:00
**************************************/
bool first = true;
bool odd = true;
2001-05-23 15:26:42 +02:00
FOR X IN RDB$ROLES WITH
X.RDB$ROLE_NAME NOT MISSING
SORTED BY X.RDB$ROLE_NAME
first = false;
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%38s%s", X.RDB$ROLE_NAME, (odd ? " " : NEWLINE));
odd = !odd;
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
if (!first)
2001-05-23 15:26:42 +02:00
{
isqlGlob.printf(NEWLINE);
return SKIP;
}
else
2001-05-23 15:26:42 +02:00
{
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
}
}
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
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
if (first)
{
first = false;
fb_utils::exact_name(PRV.RDB$RELATION_NAME);
strcpy(role_name, PRV.RDB$RELATION_NAME);
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
ISQL_copy_SQL_id(role_name, SQL_identifier, DBL_QUOTE);
else
strcpy(SQL_identifier, role_name);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Role %s is granted to:\n", SQL_identifier);
}
fb_utils::exact_name(PRV.RDB$USER);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s\n", PRV.RDB$USER);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR
if (first)
{
first = false;
fb_utils::exact_name(R.RDB$ROLE_NAME);
strcpy(role_name, R.RDB$ROLE_NAME);
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
ISQL_copy_SQL_id(role_name, SQL_identifier, DBL_QUOTE);
else
strcpy(SQL_identifier, role_name);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Role %s isn't granted to anyone.\n", SQL_identifier);
}
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR
2001-05-23 15:26:42 +02:00
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return (SKIP);
}
}
static processing_state show_table(
const SCHAR* relation_name,
bool isView)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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
2001-05-23 15:26:42 +02:00
*
* relation_name -- Name of table to investigate
*
**************************************/
bool first = true;
2001-05-23 15:26:42 +02:00
// Query to obtain relation information
// REL.RDB$VIEW_BLR NOT MISSING
2001-05-23 15:26:42 +02:00
FOR REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_NAME EQ relation_name
if (first) {
if (!REL.RDB$EXTERNAL_FILE.NULL)
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf("External file: %s\n", REL.RDB$EXTERNAL_FILE);
}
}
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 ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
/*
2001-05-23 15:26:42 +02:00
*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::exact_name(RFR.RDB$FIELD_NAME);
// Print the column name in first column
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%-32s", RFR.RDB$FIELD_NAME);
// 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::exact_name(FLD.RDB$FIELD_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("(%s) ", FLD.RDB$FIELD_NAME);
}
// Detect the existence of arrays
if (!FLD.RDB$DIMENSIONS.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("ARRAY OF ");
ISQL_array_dimensions (FLD.RDB$FIELD_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s ", NEWLINE);
}
// 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) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("Computed by: ");
if (!FLD.RDB$COMPUTED_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$COMPUTED_SOURCE);
isqlGlob.printf(NEWLINE);
continue;
}
// Look through types array
for (int i = 0; Column_types[i].type; i++)
if (FLD.RDB$FIELD_TYPE == Column_types[i].type) {
bool precision_known = false;
if (isqlGlob.major_ods >= ODS_VERSION10) {
// Handle Integral subtypes NUMERIC and DECIMAL
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
(FLD.RDB$FIELD_TYPE == INTEGER) ||
2004-09-22 03:55:37 +02:00
(FLD.RDB$FIELD_TYPE == BIGINT))
{
FOR FLD1 IN RDB$FIELDS WITH
FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
/* We are ODS >= 10 and could be any Dialect */
if (!FLD1.RDB$FIELD_PRECISION.NULL) {
/* We are Dialect >=3 since FIELD_PRECISION is
non-NULL */
if (FLD1.RDB$FIELD_SUB_TYPE > 0 &&
FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
{
sprintf (Print_buffer, "%s(%d, %d)",
Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE],
FLD1.RDB$FIELD_PRECISION,
-FLD1.RDB$FIELD_SCALE);
precision_known = true;
}
}
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
}
}
if (!precision_known) {
// Take a stab at numerics and decimals
if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0)) {
sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE);
}
else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0)) {
sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE);
}
else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
(FLD.RDB$FIELD_SCALE < 0))
{
sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE);
}
else {
sprintf (Print_buffer, "%s", Column_types[i].type_name);
}
}
isqlGlob.prints(Print_buffer);
break;
}
2004-04-24 16:38:27 +02:00
if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME));
// Show international character sets and collations
show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false);
}
if (FLD.RDB$FIELD_TYPE == BLOB) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" segment %u, subtype ", (USHORT) FLD.RDB$SEGMENT_LENGTH);
2004-12-07 01:33:16 +01:00
const int subtype = FLD.RDB$FIELD_SUB_TYPE;
2004-05-09 07:48:33 +02:00
if (subtype >= 0 && subtype <= MAX_BLOBSUBTYPES)
2001-05-23 15:26:42 +02:00
{
isqlGlob.prints(Sub_types[subtype]);
}
else
2001-05-23 15:26:42 +02:00
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%d", subtype);
}
// 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.
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Expression%s", NEWLINE);
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)))
2001-05-23 15:26:42 +02:00
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Not Null ");
}
else
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Nullable ");
}
// Handle defaults for columns
if (!RFR.RDB$DEFAULT_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &RFR.RDB$DEFAULT_SOURCE);
else if (!FLD.RDB$DEFAULT_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE);
isqlGlob.printf(NEWLINE);
// Validation clause for domains
if (!FLD.RDB$VALIDATION_SOURCE.NULL) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" ");
SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$VALIDATION_SOURCE);
isqlGlob.printf(NEWLINE);
}
// Handle collations
2004-04-24 16:38:27 +02:00
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);
}
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
// If this is a view and there were columns, print the view text
2001-05-23 15:26:42 +02:00
if (!first) {
FOR REL IN RDB$RELATIONS WITH
REL.RDB$RELATION_NAME EQ relation_name AND
REL.RDB$VIEW_BLR NOT MISSING
2005-05-24 06:42:01 +02:00
isqlGlob.printf("View Source:%s==== ======%s", NEWLINE, NEWLINE);
if (!REL.RDB$VIEW_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &REL.RDB$VIEW_SOURCE);
isqlGlob.printf(NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
}
// Handle any referential or primary constraint on this table
2001-05-23 15:26:42 +02:00
SCHAR collist[BUFFER_LENGTH512];
2001-05-23 15:26:42 +02:00
// Static queries for obtaining referential constraints
2001-05-23 15:26:42 +02:00
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, sizeof(collist), RELC1.RDB$INDEX_NAME, false);
if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "PRIMARY", 7)) {
fb_utils::exact_name(RELC1.RDB$CONSTRAINT_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE);
isqlGlob.printf(" Primary key (%s)%s", collist, NEWLINE);
}
else if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "UNIQUE", 6)) {
fb_utils::exact_name(RELC1.RDB$CONSTRAINT_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE);
isqlGlob.printf(" Unique key (%s)%s", collist, NEWLINE);
}
else if (!strncmp (RELC1.RDB$CONSTRAINT_TYPE, "FOREIGN", 7)) {
fb_utils::exact_name(RELC1.RDB$CONSTRAINT_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("CONSTRAINT %s:%s", RELC1.RDB$CONSTRAINT_NAME, NEWLINE);
ISQL_get_index_segments (collist, sizeof(collist), RELC1.RDB$INDEX_NAME, false);
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Foreign key (%s)", collist);
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, sizeof(collist), RELC2.RDB$INDEX_NAME, false);
fb_utils::exact_name(RELC2.RDB$RELATION_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" References %s (%s)",
RELC2.RDB$RELATION_NAME, collist);
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);
}
isqlGlob.printf(NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg (isc_status);
return ps_ERR;
END_ERROR;
}
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
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::exact_name(C_C.RDB$TRIGGER_NAME);
fb_utils::exact_name(R_C.RDB$CONSTRAINT_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("CONSTRAINT %s:%s", R_C.RDB$CONSTRAINT_NAME,
NEWLINE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf(" Not Null Column (%s)%s",
C_C.RDB$TRIGGER_NAME, NEWLINE);
}
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
// Do check constraints
2001-05-23 15:26:42 +02:00
show_check(relation_name);
// Do triggers
show_trigger(relation_name, false, false);
2001-05-23 15:26:42 +02:00
if (first)
2003-12-03 09:19:24 +01:00
return (OBJECT_NOT_FOUND);
2001-05-23 15:26:42 +02:00
return SKIP;
}
static processing_state show_trigger(
const SCHAR* object,
bool show_source,
bool isTriggerName)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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;
2001-05-23 15:26:42 +02:00
// Show all triggers
2001-05-23 15:26:42 +02:00
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
//NOT (ANY CHK IN RDB$CHECK_CONSTRAINTS WITH
// TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME)
WITH (TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING) AND
TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME
SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_NAME
if (first)
{
2005-05-24 06:42:01 +02:00
isqlGlob.printf(
"Table name Trigger name%s", NEWLINE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf(
"=========== ============%s", NEWLINE);
first = false;
}
fb_utils::exact_name(TRG.RDB$TRIGGER_NAME);
fb_utils::exact_name(TRG.RDB$RELATION_NAME);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%-32s %s%s%s",
TRG.RDB$RELATION_NAME,
TRG.RDB$TRIGGER_NAME,
(TRG.RDB$SYSTEM_FLAG == 1 ? "(system)" : ""),
NEWLINE);
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
END_ERROR;
2001-05-23 15:26:42 +02:00
if (first)
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
else
return (SKIP);
}
// Show triggers for the named object
// and avoid check constraints
2004-05-09 07:48:33 +02:00
BASED_ON RDB$TRIGGERS.RDB$TRIGGER_NAME triggerName;
BASED_ON RDB$TRIGGERS.RDB$RELATION_NAME relationName;
if (isTriggerName) {
sprintf(triggerName, "%s", object);
relationName[0] = '\0';
}
else {
sprintf(relationName, "%s", object);
triggerName[0] = '\0';
}
2001-05-23 15:26:42 +02:00
FOR TRG IN RDB$TRIGGERS WITH
(TRG.RDB$RELATION_NAME EQ relationName OR
TRG.RDB$TRIGGER_NAME EQ triggerName) AND
(TRG.RDB$SYSTEM_FLAG EQ 0 OR TRG.RDB$SYSTEM_FLAG MISSING)
SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE,
TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME;
//bool 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 ps_ERR;
//END_ERROR;
//if (skip)
// continue;
fb_utils::exact_name(TRG.RDB$TRIGGER_NAME);
fb_utils::exact_name(TRG.RDB$RELATION_NAME);
if (first) {
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%sTriggers on Table %s:%s",
NEWLINE,
TRG.RDB$RELATION_NAME,
NEWLINE);
first = false;
}
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%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);
if (show_source) {
// Use print_blob to print the blob
if (!TRG.RDB$TRIGGER_SOURCE.NULL)
SHOW_print_metadata_text_blob (isqlGlob.Out, &TRG.RDB$TRIGGER_SOURCE);
2005-05-24 06:42:01 +02:00
isqlGlob.printf("%s+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%s", NEWLINE, NEWLINE);
}
2001-05-23 15:26:42 +02:00
END_FOR
ON_ERROR
ISQL_errmsg(isc_status);
return ps_ERR;
2001-05-23 15:26:42 +02:00
END_ERROR;
if (first)
2003-12-03 09:19:24 +01:00
return OBJECT_NOT_FOUND;
2001-05-23 15:26:42 +02:00
return SKIP;
}
2003-09-09 13:03:37 +02:00