2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Command Oriented Query Language
|
|
|
|
* MODULE: dtr.c
|
|
|
|
* DESCRIPTION: Top level driving module
|
|
|
|
*
|
|
|
|
* 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#define QLI_MAIN
|
2001-07-30 01:43:24 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ib_stdio.h"
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include "../qli/dtr.h"
|
|
|
|
#include "../qli/parse.h"
|
|
|
|
#include "../qli/compile.h"
|
|
|
|
#include "../jrd/perf.h"
|
|
|
|
#include "../jrd/license.h"
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "../jrd/gds.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../qli/all_proto.h"
|
|
|
|
#include "../qli/compi_proto.h"
|
|
|
|
#include "../qli/err_proto.h"
|
|
|
|
#include "../qli/exe_proto.h"
|
|
|
|
#include "../qli/form_proto.h"
|
|
|
|
#include "../qli/expan_proto.h"
|
|
|
|
#include "../qli/gener_proto.h"
|
|
|
|
#include "../qli/help_proto.h"
|
|
|
|
#include "../qli/lex_proto.h"
|
|
|
|
#include "../qli/meta_proto.h"
|
|
|
|
#include "../qli/parse_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/perf_proto.h"
|
2001-12-24 03:51:06 +01:00
|
|
|
#include "../include/fb_exception.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef VMS
|
|
|
|
#define STARTUP_FILE "QLI_STARTUP"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef STARTUP_FILE
|
|
|
|
#define STARTUP_FILE "HOME" /* Assume its Unix */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef SIGQUIT
|
|
|
|
#define SIGQUIT SIGINT
|
|
|
|
#define SIGPIPE SIGINT
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Program wide globals */
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
jmp_buf QLI_env; /* Error return environment */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
TEXT *QLI_error;
|
|
|
|
USHORT sw_verify, sw_trace, sw_forms, sw_buffers;
|
|
|
|
USHORT QLI_lines = 60, QLI_prompt_count, QLI_reprompt, QLI_name_columns = 0;
|
|
|
|
|
|
|
|
/* Let's define the default number of columns on a machine by machine basis */
|
|
|
|
|
|
|
|
#ifdef VMS
|
|
|
|
USHORT QLI_columns = 80;
|
|
|
|
#else
|
|
|
|
USHORT QLI_columns = 80;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern TEXT *QLI_prompt;
|
|
|
|
|
|
|
|
static void enable_signals(void);
|
|
|
|
static USHORT process_statement(USHORT);
|
|
|
|
static void CLIB_ROUTINE signal_arith_excp(USHORT, USHORT, USHORT);
|
|
|
|
static void CLIB_ROUTINE signal_quit(void);
|
|
|
|
static BOOLEAN yes_no(USHORT, TEXT *);
|
|
|
|
|
|
|
|
typedef struct answer_t {
|
|
|
|
TEXT answer[30];
|
|
|
|
BOOLEAN value;
|
|
|
|
} *ANS;
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
static int yes_no_loaded = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
static struct answer_t answer_table[] = {
|
|
|
|
"", FALSE, /* NO */
|
|
|
|
"", TRUE, /* YES */
|
|
|
|
NULL, 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int CLIB_ROUTINE main( int argc, char **argv)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a i n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Top level routine.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT **arg_end, *p, *q, *r, *end, c, *startup_file, *application_file;
|
|
|
|
SCHAR home_directory[256];
|
|
|
|
PLB temp;
|
|
|
|
USHORT flush_flag, banner_flag, version_flag, got_started;
|
|
|
|
#ifdef VMS
|
|
|
|
USHORT vms_tryagain_flag;
|
|
|
|
#endif
|
|
|
|
SLONG debug_value;
|
|
|
|
jmp_buf env;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
#ifdef __OVERLAY__
|
|
|
|
_OvrInitEms(0, 0, 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Look at options, if any */
|
|
|
|
|
|
|
|
startup_file = STARTUP_FILE;
|
|
|
|
|
|
|
|
#ifdef UNIX
|
|
|
|
/* If a Unix system, get home directory from environment */
|
|
|
|
startup_file = getenv("HOME");
|
|
|
|
if (startup_file == NULL) {
|
|
|
|
startup_file = ".qli_startup";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
strcpy(home_directory, startup_file);
|
|
|
|
strcat(home_directory, "/.qli_startup");
|
|
|
|
startup_file = home_directory;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
application_file = NULL;
|
|
|
|
ALLQ_init();
|
|
|
|
LEX_init();
|
|
|
|
version_flag = flush_flag = FALSE;
|
|
|
|
banner_flag = TRUE;
|
|
|
|
sw_buffers = 0;
|
|
|
|
strcpy(QLI_prompt_string, "QLI> ");
|
|
|
|
strcpy(QLI_cont_string, "CON> ");
|
|
|
|
QLI_prompt = QLI_prompt_string;
|
|
|
|
QLI_matching_language = 0;
|
|
|
|
QLI_default_user[0] = 0;
|
|
|
|
QLI_default_password[0] = 0;
|
|
|
|
QLI_charset[0] = 0;
|
|
|
|
|
|
|
|
#ifdef DEVBUILD
|
|
|
|
QLI_hex_output = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
|
|
|
QLI_interp = HOST_INTERP;
|
|
|
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef VMS
|
|
|
|
argc = VMS_parse(&argv, argc);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (arg_end = argv + argc, argv++; argv < arg_end;) {
|
|
|
|
p = *argv++;
|
|
|
|
if (*p++ != '-') {
|
|
|
|
banner_flag = FALSE;
|
|
|
|
LEX_pop_line();
|
|
|
|
LEX_push_string(p - 1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while (c = *p++)
|
|
|
|
switch (UPPER(c)) {
|
|
|
|
case 'A':
|
|
|
|
if (argv >= arg_end) {
|
|
|
|
ERRQ_msg_put(23, NULL, NULL, NULL, NULL, NULL); /* Msg23 Please retry, supplying an application script file name */
|
|
|
|
exit(FINI_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
application_file = *argv++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B':
|
|
|
|
if (argv < arg_end && **argv != '-')
|
|
|
|
sw_buffers = atoi(*argv++);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'I':
|
|
|
|
if (argv >= arg_end || **argv == '-')
|
|
|
|
startup_file = NULL;
|
|
|
|
else
|
|
|
|
startup_file = *argv++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'N':
|
|
|
|
banner_flag = FALSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'P':
|
|
|
|
if (argv >= arg_end || **argv == '-')
|
|
|
|
break;
|
|
|
|
r = QLI_default_password;
|
|
|
|
end = r + sizeof(QLI_default_password) - 1;
|
|
|
|
for (q = *argv++; *q && r < end;)
|
|
|
|
*r++ = *q++;
|
|
|
|
*r = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'T':
|
|
|
|
sw_trace = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'U':
|
|
|
|
if (argv >= arg_end || **argv == '-')
|
|
|
|
break;
|
|
|
|
r = QLI_default_user;
|
|
|
|
end = r + sizeof(QLI_default_user) - 1;
|
|
|
|
for (q = *argv++; *q && r < end;)
|
|
|
|
*r++ = *q++;
|
|
|
|
*r = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'V':
|
|
|
|
sw_verify = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifndef PC_PLATFORM
|
|
|
|
case 'X':
|
|
|
|
debug_value = 1;
|
|
|
|
gds__set_debug(debug_value);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This switch's name is arbitrary; since it is an internal
|
|
|
|
mechanism it can be changed at will */
|
|
|
|
|
|
|
|
case 'Y':
|
|
|
|
QLI_trace = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'Z':
|
|
|
|
version_flag = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERRQ_msg_put(469, (TEXT *) c, NULL, NULL, NULL, NULL); /* Msg469 qli: ignoring unknown switch %c */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enable_signals();
|
|
|
|
|
|
|
|
if (banner_flag)
|
|
|
|
ERRQ_msg_put(24, NULL, NULL, NULL, NULL, NULL); /* Msg24 Welcome to QLI Query Language Interpreter */
|
|
|
|
|
|
|
|
if (version_flag)
|
|
|
|
ERRQ_msg_put(25, GDS_VERSION, NULL, NULL, NULL, NULL); /* Msg25 qli version %s */
|
|
|
|
|
|
|
|
if (application_file)
|
|
|
|
LEX_push_file(application_file, TRUE);
|
|
|
|
|
|
|
|
if (startup_file)
|
|
|
|
LEX_push_file(startup_file, FALSE);
|
|
|
|
|
|
|
|
#ifdef VMS
|
|
|
|
vms_tryagain_flag = FALSE;
|
|
|
|
if (startup_file)
|
|
|
|
vms_tryagain_flag = LEX_push_file(startup_file, FALSE);
|
|
|
|
|
|
|
|
/* If default value of startup file wasn't altered by the use of -i,
|
|
|
|
and LEX returned FALSE (above), try the old logical name, QLI_INIT */
|
|
|
|
|
|
|
|
if (!vms_tryagain_flag && startup_file
|
|
|
|
&& !(strcmp(startup_file, STARTUP_FILE))) LEX_push_file("QLI_INIT",
|
|
|
|
FALSE);
|
|
|
|
#endif
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
for (got_started = 0; !got_started;)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
got_started = 1;
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
|
|
|
QLI_env = env;
|
|
|
|
PAR_token();
|
|
|
|
}
|
|
|
|
catch (...) {
|
2001-05-23 15:26:42 +02:00
|
|
|
/* try again */
|
|
|
|
got_started = 0;
|
|
|
|
ERRQ_pending();
|
|
|
|
}
|
|
|
|
}
|
2001-07-30 01:43:24 +02:00
|
|
|
memset(QLI_env, 0, sizeof(QLI_env));
|
2001-05-23 15:26:42 +02:00
|
|
|
QLI_error = NULL;
|
|
|
|
|
|
|
|
/* Loop until end of file or forced exit */
|
|
|
|
|
|
|
|
while (QLI_line) {
|
|
|
|
temp = QLI_default_pool = ALLQ_pool();
|
|
|
|
flush_flag = process_statement(flush_flag);
|
|
|
|
ERRQ_pending();
|
|
|
|
if (sw_forms)
|
|
|
|
FORM_reset();
|
|
|
|
ALLQ_rlpool(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
FORM_fini();
|
|
|
|
HELP_fini();
|
|
|
|
MET_shutdown();
|
|
|
|
LEX_fini();
|
|
|
|
ALLQ_fini();
|
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
/* Report any memory leaks noticed.
|
|
|
|
* We don't particularly care about QLI specific memory leaks, so all
|
|
|
|
* QLI allocations have been marked as "don't report". However, much
|
|
|
|
* of the test-base uses QLI so having a report when QLI finishes
|
|
|
|
* could find leaks within the engine.
|
|
|
|
*/
|
|
|
|
gds_alloc_report(0, __FILE__, __LINE__);
|
|
|
|
#endif
|
|
|
|
exit(FINI_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void enable_signals(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e n a b l e _ s i g n a l s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Enable signals.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SLONG mask;
|
|
|
|
void (*prev_handler) ();
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
signal(SIGQUIT, (void(*)(int)) signal_quit);
|
|
|
|
signal(SIGINT, (void(*)(int)) signal_quit);
|
|
|
|
signal(SIGPIPE, (void(*)(int)) signal_quit);
|
|
|
|
signal(SIGFPE, (void(*)(int)) signal_arith_excp);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static USHORT process_statement( USHORT flush_flag)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p r o c e s s _ s t a t e m e n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Parse, compile, and execute a single statement. If an input flush
|
|
|
|
* is required, return TRUE (or status), otherwise return FALSE.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SYN syntax_tree;
|
|
|
|
BLK expanded_tree, execution_tree;
|
|
|
|
DBB dbb;
|
|
|
|
PERF statistics;
|
|
|
|
TEXT buffer[512], report[256], *p;
|
|
|
|
jmp_buf env;
|
|
|
|
|
|
|
|
/* Clear database active flags in preparation for a new statement */
|
|
|
|
|
|
|
|
QLI_abort = FALSE;
|
|
|
|
execution_tree = NULL;
|
|
|
|
|
|
|
|
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
|
|
|
|
dbb->dbb_flags &= ~DBB_active;
|
|
|
|
|
|
|
|
/* If the last statement wrote out anything to the terminal, skip a line */
|
|
|
|
|
|
|
|
if (QLI_skip_line) {
|
|
|
|
ib_printf("\n");
|
|
|
|
QLI_skip_line = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable signal handling for the next statement. Each signal will
|
|
|
|
be caught at least once, then reset to allow the user to really
|
|
|
|
kill the process */
|
|
|
|
|
|
|
|
enable_signals();
|
|
|
|
|
|
|
|
/* Enable error unwinding and enable the unwinding environment */
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
QLI_env = env;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Set up the appropriate prompt and get the first significant token. If
|
|
|
|
we don't get one, we're at end of file */
|
|
|
|
|
|
|
|
QLI_prompt = QLI_prompt_string;
|
|
|
|
|
|
|
|
/* This needs to be done after setting QLI_prompt to prevent
|
|
|
|
* and infinite loop in LEX/next_line.
|
|
|
|
*/
|
|
|
|
/* If there was a prior syntax error, flush the token stream */
|
|
|
|
|
|
|
|
if (flush_flag)
|
|
|
|
LEX_flush();
|
|
|
|
|
|
|
|
while (QLI_token->tok_keyword == KW_SEMI)
|
|
|
|
LEX_token();
|
|
|
|
|
|
|
|
PAR_real();
|
|
|
|
|
|
|
|
if (!QLI_line)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
EXEC_poll_abort();
|
|
|
|
|
|
|
|
/* Mark the current token as starting the statement. This is allows
|
|
|
|
the EDIT command to find the last statement */
|
|
|
|
|
|
|
|
LEX_mark_statement();
|
|
|
|
|
|
|
|
/* Change the prompt string to the continuation prompt, and parse
|
|
|
|
the next statement */
|
|
|
|
|
|
|
|
QLI_prompt = QLI_cont_string;
|
|
|
|
|
|
|
|
if (!(syntax_tree = PARQ_parse()))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
EXEC_poll_abort();
|
|
|
|
|
|
|
|
/* If the statement was EXIT, force end of file on command input */
|
|
|
|
|
|
|
|
if (syntax_tree->syn_type == nod_exit) {
|
|
|
|
QLI_line = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the statement was quit, ask the user if he want to rollback */
|
|
|
|
|
|
|
|
if (syntax_tree->syn_type == nod_quit) {
|
|
|
|
QLI_line = NULL;
|
|
|
|
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
|
|
|
|
if ((dbb->dbb_transaction) && (dbb->dbb_flags & DBB_updates))
|
|
|
|
if (yes_no(460, dbb->dbb_symbol->sym_string)) /* Msg460 Do you want to rollback updates for <dbb>? */
|
|
|
|
MET_transaction(nod_rollback, dbb);
|
|
|
|
else
|
|
|
|
MET_transaction(nod_commit, dbb);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Expand the statement. It will return NULL is the statement was
|
|
|
|
a command. An error will be unwound */
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
if (!(expanded_tree = (BLK) EXP_expand(syntax_tree)))
|
2001-05-23 15:26:42 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Compile the statement */
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
if (!(execution_tree = (BLK) CMPQ_compile((nod*) expanded_tree)))
|
2001-05-23 15:26:42 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Generate any BLR needed to support the request */
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
if (!GEN_generate(( (nod*) execution_tree)))
|
2001-05-23 15:26:42 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (QLI_statistics)
|
|
|
|
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
|
|
|
|
if (dbb->dbb_flags & DBB_active) {
|
|
|
|
if (!dbb->dbb_statistics) {
|
|
|
|
dbb->dbb_statistics =
|
|
|
|
(int *) gds__alloc((SLONG) sizeof(PERF));
|
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
/* We don't care about QLI specific memory leaks for V4.0 */
|
|
|
|
gds_alloc_flag_unfreed((void *) dbb->dbb_statistics); /* QLI: don't care */
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef PC_PLATFORM
|
2001-07-12 07:46:06 +02:00
|
|
|
perf_get_info((int**)&dbb->dbb_handle, (perf*) dbb->dbb_statistics);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute the request, for better or worse */
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
EXEC_top((nod*) execution_tree);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (QLI_statistics)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
if (dbb->dbb_flags & DBB_active)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifndef PC_PLATFORM
|
|
|
|
ERRQ_msg_get(505, report);
|
|
|
|
/* Msg505 " reads = !r writes = !w fetches = !f marks = !m\n" */
|
|
|
|
ERRQ_msg_get(506, report + strlen(report));
|
|
|
|
/* Msg506 " elapsed = !e cpu = !u system = !s mem = !x, buffers = !b" */
|
2001-07-12 07:46:06 +02:00
|
|
|
perf_get_info((int**)&dbb->dbb_handle, &statistics);
|
|
|
|
perf_format((perf*) dbb->dbb_statistics, &statistics,
|
2001-05-23 15:26:42 +02:00
|
|
|
report, buffer, 0);
|
|
|
|
#endif
|
|
|
|
ERRQ_msg_put(26, dbb->dbb_filename, buffer, NULL, NULL, NULL); /* Msg26 Statistics for database %s %s */
|
|
|
|
QLI_skip_line = TRUE;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Release resources associated with the request */
|
|
|
|
|
|
|
|
GEN_release();
|
|
|
|
|
|
|
|
return FALSE;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
} // try
|
|
|
|
catch (const Firebird::status_longjmp_error& e) {
|
|
|
|
GEN_release();
|
|
|
|
return e.value();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void CLIB_ROUTINE signal_arith_excp(USHORT sig, USHORT code, USHORT scp)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s i g n a l _ a r i t h _ e x c p
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Catch arithmetic exception.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT msg_number;
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
#ifdef FPE_INOVF_TRAP
|
|
|
|
case FPE_INTOVF_TRAP:
|
|
|
|
msg_number = 14; /* Msg14 integer overflow */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FPE_INTDIV_TRAP
|
|
|
|
case FPE_INTDIV_TRAP:
|
|
|
|
msg_number = 15; /* Msg15 integer division by zero */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FPE_FLTOVF_TRAP
|
|
|
|
case FPE_FLTOVF_TRAP:
|
|
|
|
msg_number = 16; /* Msg16 floating overflow trap */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FPE_FLTDIV_TRAP
|
|
|
|
case FPE_FLTDIV_TRAP:
|
|
|
|
msg_number = 17; /* Msg17 floating division by zero */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FPE_FLTUND_TRAP
|
|
|
|
case FPE_FLTUND_TRAP:
|
|
|
|
msg_number = 18; /* Msg18 floating underflow trap */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FPE_FLTOVF_FAULT
|
|
|
|
case FPE_FLTOVF_FAULT:
|
|
|
|
msg_number = 19; /* Msg19 floating overflow fault */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FPE_FLTUND_FAULT
|
|
|
|
case FPE_FLTUND_FAULT:
|
|
|
|
msg_number = 20; /* Msg20 floating underflow fault */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
msg_number = 21; /* Msg21 arithmetic exception */
|
|
|
|
}
|
|
|
|
|
2001-07-12 07:46:06 +02:00
|
|
|
signal(SIGFPE, (void(*)(int)) signal_arith_excp);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
IBERROR(msg_number);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void CLIB_ROUTINE signal_quit(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s i g n a l _ q u i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Stop whatever we happened to be doing.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
void (*prev_handler) ();
|
|
|
|
|
|
|
|
signal(SIGQUIT, SIG_DFL);
|
|
|
|
signal(SIGINT, SIG_DFL);
|
|
|
|
|
|
|
|
EXEC_abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOLEAN yes_no( USHORT number, TEXT * arg1)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* y e s _ n o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Put out a prompt that expects a yes/no
|
|
|
|
* answer, and keep trying until we get an
|
|
|
|
* acceptable answer (e.g. y, Yes, N, etc.)
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT buffer[256], prompt[256], *p, *q, c;
|
|
|
|
ANS response;
|
|
|
|
|
|
|
|
ERRQ_msg_format(number, sizeof(prompt), prompt, arg1, NULL, NULL, NULL,
|
|
|
|
NULL);
|
|
|
|
if (!yes_no_loaded) {
|
|
|
|
yes_no_loaded = 1;
|
|
|
|
if (!ERRQ_msg_get(498, answer_table[0].answer)) /* Msg498 NO */
|
|
|
|
strcpy(answer_table[0].answer, "NO"); /* default if msg_get fails */
|
|
|
|
if (!ERRQ_msg_get(497, answer_table[1].answer)) /* Msg497 YES */
|
|
|
|
strcpy(answer_table[1].answer, "YES");
|
|
|
|
}
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
buffer[0] = 0;
|
|
|
|
if (!LEX_get_line(prompt, buffer, sizeof(buffer)))
|
|
|
|
return TRUE;
|
|
|
|
for (response = answer_table; (TEXT *) response->answer; response++) {
|
|
|
|
p = buffer;
|
|
|
|
while (*p == ' ')
|
|
|
|
p++;
|
|
|
|
if (*p == EOF)
|
|
|
|
return TRUE;
|
|
|
|
for (q = response->answer; *p && UPPER(*p) == *q++; p++);
|
|
|
|
if (!*p || *p == '\n')
|
|
|
|
return response->value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|