mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 14:03:04 +01:00
2903 lines
90 KiB
Plaintext
2903 lines
90 KiB
Plaintext
|
/*
|
||
|
* PROGRAM: Interactive SQL utility
|
||
|
* MODULE: extract.e
|
||
|
* DESCRIPTION: Definition extract routines
|
||
|
*
|
||
|
* The contents of this file are subject to the Interbase Public
|
||
|
* License Version 1.0 (the "License"); you may not use this file
|
||
|
* except in compliance with the License. You may obtain a copy
|
||
|
* of the License at http://www.Inprise.com/IPL.html
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an
|
||
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||
|
* or implied. See the License for the specific language governing
|
||
|
* rights and limitations under the License.
|
||
|
*
|
||
|
* The Original Code was created by Inprise Corporation
|
||
|
* and its predecessors. Portions created by Inprise Corporation are
|
||
|
* Copyright (C) Inprise Corporation.
|
||
|
*
|
||
|
* All Rights Reserved.
|
||
|
* Contributor(s): ______________________________________.
|
||
|
* $Id: extract.e,v 1.1.1.1 2001-05-23 13:26:02 tamlin Exp $
|
||
|
* Revision 1.3 2000/11/22 17:07:25 patrickgriffin
|
||
|
* In get_procedure_args change comment style from // to /*
|
||
|
*
|
||
|
* ...pat
|
||
|
*
|
||
|
* Revision 1.2 2000/11/18 16:49:24 fsg
|
||
|
* Increased PRINT_BUFFER_LENGTH to 2048 to show larger plans
|
||
|
* Fixed Bug #122563 in extract.e get_procedure_args
|
||
|
* Apparently this has to be done in show.e also,
|
||
|
* but that is for another day :-)
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "../jrd/ib_stdio.h"
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#include <ctype.h> /* isdigit */
|
||
|
#ifdef GUI_TOOLS
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
#include "../jrd/common.h"
|
||
|
#include "../include/jrd/gds.h"
|
||
|
#include "../dsql/dsql.h"
|
||
|
#include "../isql/isql.h"
|
||
|
#include "../jrd/constants.h"
|
||
|
#include "../isql/extra_proto.h"
|
||
|
#include "../isql/isql_proto.h"
|
||
|
#include "../isql/show_proto.h"
|
||
|
#include "../jrd/gds_proto.h"
|
||
|
#include "../jrd/ods.h"
|
||
|
|
||
|
DATABASE DB = EXTERN COMPILETIME "yachts.lnk";
|
||
|
|
||
|
extern USHORT major_ods;
|
||
|
extern USHORT minor_ods;
|
||
|
extern SSHORT V33;
|
||
|
|
||
|
static void list_all_grants(void);
|
||
|
static void list_all_procs(void);
|
||
|
static void list_all_tables(SSHORT, SSHORT);
|
||
|
static void list_all_triggers(void);
|
||
|
static void list_check(void);
|
||
|
static void list_create_db(void);
|
||
|
static void list_domain_table(SCHAR *, SSHORT);
|
||
|
static void list_domains(SSHORT);
|
||
|
static void list_exception(void);
|
||
|
static void list_filters(void);
|
||
|
static void list_foreign(void);
|
||
|
static void list_functions(void);
|
||
|
static void list_generators(void);
|
||
|
static void list_index(void);
|
||
|
static void list_views(void);
|
||
|
|
||
|
static void get_procedure_args(SCHAR *);
|
||
|
|
||
|
#define MAX_INTSUBTYPES 2
|
||
|
#define MAXSUBTYPES 8
|
||
|
#define BLANK '\040'
|
||
|
#define DBL_QUOTE '\042'
|
||
|
#define SINGLE_QUOTE '\''
|
||
|
|
||
|
extern IB_FILE *Out;
|
||
|
|
||
|
/* Command terminator and procedure terminator */
|
||
|
|
||
|
extern SQLTYPES Column_types[];
|
||
|
extern SCHAR *Integral_subtypes[];
|
||
|
extern SCHAR *Sub_types[];
|
||
|
extern SCHAR *Trigger_types[];
|
||
|
|
||
|
static SCHAR *Procterm = "^"; /* TXNN: script use only */
|
||
|
|
||
|
/* Maybe 512 would be really enough as Print_buffer size, but
|
||
|
as we have PRINT_BUFFER_LENGTH in isql.h, we should use it
|
||
|
FSG 17.Nov.2000
|
||
|
*/
|
||
|
|
||
|
static TEXT Print_buffer[PRINT_BUFFER_LENGTH];
|
||
|
static TEXT SQL_identifier[BUFFER_LENGTH128];
|
||
|
static TEXT SQL_identifier2[BUFFER_LENGTH128];
|
||
|
|
||
|
|
||
|
|
||
|
SSHORT EXTRACT_ddl( int flag, SCHAR * tabname)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E X T R A C T _ d d l
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Extract all sql information
|
||
|
* 0 flag means SQL only tables. 1 flag means all tables
|
||
|
*
|
||
|
**************************************/
|
||
|
SCHAR errbuf[MSG_LENGTH];
|
||
|
SSHORT ret_code = FINI_OK;
|
||
|
USHORT did_attach = FALSE;
|
||
|
USHORT did_start = FALSE;
|
||
|
SSHORT default_char_set_id;
|
||
|
|
||
|
if (!DB)
|
||
|
{
|
||
|
if (isc_attach_database(gds__status, 0, Db_name, &DB, 0, (SCHAR *) 0))
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
did_attach = TRUE;
|
||
|
}
|
||
|
|
||
|
ISQL_get_version(FALSE);
|
||
|
if (SQL_dialect != db_SQL_dialect)
|
||
|
{
|
||
|
sprintf(Print_buffer,
|
||
|
"/*=========================================================*/%s",
|
||
|
NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer,
|
||
|
"/*= ==*/%s",
|
||
|
NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer,
|
||
|
"/*= Command Line -sqldialect %d is overwritten by ==*/%s",
|
||
|
SQL_dialect, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer,
|
||
|
"/*= Database SQL Dialect %d. ==*/%s",
|
||
|
db_SQL_dialect, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer,
|
||
|
"/*= ==*/%s",
|
||
|
NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer,
|
||
|
"/*=========================================================*/%s",
|
||
|
NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
sprintf(Print_buffer, " %s", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer, "SET SQL DIALECT %d; %s", db_SQL_dialect, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
sprintf(Print_buffer, " %s", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
if (!gds__trans)
|
||
|
{
|
||
|
if (isc_start_transaction(gds__status,
|
||
|
&gds__trans,
|
||
|
1,
|
||
|
&DB,
|
||
|
0,
|
||
|
(SCHAR *) 0))
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
did_start = TRUE;
|
||
|
}
|
||
|
|
||
|
default_char_set_id = ISQL_get_default_char_set_id();
|
||
|
|
||
|
/* If a table name was passed, extract only that table and domains */
|
||
|
if (*tabname)
|
||
|
{
|
||
|
if (EXTRACT_list_table(tabname, NULL, 1, default_char_set_id))
|
||
|
{
|
||
|
gds__msg_format(NULL_PTR, ISQL_MSG_FAC, NOT_FOUND, sizeof(errbuf),
|
||
|
errbuf, tabname, NULL, NULL, NULL, NULL);
|
||
|
STDERROUT(errbuf, 1);
|
||
|
ret_code = (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
list_create_db();
|
||
|
list_filters();
|
||
|
list_functions();
|
||
|
list_domains(default_char_set_id);
|
||
|
list_all_tables(flag, default_char_set_id);
|
||
|
list_index();
|
||
|
list_foreign();
|
||
|
list_generators();
|
||
|
list_views();
|
||
|
list_check();
|
||
|
list_exception();
|
||
|
list_all_procs();
|
||
|
list_all_triggers();
|
||
|
list_all_grants();
|
||
|
}
|
||
|
|
||
|
if (gds__trans && did_start)
|
||
|
if (isc_commit_transaction(gds__status, &gds__trans))
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
|
||
|
if (DB && did_attach)
|
||
|
{
|
||
|
if (isc_detach_database(gds__status, &DB))
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
DB = NULL;
|
||
|
}
|
||
|
|
||
|
return (SSHORT) ret_code;
|
||
|
}
|
||
|
|
||
|
|
||
|
SSHORT EXTRACT_list_table(SCHAR * relation_name,
|
||
|
SCHAR * new_name,
|
||
|
SSHORT domain_flag, SSHORT default_char_set_id)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E X T R A C T _ l i s t _ t a b l e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Shows columns, types, info for a given table name
|
||
|
* and text of views.
|
||
|
* Use a GDML query to get the info and print it.
|
||
|
* If a new_name is passed, substitute it for relation_name
|
||
|
*
|
||
|
* relation_name -- Name of table to investigate
|
||
|
* new_name -- Name of a new name for a replacement table
|
||
|
* domain_flag -- extract needed domains before the table
|
||
|
* default_char_set_id -- character set def to supress
|
||
|
*
|
||
|
**************************************/
|
||
|
/**************************************
|
||
|
* default_char_set_id warrents special
|
||
|
* consideration. If the metadata for a
|
||
|
* table is being extracted when there is
|
||
|
* really no need to redundantly and repeatedly
|
||
|
* list the databases default character set
|
||
|
* for every field.
|
||
|
*
|
||
|
* At the same time there is a need to list
|
||
|
* the character set NONE when it is not
|
||
|
* the default character set for the database.
|
||
|
*
|
||
|
* EXCEPT! If the metadata is being extracted
|
||
|
* with the intention of coping that tables structure
|
||
|
* into another database, and it is not possible
|
||
|
* to know the default character set for the
|
||
|
* target database, then list every fields
|
||
|
* character set. This includes the character
|
||
|
* set NONE.
|
||
|
*
|
||
|
* Fields with no character set definition will
|
||
|
* not have any character set listed.
|
||
|
*
|
||
|
* Use -1 as the default_char_set_id
|
||
|
* in this case.
|
||
|
*
|
||
|
* POTENTIAL TRAP! Consider the following:
|
||
|
* When copying a table from one database
|
||
|
* to another how should fields using the
|
||
|
* default character set be handled?
|
||
|
*
|
||
|
* If both databases have the same default
|
||
|
* character set, then there is no problem
|
||
|
* or confusion.
|
||
|
*
|
||
|
* If the databases have different default
|
||
|
* character sets then should fields using
|
||
|
* the default is the source database use
|
||
|
* the default of the target database?
|
||
|
*
|
||
|
**************************************/
|
||
|
|
||
|
USHORT first;
|
||
|
SSHORT collation, char_set_id;
|
||
|
SSHORT i;
|
||
|
SCHAR *collist, char_sets[86];
|
||
|
SSHORT subtype;
|
||
|
SSHORT intchar;
|
||
|
|
||
|
/* Query to obtain relation detail information */
|
||
|
|
||
|
first = TRUE;
|
||
|
collist = NULL;
|
||
|
intchar = 0;
|
||
|
|
||
|
FOR REL IN RDB$RELATIONS CROSS
|
||
|
RFR IN RDB$RELATION_FIELDS CROSS
|
||
|
FLD IN RDB$FIELDS WITH
|
||
|
RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND
|
||
|
RFR.RDB$RELATION_NAME EQ REL.RDB$RELATION_NAME AND
|
||
|
REL.RDB$RELATION_NAME EQ relation_name
|
||
|
SORTED BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
first = FALSE;
|
||
|
/* Do we need to print domains */
|
||
|
if (domain_flag)
|
||
|
list_domain_table (relation_name,default_char_set_id);
|
||
|
|
||
|
ISQL_blankterm (REL.RDB$OWNER_NAME);
|
||
|
sprintf (Print_buffer, "%s/* Table: %s, Owner: %s */%s",
|
||
|
NEWLINE,
|
||
|
relation_name,
|
||
|
REL.RDB$OWNER_NAME,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
if (new_name)
|
||
|
ISQL_copy_SQL_id (new_name, &SQL_identifier, DBL_QUOTE);
|
||
|
else
|
||
|
ISQL_copy_SQL_id (relation_name, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CREATE TABLE %s ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CREATE TABLE %s ",
|
||
|
new_name ? new_name : relation_name);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
if (!REL.RDB$EXTERNAL_FILE.NULL)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (REL.RDB$EXTERNAL_FILE, &SQL_identifier2,
|
||
|
SINGLE_QUOTE);
|
||
|
sprintf (Print_buffer, "EXTERNAL FILE %s ", SQL_identifier2);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
ISQL_printf (Out, "(");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, ",%s%s", NEWLINE, TAB);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (ISQL_blankterm (RFR.RDB$FIELD_NAME),
|
||
|
&SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "%s ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "%s ", ISQL_blankterm (RFR.RDB$FIELD_NAME));
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/*
|
||
|
** Check first for computed fields, then domains.
|
||
|
** If this is a known domain, then just print the domain rather than type
|
||
|
** Domains won't have length, array, or blob definitions, but they
|
||
|
** may have not null, default and check overriding their definitions
|
||
|
*/
|
||
|
|
||
|
if (!FLD.RDB$COMPUTED_BLR.NULL)
|
||
|
{
|
||
|
ISQL_printf (Out, "COMPUTED BY ");
|
||
|
if (!FLD.RDB$COMPUTED_SOURCE.NULL)
|
||
|
ISQL_print_validation (Out, &FLD.RDB$COMPUTED_SOURCE, 1, gds__trans);
|
||
|
}
|
||
|
else if (!((strncmp(FLD.RDB$FIELD_NAME, "RDB$", 4) == 0) &&
|
||
|
isdigit (FLD.RDB$FIELD_NAME[4]) &&
|
||
|
FLD.RDB$SYSTEM_FLAG != 1))
|
||
|
{
|
||
|
ISQL_blankterm (FLD.RDB$FIELD_NAME);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (FLD.RDB$FIELD_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "%s", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "%s", FLD.RDB$FIELD_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
/* International character sets */
|
||
|
if ((FLD.RDB$FIELD_TYPE == FCHAR || FLD.RDB$FIELD_TYPE == VARCHAR)
|
||
|
&& !RFR.RDB$COLLATION_ID.NULL && RFR.RDB$COLLATION_ID)
|
||
|
{
|
||
|
char_sets [0] = '\0';
|
||
|
collation = RFR.RDB$COLLATION_ID;
|
||
|
ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, collation, TRUE, char_sets);
|
||
|
if (char_sets [0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Look through types array */
|
||
|
for (i = 0; Column_types [i].type; i++)
|
||
|
if (FLD.RDB$FIELD_TYPE == Column_types [i].type)
|
||
|
{
|
||
|
BOOLEAN precision_known = FALSE;
|
||
|
|
||
|
if (major_ods >= ODS_VERSION10)
|
||
|
{
|
||
|
/* Handle Integral subtypes NUMERIC and DECIMAL */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
|
||
|
(FLD.RDB$FIELD_TYPE == INTEGER) ||
|
||
|
(FLD.RDB$FIELD_TYPE == blr_int64))
|
||
|
{
|
||
|
FOR FLD1 IN RDB$FIELDS WITH
|
||
|
FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
|
||
|
|
||
|
/* We are ODS >= 10 and could be any Dialect */
|
||
|
if (!FLD1.RDB$FIELD_PRECISION.NULL)
|
||
|
{
|
||
|
/* We are Dialect >=3 since FIELD_PRECISION is non-NULL */
|
||
|
if (FLD1.RDB$FIELD_SUB_TYPE > 0 &&
|
||
|
FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s(%d, %d)",
|
||
|
Integral_subtypes [FLD1.RDB$FIELD_SUB_TYPE],
|
||
|
FLD1.RDB$FIELD_PRECISION,
|
||
|
-FLD1.RDB$FIELD_SCALE);
|
||
|
precision_known = TRUE;
|
||
|
}
|
||
|
}
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (isc_status);
|
||
|
return ERR;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (precision_known == FALSE)
|
||
|
{
|
||
|
|
||
|
/* Take a stab at numerics and decimals */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(4, %d)",
|
||
|
-FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == INTEGER) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(9, %d)",
|
||
|
-FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(15, %d)",
|
||
|
-FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "%s",
|
||
|
Column_types [i].type_name);
|
||
|
}
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ((FLD.RDB$FIELD_TYPE == FCHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR))
|
||
|
if (FLD.RDB$CHARACTER_LENGTH.NULL)
|
||
|
{
|
||
|
|
||
|
sprintf (Print_buffer, "(%d)", FLD.RDB$FIELD_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "(%d)", FLD.RDB$CHARACTER_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
/* Catch arrays after printing the type */
|
||
|
|
||
|
if (!FLD.RDB$DIMENSIONS.NULL)
|
||
|
ISQL_array_dimensions (FLD.RDB$FIELD_NAME);
|
||
|
|
||
|
if (FLD.RDB$FIELD_TYPE == BLOB)
|
||
|
{
|
||
|
subtype = FLD.RDB$FIELD_SUB_TYPE;
|
||
|
ISQL_printf (Out, " SUB_TYPE ");
|
||
|
if ((subtype > 0) && (subtype <= MAXSUBTYPES))
|
||
|
ISQL_printf (Out, Sub_types [subtype]);
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%d", subtype);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
sprintf (Print_buffer, " SEGMENT SIZE %u",
|
||
|
(USHORT) FLD.RDB$SEGMENT_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
/* International character sets */
|
||
|
if ((FLD.RDB$FIELD_TYPE == FCHAR || FLD.RDB$FIELD_TYPE == VARCHAR ||
|
||
|
FLD.RDB$FIELD_TYPE == BLOB) &&
|
||
|
!FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
{
|
||
|
|
||
|
char_sets [0] = '\0';
|
||
|
|
||
|
/* Override rdb$fields id with relation_fields if present */
|
||
|
|
||
|
collation = 0;
|
||
|
if (!RFR.RDB$COLLATION_ID.NULL)
|
||
|
collation = RFR.RDB$COLLATION_ID;
|
||
|
else if (!FLD.RDB$COLLATION_ID.NULL)
|
||
|
collation = FLD.RDB$COLLATION_ID;
|
||
|
|
||
|
char_set_id = 0;
|
||
|
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
char_set_id = FLD.RDB$CHARACTER_SET_ID;
|
||
|
if ((char_set_id != default_char_set_id) || collation)
|
||
|
ISQL_get_character_sets (char_set_id, 0, FALSE, char_sets);
|
||
|
if (char_sets [0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
if (!char_set_id)
|
||
|
intchar = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Handle defaults for columns */
|
||
|
|
||
|
if (!RFR.RDB$DEFAULT_SOURCE.NULL)
|
||
|
{
|
||
|
|
||
|
ISQL_printf (Out, " ");
|
||
|
SHOW_print_metadata_text_blob (Out, &RFR.RDB$DEFAULT_SOURCE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* The null flag is either 1 or null (for nullable) . if there is
|
||
|
** a constraint name, print that too. Domains cannot have named
|
||
|
** constraints. The column name is in rdb$trigger_name in
|
||
|
** rdb$check_constraints. We hope we get at most one row back.
|
||
|
*/
|
||
|
|
||
|
if (RFR.RDB$NULL_FLAG == 1)
|
||
|
{
|
||
|
FOR RCO IN RDB$RELATION_CONSTRAINTS CROSS
|
||
|
CON IN RDB$CHECK_CONSTRAINTS WITH
|
||
|
CON.RDB$TRIGGER_NAME = RFR.RDB$FIELD_NAME AND
|
||
|
CON.RDB$CONSTRAINT_NAME = RCO.RDB$CONSTRAINT_NAME AND
|
||
|
RCO.RDB$CONSTRAINT_TYPE EQ "NOT NULL" AND
|
||
|
RCO.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME
|
||
|
|
||
|
if (strncmp(CON.RDB$CONSTRAINT_NAME, "INTEG", 5))
|
||
|
{
|
||
|
ISQL_blankterm(CON.RDB$CONSTRAINT_NAME);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
|
||
|
ISQL_copy_SQL_id (CON.RDB$CONSTRAINT_NAME, &SQL_identifier,
|
||
|
DBL_QUOTE);
|
||
|
sprintf (Print_buffer, " CONSTRAINT %s", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, " CONSTRAINT %s",
|
||
|
CON.RDB$CONSTRAINT_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (gds__status);
|
||
|
return (SSHORT)FINI_ERROR;
|
||
|
END_ERROR;
|
||
|
|
||
|
|
||
|
ISQL_printf (Out, " NOT NULL");
|
||
|
}
|
||
|
|
||
|
if ((FLD.RDB$FIELD_TYPE == FCHAR || FLD.RDB$FIELD_TYPE == VARCHAR ||
|
||
|
FLD.RDB$FIELD_TYPE == BLOB) &&
|
||
|
!FLD.RDB$CHARACTER_SET_ID.NULL && FLD.RDB$CHARACTER_SET_ID && intchar)
|
||
|
{
|
||
|
collation = 0;
|
||
|
if (!RFR.RDB$COLLATION_ID.NULL)
|
||
|
collation = RFR.RDB$COLLATION_ID;
|
||
|
else if (!FLD.RDB$COLLATION_ID.NULL)
|
||
|
collation = FLD.RDB$COLLATION_ID;
|
||
|
|
||
|
char_set_id = 0;
|
||
|
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
char_set_id = FLD.RDB$CHARACTER_SET_ID;
|
||
|
|
||
|
if (collation)
|
||
|
{
|
||
|
char_sets[0] = '\0';
|
||
|
ISQL_get_character_sets (char_set_id, collation, TRUE, char_sets);
|
||
|
if (char_sets [0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
if (!V33)
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
END_ERROR;
|
||
|
|
||
|
/* Do primary and unique keys only. references come later */
|
||
|
|
||
|
collist = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH512 * 2);
|
||
|
if (!collist)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
return ((SSHORT) FINI_ERROR);
|
||
|
}
|
||
|
|
||
|
FOR RELC IN RDB$RELATION_CONSTRAINTS WITH
|
||
|
(RELC.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY" OR
|
||
|
RELC.RDB$CONSTRAINT_TYPE EQ "UNIQUE") AND
|
||
|
RELC.RDB$RELATION_NAME EQ relation_name
|
||
|
SORTED BY RELC.RDB$CONSTRAINT_NAME
|
||
|
|
||
|
sprintf (Print_buffer, ",%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
/* If the name of the constraint is not INTEG..., print it */
|
||
|
if (strncmp(RELC.RDB$CONSTRAINT_NAME, "INTEG", 5))
|
||
|
{
|
||
|
ISQL_blankterm(RELC.RDB$CONSTRAINT_NAME);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (RELC.RDB$CONSTRAINT_NAME, &SQL_identifier,
|
||
|
DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CONSTRAINT %s ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CONSTRAINT %s ", RELC.RDB$CONSTRAINT_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
if (!strncmp (RELC.RDB$CONSTRAINT_TYPE, "PRIMARY", 7))
|
||
|
{
|
||
|
ISQL_get_index_segments (collist, RELC.RDB$INDEX_NAME, TRUE);
|
||
|
sprintf (Print_buffer, "PRIMARY KEY (%s)", collist);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
else if (!strncmp (RELC.RDB$CONSTRAINT_TYPE, "UNIQUE", 6))
|
||
|
{
|
||
|
ISQL_get_index_segments (collist, RELC.RDB$INDEX_NAME, TRUE);
|
||
|
sprintf (Print_buffer, "UNIQUE (%s)", collist);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
if (collist)
|
||
|
ISQL_FREE(collist);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
END_ERROR;
|
||
|
|
||
|
/* Check constaints are now deferred*/
|
||
|
|
||
|
sprintf(Print_buffer, ")%s%s", Term, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
if (collist)
|
||
|
ISQL_FREE(collist);
|
||
|
|
||
|
return (SSHORT) FINI_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef GUI_TOOLS
|
||
|
void EXTRACT_list_view( SCHAR * viewname)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E X T R A C T _ l i s t _ v i e w
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Show text of the specified view.
|
||
|
* Use a SQL query to get the info and print it.
|
||
|
* Note: This should also contain check option
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first;
|
||
|
|
||
|
if (!DB)
|
||
|
if (isc_attach_database(gds__status, 0, Db_name, &DB, 0, (SCHAR *) 0))
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return (SSHORT) FINI_ERROR;
|
||
|
}
|
||
|
if (!gds__trans)
|
||
|
isc_start_transaction(gds__status, &gds__trans, 1, &DB, 0,
|
||
|
(SCHAR *) 0);
|
||
|
|
||
|
/* If this is a view, use print_blob to print the view text */
|
||
|
|
||
|
FOR REL IN RDB$RELATIONS WITH
|
||
|
(REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND
|
||
|
REL.RDB$VIEW_BLR NOT MISSING AND
|
||
|
REL.RDB$RELATION_NAME = viewname AND
|
||
|
REL.RDB$FLAGS = REL_sql
|
||
|
SORTED BY REL.RDB$RELATION_ID
|
||
|
|
||
|
first = TRUE;
|
||
|
ISQL_blankterm (REL.RDB$RELATION_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
ISQL_copy_SQL_id (REL.RDB$RELATION_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
else
|
||
|
strcpy (SQL_identifier, REL.RDB$RELATION_NAME);
|
||
|
|
||
|
ISQL_blankterm (REL.RDB$OWNER_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, "%s/* View: %s, Owner: %s */%s",
|
||
|
NEWLINE,
|
||
|
SQL_identifier,
|
||
|
REL.RDB$OWNER_NAME,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer, "CREATE VIEW %s (", SQL_identifier);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Get column list */
|
||
|
FOR RFR IN RDB$RELATION_FIELDS WITH
|
||
|
RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME
|
||
|
SORTED BY RFR.RDB$FIELD_POSITION
|
||
|
|
||
|
ISQL_blankterm (RFR.RDB$FIELD_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
ISQL_blankterm (RFR.RDB$FIELD_NAME, &SQL_identifier);
|
||
|
else
|
||
|
strcpy (SQL_identifier, RFR.RDB$FIELD_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", (first ? "" : ", "), SQL_identifier);
|
||
|
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
first = FALSE;
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
sprintf (Print_buffer, ") AS%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
if (!REL.RDB$VIEW_SOURCE.NULL)
|
||
|
SHOW_print_metadata_text_blob (Out, &REL.RDB$VIEW_SOURCE);
|
||
|
sprintf (Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static void get_procedure_args( SCHAR * proc_name)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* g e t _ p r o c e d u r e _ a r g s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* This function extract the procedure parameters and adds it to the
|
||
|
* extract file
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT ptype, first_time, i, header = TRUE;
|
||
|
TEXT msg[MSG_LENGTH];
|
||
|
SCHAR char_sets[86];
|
||
|
|
||
|
/* query to retrieve the parameters. */
|
||
|
{
|
||
|
|
||
|
|
||
|
/* placed the two identical code blocks into one
|
||
|
for loop as suggested by Ann H. and Claudio C.
|
||
|
FSG 18.Nov.2000
|
||
|
*/
|
||
|
|
||
|
/* Parameter types 0 = input */
|
||
|
/* Parameter types 1 = return */
|
||
|
|
||
|
for (ptype = 0; ptype < 2; ptype++)
|
||
|
{
|
||
|
first_time = TRUE;
|
||
|
|
||
|
FOR PRM IN RDB$PROCEDURE_PARAMETERS CROSS
|
||
|
FLD IN RDB$FIELDS WITH
|
||
|
PRM.RDB$PROCEDURE_NAME = proc_name AND
|
||
|
PRM.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND
|
||
|
PRM.RDB$PARAMETER_TYPE = ptype
|
||
|
SORTED BY PRM.RDB$PARAMETER_NUMBER
|
||
|
|
||
|
if (first_time)
|
||
|
{
|
||
|
first_time = FALSE;
|
||
|
if (ptype==0)
|
||
|
{ /* this is the input part */
|
||
|
ISQL_printf (Out, "(");
|
||
|
}
|
||
|
else
|
||
|
{ /* we are in the output part */
|
||
|
ISQL_printf (Out, "RETURNS (");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, ",%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
ISQL_blankterm (PRM.RDB$PARAMETER_NAME);
|
||
|
sprintf (Print_buffer, "%s ", PRM.RDB$PARAMETER_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Get column type name to print */
|
||
|
for (i = 0; Column_types [i].type; i++)
|
||
|
if (FLD.RDB$FIELD_TYPE == Column_types [i].type)
|
||
|
{
|
||
|
BOOLEAN precision_known = FALSE;
|
||
|
|
||
|
if (major_ods >= ODS_VERSION10)
|
||
|
{
|
||
|
/* Handle Integral subtypes NUMERIC and DECIMAL */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
|
||
|
(FLD.RDB$FIELD_TYPE == INTEGER) ||
|
||
|
(FLD.RDB$FIELD_TYPE == blr_int64))
|
||
|
{
|
||
|
/* We are ODS >= 10 and could be any Dialect */
|
||
|
|
||
|
FOR FLD1 IN RDB$FIELDS WITH
|
||
|
FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
|
||
|
|
||
|
if (!FLD1.RDB$FIELD_PRECISION.NULL)
|
||
|
{
|
||
|
/* We are Dialect >=3 since FIELD_PRECISION is non-NULL */
|
||
|
if (FLD1.RDB$FIELD_SUB_TYPE > 0 &&
|
||
|
FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s(%d, %d)",
|
||
|
Integral_subtypes [FLD1.RDB$FIELD_SUB_TYPE],
|
||
|
FLD1.RDB$FIELD_PRECISION,
|
||
|
-FLD1.RDB$FIELD_SCALE);
|
||
|
precision_known = TRUE;
|
||
|
}
|
||
|
}
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (isc_status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
}
|
||
|
if (precision_known == FALSE)
|
||
|
{
|
||
|
/* Take a stab at numerics and decimals */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(4, %d)",
|
||
|
-FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == INTEGER) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(9, %d)",
|
||
|
-FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(15, %d)",
|
||
|
-FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s",
|
||
|
Column_types [i].type_name);
|
||
|
}
|
||
|
}
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Changed this to return RDB$CHARACTER_LENGTH if available
|
||
|
Fix for Bug #122563
|
||
|
FSG 18.Nov.2000
|
||
|
*/
|
||
|
if ((FLD.RDB$FIELD_TYPE == FCHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR))
|
||
|
if (FLD.RDB$CHARACTER_LENGTH.NULL)
|
||
|
{
|
||
|
|
||
|
sprintf (Print_buffer, "(%d)", FLD.RDB$FIELD_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "(%d)", FLD.RDB$CHARACTER_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Show international character sets and collations */
|
||
|
if (!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
{
|
||
|
char_sets [0] = 0;
|
||
|
if (FLD.RDB$COLLATION_ID.NULL)
|
||
|
FLD.RDB$COLLATION_ID = 0;
|
||
|
|
||
|
if (FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
FLD.RDB$CHARACTER_SET_ID = 0;
|
||
|
|
||
|
ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID,
|
||
|
FLD.RDB$COLLATION_ID, FALSE, char_sets);
|
||
|
if (char_sets [0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
if (!V33)
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
}
|
||
|
END_ERROR;
|
||
|
|
||
|
/* If there was at least one param, close parens */
|
||
|
|
||
|
if (!first_time)
|
||
|
{
|
||
|
sprintf(Print_buffer, ")%s", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
} /* end for ptype */
|
||
|
sprintf(Print_buffer, "AS %s", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static void list_all_grants(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ a l l _ g r a n t s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Print the permissions on all user tables.
|
||
|
*
|
||
|
* Get separate permissions on table/views and then procedures
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first = TRUE;
|
||
|
TEXT prev_owner[44];
|
||
|
|
||
|
/******************************************************************
|
||
|
**
|
||
|
** process GRANT roles
|
||
|
**
|
||
|
*******************************************************************/
|
||
|
|
||
|
if (major_ods >= ODS_VERSION9)
|
||
|
{
|
||
|
prev_owner[0] = '\0';
|
||
|
|
||
|
FOR XX IN RDB$ROLES
|
||
|
SORTED BY XX.RDB$ROLE_NAME
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* Grant role for this database */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
first = FALSE;
|
||
|
|
||
|
/* Null terminate name string */
|
||
|
ISQL_blankterm (XX.RDB$ROLE_NAME);
|
||
|
ISQL_blankterm (XX.RDB$OWNER_NAME);
|
||
|
|
||
|
if (strcmp (prev_owner, XX.RDB$OWNER_NAME) != 0)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* Role: %s, Owner: %s */%s",
|
||
|
NEWLINE,
|
||
|
XX.RDB$ROLE_NAME,
|
||
|
XX.RDB$OWNER_NAME,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
strcpy (prev_owner, XX.RDB$OWNER_NAME);
|
||
|
}
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
|
||
|
ISQL_copy_SQL_id (XX.RDB$ROLE_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CREATE ROLE %s;%s",
|
||
|
SQL_identifier, NEWLINE);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CREATE ROLE %s;%s",
|
||
|
XX.RDB$ROLE_NAME, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
|
||
|
/* This version of cursor gets only sql tables identified by security class
|
||
|
and misses views, getting only null view_source */
|
||
|
|
||
|
first = TRUE;
|
||
|
|
||
|
FOR REL IN RDB$RELATIONS WITH
|
||
|
(REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND
|
||
|
REL.RDB$SECURITY_CLASS STARTING "SQL$"
|
||
|
SORTED BY REL.RDB$RELATION_NAME
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* Grant permissions for this database */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first = FALSE;
|
||
|
|
||
|
/* Null terminate name string */
|
||
|
|
||
|
ISQL_blankterm (REL.RDB$RELATION_NAME);
|
||
|
|
||
|
SHOW_grants (REL.RDB$RELATION_NAME, Term);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf(Print_buffer, "%s/* Grant permissions for this database */%s",
|
||
|
NEWLINE, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
first = FALSE;
|
||
|
}
|
||
|
|
||
|
SHOW_grant_roles(Term);
|
||
|
|
||
|
/* Again for stored procedures */
|
||
|
FOR PRC IN RDB$PROCEDURES
|
||
|
SORTED BY PRC.RDB$PROCEDURE_NAME
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* Grant permissions for this database */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first = FALSE;
|
||
|
|
||
|
/* Null terminate name string */
|
||
|
|
||
|
ISQL_blankterm (PRC.RDB$PROCEDURE_NAME);
|
||
|
|
||
|
SHOW_grants (PRC.RDB$PROCEDURE_NAME, Term);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_all_procs()
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ a l l _ p r o c s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Shows text of a stored procedure given a name.
|
||
|
* or lists procedures if no argument.
|
||
|
* Since procedures may reference each other, we will create all
|
||
|
* dummy procedures of the correct name, then alter these to their
|
||
|
* correct form.
|
||
|
* Add the parameter names when these procedures are created.
|
||
|
*
|
||
|
* procname -- Name of procedure to investigate
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first_time, i, header = TRUE;
|
||
|
TEXT msg[MSG_LENGTH];
|
||
|
SCHAR char_sets[86];
|
||
|
static CONST SCHAR *create_procedure_str1 = "CREATE PROCEDURE %s ";
|
||
|
static CONST SCHAR *create_procedure_str2 = "BEGIN EXIT; END %s%s";
|
||
|
|
||
|
|
||
|
/* First the dummy procedures */
|
||
|
/* create the procedures with their parameters */
|
||
|
|
||
|
FOR PRC IN RDB$PROCEDURES
|
||
|
SORTED BY PRC.RDB$PROCEDURE_NAME
|
||
|
if (header)
|
||
|
{
|
||
|
sprintf (Print_buffer, "COMMIT WORK;%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer, "SET AUTODDL OFF;%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer, "SET TERM %s %s%s", Procterm, Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer, "%s/* Stored procedures */%s", NEWLINE, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
header = FALSE;
|
||
|
}
|
||
|
ISQL_blankterm (PRC.RDB$PROCEDURE_NAME);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (PRC.RDB$PROCEDURE_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, create_procedure_str1,
|
||
|
SQL_identifier);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
get_procedure_args (SQL_identifier);
|
||
|
sprintf (Print_buffer, create_procedure_str2, Procterm, NEWLINE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, create_procedure_str1,
|
||
|
PRC.RDB$PROCEDURE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
get_procedure_args (PRC.RDB$PROCEDURE_NAME);
|
||
|
sprintf (Print_buffer, create_procedure_str2, Procterm, NEWLINE);
|
||
|
}
|
||
|
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
if (!V33)
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
}
|
||
|
END_ERROR;
|
||
|
|
||
|
/* This query gets the procedure name and the source. We then nest a query
|
||
|
to retrieve the parameters. Alter is used, because the procedures are already there*/
|
||
|
FOR PRC IN RDB$PROCEDURES
|
||
|
SORTED BY PRC.RDB$PROCEDURE_NAME
|
||
|
|
||
|
ISQL_blankterm (PRC.RDB$PROCEDURE_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (PRC.RDB$PROCEDURE_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "%sALTER PROCEDURE %s ", NEWLINE,
|
||
|
SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "%sALTER PROCEDURE %s ", NEWLINE,
|
||
|
PRC.RDB$PROCEDURE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
get_procedure_args (PRC.RDB$PROCEDURE_NAME);
|
||
|
|
||
|
/* Print the procedure body */
|
||
|
|
||
|
if (!PRC.RDB$PROCEDURE_SOURCE.NULL)
|
||
|
SHOW_print_metadata_text_blob (Out, &PRC.RDB$PROCEDURE_SOURCE);
|
||
|
|
||
|
sprintf (Print_buffer, " %s%s", Procterm, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_msg_get(GEN_ERR, msg, (TEXT *) isc_sqlcode(gds__status), NULL,
|
||
|
NULL, NULL, NULL);
|
||
|
STDERROUT(msg, 1); /* Statement failed, SQLCODE = %d\n\n */
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
/* Only reset the terminators is there were procs to print */
|
||
|
if (!header)
|
||
|
{
|
||
|
sprintf(Print_buffer, "SET TERM %s %s%s", Term, Procterm, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
sprintf(Print_buffer, "COMMIT WORK %s%s", Term, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
sprintf(Print_buffer, "SET AUTODDL ON;%s", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_all_tables( SSHORT flag, SSHORT default_char_set_id)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ a l l _ t a b l e s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Extract the names of all user tables from
|
||
|
* rdb$relations. Filter SQL tables by
|
||
|
* security class after we fetch them
|
||
|
* Parameters: flag -- 0, get all tables
|
||
|
*
|
||
|
**************************************/
|
||
|
|
||
|
/* This version of cursor gets only sql tables identified by security class
|
||
|
and misses views, getting only null view_source */
|
||
|
|
||
|
FOR REL IN RDB$RELATIONS WITH
|
||
|
(REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND
|
||
|
REL.RDB$VIEW_BLR MISSING
|
||
|
SORTED BY REL.RDB$RELATION_NAME
|
||
|
|
||
|
/* If this is not an SQL table and we aren't doing ALL objects */
|
||
|
if ((REL.RDB$FLAGS != REL_sql) && (flag != ALL_objects))
|
||
|
continue;
|
||
|
/* Null terminate name string */
|
||
|
|
||
|
ISQL_blankterm (REL.RDB$RELATION_NAME);
|
||
|
|
||
|
if (flag || !strncmp (REL.RDB$SECURITY_CLASS, "SQL$", 4))
|
||
|
EXTRACT_list_table (REL.RDB$RELATION_NAME, NULL, 0,default_char_set_id);
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
ROLLBACK;
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_all_triggers()
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ a l l _ t r i g g e r s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Lists triggers in general on non-system
|
||
|
* tables with sql source only.
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT header = TRUE;
|
||
|
|
||
|
|
||
|
/* Query gets the trigger info for non-system triggers with
|
||
|
source that are not part of an SQL constraint */
|
||
|
|
||
|
FOR TRG IN RDB$TRIGGERS CROSS REL IN RDB$RELATIONS OVER RDB$RELATION_NAME
|
||
|
WITH (REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND
|
||
|
NOT (ANY CHK IN RDB$CHECK_CONSTRAINTS WITH
|
||
|
TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME)
|
||
|
SORTED BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE,
|
||
|
TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME
|
||
|
|
||
|
if (header)
|
||
|
{
|
||
|
sprintf (Print_buffer, "SET TERM %s %s%s", Procterm, Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer,
|
||
|
"%s/* Triggers only will work for SQL triggers */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
header = FALSE;
|
||
|
}
|
||
|
ISQL_blankterm (TRG.RDB$TRIGGER_NAME);
|
||
|
ISQL_blankterm (TRG.RDB$RELATION_NAME);
|
||
|
|
||
|
if (TRG.RDB$TRIGGER_INACTIVE.NULL)
|
||
|
TRG.RDB$TRIGGER_INACTIVE = 0;
|
||
|
|
||
|
/* If trigger is not SQL put it in comments */
|
||
|
if (TRG.RDB$FLAGS != TRG_sql)
|
||
|
ISQL_printf (Out, "/* ");
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (TRG.RDB$TRIGGER_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
ISQL_copy_SQL_id (TRG.RDB$RELATION_NAME, &SQL_identifier2, DBL_QUOTE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strcpy (SQL_identifier, TRG.RDB$TRIGGER_NAME);
|
||
|
strcpy (SQL_identifier2, TRG.RDB$RELATION_NAME);
|
||
|
}
|
||
|
|
||
|
sprintf (Print_buffer, "CREATE TRIGGER %s FOR %s %s%s %s POSITION %d %s",
|
||
|
SQL_identifier, SQL_identifier2, NEWLINE,
|
||
|
(TRG.RDB$TRIGGER_INACTIVE ? "INACTIVE" : "ACTIVE"),
|
||
|
Trigger_types [TRG.RDB$TRIGGER_TYPE], TRG.RDB$TRIGGER_SEQUENCE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
if (!TRG.RDB$TRIGGER_SOURCE.NULL)
|
||
|
SHOW_print_metadata_text_blob (Out, &TRG.RDB$TRIGGER_SOURCE);
|
||
|
|
||
|
sprintf (Print_buffer, " %s%s", Procterm, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer, " %s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
if (TRG.RDB$FLAGS != TRG_sql)
|
||
|
{
|
||
|
sprintf (Print_buffer, "*/%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
if (!header)
|
||
|
{
|
||
|
sprintf(Print_buffer, "COMMIT WORK %s%s", Procterm, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
sprintf(Print_buffer, "SET TERM %s %s%s", Term, Procterm, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_check(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ c h e c k
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List check constraints for all objects to allow forward references
|
||
|
*
|
||
|
**************************************/
|
||
|
|
||
|
/* Query gets the check clauses for triggers stored for check constraints */
|
||
|
|
||
|
FOR TRG IN RDB$TRIGGERS CROSS
|
||
|
CHK IN RDB$CHECK_CONSTRAINTS WITH
|
||
|
TRG.RDB$TRIGGER_TYPE EQ 1 AND
|
||
|
TRG.RDB$TRIGGER_NAME EQ CHK.RDB$TRIGGER_NAME AND
|
||
|
(ANY RELC IN RDB$RELATION_CONSTRAINTS WITH
|
||
|
CHK.RDB$CONSTRAINT_NAME EQ RELC.RDB$CONSTRAINT_NAME)
|
||
|
REDUCED TO CHK.RDB$CONSTRAINT_NAME
|
||
|
SORTED BY CHK.RDB$CONSTRAINT_NAME
|
||
|
|
||
|
|
||
|
ISQL_blankterm(TRG.RDB$RELATION_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, " %s ", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (TRG.RDB$RELATION_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "ALTER TABLE %s ADD %s%s",
|
||
|
SQL_identifier, NEWLINE, TAB);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "ALTER TABLE %s ADD %s%s",
|
||
|
TRG.RDB$RELATION_NAME, NEWLINE, TAB);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* If the name of the constraint is not INTEG..., print it */
|
||
|
if (strncmp(CHK.RDB$CONSTRAINT_NAME, "INTEG", 5))
|
||
|
{
|
||
|
ISQL_blankterm(CHK.RDB$CONSTRAINT_NAME);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (CHK.RDB$CONSTRAINT_NAME, &SQL_identifier,
|
||
|
DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CONSTRAINT %s ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CONSTRAINT %s ", CHK.RDB$CONSTRAINT_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
if (!TRG.RDB$TRIGGER_SOURCE.NULL)
|
||
|
SHOW_print_metadata_text_blob (Out, &TRG.RDB$TRIGGER_SOURCE);
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void print_set( SSHORT * set_used)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* p r i n t _ s e t
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* print (using ISQL_printf) the word "SET"
|
||
|
* if the first line of the ALTER DATABASE
|
||
|
* settings options. Also, add trailing
|
||
|
* comma for end of prior line if needed.
|
||
|
*
|
||
|
* uses Print_buffer, a global
|
||
|
*
|
||
|
**************************************/
|
||
|
if (!*set_used)
|
||
|
{
|
||
|
sprintf(Print_buffer, " SET ");
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
*set_used = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf(Print_buffer, ", %s ", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
}
|
||
|
static void list_create_db(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ c r e a t e _ d b
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Print the create database command if requested. At least put
|
||
|
* the page size in a comment with the extracted db name
|
||
|
*
|
||
|
**************************************/
|
||
|
SCHAR info_buf[20];
|
||
|
static CONST SCHAR page_items[] = {
|
||
|
isc_info_page_size,
|
||
|
isc_info_end
|
||
|
};
|
||
|
static CONST SCHAR wal_items[] = {
|
||
|
isc_info_num_wal_buffers,
|
||
|
isc_info_wal_buffer_size,
|
||
|
isc_info_wal_grpc_wait_usecs,
|
||
|
isc_info_wal_ckpt_length,
|
||
|
isc_info_end
|
||
|
};
|
||
|
|
||
|
SSHORT nodb = FALSE, first = TRUE, first_file = TRUE, has_wal =
|
||
|
FALSE, set_used = FALSE;
|
||
|
USHORT translate = FALSE;
|
||
|
SCHAR *d, *buffer, item;
|
||
|
int length;
|
||
|
SLONG value_out;
|
||
|
|
||
|
buffer = NULL;
|
||
|
/* Comment out the create database if no db param was specified */
|
||
|
if (!*Target_db)
|
||
|
{
|
||
|
ISQL_printf(Out, "/* ");
|
||
|
strcpy(Target_db, Db_name);
|
||
|
nodb = TRUE;
|
||
|
}
|
||
|
sprintf(Print_buffer, "CREATE DATABASE '%s'", Target_db);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
/* Get the page size from db_info call */
|
||
|
SHOW_dbb_parameters(DB, info_buf, page_items, sizeof(page_items),
|
||
|
translate);
|
||
|
sprintf(Print_buffer, " %s", info_buf);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
|
||
|
FOR DBP IN RDB$DATABASE
|
||
|
WITH DBP.RDB$CHARACTER_SET_NAME NOT MISSING
|
||
|
AND DBP.RDB$CHARACTER_SET_NAME != " ";
|
||
|
sprintf (Print_buffer, " DEFAULT CHARACTER SET %s",
|
||
|
ISQL_blankterm (DBP.RDB$CHARACTER_SET_NAME));
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
if (!V33)
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
}
|
||
|
END_ERROR;
|
||
|
|
||
|
if (nodb)
|
||
|
{
|
||
|
sprintf(Print_buffer, " */%s", NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf(Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
/* List secondary files and shadows as alter db and create shadow in comment */
|
||
|
|
||
|
|
||
|
FOR FIL IN RDB$FILES
|
||
|
SORTED BY FIL.RDB$SHADOW_NUMBER, FIL.RDB$FILE_SEQUENCE
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* Add secondary files in comments %s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
first = FALSE;
|
||
|
/* reset nulls to zero */
|
||
|
|
||
|
if (FIL.RDB$FILE_FLAGS.NULL)
|
||
|
FIL.RDB$FILE_FLAGS = 0;
|
||
|
if (FIL.RDB$FILE_LENGTH.NULL)
|
||
|
FIL.RDB$FILE_LENGTH = 0;
|
||
|
if (FIL.RDB$FILE_SEQUENCE.NULL)
|
||
|
FIL.RDB$FILE_SEQUENCE = 0;
|
||
|
if (FIL.RDB$FILE_START.NULL)
|
||
|
FIL.RDB$FILE_START = 0;
|
||
|
ISQL_blankterm (FIL.RDB$FILE_NAME);
|
||
|
|
||
|
/* Pure secondary files */
|
||
|
if (FIL.RDB$FILE_FLAGS == 0)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%sALTER DATABASE ADD FILE '%s'",
|
||
|
NEWLINE,
|
||
|
FIL.RDB$FILE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
if (FIL.RDB$FILE_START)
|
||
|
{
|
||
|
sprintf (Print_buffer, " STARTING %ld", FIL.RDB$FILE_START);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
if (FIL.RDB$FILE_LENGTH)
|
||
|
{
|
||
|
sprintf (Print_buffer, " LENGTH %ld", FIL.RDB$FILE_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
sprintf (Print_buffer, "%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
if (FIL.RDB$FILE_FLAGS & FILE_cache)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%sALTER DATABASE ADD CACHE '%s' LENGTH %ld%s",
|
||
|
NEWLINE,
|
||
|
FIL.RDB$FILE_NAME,
|
||
|
FIL.RDB$FILE_LENGTH,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
if (FIL.RDB$FILE_FLAGS & FILE_shadow)
|
||
|
{
|
||
|
if (FIL.RDB$FILE_SEQUENCE)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%sFILE '%s' ", TAB, FIL.RDB$FILE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%sCREATE SHADOW %d '%s' ",
|
||
|
NEWLINE,
|
||
|
FIL.RDB$SHADOW_NUMBER,
|
||
|
FIL.RDB$FILE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
if (FIL.RDB$FILE_FLAGS & FILE_inactive)
|
||
|
ISQL_printf (Out, "INACTIVE ");
|
||
|
if (FIL.RDB$FILE_FLAGS & FILE_manual)
|
||
|
ISQL_printf (Out, "MANUAL ");
|
||
|
else
|
||
|
ISQL_printf (Out, "AUTO ");
|
||
|
if (FIL.RDB$FILE_FLAGS & FILE_conditional)
|
||
|
ISQL_printf (Out, "CONDITIONAL ");
|
||
|
}
|
||
|
if (FIL.RDB$FILE_LENGTH)
|
||
|
{
|
||
|
sprintf (Print_buffer, "LENGTH %ld ", FIL.RDB$FILE_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
if (FIL.RDB$FILE_START)
|
||
|
{
|
||
|
sprintf (Print_buffer, "STARTING %ld ", FIL.RDB$FILE_START);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
ISQL_printf (Out, NEWLINE);
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
FOR WAL IN RDB$LOG_FILES
|
||
|
SORTED BY WAL.RDB$FILE_FLAGS, WAL.RDB$FILE_SEQUENCE
|
||
|
|
||
|
has_wal = TRUE;
|
||
|
if (first)
|
||
|
{
|
||
|
if (nodb)
|
||
|
{
|
||
|
sprintf (Print_buffer, "/*%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
sprintf (Print_buffer, "%sALTER DATABASE ADD ", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first = FALSE;
|
||
|
|
||
|
if (first_file)
|
||
|
ISQL_printf (Out, "LOGFILE ");
|
||
|
|
||
|
if (WAL.RDB$FILE_FLAGS & LOG_default)
|
||
|
;
|
||
|
|
||
|
/* Overflow files also have the serial bit set */
|
||
|
else if (WAL.RDB$FILE_FLAGS & LOG_overflow)
|
||
|
{
|
||
|
sprintf (Print_buffer, ")%s OVERFLOW '%s'",
|
||
|
NEWLINE,
|
||
|
WAL.RDB$FILE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
else if (WAL.RDB$FILE_FLAGS & LOG_serial)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s BASE_NAME '%s'",
|
||
|
NEWLINE,
|
||
|
WAL.RDB$FILE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
/* Since we are fetching order by FILE_FLAGS, the LOG_0verflow will
|
||
|
** be last. It will only appear if there were named round robin,
|
||
|
** so we must close the parens first
|
||
|
*/
|
||
|
|
||
|
/* We have round robin and overflow file specifications */
|
||
|
else
|
||
|
{
|
||
|
if (first_file)
|
||
|
ISQL_printf (Out, "(");
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, ",%s ", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first_file = FALSE;
|
||
|
|
||
|
sprintf (Print_buffer, "'%s'", WAL.RDB$FILE_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
/* Any file can have a length */
|
||
|
if (!WAL.RDB$FILE_LENGTH.NULL && WAL.RDB$FILE_LENGTH)
|
||
|
{
|
||
|
sprintf (Print_buffer, " SIZE %ld ", WAL.RDB$FILE_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
if (!V33)
|
||
|
{
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
}
|
||
|
END_ERROR;
|
||
|
|
||
|
ISQL_printf(Out, NEWLINE);
|
||
|
/*************************************************************
|
||
|
** gds__info_num_wal_buffers for NUM_LOG_BUFFERS
|
||
|
** gds__info_wal_buffer_size for LOG_BUFFER_SIZE
|
||
|
** gds__info_wal_grpc_wait_usecs for GROUP_COMMIT_WAIT_TIME
|
||
|
** gds__info_wal_ckpt_length for CHECK_POINT_LENGTH
|
||
|
**
|
||
|
**************************************************************/
|
||
|
|
||
|
if (has_wal)
|
||
|
{
|
||
|
buffer = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH128);
|
||
|
if (!buffer)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!isc_database_info
|
||
|
(gds__status, &DB, sizeof(wal_items), wal_items, BUFFER_LENGTH128,
|
||
|
buffer))
|
||
|
{
|
||
|
for (d = buffer; *d != isc_info_end;)
|
||
|
{
|
||
|
item = *d++;
|
||
|
length = isc_vax_integer(d, 2);
|
||
|
d += 2;
|
||
|
value_out = isc_vax_integer(d, length);
|
||
|
switch (item)
|
||
|
{
|
||
|
case isc_info_end:
|
||
|
break;
|
||
|
|
||
|
case isc_info_num_wal_buffers:
|
||
|
print_set(&set_used);
|
||
|
sprintf(Print_buffer, "NUM_LOG_BUFFERS = %ld", value_out);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
break;
|
||
|
|
||
|
case isc_info_wal_buffer_size:
|
||
|
print_set(&set_used);
|
||
|
sprintf(Print_buffer, "LOG_BUFFER_SIZE = %ld", value_out);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
break;
|
||
|
|
||
|
case isc_info_wal_grpc_wait_usecs:
|
||
|
print_set(&set_used);
|
||
|
sprintf(Print_buffer, "GROUP_COMMIT_WAIT_TIME = %ld",
|
||
|
value_out);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
break;
|
||
|
|
||
|
case isc_info_wal_ckpt_length:
|
||
|
print_set(&set_used);
|
||
|
sprintf(Print_buffer, "CHECK_POINT_LENGTH = %ld",
|
||
|
value_out);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
d += length;
|
||
|
}
|
||
|
}
|
||
|
if (buffer)
|
||
|
ISQL_FREE(buffer);
|
||
|
}
|
||
|
|
||
|
if (!first)
|
||
|
{
|
||
|
if (nodb)
|
||
|
{
|
||
|
sprintf(Print_buffer, "%s */%s", NEWLINE, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf(Print_buffer, "%s%s%s", Term, NEWLINE, NEWLINE);
|
||
|
ISQL_printf(Out, Print_buffer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_domain_table( SCHAR * table_name, SSHORT default_char_set_id)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ d o m a i n _ t a b l e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List domains as identified by fields with any constraints on them
|
||
|
* for the named table
|
||
|
*
|
||
|
* Parameters: table_name == only extract domains for this table
|
||
|
* default_char_set_id -- character set def to supress
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first = TRUE;
|
||
|
SSHORT i;
|
||
|
SCHAR char_sets[86];
|
||
|
SSHORT subtype;
|
||
|
|
||
|
FOR FLD IN RDB$FIELDS CROSS
|
||
|
RFR IN RDB$RELATION_FIELDS WITH
|
||
|
RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND
|
||
|
RFR.RDB$RELATION_NAME EQ table_name
|
||
|
SORTED BY FLD.RDB$FIELD_NAME
|
||
|
|
||
|
/* Skip over artifical domains */
|
||
|
if (strncmp (FLD.RDB$FIELD_NAME, "RDB$", 4) == 0 &&
|
||
|
isdigit (FLD.RDB$FIELD_NAME[4]) &&
|
||
|
FLD.RDB$SYSTEM_FLAG != 1)
|
||
|
continue;
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "/* Domain definitions */%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
first = FALSE;
|
||
|
}
|
||
|
ISQL_blankterm(FLD.RDB$FIELD_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, "CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
for (i = 0; Column_types [i].type; i++)
|
||
|
if (FLD.RDB$FIELD_TYPE == Column_types [i].type)
|
||
|
{
|
||
|
BOOLEAN precision_known = FALSE;
|
||
|
|
||
|
if (major_ods >= ODS_VERSION10)
|
||
|
{
|
||
|
/* Handle Integral subtypes NUMERIC and DECIMAL */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
|
||
|
(FLD.RDB$FIELD_TYPE == INTEGER) ||
|
||
|
(FLD.RDB$FIELD_TYPE == blr_int64))
|
||
|
{
|
||
|
/* We are ODS >= 10 and could be any Dialect */
|
||
|
|
||
|
FOR FLD1 IN RDB$FIELDS WITH
|
||
|
FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
|
||
|
if (!FLD1.RDB$FIELD_PRECISION.NULL)
|
||
|
{
|
||
|
/* We are Dialect >=3 since FIELD_PRECISION is non-NULL */
|
||
|
if (FLD1.RDB$FIELD_SUB_TYPE > 0 &&
|
||
|
FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s(%d, %d)",
|
||
|
Integral_subtypes [FLD1.RDB$FIELD_SUB_TYPE],
|
||
|
FLD1.RDB$FIELD_PRECISION,
|
||
|
-FLD1.RDB$FIELD_SCALE);
|
||
|
precision_known = TRUE;
|
||
|
}
|
||
|
}
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (isc_status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (precision_known == FALSE)
|
||
|
{
|
||
|
/* Take a stab at numerics and decimals */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s", Column_types [i].type_name);
|
||
|
}
|
||
|
}
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (FLD.RDB$FIELD_TYPE == BLOB)
|
||
|
{
|
||
|
subtype = FLD.RDB$FIELD_SUB_TYPE;
|
||
|
ISQL_printf (Out, " SUB_TYPE ");
|
||
|
if ((subtype > 0) && (subtype <= MAXSUBTYPES))
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s", Sub_types [subtype]);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%d", subtype);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
sprintf (Print_buffer, " SEGMENT SIZE %u", (USHORT) FLD.RDB$SEGMENT_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
else if ((FLD.RDB$FIELD_TYPE == FCHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR))
|
||
|
{
|
||
|
/* Length for chars */
|
||
|
sprintf (Print_buffer, "(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME));
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
};
|
||
|
|
||
|
/* Bug 8261: do not show the collation information just yet! If you
|
||
|
do, then the domain syntax when printed is not correct */
|
||
|
|
||
|
/* since the character set is part of the field type, display that
|
||
|
information now. */
|
||
|
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
{
|
||
|
|
||
|
char_sets[0] = 0;
|
||
|
if ((FLD.RDB$CHARACTER_SET_ID != default_char_set_id) ||
|
||
|
(!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0))
|
||
|
ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, FALSE, FALSE, char_sets);
|
||
|
if (char_sets[0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
|
||
|
if (!FLD.RDB$DIMENSIONS.NULL)
|
||
|
ISQL_array_dimensions (FLD.RDB$FIELD_NAME);
|
||
|
|
||
|
if (!FLD.RDB$DEFAULT_SOURCE.NULL)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s%s ", NEWLINE, TAB);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
SHOW_print_metadata_text_blob (Out, &FLD.RDB$DEFAULT_SOURCE);
|
||
|
}
|
||
|
if (!FLD.RDB$VALIDATION_SOURCE.NULL)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s%s ", NEWLINE, TAB);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
ISQL_print_validation (Out, &FLD.RDB$VALIDATION_SOURCE, 0, gds__trans);
|
||
|
}
|
||
|
if (FLD.RDB$NULL_FLAG == 1)
|
||
|
ISQL_printf (Out, " NOT NULL");
|
||
|
|
||
|
/* Bug 8261: Now show the collation order information */
|
||
|
/* Show the collation order if one has been specified. If the collation
|
||
|
order is the default for the character set being used, then no collation
|
||
|
order will be shown ( because it isn't needed ).
|
||
|
|
||
|
If the collation id is 0, then the default for the character set is
|
||
|
being used so there is no need to retrieve the collation information.*/
|
||
|
|
||
|
if (!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0)
|
||
|
{
|
||
|
char_sets[0] = 0;
|
||
|
ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, TRUE, char_sets);
|
||
|
if (char_sets[0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_domains( SSHORT default_char_set_id)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ d o m a i n s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List domains
|
||
|
*
|
||
|
* Parameters:
|
||
|
* default_char_set_id -- character set def to supress
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first = TRUE;
|
||
|
SSHORT i;
|
||
|
SCHAR char_sets[86];
|
||
|
SSHORT subtype;
|
||
|
|
||
|
FOR FLD IN RDB$FIELDS WITH
|
||
|
FLD.RDB$FIELD_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *"
|
||
|
AND FLD.RDB$SYSTEM_FLAG NE 1
|
||
|
SORTED BY FLD.RDB$FIELD_NAME
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "/* Domain definitions */%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
first = FALSE;
|
||
|
}
|
||
|
ISQL_blankterm(FLD.RDB$FIELD_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id(FLD.RDB$FIELD_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CREATE DOMAIN %s AS ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME);
|
||
|
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Get domain type */
|
||
|
for (i = 0; Column_types [i].type; i++)
|
||
|
if (FLD.RDB$FIELD_TYPE == Column_types [i].type)
|
||
|
{
|
||
|
BOOLEAN precision_known = FALSE;
|
||
|
|
||
|
if (major_ods >= ODS_VERSION10)
|
||
|
{
|
||
|
/* Handle Integral subtypes NUMERIC and DECIMAL */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) ||
|
||
|
(FLD.RDB$FIELD_TYPE == INTEGER) ||
|
||
|
(FLD.RDB$FIELD_TYPE == blr_int64))
|
||
|
{
|
||
|
/* We are ODS >= 10 and could be any Dialect */
|
||
|
FOR FLD1 IN RDB$FIELDS WITH
|
||
|
FLD1.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
|
||
|
|
||
|
if (!FLD1.RDB$FIELD_PRECISION.NULL)
|
||
|
{
|
||
|
/* We are Dialect >=3 since FIELD_PRECISION is non-NULL */
|
||
|
if (FLD1.RDB$FIELD_SUB_TYPE > 0 &&
|
||
|
FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s(%d, %d)",
|
||
|
Integral_subtypes [FLD1.RDB$FIELD_SUB_TYPE],
|
||
|
FLD1.RDB$FIELD_PRECISION,
|
||
|
-FLD1.RDB$FIELD_SCALE);
|
||
|
precision_known = TRUE;
|
||
|
}
|
||
|
}
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (isc_status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (precision_known == FALSE)
|
||
|
{
|
||
|
/* Take a stab at numerics and decimals */
|
||
|
if ((FLD.RDB$FIELD_TYPE == SMALLINT) && (FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(4, %d)", -FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == INTEGER) && (FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(9, %d)", -FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FLD.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
|
||
|
(FLD.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (Print_buffer, "NUMERIC(15, %d)", -FLD.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s", Column_types [i].type_name);
|
||
|
}
|
||
|
}
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (FLD.RDB$FIELD_TYPE == BLOB)
|
||
|
{
|
||
|
subtype = FLD.RDB$FIELD_SUB_TYPE;
|
||
|
ISQL_printf (Out, " SUB_TYPE ");
|
||
|
|
||
|
if ((subtype > 0) && (subtype <= MAXSUBTYPES))
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s", Sub_types [subtype]);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf (Print_buffer, "%d", subtype);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
sprintf (Print_buffer, " SEGMENT SIZE %u", (USHORT) FLD.RDB$SEGMENT_LENGTH);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
else if ((FLD.RDB$FIELD_TYPE == FCHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR))
|
||
|
{
|
||
|
/* Length for chars */
|
||
|
sprintf (Print_buffer, "(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME));
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
};
|
||
|
|
||
|
/* Bug 8261: do not show the collation information just yet! If you
|
||
|
do, then the domain syntax when printed is not correct */
|
||
|
|
||
|
/* since the character set is part of the field type, display that
|
||
|
information now. */
|
||
|
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
|
||
|
{
|
||
|
char_sets[0] = 0;
|
||
|
if ((FLD.RDB$CHARACTER_SET_ID != default_char_set_id) ||
|
||
|
(!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0))
|
||
|
ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, FALSE, FALSE, char_sets);
|
||
|
if (char_sets[0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
|
||
|
if (!FLD.RDB$DIMENSIONS.NULL)
|
||
|
ISQL_array_dimensions (FLD.RDB$FIELD_NAME);
|
||
|
|
||
|
if (!FLD.RDB$DEFAULT_SOURCE.NULL)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s%s ", NEWLINE, TAB);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
SHOW_print_metadata_text_blob (Out, &FLD.RDB$DEFAULT_SOURCE);
|
||
|
}
|
||
|
if (!FLD.RDB$VALIDATION_SOURCE.NULL)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s%s ", NEWLINE, TAB);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
ISQL_print_validation (Out, &FLD.RDB$VALIDATION_SOURCE, 0, gds__trans);
|
||
|
}
|
||
|
if (FLD.RDB$NULL_FLAG == 1)
|
||
|
ISQL_printf (Out, " NOT NULL");
|
||
|
|
||
|
/* Bug 8261: Now show the collation order information */
|
||
|
/* Show the collation order if one has been specified. If the collation
|
||
|
order is the default for the character set being used, then no collation
|
||
|
order will be shown ( because it isn't needed
|
||
|
|
||
|
If the collation id is 0, then the default for the character set is
|
||
|
being used so there is no need to retrieve the collation information.*/
|
||
|
|
||
|
if (!FLD.RDB$COLLATION_ID.NULL && FLD.RDB$COLLATION_ID != 0)
|
||
|
{
|
||
|
char_sets[0] = 0;
|
||
|
ISQL_get_character_sets (FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID, TRUE, char_sets);
|
||
|
if (char_sets[0])
|
||
|
ISQL_printf (Out, char_sets);
|
||
|
}
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_exception(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ e x c e p t i o n
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List all exceptions defined in the database
|
||
|
*
|
||
|
* Parameters: none
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first = TRUE;
|
||
|
|
||
|
FOR EXC IN RDB$EXCEPTIONS
|
||
|
SORTED BY EXC.RDB$EXCEPTION_NAME
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* Exceptions */%s", NEWLINE, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first = FALSE;
|
||
|
ISQL_blankterm (EXC.RDB$EXCEPTION_NAME);
|
||
|
|
||
|
ISQL_copy_SQL_id (EXC.RDB$MESSAGE, &SQL_identifier2, SINGLE_QUOTE);
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (EXC.RDB$EXCEPTION_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CREATE EXCEPTION %s %s%s%s",
|
||
|
SQL_identifier, SQL_identifier2, Term, NEWLINE);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CREATE EXCEPTION %s %s%s%s",
|
||
|
EXC.RDB$EXCEPTION_NAME, SQL_identifier2, Term, NEWLINE);
|
||
|
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_filters(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ f i l t e r s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List all blob filters
|
||
|
*
|
||
|
* Parameters: none
|
||
|
* Results in
|
||
|
* DECLARE FILTER <fname> INPUT_TYPE <blob_sub_type> OUTPUT_TYPE <blob_subtype>
|
||
|
* ENTRY_POINT <string> MODULE_NAME <string>
|
||
|
**************************************/
|
||
|
SSHORT first = TRUE;
|
||
|
|
||
|
FOR FIL IN RDB$FILTERS
|
||
|
SORTED BY FIL.RDB$FUNCTION_NAME
|
||
|
|
||
|
ISQL_blankterm (FIL.RDB$FUNCTION_NAME);
|
||
|
ISQL_blankterm (FIL.RDB$MODULE_NAME);
|
||
|
ISQL_blankterm (FIL.RDB$ENTRYPOINT);
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* BLOB Filter declarations */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first = FALSE;
|
||
|
|
||
|
sprintf (Print_buffer, "DECLARE FILTER %s INPUT_TYPE %d OUTPUT_TYPE %d%s%sENTRY_POINT '%s' MODULE_NAME '%s'%s%s%s",
|
||
|
FIL.RDB$FUNCTION_NAME, FIL.RDB$INPUT_SUB_TYPE, FIL.RDB$OUTPUT_SUB_TYPE,
|
||
|
NEWLINE, TAB, FIL.RDB$ENTRYPOINT, FIL.RDB$MODULE_NAME, Term, NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_foreign()
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ f o r e i g n
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List all foreign key constraints and alter the tables
|
||
|
*
|
||
|
**************************************/
|
||
|
SCHAR *collist;
|
||
|
|
||
|
collist = NULL;
|
||
|
collist = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH512 * 2);
|
||
|
if (!collist)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Static queries for obtaining foreign constraints, where RELC1 is the
|
||
|
foreign key constraints, RELC2 is the primary key lookup and REFC
|
||
|
is the join table */
|
||
|
|
||
|
FOR RELC1 IN RDB$RELATION_CONSTRAINTS CROSS
|
||
|
RELC2 IN RDB$RELATION_CONSTRAINTS CROSS
|
||
|
REFC IN RDB$REF_CONSTRAINTS WITH
|
||
|
RELC1.RDB$CONSTRAINT_TYPE EQ "FOREIGN KEY" AND
|
||
|
REFC.RDB$CONST_NAME_UQ EQ RELC2.RDB$CONSTRAINT_NAME AND
|
||
|
REFC.RDB$CONSTRAINT_NAME EQ RELC1.RDB$CONSTRAINT_NAME AND
|
||
|
(RELC2.RDB$CONSTRAINT_TYPE EQ "UNIQUE" OR
|
||
|
RELC2.RDB$CONSTRAINT_TYPE EQ "PRIMARY KEY")
|
||
|
SORTED BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME
|
||
|
|
||
|
ISQL_blankterm (RELC1.RDB$RELATION_NAME);
|
||
|
ISQL_blankterm (RELC2.RDB$RELATION_NAME);
|
||
|
|
||
|
ISQL_get_index_segments (collist, RELC1.RDB$INDEX_NAME, TRUE);
|
||
|
|
||
|
sprintf (Print_buffer, " %s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (RELC1.RDB$RELATION_NAME, &SQL_identifier,
|
||
|
DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "ALTER TABLE %s ADD ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "ALTER TABLE %s ADD ",
|
||
|
RELC1.RDB$RELATION_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* If the name of the constraint is not INTEG..., print it.
|
||
|
INTEG... are internally generated names. */
|
||
|
if (!RELC1.RDB$CONSTRAINT_NAME.NULL &&
|
||
|
strncmp(RELC1.RDB$CONSTRAINT_NAME, "INTEG", 5))
|
||
|
{
|
||
|
ISQL_truncate_term (RELC1.RDB$CONSTRAINT_NAME,
|
||
|
strlen(RELC1.RDB$CONSTRAINT_NAME));
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (RELC1.RDB$CONSTRAINT_NAME, &SQL_identifier,
|
||
|
DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CONSTRAINT %s ", SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CONSTRAINT %s ",
|
||
|
RELC1.RDB$CONSTRAINT_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (RELC2.RDB$RELATION_NAME, &SQL_identifier,
|
||
|
DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "FOREIGN KEY (%s) REFERENCES %s ",
|
||
|
collist, SQL_identifier);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "FOREIGN KEY (%s) REFERENCES %s ",
|
||
|
collist,
|
||
|
RELC2.RDB$RELATION_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Get the column list for the primary key */
|
||
|
|
||
|
ISQL_get_index_segments (collist, RELC2.RDB$INDEX_NAME, TRUE);
|
||
|
|
||
|
sprintf (Print_buffer, "(%s)", collist);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Add the referential actions, if any */
|
||
|
if (!REFC.RDB$UPDATE_RULE.NULL)
|
||
|
{
|
||
|
ISQL_truncate_term (REFC.RDB$UPDATE_RULE,
|
||
|
strlen(REFC.RDB$UPDATE_RULE));
|
||
|
ISQL_ri_action_print (REFC.RDB$UPDATE_RULE, " ON UPDATE", TRUE);
|
||
|
}
|
||
|
|
||
|
if (!REFC.RDB$DELETE_RULE.NULL)
|
||
|
{
|
||
|
ISQL_truncate_term (REFC.RDB$DELETE_RULE,
|
||
|
strlen(REFC.RDB$DELETE_RULE));
|
||
|
ISQL_ri_action_print (REFC.RDB$DELETE_RULE, " ON DELETE", TRUE);
|
||
|
}
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
ISQL_FREE(collist);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
ISQL_FREE(collist);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_functions(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ f u n c t i o n s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* List all external functions
|
||
|
*
|
||
|
* Parameters: none
|
||
|
* Results in
|
||
|
* DECLARE EXTERNAL FUNCTION function_name
|
||
|
* CHAR [256] , INTEGER, ....
|
||
|
* RETURNS INTEGER BY VALUE
|
||
|
* ENTRY_POINT entrypoint MODULE_NAME module;
|
||
|
**************************************/
|
||
|
SSHORT first = TRUE, firstarg = TRUE;
|
||
|
SSHORT i;
|
||
|
SCHAR *return_buffer;
|
||
|
SCHAR *type_buffer;
|
||
|
SCHAR *buffer;
|
||
|
|
||
|
buffer = NULL;
|
||
|
type_buffer = NULL;
|
||
|
return_buffer = NULL;
|
||
|
|
||
|
buffer = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH360);
|
||
|
if (!buffer)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
type_buffer = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH128);
|
||
|
if (!type_buffer)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
ISQL_FREE(buffer);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
return_buffer = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH128);
|
||
|
if (!return_buffer)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
ISQL_FREE(type_buffer);
|
||
|
ISQL_FREE(buffer);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
FOR FUN IN RDB$FUNCTIONS
|
||
|
SORTED BY FUN.RDB$FUNCTION_NAME
|
||
|
|
||
|
ISQL_blankterm (FUN.RDB$FUNCTION_NAME);
|
||
|
ISQL_blankterm (FUN.RDB$MODULE_NAME);
|
||
|
ISQL_blankterm (FUN.RDB$ENTRYPOINT);
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s/* External Function declarations */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
first = FALSE;
|
||
|
}
|
||
|
|
||
|
/* Start new function declaration */
|
||
|
sprintf (Print_buffer, "DECLARE EXTERNAL FUNCTION %s %s",
|
||
|
FUN.RDB$FUNCTION_NAME,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
firstarg = TRUE;
|
||
|
|
||
|
FOR FNA IN RDB$FUNCTION_ARGUMENTS WITH
|
||
|
FUN.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME
|
||
|
SORTED BY FNA.RDB$ARGUMENT_POSITION
|
||
|
|
||
|
/* Find parameter type */
|
||
|
i = 0;
|
||
|
while (FNA.RDB$FIELD_TYPE != Column_types [i].type)
|
||
|
i++;
|
||
|
|
||
|
/* Print length where appropriate */
|
||
|
if ((FNA.RDB$FIELD_TYPE == FCHAR) ||
|
||
|
(FNA.RDB$FIELD_TYPE == VARCHAR) ||
|
||
|
(FNA.RDB$FIELD_TYPE == CSTRING))
|
||
|
{
|
||
|
USHORT did_charset;
|
||
|
did_charset = 0;
|
||
|
FOR CHARSET IN RDB$CHARACTER_SETS
|
||
|
WITH CHARSET.RDB$CHARACTER_SET_ID = FNA.RDB$CHARACTER_SET_ID
|
||
|
|
||
|
did_charset = 1;
|
||
|
ISQL_blankterm (CHARSET.RDB$CHARACTER_SET_NAME);
|
||
|
sprintf (type_buffer, "%s(%d) CHARACTER SET %s",
|
||
|
Column_types [i].type_name,
|
||
|
(FNA.RDB$FIELD_LENGTH / MAX (1,CHARSET.RDB$BYTES_PER_CHARACTER)),
|
||
|
CHARSET.RDB$CHARACTER_SET_NAME);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
if (!did_charset)
|
||
|
sprintf (type_buffer, "%s(%d)", Column_types [i].type_name,
|
||
|
FNA.RDB$FIELD_LENGTH);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BOOLEAN precision_known = FALSE;
|
||
|
|
||
|
if ( (major_ods >= ODS_VERSION10) &&
|
||
|
((FNA.RDB$FIELD_TYPE == SMALLINT) ||
|
||
|
(FNA.RDB$FIELD_TYPE == INTEGER) ||
|
||
|
(FNA.RDB$FIELD_TYPE == blr_int64)))
|
||
|
{
|
||
|
FOR FNA1 IN RDB$FUNCTION_ARGUMENTS WITH
|
||
|
FNA1.RDB$FUNCTION_NAME EQ FNA.RDB$FUNCTION_NAME AND
|
||
|
FNA1.RDB$ARGUMENT_POSITION EQ FNA.RDB$ARGUMENT_POSITION
|
||
|
|
||
|
/* We are ODS >= 10 and could be any Dialect */
|
||
|
if (!FNA1.RDB$FIELD_PRECISION.NULL)
|
||
|
{
|
||
|
/* We are Dialect >=3 since FIELD_PRECISION is non-NULL */
|
||
|
if (FNA1.RDB$FIELD_SUB_TYPE > 0 &&
|
||
|
FNA1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
|
||
|
{
|
||
|
sprintf (type_buffer, "%s(%d, %d)",
|
||
|
Integral_subtypes [FNA1.RDB$FIELD_SUB_TYPE],
|
||
|
FNA1.RDB$FIELD_PRECISION,
|
||
|
-FNA1.RDB$FIELD_SCALE);
|
||
|
precision_known = TRUE;
|
||
|
}
|
||
|
} /* if field_precision is not null */
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (isc_status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
} /* if major_ods >= ods_version10 && */
|
||
|
|
||
|
if (!precision_known)
|
||
|
{
|
||
|
/* Take a stab at numerics and decimals */
|
||
|
if ((FNA.RDB$FIELD_TYPE == SMALLINT) &&
|
||
|
(FNA.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (type_buffer, "NUMERIC(4, %d)",
|
||
|
-FNA.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FNA.RDB$FIELD_TYPE == INTEGER) &&
|
||
|
(FNA.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (type_buffer, "NUMERIC(9, %d)",
|
||
|
-FNA.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else if ((FNA.RDB$FIELD_TYPE == DOUBLE_PRECISION) &&
|
||
|
(FNA.RDB$FIELD_SCALE < 0))
|
||
|
{
|
||
|
sprintf (type_buffer, "NUMERIC(15, %d)",
|
||
|
-FNA.RDB$FIELD_SCALE);
|
||
|
}
|
||
|
else
|
||
|
sprintf (type_buffer, "%s",
|
||
|
Column_types [i].type_name);
|
||
|
} /* if !precision_known */
|
||
|
} /* if FCHAR or VARCHAR or CSTRING ... else */
|
||
|
|
||
|
/* If a return argument, save it for the end, otherwise print */
|
||
|
|
||
|
/*
|
||
|
* Changed the following to not return a BLOB by value.
|
||
|
* To be sincere, this code doesn't cater for the RETURNS PARAMETER syntax but
|
||
|
* it would require more surgery than I'm willing to do, since I'm sick of isql
|
||
|
* so I started my own metadata extraction utility based on IBO that does this
|
||
|
* trick and others.
|
||
|
* Claudio Valderrama (by way of) MOD 23-Apr-2001
|
||
|
*/
|
||
|
|
||
|
if (FUN.RDB$RETURN_ARGUMENT == FNA.RDB$ARGUMENT_POSITION)
|
||
|
{
|
||
|
const char* pszA2 =
|
||
|
(((SSHORT)abs(FNA.RDB$MECHANISM) == FUN_reference ||
|
||
|
FNA.RDB$FIELD_TYPE == BLOB) ? "" : "BY VALUE");
|
||
|
|
||
|
const char* pszA3 =
|
||
|
(FNA.RDB$MECHANISM < 0 ? "FREE_IT" : "");
|
||
|
|
||
|
sprintf(return_buffer,
|
||
|
"RETURNS %s %s %s",
|
||
|
type_buffer,
|
||
|
pszA2,
|
||
|
pszA3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* First arg needs no comma */
|
||
|
sprintf (Print_buffer, "%s%s", (firstarg ? "" : ", "), type_buffer);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
firstarg = FALSE;
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (gds__status);
|
||
|
ISQL_FREE (type_buffer);
|
||
|
ISQL_FREE (return_buffer);
|
||
|
ISQL_FREE (buffer);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
/* Print the return type -- All functions return a type */
|
||
|
sprintf (Print_buffer, "%s%s%s",
|
||
|
NEWLINE,
|
||
|
return_buffer,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Print out entrypoint information */
|
||
|
sprintf (Print_buffer, "ENTRY_POINT '%s' MODULE_NAME '%s'%s%s%s",
|
||
|
FUN.RDB$ENTRYPOINT,
|
||
|
FUN.RDB$MODULE_NAME,
|
||
|
Term,
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
ISQL_FREE(type_buffer);
|
||
|
ISQL_FREE(return_buffer);
|
||
|
ISQL_FREE(buffer);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
ISQL_FREE(type_buffer);
|
||
|
ISQL_FREE(return_buffer);
|
||
|
ISQL_FREE(buffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
static void list_generators(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ g e n e r a t o r s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Re create all non-system generators
|
||
|
*
|
||
|
**************************************/
|
||
|
|
||
|
ISQL_printf(Out, NEWLINE);
|
||
|
|
||
|
FOR GEN IN RDB$GENERATORS WITH
|
||
|
GEN.RDB$GENERATOR_NAME NOT MATCHING "RDB$+" USING "+=[0-9][0-9]* *" AND
|
||
|
GEN.RDB$GENERATOR_NAME NOT MATCHING "SQL$+" USING "+=[0-9][0-9]* *" AND
|
||
|
(GEN.RDB$SYSTEM_FLAG MISSING OR GEN.RDB$SYSTEM_FLAG NE 1)
|
||
|
SORTED BY GEN.RDB$GENERATOR_NAME
|
||
|
|
||
|
ISQL_blankterm (GEN.RDB$GENERATOR_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
ISQL_copy_SQL_id (GEN.RDB$GENERATOR_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
else
|
||
|
strcpy (SQL_identifier, GEN.RDB$GENERATOR_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, "CREATE GENERATOR %s%s%s",
|
||
|
SQL_identifier,
|
||
|
Term,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
ISQL_printf(Out, NEWLINE);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_index()
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ i n d e x
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Define all non-constraint indices
|
||
|
* Use a static SQL query to get the info and print it.
|
||
|
*
|
||
|
* Uses get_index_segment to provide a key list for each index
|
||
|
*
|
||
|
**************************************/
|
||
|
SCHAR *collist;
|
||
|
SSHORT first = TRUE;
|
||
|
|
||
|
|
||
|
collist = NULL;
|
||
|
collist = (SCHAR *) ISQL_ALLOC(BUFFER_LENGTH512 * 2);
|
||
|
if (!collist)
|
||
|
{
|
||
|
isc_status[0] = isc_arg_gds;
|
||
|
isc_status[1] = isc_virmemexh;
|
||
|
isc_status[2] = isc_arg_end;
|
||
|
ISQL_errmsg(isc_status);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
FOR IDX IN RDB$INDICES CROSS RELC IN RDB$RELATIONS
|
||
|
OVER RDB$RELATION_NAME
|
||
|
WITH (RELC.RDB$SYSTEM_FLAG NE 1 OR RELC.RDB$SYSTEM_FLAG MISSING)
|
||
|
AND NOT (ANY RC IN RDB$RELATION_CONSTRAINTS
|
||
|
WITH RC.RDB$INDEX_NAME EQ IDX.RDB$INDEX_NAME)
|
||
|
SORTED BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME
|
||
|
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
sprintf (Print_buffer,
|
||
|
"%s/* Index definitions for all user tables */%s",
|
||
|
NEWLINE,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
first = FALSE;
|
||
|
/* Strip trailing blanks */
|
||
|
|
||
|
ISQL_blankterm (IDX.RDB$RELATION_NAME);
|
||
|
ISQL_blankterm (IDX.RDB$INDEX_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
{
|
||
|
ISQL_copy_SQL_id (IDX.RDB$INDEX_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
ISQL_copy_SQL_id (IDX.RDB$RELATION_NAME, &SQL_identifier2, DBL_QUOTE);
|
||
|
sprintf (Print_buffer, "CREATE%s%s INDEX %s ON %s(",
|
||
|
(IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""),
|
||
|
(IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""),
|
||
|
SQL_identifier,
|
||
|
SQL_identifier2);
|
||
|
}
|
||
|
else
|
||
|
sprintf (Print_buffer, "CREATE%s%s INDEX %s ON %s(",
|
||
|
(IDX.RDB$UNIQUE_FLAG ? " UNIQUE" : ""),
|
||
|
(IDX.RDB$INDEX_TYPE ? " DESCENDING" : ""),
|
||
|
IDX.RDB$INDEX_NAME,
|
||
|
IDX.RDB$RELATION_NAME);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Get column names */
|
||
|
|
||
|
if (ISQL_get_index_segments (collist, IDX.RDB$INDEX_NAME, TRUE))
|
||
|
{
|
||
|
sprintf (Print_buffer, "%s)%s%s", collist, Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
}
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
ISQL_FREE(collist);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
|
||
|
ISQL_FREE(collist);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void list_views()
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i s t _ v i e w s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Show text of views.
|
||
|
* Use a SQL query to get the info and print it.
|
||
|
* Note: This should also contain check option
|
||
|
*
|
||
|
**************************************/
|
||
|
SSHORT first;
|
||
|
|
||
|
/* If this is a view, use print_blob to print the view text */
|
||
|
|
||
|
FOR REL IN RDB$RELATIONS WITH
|
||
|
(REL.RDB$SYSTEM_FLAG NE 1 OR REL.RDB$SYSTEM_FLAG MISSING) AND
|
||
|
REL.RDB$VIEW_BLR NOT MISSING AND
|
||
|
REL.RDB$FLAGS = REL_sql
|
||
|
SORTED BY REL.RDB$RELATION_ID
|
||
|
|
||
|
first = TRUE;
|
||
|
ISQL_blankterm (REL.RDB$RELATION_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
ISQL_copy_SQL_id (REL.RDB$RELATION_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
else
|
||
|
strcpy (SQL_identifier, REL.RDB$RELATION_NAME);
|
||
|
|
||
|
ISQL_blankterm (REL.RDB$OWNER_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, "%s/* View: %s, Owner: %s */%s",
|
||
|
NEWLINE,
|
||
|
REL.RDB$RELATION_NAME,
|
||
|
REL.RDB$OWNER_NAME,
|
||
|
NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
sprintf (Print_buffer, "CREATE VIEW %s (", SQL_identifier);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
/* Get column list */
|
||
|
FOR RFR IN RDB$RELATION_FIELDS WITH
|
||
|
RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME
|
||
|
SORTED BY RFR.RDB$FIELD_POSITION
|
||
|
|
||
|
ISQL_blankterm (RFR.RDB$FIELD_NAME);
|
||
|
|
||
|
if (db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||
|
ISQL_copy_SQL_id (RFR.RDB$FIELD_NAME, &SQL_identifier, DBL_QUOTE);
|
||
|
else
|
||
|
strcpy (SQL_identifier, RFR.RDB$FIELD_NAME);
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", (first ? "" : ", "), SQL_identifier);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
first = FALSE;
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg (gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
sprintf (Print_buffer, ") AS%s", NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
if (!REL.RDB$VIEW_SOURCE.NULL)
|
||
|
SHOW_print_metadata_text_blob (Out, &REL.RDB$VIEW_SOURCE);
|
||
|
|
||
|
sprintf (Print_buffer, "%s%s", Term, NEWLINE);
|
||
|
ISQL_printf (Out, Print_buffer);
|
||
|
|
||
|
END_FOR
|
||
|
ON_ERROR
|
||
|
ISQL_errmsg(gds__status);
|
||
|
return;
|
||
|
END_ERROR;
|
||
|
}
|