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

568 lines
14 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: command.cpp
2001-05-23 15:26:42 +02:00
* 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"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <stdlib.h>
#include <string.h>
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../qli/dtr.h"
#include "../qli/parse.h"
#include "../qli/compile.h"
#include "../qli/exe.h"
//#include "../jrd/license.h"
2001-05-23 15:26:42 +02:00
#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"
using MsgFormat::SafeArg;
2009-01-10 11:51:02 +01:00
static void dump_procedure(qli_dbb*, FILE*, const TEXT*, USHORT, FB_API_HANDLE);
static void extract_procedure(void*, const TEXT*, USHORT, qli_dbb*, ISC_QUAD&);
2001-05-23 15:26:42 +02:00
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
static SCHAR db_items[] =
2001-07-12 07:46:06 +02:00
{ gds_info_page_size, gds_info_allocation, gds_info_end };
#endif
2001-05-23 15:26:42 +02:00
2008-01-15 21:15:58 +01:00
bool CMD_check_ready()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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
2001-05-23 15:26:42 +02:00
* message.
*
**************************************/
if (QLI_databases)
2004-03-07 08:58:55 +01:00
return false;
2001-05-23 15:26:42 +02:00
ERRQ_msg_put(95); // Msg95 No databases are currently ready
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
void CMD_copy_procedure( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C M D _ c o p y _ p r o c e d u r e
*
**************************************
*
* Functional description
* Copy one procedure to another, possibly
2001-05-23 15:26:42 +02:00
* across databases
*
**************************************/
QPR old_proc = (QPR) node->syn_arg[0];
QPR new_proc = (QPR) node->syn_arg[1];
2001-05-23 15:26:42 +02:00
2008-12-09 08:24:32 +01:00
PRO_copy_procedure(old_proc->qpr_database, old_proc->qpr_name->nam_string,
new_proc->qpr_database, new_proc->qpr_name->nam_string);
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
void CMD_define_procedure( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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 = (QPR) node->syn_arg[0];
2001-05-23 15:26:42 +02:00
if (!(proc->qpr_database))
proc->qpr_database = QLI_databases;
PRO_create(proc->qpr_database, proc->qpr_name->nam_string);
}
2004-03-07 08:58:55 +01:00
void CMD_delete_proc( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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 = (QPR) node->syn_arg[0];
2001-05-23 15:26:42 +02:00
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, SafeArg() << proc->qpr_name->nam_string << // Msg88 Procedure %s not found in database %s
proc->qpr_database->dbb_symbol->sym_string);
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
void CMD_edit_proc( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C M D _ e d i t _ p r o c
*
**************************************
*
* Functional description
* Edit a procedure in the specified database.
*
**************************************/
QPR proc = (QPR) node->syn_arg[0];
2001-05-23 15:26:42 +02:00
if (!proc->qpr_database)
proc->qpr_database = QLI_databases;
PRO_edit_procedure(proc->qpr_database, proc->qpr_name->nam_string);
}
2004-03-07 08:58:55 +01:00
void CMD_extract( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C M D _ e x t r a c t
*
**************************************
*
* Functional description
* Extract a series of procedures.
*
**************************************/
2004-04-29 00:36:29 +02:00
FILE* file = (FILE*) EXEC_open_output((qli_nod*) node->syn_arg[1]);
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
qli_syntax* list = node->syn_arg[0];
2009-01-10 11:51:02 +01:00
if (list)
{
2004-03-07 08:58:55 +01:00
qli_syntax** ptr = list->syn_arg;
2008-12-09 08:24:32 +01:00
for (const qli_syntax* const* const end = ptr + list->syn_count; ptr < end; ptr++)
2004-03-07 08:58:55 +01:00
{
2003-10-16 10:51:06 +02:00
QPR proc = (QPR) *ptr;
2009-01-10 11:51:02 +01:00
qli_dbb* database = proc->qpr_database;
2008-01-15 21:15:58 +01:00
if (!database)
2001-05-23 15:26:42 +02:00
database = QLI_databases;
2008-01-15 21:15:58 +01:00
2003-10-16 10:51:06 +02:00
NAM name = proc->qpr_name;
2004-05-03 01:06:37 +02:00
FB_API_HANDLE blob = PRO_fetch_procedure(database, name->nam_string);
2003-10-16 10:51:06 +02:00
if (!blob) {
ERRQ_msg_put(89, // Msg89 Procedure %s not found in database %s
SafeArg() << name->nam_string <<
database->dbb_symbol->sym_string);
2001-05-23 15:26:42 +02:00
continue;
}
2008-12-09 08:24:32 +01:00
dump_procedure(database, file, name->nam_string, name->nam_length, blob);
2001-05-23 15:26:42 +02:00
}
2003-10-16 10:51:06 +02:00
}
2001-05-23 15:26:42 +02:00
else {
CMD_check_ready();
2009-01-10 11:51:02 +01:00
for (qli_dbb* database = QLI_databases; database; database = database->dbb_next)
2003-10-16 10:51:06 +02:00
{
PRO_scan(database, extract_procedure, file);
2003-10-16 10:51:06 +02:00
}
2001-05-23 15:26:42 +02:00
}
#ifdef WIN_NT
2004-02-02 12:02:12 +01:00
if (((qli_nod*) node->syn_arg[1])->nod_arg[e_out_pipe])
2001-05-23 15:26:42 +02:00
_pclose(file);
else
#endif
2004-04-29 00:36:29 +02:00
fclose(file);
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
void CMD_finish( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C M D _ f i n i s h
*
**************************************
*
* Functional description
* Perform FINISH. Either finish listed databases or everything.
*
**************************************/
if (node->syn_count == 0) {
while (QLI_databases)
MET_finish(QLI_databases);
return;
}
for (USHORT i = 0; i < node->syn_count; i++)
2009-01-10 11:51:02 +01:00
MET_finish((qli_dbb*) node->syn_arg[i]);
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
void CMD_rename_proc( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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 = (QPR) node->syn_arg[0];
QPR new_proc = (QPR) node->syn_arg[1];
2008-12-05 02:20:14 +01:00
2009-01-10 11:51:02 +01:00
qli_dbb* database = old_proc->qpr_database;
2003-10-16 10:51:06 +02:00
if (!database)
2001-05-23 15:26:42 +02:00
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
NAM old_name = old_proc->qpr_name;
NAM new_name = new_proc->qpr_name;
2001-05-23 15:26:42 +02:00
2008-12-09 08:24:32 +01:00
if (PRO_rename_procedure(database, old_name->nam_string, new_name->nam_string))
2003-10-16 10:51:06 +02:00
{
return;
}
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
ERRQ_error(85, SafeArg() << old_name->nam_string << database->dbb_symbol->sym_string);
// Msg85 Procedure %s not found in database %s
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
void CMD_set( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C M D _ s e t
*
**************************************
*
* Functional description
* Set various options.
*
**************************************/
USHORT length;
2004-03-07 08:58:55 +01:00
const qli_const* string;
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
const qli_syntax* const* ptr = node->syn_arg;
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
for (USHORT i = 0; i < node->syn_count; i++)
{
2004-03-14 06:51:54 +01:00
const USHORT foo = (USHORT)(IPTR) *ptr++;
const enum set_t sw = (enum set_t) foo;
2004-03-07 08:58:55 +01:00
const qli_syntax* value = *ptr++;
2009-01-10 11:51:02 +01:00
switch (sw)
{
2001-05-23 15:26:42 +02:00
case set_blr:
2004-03-14 06:51:54 +01:00
QLI_blr = (bool)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_statistics:
2004-03-14 06:51:54 +01:00
QLI_statistics = (bool)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_columns:
2004-03-14 06:51:54 +01:00
QLI_name_columns = QLI_columns = (USHORT)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_lines:
2004-03-14 06:51:54 +01:00
QLI_lines = (USHORT)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_semi:
2004-03-14 06:51:54 +01:00
QLI_semi = (bool)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_echo:
2004-03-14 06:51:54 +01:00
QLI_echo = (bool)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
2008-12-09 08:24:32 +01:00
//case set_form:
// IBERROR(484); // FORMs not supported
// break;
2001-05-23 15:26:42 +02:00
case set_password:
2004-02-02 12:02:12 +01:00
string = (qli_const*) value;
2008-12-09 08:24:32 +01:00
length = MIN(string->con_desc.dsc_length, sizeof(QLI_default_password));
2001-07-12 07:46:06 +02:00
strncpy(QLI_default_password, (char*) string->con_data, length);
2001-05-23 15:26:42 +02:00
QLI_default_password[length] = 0;
break;
case set_prompt:
2004-02-02 12:02:12 +01:00
string = (qli_const*) value;
2001-05-23 15:26:42 +02:00
if (string->con_desc.dsc_length > sizeof(QLI_prompt_string))
ERRQ_error(86); // Msg86 substitute prompt string too long
2008-12-09 08:24:32 +01:00
strncpy(QLI_prompt_string, (char*) string->con_data, string->con_desc.dsc_length);
2001-05-23 15:26:42 +02:00
QLI_prompt_string[string->con_desc.dsc_length] = 0;
break;
case set_continuation:
2004-02-02 12:02:12 +01:00
string = (qli_const*) value;
2001-05-23 15:26:42 +02:00
if (string->con_desc.dsc_length > sizeof(QLI_cont_string))
ERRQ_error(87); // Msg87 substitute prompt string too long
2008-12-09 08:24:32 +01:00
strncpy(QLI_cont_string, (char*) string->con_data, string->con_desc.dsc_length);
2001-05-23 15:26:42 +02:00
QLI_cont_string[string->con_desc.dsc_length] = 0;
break;
case set_matching_language:
if (QLI_matching_language)
2001-07-12 07:46:06 +02:00
ALLQ_release((FRB) QLI_matching_language);
2004-02-02 12:02:12 +01:00
if (!(string = (qli_const*) value)) {
2001-05-23 15:26:42 +02:00
QLI_matching_language = NULL;
break;
}
2008-12-09 08:24:32 +01:00
QLI_matching_language = (qli_const*) ALLOCPV(type_con, string->con_desc.dsc_length);
2001-07-12 07:46:06 +02:00
strncpy((char*)QLI_matching_language->con_data, (char*)string->con_data,
2001-05-23 15:26:42 +02:00
string->con_desc.dsc_length);
QLI_matching_language->con_desc.dsc_dtype = dtype_text;
2008-12-09 08:24:32 +01:00
QLI_matching_language->con_desc.dsc_address = QLI_matching_language->con_data;
QLI_matching_language->con_desc.dsc_length = string->con_desc.dsc_length;
2001-05-23 15:26:42 +02:00
break;
case set_user:
2004-02-02 12:02:12 +01:00
string = (qli_const*) value;
2008-12-09 08:24:32 +01:00
length = MIN(string->con_desc.dsc_length, sizeof(QLI_default_user));
2001-07-12 07:46:06 +02:00
strncpy(QLI_default_user, (char*)string->con_data, length);
2001-05-23 15:26:42 +02:00
QLI_default_user[length] = 0;
break;
break;
case set_count:
2004-03-14 06:51:54 +01:00
QLI_count = (USHORT)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_charset:
2004-03-07 08:58:55 +01:00
{
if (!value) {
QLI_charset[0] = 0;
break;
}
const TEXT* name = ((NAM) value)->nam_string;
length = MIN(strlen(name), sizeof(QLI_charset));
strncpy(QLI_charset, name, length);
QLI_charset[length] = 0;
2001-05-23 15:26:42 +02:00
break;
}
#ifdef DEV_BUILD
case set_explain:
2004-03-14 06:51:54 +01:00
QLI_explain = (bool)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
case set_hex_output:
2004-03-14 06:51:54 +01:00
QLI_hex_output = (bool)(IPTR) value;
2001-05-23 15:26:42 +02:00
break;
#endif
default:
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(6); // Msg6 set option not implemented
2001-05-23 15:26:42 +02:00
}
}
}
2004-03-07 08:58:55 +01:00
void CMD_shell( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C M D _ s h e l l
*
**************************************
*
* Functional description
* Invoke operating system shell.
*
**************************************/
TEXT buffer[256];
2001-05-23 15:26:42 +02:00
// Copy command, inserting extra blank at end.
2001-05-23 15:26:42 +02:00
TEXT* p = buffer;
2004-03-07 08:58:55 +01:00
const qli_const* constant = (qli_const*) node->syn_arg[0];
2009-01-10 11:51:02 +01:00
if (constant)
{
2008-01-15 21:15:58 +01:00
const USHORT l = constant->con_desc.dsc_length;
if (l)
2008-01-15 21:15:58 +01:00
memcpy(p, constant->con_data, l);
p += l;
2001-05-23 15:26:42 +02:00
*p++ = ' ';
*p = 0;
}
else
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
#ifndef WIN_NT
strcpy(buffer, "$SHELL");
#else
strcpy(buffer, "%ComSpec%");
#endif
}
2008-01-15 21:15:58 +01:00
2001-05-23 15:26:42 +02:00
system(buffer);
}
2004-03-07 08:58:55 +01:00
void CMD_transaction( qli_syntax* node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* 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.
*
**************************************/
/* 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)
2008-01-15 21:15:58 +01:00
{
2008-12-09 08:24:32 +01:00
if ((node->syn_count > 1) || (node->syn_count == 0 && QLI_databases->dbb_next))
{
2001-05-23 15:26:42 +02:00
node->syn_type = nod_prepare;
CMD_transaction(node);
node->syn_type = nod_commit;
}
else if (node->syn_count == 1) {
2009-01-10 11:51:02 +01:00
qli_dbb* tmp_db = (qli_dbb*) node->syn_arg[0];
tmp_db->dbb_flags |= DBB_prepared;
2001-05-23 15:26:42 +02:00
}
else
QLI_databases->dbb_flags |= DBB_prepared;
2008-01-15 21:15:58 +01:00
}
2001-05-23 15:26:42 +02:00
2008-12-05 02:20:14 +01:00
if (node->syn_count == 0)
2008-01-15 21:15:58 +01:00
{
2009-01-10 11:51:02 +01:00
for (qli_dbb* db_iter = QLI_databases; db_iter; db_iter = db_iter->dbb_next)
{
2008-12-09 08:24:32 +01:00
if ((node->syn_type == nod_commit) && !(db_iter->dbb_flags & DBB_prepared))
{
ERRQ_msg_put(465, db_iter->dbb_symbol->sym_string);
}
2001-05-23 15:26:42 +02:00
else if (node->syn_type == nod_prepare)
db_iter->dbb_flags |= DBB_prepared;
if (db_iter->dbb_transaction)
MET_transaction(node->syn_type, db_iter);
if (db_iter->dbb_meta_trans)
MET_meta_commit(db_iter);
if (db_iter->dbb_proc_trans)
PRO_commit(db_iter);
2001-05-23 15:26:42 +02:00
}
return;
}
2004-03-07 08:58:55 +01:00
qli_syntax** ptr = node->syn_arg;
2008-12-09 08:24:32 +01:00
for (const qli_syntax* const* const end = ptr + node->syn_count; ptr < end; ptr++)
2004-03-07 08:58:55 +01:00
{
2009-01-10 11:51:02 +01:00
qli_dbb* database = (qli_dbb*) *ptr;
2008-12-09 08:24:32 +01:00
if ((node->syn_type == nod_commit) && !(database->dbb_flags & DBB_prepared))
{
ERRQ_msg_put(465, database->dbb_symbol->sym_string);
}
2001-05-23 15:26:42 +02:00
else if (node->syn_type == nod_prepare)
database->dbb_flags |= DBB_prepared;
if (database->dbb_transaction)
MET_transaction(node->syn_type, database);
}
}
2009-01-10 11:51:02 +01:00
static void dump_procedure(qli_dbb* database,
2004-04-29 00:36:29 +02:00
FILE* file,
2004-05-03 01:06:37 +02:00
const TEXT* name, USHORT length, FB_API_HANDLE blob)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d u m p _ p r o c e d u r e
*
**************************************
*
* Functional description
* Extract a procedure from a database.
*
**************************************/
TEXT buffer[256];
2004-04-29 00:36:29 +02:00
fprintf(file, "DELETE PROCEDURE %.*s;\n", length, name);
fprintf(file, "DEFINE PROCEDURE %.*s\n", length, name);
2001-05-23 15:26:42 +02:00
while (PRO_get_line(blob, buffer, sizeof(buffer)))
2004-04-29 00:36:29 +02:00
fputs(buffer, file);
2001-05-23 15:26:42 +02:00
PRO_close(database, blob);
2004-04-29 00:36:29 +02:00
fprintf(file, "END_PROCEDURE\n\n");
2001-05-23 15:26:42 +02:00
}
2009-01-10 11:51:02 +01:00
static void extract_procedure(void* file,
const TEXT* name,
2009-01-10 11:51:02 +01:00
USHORT length, qli_dbb* database, ISC_QUAD& blob_id)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e x t r a c t _ p r o c e d u r e
*
**************************************
*
* Functional description
* Extract a procedure from a database.
*
**************************************/
2004-05-03 01:06:37 +02:00
FB_API_HANDLE blob = PRO_open_blob(database, blob_id);
2004-04-29 00:36:29 +02:00
dump_procedure(database, static_cast<FILE*>(file), name, length, blob);
2001-05-23 15:26:42 +02:00
}