8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 06:43:04 +01:00
firebird-mirror/src/qli/command.cpp
2003-08-22 10:56:55 +00:00

625 lines
15 KiB
C++

/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: command.c
* DESCRIPTION: Interprete commands
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../jrd/ib_stdio.h"
#include <stdlib.h>
#include <string.h>
#include "../jrd/gds.h"
#include "../qli/dtr.h"
#include "../qli/parse.h"
#include "../qli/compile.h"
#include "../qli/exe.h"
#include "../jrd/license.h"
#include "../qli/all_proto.h"
#include "../qli/err_proto.h"
#include "../qli/exe_proto.h"
#include "../qli/meta_proto.h"
#include "../qli/proc_proto.h"
#include "../jrd/gds_proto.h"
#ifdef VMS
#include <descrip.h>
#endif
static void dump_procedure(DBB, IB_FILE *, TEXT *, USHORT, FRBRD *);
static void extract_procedure(IB_FILE *, TEXT *, USHORT, DBB, SLONG *);
extern USHORT QLI_lines, QLI_columns, QLI_form_mode, QLI_name_columns;
#ifdef NOT_USED_OR_REPLACED
static SCHAR db_items[] =
{ gds_info_page_size, gds_info_allocation, gds_info_end };
#endif
int CMD_check_ready(void)
{
/**************************************
*
* C M D _ c h e c k _ r e a d y
*
**************************************
*
* Functional description
* Make sure at least one database is ready. If not, give a
* message.
*
**************************************/
if (QLI_databases)
return FALSE;
ERRQ_msg_put(95, NULL, NULL, NULL, NULL, NULL); /* Msg95 No databases are currently ready */
return TRUE;
}
void CMD_copy_procedure( SYN node)
{
/**************************************
*
* C M D _ c o p y _ p r o c e d u r e
*
**************************************
*
* Functional description
* Copy one procedure to another, possibly
* across databases
*
**************************************/
QPR new_proc, old_proc;
old_proc = (QPR) node->syn_arg[0];
new_proc = (QPR) node->syn_arg[1];
PRO_copy_procedure(old_proc->qpr_database,
old_proc->qpr_name->nam_string,
new_proc->qpr_database,
new_proc->qpr_name->nam_string);
}
void CMD_define_procedure( SYN node)
{
/**************************************
*
* C M D _ d e f i n e _ p r o c e d u r e
*
**************************************
*
* Functional description
* Define a procedure in the named database
* or in the most recently readied database.
*
**************************************/
QPR proc;
proc = (QPR) node->syn_arg[0];
if (!(proc->qpr_database))
proc->qpr_database = QLI_databases;
PRO_create(proc->qpr_database, proc->qpr_name->nam_string);
}
void CMD_delete_proc( SYN node)
{
/**************************************
*
* C M D _ d e l e t e _ p r o c
*
**************************************
*
* Functional description
* Delete a procedure in the named database
* or in the most recently readied database.
*
**************************************/
QPR proc;
proc = (QPR) node->syn_arg[0];
if (!proc->qpr_database)
proc->qpr_database = QLI_databases;
if (PRO_delete_procedure(proc->qpr_database, proc->qpr_name->nam_string))
return;
ERRQ_msg_put(88, proc->qpr_name->nam_string, /* Msg88 Procedure %s not found in database %s */
proc->qpr_database->dbb_symbol->sym_string, NULL, NULL,
NULL);
}
void CMD_edit_proc( SYN node)
{
/**************************************
*
* C M D _ e d i t _ p r o c
*
**************************************
*
* Functional description
* Edit a procedure in the specified database.
*
**************************************/
QPR proc;
proc = (QPR) node->syn_arg[0];
if (!proc->qpr_database)
proc->qpr_database = QLI_databases;
PRO_edit_procedure(proc->qpr_database, proc->qpr_name->nam_string);
}
void CMD_extract( SYN node)
{
/**************************************
*
* C M D _ e x t r a c t
*
**************************************
*
* Functional description
* Extract a series of procedures.
*
**************************************/
SYN list, *ptr, *end;
QPR proc;
DBB database;
NAM name;
IB_FILE *file;
FRBRD *blob;
file = (IB_FILE*) EXEC_open_output((QLI_NOD) node->syn_arg[1]);
if (list = node->syn_arg[0])
for (ptr = list->syn_arg, end = ptr + list->syn_count; ptr < end;
ptr++) {
proc = (QPR) * ptr;
if (!(database = proc->qpr_database))
database = QLI_databases;
name = proc->qpr_name;
if (!(blob = PRO_fetch_procedure(database, name->nam_string))) {
ERRQ_msg_put(89, /* Msg89 Procedure %s not found in database %s */
name->nam_string,
database->dbb_symbol->sym_string, NULL, NULL,
NULL);
continue;
}
dump_procedure(database, file, name->nam_string, name->nam_length,
blob);
}
else {
CMD_check_ready();
for (database = QLI_databases; database;
database =
database->dbb_next) PRO_scan(database, (void (*)()) extract_procedure, file);
}
#ifdef WIN_NT
if (((QLI_NOD) node->syn_arg[1])->nod_arg[e_out_pipe])
_pclose(file);
else
#endif
ib_fclose(file);
}
void CMD_finish( SYN node)
{
/**************************************
*
* C M D _ f i n i s h
*
**************************************
*
* Functional description
* Perform FINISH. Either finish listed databases or everything.
*
**************************************/
USHORT i;
if (node->syn_count == 0) {
while (QLI_databases)
MET_finish(QLI_databases);
return;
}
for (i = 0; i < node->syn_count; i++)
MET_finish((DBB) node->syn_arg[i]);
}
void CMD_rename_proc( SYN node)
{
/**************************************
*
* C M D _ r e n a m e _ p r o c
*
**************************************
*
* Functional description
* Rename a procedure in the named database,
* or the most recently readied database.
*
**************************************/
QPR old_proc, new_proc;
DBB database;
NAM old_name, new_name;
old_proc = (QPR) node->syn_arg[0];
new_proc = (QPR) node->syn_arg[1];
if (!(database = old_proc->qpr_database))
database = QLI_databases;
if (new_proc->qpr_database && (new_proc->qpr_database != database))
IBERROR(84); /* Msg84 Procedures can not be renamed across databases. Try COPY */
old_name = old_proc->qpr_name;
new_name = new_proc->qpr_name;
if (PRO_rename_procedure
(database, old_name->nam_string, new_name->nam_string)) return;
ERRQ_error(85, /* Msg85 Procedure %s not found in database %s */
old_name->nam_string, database->dbb_symbol->sym_string, NULL,
NULL, NULL);
}
void CMD_set( SYN node)
{
/**************************************
*
* C M D _ s e t
*
**************************************
*
* Functional description
* Set various options.
*
**************************************/
SYN *ptr, value;
enum set_t sw;
USHORT i, foo, length;
CON string;
TEXT *name;
ptr = node->syn_arg;
for (i = 0; i < node->syn_count; i++) {
foo = (USHORT)(ULONG) * ptr++;
sw = (enum set_t) foo;
value = *ptr++;
switch (sw) {
case set_blr:
QLI_blr = (USHORT)(ULONG) value;
break;
case set_statistics:
QLI_statistics = (USHORT)(ULONG) value;
break;
case set_columns:
QLI_name_columns = QLI_columns = (USHORT)(ULONG) value;
break;
case set_lines:
QLI_lines = (USHORT)(ULONG) value;
break;
case set_semi:
QLI_semi = (USHORT)(ULONG) value;
break;
case set_echo:
QLI_echo = (USHORT)(ULONG) value;
break;
case set_form:
IBERROR(484); /* FORMs not supported */
break;
case set_password:
string = (CON) value;
length =
MIN(string->con_desc.dsc_length,
sizeof(QLI_default_password));
strncpy(QLI_default_password, (char*) string->con_data, length);
QLI_default_password[length] = 0;
break;
case set_prompt:
string = (CON) value;
if (string->con_desc.dsc_length > sizeof(QLI_prompt_string))
ERRQ_error(86, NULL, NULL, NULL, NULL, NULL); /* Msg86 substitute prompt string too long */
strncpy(QLI_prompt_string, (char*) string->con_data,
string->con_desc.dsc_length);
QLI_prompt_string[string->con_desc.dsc_length] = 0;
break;
case set_continuation:
string = (CON) value;
if (string->con_desc.dsc_length > sizeof(QLI_cont_string))
ERRQ_error(87, NULL, NULL, NULL, NULL, NULL); /* Msg87 substitute prompt string too long */
strncpy(QLI_cont_string, (char*) string->con_data,
string->con_desc.dsc_length);
QLI_cont_string[string->con_desc.dsc_length] = 0;
break;
case set_matching_language:
if (QLI_matching_language)
ALLQ_release((FRB) QLI_matching_language);
if (!(string = (CON) value)) {
QLI_matching_language = NULL;
break;
}
QLI_matching_language =
(CON) ALLOCPV(type_con, string->con_desc.dsc_length);
strncpy((char*)QLI_matching_language->con_data, (char*)string->con_data,
string->con_desc.dsc_length);
QLI_matching_language->con_desc.dsc_dtype = dtype_text;
QLI_matching_language->con_desc.dsc_address =
QLI_matching_language->con_data;
QLI_matching_language->con_desc.dsc_length =
string->con_desc.dsc_length;
break;
case set_user:
string = (CON) value;
length =
MIN(string->con_desc.dsc_length, sizeof(QLI_default_user));
strncpy(QLI_default_user, (char*)string->con_data, length);
QLI_default_user[length] = 0;
break;
break;
case set_count:
QLI_count = (USHORT)(ULONG) value;
break;
case set_charset:
if (!value) {
QLI_charset[0] = 0;
break;
}
name = ((NAM) value)->nam_string;
length = MIN(strlen(name), sizeof(QLI_charset));
strncpy(QLI_charset, name, length);
QLI_charset[length] = 0;
break;
#ifdef DEV_BUILD
case set_explain:
QLI_explain = (USHORT)(ULONG) value;
break;
case set_hex_output:
QLI_hex_output = (USHORT)(ULONG) value;
break;
#endif
default:
BUGCHECK(6); /* Msg6 set option not implemented */
}
}
}
void CMD_shell( SYN node)
{
/**************************************
*
* C M D _ s h e l l
*
**************************************
*
* Functional description
* Invoke operating system shell.
*
**************************************/
TEXT buffer[256], *p, *q;
USHORT l;
CON constant;
#ifdef VMS
int status, return_status, mask;
struct dsc$descriptor desc, *ptr;
#endif
/* Copy command, inserting extra blank at end. */
p = buffer;
if (constant = (CON) node->syn_arg[0]) {
q = (TEXT *) constant->con_data;
if (l = constant->con_desc.dsc_length)
do
*p++ = *q++;
while (--l);
*p++ = ' ';
*p = 0;
}
else
#ifndef WIN_NT
strcpy(buffer, "$SHELL");
#else
strcpy(buffer, "%ComSpec%");
#endif
#ifdef VMS
if (constant) {
desc.dsc$b_dtype = DSC$K_DTYPE_T;
desc.dsc$b_class = DSC$K_CLASS_S;
desc.dsc$w_length = p - buffer;
desc.dsc$a_pointer = buffer;
ptr = &desc;
}
else
ptr = NULL;
return_status = 0;
mask = 1;
status = lib$spawn(ptr, /* Command to be executed */
NULL, /* Command file */
NULL, /* Output file */
&mask, /* sub-process characteristics mask */
NULL, /* sub-process name */
NULL, /* returned process id */
&return_status, /* completion status */
&15); /* event flag for completion */
if (status & 1)
while (!return_status)
sys$waitfr(15);
#else
system(buffer);
#endif
}
void CMD_transaction( SYN node)
{
/**************************************
*
* C M D _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Perform COMMIT, ROLLBACK or PREPARE
* on listed databases or everything.
*
**************************************/
SYN *ptr, *end;
DBB database;
/* If there aren't any open databases then obviously
there isn't anything to commit. */
if (node->syn_count == 0 && !QLI_databases)
return;
if (node->syn_type == nod_commit)
if ((node->syn_count > 1) ||
(node->syn_count == 0 && QLI_databases->dbb_next)) {
node->syn_type = nod_prepare;
CMD_transaction(node);
node->syn_type = nod_commit;
}
else if (node->syn_count == 1) {
database = (DBB) node->syn_arg[0];
database->dbb_flags |= DBB_prepared;
}
else
QLI_databases->dbb_flags |= DBB_prepared;
if (node->syn_count == 0) {
for (database = QLI_databases; database;
database = database->dbb_next) {
if ((node->syn_type == nod_commit)
&& !(database->dbb_flags & DBB_prepared)) ERRQ_msg_put(465,
database->
dbb_symbol->
sym_string,
NULL,
NULL,
NULL,
NULL);
else if (node->syn_type == nod_prepare)
database->dbb_flags |= DBB_prepared;
if (database->dbb_transaction)
MET_transaction(node->syn_type, database);
if (database->dbb_meta_trans)
MET_meta_commit(database);
if (database->dbb_proc_trans)
PRO_commit(database);
}
return;
}
for (ptr = node->syn_arg, end = ptr + node->syn_count; ptr < end; ptr++) {
database = (DBB) * ptr;
if ((node->syn_type == nod_commit) &&
!(database->dbb_flags & DBB_prepared))
ERRQ_msg_put(465, database->dbb_symbol->sym_string, NULL,
NULL, NULL, NULL);
else if (node->syn_type == nod_prepare)
database->dbb_flags |= DBB_prepared;
if (database->dbb_transaction)
MET_transaction(node->syn_type, database);
}
}
static void dump_procedure(
DBB database,
IB_FILE * file,
TEXT * name, USHORT length, FRBRD *blob)
{
/**************************************
*
* d u m p _ p r o c e d u r e
*
**************************************
*
* Functional description
* Extract a procedure from a database.
*
**************************************/
TEXT buffer[256];
ib_fprintf(file, "DELETE PROCEDURE %.*s;\n", length, name);
ib_fprintf(file, "DEFINE PROCEDURE %.*s\n", length, name);
while (PRO_get_line(blob, buffer, sizeof(buffer)))
ib_fputs(buffer, file);
PRO_close(database, blob);
ib_fprintf(file, "END_PROCEDURE\n\n");
}
static void extract_procedure(
IB_FILE * file,
TEXT * name,
USHORT length, DBB database, SLONG * blob_id)
{
/**************************************
*
* e x t r a c t _ p r o c e d u r e
*
**************************************
*
* Functional description
* Extract a procedure from a database.
*
**************************************/
FRBRD *blob;
blob = PRO_open_blob(database, blob_id);
dump_procedure(database, file, name, length, blob);
}