8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 07:23:04 +01:00

1. BIGINT is now the only keyword for the 64-bit exact numerics and it's available

in dialect 3 only.
2. BREAK statement has been disabled in triggers (like EXIT) because of the known
   BLR limitations. I hope it can be safely used in stored procedures though, hence
   I'd prefer to have it officially documented.
3. More complete implementation of the GROUP BY clause. You can group by internal
   functions and have ability to use more complex grouping conditions than before.
   By Arno Brinkman.
4. Allowed declaring and defining local variables at the same time.
   By Claudio Valderrama.
   Syntax: declare [variable] <var_name> <var_type> [{= | default} <default_value>]
5. Allowed ordinals to be used in the GROUP BY clause (like ORDER BY).
   By Arno Brinkman.
   Example: select extract(month from order_date), sum(order_sum) from orders group by 1
6. The first approach to the ALTER VIEW statement. Only high-level implementation so far.
   A lot of work in dfw.epp, metd.epp, etc. still required.
   By Dmitry Yemanov.
This commit is contained in:
dimitr 2002-08-11 08:04:54 +00:00
parent fd63bb8fd6
commit 7922269845
13 changed files with 3618 additions and 3292 deletions

View File

@ -20,7 +20,7 @@
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* $Id: ddl.cpp,v 1.10 2002-07-02 12:17:44 dimitr Exp $
* $Id: ddl.cpp,v 1.11 2002-08-11 08:04:52 dimitr Exp $
* 2001.5.20 Claudio Valderrama: Stop null pointer that leads to a crash,
* caused by incomplete yacc syntax that allows ALTER DOMAIN dom SET;
*
@ -59,8 +59,8 @@
* 2001.10.26 Claudio Valderrama: added a call to the new METD_drop_function()
* in DDL_execute() so the metadata cache for udfs can be refreshed.
* 2001.12.06 Claudio Valderrama: DDL_resolve_intl_type should calculate field length
*
*
* 2002.08.04 Claudio Valderrama: allow declaring and defining variables at the same time
* 2002.08.04 Dmitry Yemanov: ALTER VIEW
*/
#include "firebird.h"
@ -125,7 +125,7 @@ static void define_trigger(REQ, NOD);
static void define_udf(REQ);
static void define_update_action(REQ, NOD *, NOD *);
static void define_upd_cascade_trg(REQ, NOD, NOD, NOD, TEXT *, TEXT *);
static void define_view(REQ);
static void define_view(REQ, NOD_TYPE);
static void define_view_trigger(REQ, NOD, NOD, NOD);
static void delete_procedure(REQ, NOD, BOOLEAN);
static void delete_relation_view(REQ, NOD, BOOLEAN);
@ -139,13 +139,13 @@ static void modify_domain(REQ);
static void modify_field(REQ, NOD, SSHORT, STR);
static void modify_index(REQ);
static void modify_privilege(REQ, NOD_TYPE, SSHORT, UCHAR *, NOD, NOD, STR);
static void process_role_nm_list(REQ, SSHORT, NOD, NOD, NOD_TYPE);
static SCHAR modify_privileges(REQ, NOD_TYPE, SSHORT, NOD, NOD, NOD);
static void modify_relation(REQ);
static void process_role_nm_list(REQ, SSHORT, NOD, NOD, NOD_TYPE);
static void put_descriptor(REQ, DSC *);
static void put_dtype(REQ, FLD, USHORT);
static void put_field(REQ, FLD, BOOLEAN);
static void put_local_variable(REQ, VAR);
static void put_local_variable(REQ, VAR, NOD);
static SSHORT put_local_variables(REQ, NOD, SSHORT);
static void put_msg_field(REQ, FLD);
static NOD replace_field_names(NOD, NOD, NOD, SSHORT);
@ -450,7 +450,6 @@ void DDL_resolve_intl_type2(REQ request,
**************************************/
INTLSYM resolved_type;
ULONG field_length;
if ((field->fld_dtype > dtype_any_text) && field->fld_dtype != dtype_blob)
{
@ -2324,6 +2323,7 @@ static void define_procedure( REQ request, NOD_TYPE op)
request->append_cstring(gds_dyn_def_parameter, field->fld_name);
request->append_number(gds_dyn_prm_number, position);
request->append_number(gds_dyn_prm_type, 0);
DDL_resolve_intl_type(request, field, NULL);
put_field(request, field, FALSE);
@ -2432,7 +2432,7 @@ static void define_procedure( REQ request, NOD_TYPE op)
{
parameter = *ptr;
variable = (VAR) parameter->nod_arg[e_var_variable];
put_local_variable(request, variable);
put_local_variable(request, variable, 0);
}
}
@ -3267,7 +3267,7 @@ static void define_upd_cascade_trg( REQ request,
}
static void define_view( REQ request)
static void define_view( REQ request, NOD_TYPE op)
{
/**************************************
*
@ -3294,10 +3294,39 @@ static void define_view( REQ request)
node = request->req_ddl_node;
view_name = (STR) node->nod_arg[e_view_name];
request->append_cstring(gds_dyn_def_view,
reinterpret_cast<char*>(view_name->str_data));
save_relation(request, view_name);
request->append_number(gds_dyn_rel_sql_protection, 1);
if (op == nod_def_view)
{
request->append_cstring(gds_dyn_def_view,
reinterpret_cast<char*>(view_name->str_data));
request->append_number(gds_dyn_rel_sql_protection, 1);
save_relation(request, view_name);
}
else // nod_mod_view
{
request->append_cstring(gds_dyn_mod_view,
reinterpret_cast<char*>(view_name->str_data));
relation = METD_get_relation(request, view_name);
if (relation)
{
for (field = relation->rel_fields; field;
field = field->fld_next)
{
request->append_cstring(gds_dyn_delete_local_fld,
field->fld_name);
request->append_uchar(gds_dyn_end);
}
}
else
{
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) -607,
/* gds_arg_gds, gds__dsql_command_err,
gds_arg_gds, gds__dsql_view_not_found, */
gds_arg_gds, 336068783L,
gds_arg_string, view_name->str_data,
gds_arg_end);
}
}
/* compile the SELECT statement into a record selection expression,
making sure to bump the context number since view contexts start
@ -3952,7 +3981,8 @@ static void generate_dyn( REQ request, NOD node)
break;
case nod_def_view:
define_view(request);
case nod_mod_view:
define_view(request, node->nod_type);
break;
case nod_def_exception:
@ -5265,7 +5295,7 @@ static void put_field( REQ request, FLD field, BOOLEAN udf_flag)
}
static void put_local_variable( REQ request, VAR variable)
static void put_local_variable( REQ request, VAR variable, NOD host_param)
{
/**************************************
*
@ -5293,10 +5323,20 @@ static void put_local_variable( REQ request, VAR variable)
put_dtype(request, field, TRUE);
field->fld_dtype = dtype;
// Initialize variable to NULL
/* Check for a default value, borrowed from define_domain */
request->append_uchar(blr_assignment);
request->append_uchar(blr_null);
NOD node = (host_param) ? host_param->nod_arg[e_dfl_default] : 0;
if (node)
{
node = PASS1_node(request, node, 0);
GEN_expr(request, node);
}
else
{
// Initialize variable to NULL
request->append_uchar(blr_null);
}
request->append_uchar(blr_variable);
request->append_ushort(variable->var_variable_number);
}
@ -5339,7 +5379,7 @@ static SSHORT put_local_variables(REQ request, NOD parameters, SSHORT locals)
locals);
*ptr = var_node;
VAR variable = (VAR) var_node->nod_arg[e_var_variable];
put_local_variable(request, variable);
put_local_variable(request, variable, parameter);
locals++;
}
}

View File

@ -239,8 +239,7 @@
#define SKIP 495
#define CONNECTION_ID 496
#define TRANSACTION_ID 497
#define LARGEINT 498
#define KW_INT64 499
#define CASE 500
#define NULLIF 501
#define COALESCE 502
#define BIGINT 498
#define CASE 499
#define NULLIF 500
#define COALESCE 501

View File

@ -28,7 +28,7 @@
* Contributor(s):
*
*
* $Id: keywords.cpp,v 1.4 2002-08-03 15:27:20 dimitr Exp $
* $Id: keywords.cpp,v 1.5 2002-08-11 08:04:53 dimitr Exp $
*
*/
@ -74,6 +74,7 @@ static CONST TOK tokens [] = {
{BEFORE, "BEFORE", 1},
{BEGIN, "BEGIN", 1},
{BETWEEN, "BETWEEN", 1},
{BIGINT, "BIGINT", 2},
{BLOB, "BLOB", 1},
{KW_BREAK, "BREAK", 2},
{BY, "BY", 1},
@ -158,14 +159,12 @@ static CONST TOK tokens [] = {
{INPUT_TYPE, "INPUT_TYPE", 1},
{INSERT, "INSERT", 1},
{KW_INT, "INT", 1},
{KW_INT64, "INT64", 2},
{INTEGER, "INTEGER", 1},
{INTO, "INTO", 1},
{IS, "IS", 1},
{ISOLATION, "ISOLATION", 1},
{JOIN, "JOIN", 1},
{KEY, "KEY", 1},
{LARGEINT, "LARGEINT", 2},
{LEFT, "LEFT", 1},
{LENGTH, "LENGTH", 1},
{LEVEL, "LEVEL", 1},

View File

@ -1099,7 +1099,7 @@ void MAKE_desc_from_list( DSC * desc, NOD node)
{
/* ignore NULL value from walking */
tnod = *arg;
if (tnod->nod_type == nod_null)
if (tnod->nod_type == nod_null || tnod->nod_type == nod_parameter)
continue;
MAKE_desc(&desc1, *arg);
if (firstarg)
@ -1227,12 +1227,11 @@ void MAKE_desc_from_list( DSC * desc, NOD node)
}
}
/* If we haven't had a type at all then all values are NULL nodes */
/* If we haven't had a type at all then all values are NULL and/or parameter nodes */
if (firstarg)
{
maxtextlength = desc1.dsc_length;
text_in_list = 1;
firstarg = 0;
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 804,
gds_arg_gds, gds_dsql_datatype_err, 0);
}
desc->dsc_flags = DSC_nullable;

View File

@ -27,6 +27,7 @@
* 2002.07.30 Arno Brinkman:
* 2002.07.30 Added nod_searched_case, nod_simple_case, nod_coalesce
* 2002.07.30 and constants for arguments
* 2002.08.04 Dmitry Yemanov: ALTER VIEW
*/
#ifndef _DSQL_NODE_H_
@ -316,7 +317,8 @@ typedef ENUM nod_t
nod_internal_info, /* internal engine info */
nod_searched_case, /* searched CASE function */
nod_simple_case, /* simple CASE function */
nod_coalesce /* COALESCE function */
nod_coalesce, /* COALESCE function */
nod_mod_view /* ALTER VIEW */
} NOD_TYPE;

File diff suppressed because it is too large Load Diff

View File

@ -43,8 +43,12 @@
* 2002.07.30 tokens CASE, NULLIF, COALESCE added
* 2002.07.30 See block < CASE expression > what is added to value as case_expression
* 2002.07.30 function is split up into aggregate_function, numeric_value_function, string_value_function, generate_value_function
* 2002.07.30 new group_by_function and added to grp_column_elem. (TODO: allow these functions in select_group_by_list inside the engine)
* 2002.07.30 new group_by_function and added to grp_column_elem
* 2002.07.30 cast removed from function and added as cast_specification to value
* 2002.08.04 Claudio Valderrama: allow declaring and defining variables at the same time
* 2002.08.04 Dmitry Yemanov: ALTER VIEW
* 2002.08.06 Arno Brinkman: ordinal added to grp_column_elem for using positions in group by
* 2002.08.07 Dmitry Yemanov: INT64/LARGEINT are replaced with BIGINT and available in dialect 3 only
*/
@ -395,8 +399,7 @@ static void yyerror (TEXT *);
%token CONNECTION_ID
%token TRANSACTION_ID
%token LARGEINT
%token KW_INT64
%token BIGINT
%token CASE
%token NULLIF
%token COALESCE
@ -1369,9 +1372,21 @@ var_declarations : var_declaration
{ $$ = make_node (nod_list, 2, $1, $2); }
;
var_declaration : DECLARE VARIABLE column_def_name non_array_type ';'
var_declaration : DECLARE var_decl_opt column_def_name non_array_type var_init_opt ';'
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$3, NULL, NULL, NULL, NULL, NULL, NULL); }
$3, $5, NULL, NULL, NULL, NULL, NULL); }
;
var_decl_opt : VARIABLE
{ $$ = NULL; }
|
{ $$ = NULL; }
;
var_init_opt : '=' default_value
{ $$ = $2; }
| default_opt
{ $$ = $1; }
;
proc_block : proc_statement
@ -1555,6 +1570,12 @@ rview_clause : symbol_view_name column_parens_opt AS begin_string union_view
;
*/
alter_view_clause : symbol_view_name column_parens_opt AS begin_string union_view
end_string
{ $$ = make_node (nod_mod_view, (int) e_view_count,
$1, $2, $5, NULL, $6); }
;
union_view : union_view_expr
{ $$ = make_node (nod_select, (int) 2, $1, NULL); }
;
@ -1716,6 +1737,8 @@ alter_clause : EXCEPTION symbol_exception_name sql_string
| TABLE simple_table_name alter_ops
{ $$ = make_node (nod_mod_relation, (int) e_alt_count,
$2, make_list ($3)); }
| VIEW alter_view_clause
{ $$ = $2; }
| TRIGGER alter_trigger_clause
{ $$ = $2; }
| PROCEDURE alter_procedure_clause
@ -1999,8 +2022,20 @@ simple_type : non_charset_simple_type
non_charset_simple_type : national_character_type
| numeric_type
| float_type
| largeint_keyword
| BIGINT
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (gds_sqlerr, gds_arg_number, (SLONG) -104,
gds_arg_gds, isc_sql_dialect_datatype_unsupport,
gds_arg_number, client_dialect,
gds_arg_string, "BIGINT",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (gds_sqlerr, gds_arg_number, (SLONG) -104,
gds_arg_gds, isc_sql_db_dialect_dtype_unsupport,
gds_arg_number, db_dialect,
gds_arg_string, "BIGINT",
0);
g_field->fld_dtype = dtype_int64;
g_field->fld_length = sizeof (SINT64);
}
@ -2057,10 +2092,6 @@ non_charset_simple_type : national_character_type
}
;
largeint_keyword : LARGEINT
| KW_INT64
;
integer_keyword : INTEGER
| KW_INT
;
@ -2736,6 +2767,7 @@ grp_column_list : grp_column_elem
;
grp_column_elem : column_name
| ordinal
| udf
| group_by_function
| column_name COLLATE symbol_collation_name

View File

@ -86,6 +86,15 @@
*
* 2002.07.30 Arno Brinkman: Added pass1_coalesce, pass1_simple_case, pass1_searched_case
* and pass1_put_args_on_stack
*
* 2002.08.04 Arno Brinkman: Added ignore_cast as parameter to node_match,
* Changed invalid_reference procedure for allow EXTRACT, SUBSTRING, CASE,
* COALESCE and NULLIF functions in GROUP BY and as select_items.
* Removed aggregate_in_list procedure.
*
* 2002.08.07 Dmitry Yemanov: Disabled BREAK statement in triggers
*
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
*/
#include "firebird.h"
@ -117,7 +126,6 @@
ASSERT_FILENAME /* Define things assert() needs */
static BOOLEAN aggregate_found(REQ, NOD, NOD *);
static BOOLEAN aggregate_found2(REQ, NOD, NOD *, BOOLEAN *);
static BOOLEAN aggregate_in_list (NOD, BOOLEAN *, NOD);
static NOD ambiguity_check (NOD, REQ, FLD, DLLS, DLLS);
static void assign_fld_dtype_from_dsc(FLD, DSC *);
static NOD compose(NOD, NOD, NOD_TYPE);
@ -128,9 +136,9 @@ static NOD explode_outputs(REQ, PRC);
static void field_error(TEXT *, TEXT *, NOD);
static PAR find_dbkey(REQ, NOD);
static PAR find_record_version(REQ, NOD);
static BOOLEAN invalid_reference(NOD, NOD);
static BOOLEAN invalid_reference(REQ, NOD, NOD, BOOLEAN);
static void mark_ctx_outer_join(NOD);
static BOOLEAN node_match(NOD, NOD);
static BOOLEAN node_match(NOD, NOD, BOOLEAN);
static NOD pass1_alias_list(REQ, NOD);
static CTX pass1_alias(REQ, STR);
static NOD pass1_any(REQ, NOD, NOD_TYPE);
@ -925,6 +933,7 @@ NOD PASS1_statement(REQ request, NOD input, USHORT proc_flag)
case nod_def_constraint:
case nod_def_exception:
case nod_mod_relation:
case nod_mod_view:
case nod_mod_exception:
case nod_del_relation:
case nod_del_view:
@ -1239,6 +1248,9 @@ NOD PASS1_statement(REQ request, NOD input, USHORT proc_flag)
return input;
case nod_breakleave:
if (request->req_flags & REQ_trigger)
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 104, gds_arg_gds, gds_token_err, /* Token unknown */
gds_arg_gds, gds_random, gds_arg_string, "BREAK", 0);
input->nod_arg [e_break_number] = (NOD) (request->req_loop_number - 1);
return input;
@ -1478,93 +1490,6 @@ static BOOLEAN aggregate_found2(
}
static BOOLEAN aggregate_in_list (NOD sub, BOOLEAN *field, NOD list)
{
/**************************************
*
* a g g r e g a t e _ i n _ l i s t
*
**************************************
*
* Functional description
* Check for an aggregate expression in a
* node or list/chain of nodes.
*
**************************************/
BOOLEAN aggregate;
NOD *ptr, *end;
DEV_BLKCHK (sub, dsql_type_nod);
switch (sub->nod_type) {
/* handle the simple case of a straightforward aggregate */
case nod_agg_average:
case nod_agg_average2:
case nod_agg_total2:
case nod_agg_max:
case nod_agg_min:
case nod_agg_total:
case nod_agg_count:
case nod_aggregate:
case nod_map:
return TRUE;
case nod_field:
/* field is only ok if it also appears in group by */
*field = invalid_reference (sub, list);
return FALSE;
case nod_constant:
return FALSE;
/* for expressions in which an aggregate might
be buried, recursively check for one */
case nod_add:
case nod_concatenate:
case nod_divide:
case nod_multiply:
case nod_negate:
case nod_substr:
case nod_subtract:
case nod_add2:
case nod_divide2:
case nod_multiply2:
case nod_subtract2:
case nod_upcase:
case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_list:
aggregate = FALSE;
for (ptr = sub->nod_arg, end = ptr + sub->nod_count; ptr < end; ptr++)
{
DEV_BLKCHK (*ptr, dsql_type_nod);
aggregate |= aggregate_in_list (*ptr,field,list);
}
return aggregate;
case nod_cast:
case nod_udf:
case nod_gen_id:
case nod_gen_id2:
if (sub->nod_count == 2)
return (aggregate_in_list (sub->nod_arg[1],field,list));
else
return FALSE;
case nod_via:
/* Allow sub-selects - no validation in context of group by */
return TRUE;
default:
return FALSE;
}
}
static NOD ambiguity_check (NOD node, REQ request, FLD field,
DLLS relations,DLLS procedures)
{
@ -1756,6 +1681,60 @@ static NOD copy_field( NOD field, CTX context)
temp->nod_arg[e_alias_alias] = (NOD) alias;
return temp;
/*-- Added for allowing EXTRACT, SUBSTRING, CASE, ... functions in GROUP BY CLAUSE --*/
case nod_via:
return post_map(field, context);
case nod_rse:
temp = MAKE_node(field->nod_type, field->nod_count);
ptr2 = temp->nod_arg;
for (ptr = field->nod_arg, end = ptr + field->nod_count; ptr < end;
ptr++) *ptr2++ = *ptr;
return temp;
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
temp = MAKE_node(field->nod_type, field->nod_count);
temp->nod_desc = field->nod_desc;
ptr2 = temp->nod_arg;
for (ptr = field->nod_arg, end = ptr + field->nod_count; ptr < end;
ptr++)
*ptr2++ = copy_field(*ptr, context);
return temp;
case nod_relation:
case nod_or:
case nod_and:
case nod_not:
case nod_eql:
case nod_neq:
case nod_gtr:
case nod_geq:
case nod_lss:
case nod_leq:
case nod_eql_any:
case nod_neq_any:
case nod_gtr_any:
case nod_geq_any:
case nod_lss_any:
case nod_leq_any:
case nod_eql_all:
case nod_neq_all:
case nod_gtr_all:
case nod_geq_all:
case nod_lss_all:
case nod_leq_all:
case nod_between:
case nod_like:
case nod_containing:
case nod_starting:
case nod_exists:
case nod_singular:
case nod_missing:
/*--- ---*/
case nod_add:
case nod_add2:
case nod_concatenate:
@ -1770,9 +1749,6 @@ static NOD copy_field( NOD field, CTX context)
case nod_upcase:
case nod_internal_info:
case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_list:
temp = MAKE_node(field->nod_type, field->nod_count);
ptr2 = temp->nod_arg;
@ -1857,15 +1833,15 @@ static void explode_asterisk( NOD node, NOD aggregate, DLLS * stack)
node = MAKE_field(context, field, 0);
if (aggregate) {
if (invalid_reference
(node,
(NULL, node,
aggregate->
nod_arg[e_agg_group])) ERRD_post(gds_sqlerr,
gds_arg_number,
(SLONG) - 104,
gds_arg_gds,
gds_field_ref_err,
/* invalid field reference */
0);
nod_arg[e_agg_group], FALSE)) ERRD_post(gds_sqlerr,
gds_arg_number,
(SLONG) - 104,
gds_arg_gds,
gds_field_ref_err,
/* invalid field reference */
0);
}
LLS_PUSH(MAKE_field(context, field, 0), stack);
}
@ -1875,15 +1851,15 @@ static void explode_asterisk( NOD node, NOD aggregate, DLLS * stack)
node = MAKE_field(context, field, 0);
if (aggregate) {
if (invalid_reference
(node,
(NULL, node,
aggregate->
nod_arg[e_agg_group])) ERRD_post(gds_sqlerr,
gds_arg_number,
(SLONG) - 104,
gds_arg_gds,
gds_field_ref_err,
/* invalid field reference */
0);
nod_arg[e_agg_group], FALSE)) ERRD_post(gds_sqlerr,
gds_arg_number,
(SLONG) - 104,
gds_arg_gds,
gds_field_ref_err,
/* invalid field reference */
0);
}
LLS_PUSH(MAKE_field(context, field, 0), stack);
}
@ -2064,7 +2040,7 @@ static PAR find_record_version( REQ request, NOD relation_name)
}
static BOOLEAN invalid_reference( NOD node, NOD list)
static BOOLEAN invalid_reference(REQ request, NOD node, NOD list, BOOLEAN exact_field)
{
/**************************************
*
@ -2088,6 +2064,7 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
**************************************/
NOD *ptr, *end;
BOOLEAN invalid;
CTX field_context;
DEV_BLKCHK(node, dsql_type_nod);
DEV_BLKCHK(list, dsql_type_nod);
@ -2099,139 +2076,18 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
invalid = FALSE;
if (node->nod_type == nod_field)
if (list)
{
FLD field;
CTX context;
NOD reference;
if (!list)
return TRUE;
field = (FLD) node->nod_arg[e_fld_field];
context = (CTX) node->nod_arg[e_fld_context];
DEV_BLKCHK(field, dsql_type_fld);
DEV_BLKCHK(context, dsql_type_ctx);
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end;
ptr++)
/* Check if this node (with ignoring of CASTs) appear also
in the list of group by. If yes then it's allowed */
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++)
{
DEV_BLKCHK(*ptr, dsql_type_nod);
reference = *ptr;
if ((*ptr)->nod_type == nod_cast)
{
reference = (*ptr)->nod_arg[e_cast_source];
}
DEV_BLKCHK(reference, dsql_type_nod);
if (reference->nod_type == nod_field &&
field == (FLD) reference->nod_arg[e_fld_field] &&
context == (CTX) reference->nod_arg[e_fld_context])
{
return FALSE;
}
else
{
if (reference->nod_type == nod_udf )
{
return FALSE;
}
}
}
return TRUE;
}
else if (node->nod_type == nod_dbkey)
{
CTX context;
NOD reference, rel_node;
if (!list)
return TRUE;
rel_node = (NOD) node->nod_arg[0];
context = (CTX) rel_node->nod_arg[0];
DEV_BLKCHK(context, dsql_type_ctx);
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end;
ptr++)
{
DEV_BLKCHK(*ptr, dsql_type_nod);
reference = *ptr;
if ((*ptr)->nod_type == nod_cast)
{
reference = (*ptr)->nod_arg[e_cast_source];
}
DEV_BLKCHK(reference, dsql_type_nod);
if (reference->nod_type == nod_dbkey &&
rel_node == (NOD) reference->nod_arg[0] &&
context == (CTX) rel_node->nod_arg[0])
if (node_match(node, *ptr, TRUE))
{
return FALSE;
}
}
return TRUE;
}
else
{
if ((node->nod_type == nod_gen_id) ||
(node->nod_type == nod_gen_id2) ||
(node->nod_type == nod_cast)) {
if (node->nod_count == 2)
invalid |= invalid_reference(node->nod_arg[1], list);
}
else if (node->nod_type == nod_udf) {
NOD reference;
BOOLEAN non_agg_field;
if (!list) { /* validating select element with no group by */
if (node->nod_count == 2)
invalid = invalid_reference (node->nod_arg [1], list);
return invalid;
}
/* does this udf appear in list of group by */
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) {
DEV_BLKCHK(*ptr, dsql_type_nod);
reference = *ptr;
if ((*ptr)->nod_type == nod_cast) {
reference = (*ptr)->nod_arg[e_cast_source];
}
DEV_BLKCHK(reference, dsql_type_nod);
if (reference->nod_type == nod_udf) {
if (node_match (node, reference) == TRUE) {
/* select item exists in group by */
return FALSE;
}
}
}
/* if we have got here this udf element is not in group by
but it may still be valid if it has aggregate functions
as parameters in which case it points to a list to be traversed
if it doesn't then it is invalid
*/
if (node->nod_count == 2) {
if(aggregate_in_list (node->nod_arg [1], &non_agg_field,list) == TRUE) {
/* abs(trunc(sum(total)+field)) is not valid in select list
unless it also appears in the group by clause when its
value is then known
*/
if (non_agg_field == TRUE) {
invalid = TRUE;
}
else {
invalid = FALSE;
}
}
else {
invalid = TRUE;
}
return invalid;
}
return TRUE;
}
#ifdef CHECK_HAVING
/*
@ -2241,19 +2097,77 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
******************************************************
*/
else if (node->nod_type == nod_map)
{
MAP map;
map = (MAP) node->nod_arg[e_map_map];
DEV_BLKCHK(map, dsql_type_map);
invalid |= invalid_reference(map->map_node, list);
}
if (node->nod_type == nod_map)
{
MAP map;
map = (MAP) node->nod_arg[e_map_map];
DEV_BLKCHK(map, dsql_type_map);
invalid |= invalid_reference(map->map_node, list);
}
else
#endif
else
switch (node->nod_type) {
switch (node->nod_type) {
default:
ASSERT_FAIL;
/* FALLINTO */
case nod_field:
/* Wouldn't it be better to call a error from this
point where return is TRUE. Then we could give
the fieldname that's making the trouble */
if (!exact_field || !request)
{
return TRUE;
}
/* If we come here then this Field is used inside a
sub-select, singular- or exists-predicate.
The ctx_scope_level gives the info how deep the
context is inside the request.
So if the context-scope-level from the field is
lower as the scope-level from the request then
it is an invalid field */
field_context = (CTX) node->nod_arg[e_fld_context];
DEV_BLKCHK(field_context, dsql_type_ctx);
if (field_context->ctx_scope_level <= request->req_scope_level)
{
return TRUE;
}
break;
case nod_gen_id:
case nod_gen_id2:
case nod_cast:
case nod_udf:
/* If there are no arguments given to the UDF then it's always valid */
if (node->nod_count == 2)
{
invalid |= invalid_reference(request, node->nod_arg [1], list, exact_field);
}
break;
case nod_via:
case nod_exists:
case nod_singular:
//return FALSE;
for (ptr = node->nod_arg, end = ptr + node->nod_count;
ptr < end; ptr++)
{
invalid |= invalid_reference(request, *ptr, list, TRUE);
}
break;
case nod_parameter:
return FALSE;
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_add:
case nod_concatenate:
case nod_divide:
@ -2263,9 +2177,6 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
case nod_subtract:
case nod_upcase:
case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_add2:
case nod_divide2:
case nod_multiply2:
@ -2302,15 +2213,14 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
case nod_starting:
case nod_rse:
case nod_list:
case nod_via:
for (ptr = node->nod_arg, end = ptr + node->nod_count;
ptr < end; ptr++)
invalid |= invalid_reference(*ptr, list);
invalid |= invalid_reference(request, *ptr, list, exact_field);
break;
case nod_alias:
invalid |=
invalid_reference(node->nod_arg[e_alias_value], list);
invalid_reference(request, node->nod_arg[e_alias_value], list, exact_field);
break;
/* An embedded aggregate, even of an expression, is OK */
@ -2337,8 +2247,7 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
case nod_current_role:
case nod_internal_info:
return FALSE;
}
}
}
return invalid;
}
@ -2390,7 +2299,7 @@ static void mark_ctx_outer_join( NOD node)
}
static BOOLEAN node_match( NOD node1, NOD node2)
static BOOLEAN node_match( NOD node1, NOD node2, BOOLEAN ignore_cast)
{
/**************************************
*
@ -2401,6 +2310,14 @@ static BOOLEAN node_match( NOD node1, NOD node2)
* Functional description
* Compare two nodes for equality of value.
*
* [2002-08-04]--- Arno Brinkman
* If ignore_cast is TRUE and the node1 is of
* type nod_cast then node_match is calling
* itselfs again with the node1 CASTs source.
* This is for allow CAST to other datatypes
* without complaining that it's an unknown
* column reference. (Aggeregate functions)
*
**************************************/
NOD *ptr1, *ptr2, *end;
MAP map1, map2;
@ -2411,11 +2328,37 @@ static BOOLEAN node_match( NOD node1, NOD node2)
DEV_BLKCHK(node2, dsql_type_nod);
if ((!node1) && (!node2))
{
return TRUE;
}
if ((!node1) || (!node2) || (node1->nod_type != node2->nod_type)
|| (node1->nod_count != node2->nod_count))
if ((!node1) || (!node2))
{
return FALSE;
}
if (ignore_cast && node1->nod_type == nod_cast)
{
/* If node2 is also cast and same type continue with both sources */
if (node2->nod_type == nod_cast &&
node1->nod_desc.dsc_dtype == node2->nod_desc.dsc_dtype &&
node1->nod_desc.dsc_scale == node2->nod_desc.dsc_scale &&
node1->nod_desc.dsc_length == node2->nod_desc.dsc_length &&
node1->nod_desc.dsc_sub_type == node2->nod_desc.dsc_sub_type
)
{
return node_match(node1->nod_arg[e_cast_source], node2->nod_arg[e_cast_source], ignore_cast);
}
else
{
return node_match(node1->nod_arg[e_cast_source], node2, ignore_cast);
}
}
if ((node1->nod_type != node2->nod_type) || (node1->nod_count != node2->nod_count))
{
return FALSE;
}
/* This is to get rid of assertion failures when trying
to node_match nod_aggregate's children. This was happening because not
@ -2436,17 +2379,28 @@ static BOOLEAN node_match( NOD node1, NOD node2)
}
return node_match( node1->nod_arg[e_agg_group],
node2->nod_arg[e_agg_group]) &&
node2->nod_arg[e_agg_group], ignore_cast) &&
node_match( node1->nod_arg[e_agg_rse],
node2->nod_arg[e_agg_rse]);
node2->nod_arg[e_agg_rse], ignore_cast);
}
if (node1->nod_type == nod_alias) {
return node_match(node1->nod_arg[e_alias_value], node2);
if (node1->nod_type == nod_alias)
{
return node_match(node1->nod_arg[e_alias_value], node2, ignore_cast);
}
if (node2->nod_type == nod_alias) {
return node_match(node1, node2->nod_arg[e_alias_value]);
if (node2->nod_type == nod_alias)
{
return node_match(node1, node2->nod_arg[e_alias_value], ignore_cast);
}
if (node1->nod_type == nod_relation)
{
if (node1->nod_arg[e_rel_context] != node2->nod_arg[e_rel_context])
{
return FALSE;
}
return TRUE;
}
if (node1->nod_type == nod_field)
@ -2459,7 +2413,7 @@ static BOOLEAN node_match( NOD node1, NOD node2)
if (node1->nod_arg[e_fld_indices] || node2->nod_arg[e_fld_indices])
{
return node_match(node1->nod_arg[e_fld_indices],
node2->nod_arg[e_fld_indices]);
node2->nod_arg[e_fld_indices], ignore_cast);
}
return TRUE;
}
@ -2488,7 +2442,7 @@ static BOOLEAN node_match( NOD node1, NOD node2)
map2 = (MAP)node2->nod_arg[e_map_map];
DEV_BLKCHK(map1, dsql_type_map);
DEV_BLKCHK(map2, dsql_type_map);
return node_match(map1->map_node, map2->map_node);
return node_match(map1->map_node, map2->map_node, ignore_cast);
}
if ((node1->nod_type == nod_gen_id) ||
@ -2500,7 +2454,7 @@ static BOOLEAN node_match( NOD node1, NOD node2)
return FALSE;
}
if (node1->nod_count == 2) {
return node_match(node1->nod_arg[1], node2->nod_arg[1]);
return node_match(node1->nod_arg[1], node2->nod_arg[1], ignore_cast);
} else {
return TRUE;
}
@ -2543,7 +2497,7 @@ static BOOLEAN node_match( NOD node1, NOD node2)
ptr2 = node2->nod_arg;
for (end = ptr1 + node1->nod_count; ptr1 < end; ptr1++, ptr2++)
if (!node_match(*ptr1, *ptr2))
if (!node_match(*ptr1, *ptr2, ignore_cast))
return FALSE;
return TRUE;
@ -2697,7 +2651,7 @@ static NOD pass1_coalesce( REQ request, NOD input, USHORT proc_flag)
* Handle a reference to a coalesce function.
*
**************************************/
NOD node;
NOD node, *ptr, *end;
DLLS stack;
DEV_BLKCHK(request, dsql_type_req);
@ -2715,6 +2669,13 @@ static NOD pass1_coalesce( REQ request, NOD input, USHORT proc_flag)
/* Set describer for output node */
MAKE_desc(&node->nod_desc, node);
/* Set parameter-types if parameters are there */
for (ptr = node->nod_arg[0]->nod_arg, end = ptr + node->nod_arg[0]->nod_count;
ptr < end; ptr++)
{
set_parameter_type(*ptr, node, FALSE);
}
return node;
}
@ -3704,10 +3665,11 @@ static NOD pass1_rse( REQ request, NOD input, NOD order)
*
**************************************/
NOD rse, parent_rse, target_rse, aggregate, node, list, sub, *ptr, *end,
proj;
proj, slist_node, *ptr2;
DLLS stack;
CTX parent_context;
TSQL tdsql;
ULONG position;
DEV_BLKCHK(request, dsql_type_req);
DEV_BLKCHK(input, dsql_type_nod);
@ -3797,8 +3759,37 @@ static NOD pass1_rse( REQ request, NOD input, NOD order)
/* Process GROUP BY clause, if any */
if (node = input->nod_arg[e_sel_group]) {
aggregate->nod_arg[e_agg_group] = PASS1_node(request, node, 0);
if (node = input->nod_arg[e_sel_group])
{
/* if there are positions in the group by clause then replace them
by the (newly pass) items from the select_list */
aggregate->nod_arg[e_agg_group] = MAKE_node(node->nod_type,node->nod_count);
ptr2 = aggregate->nod_arg[e_agg_group]->nod_arg;
for (ptr = node->nod_arg, end = ptr + node->nod_count; ptr < end; ptr++, ptr2++)
{
sub = *ptr;
if (sub->nod_type == nod_position)
{
if ((slist_node = input->nod_arg[e_sel_list]) &&
(slist_node->nod_type == nod_list))
{
/* an select list is there */
position = (ULONG) (sub->nod_arg[0]);
if ((position < 1) || (position > (ULONG) slist_node->nod_count))
{
/* !! This error should be replaced by an good GROUP BY clause error !! */
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 104,
gds_arg_gds, gds_dsql_command_err,
gds_arg_gds, gds_field_aggregate_err, 0);
}
*ptr2 = PASS1_node(request, slist_node->nod_arg[position - 1], 0);
}
}
else
{
*ptr2 = PASS1_node(request, sub, 0);
}
}
}
if (parent_context)
@ -3819,7 +3810,7 @@ static NOD pass1_rse( REQ request, NOD input, NOD order)
if (aggregate)
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end;
ptr++)
if (invalid_reference(*ptr, aggregate->nod_arg[e_agg_group]))
if (invalid_reference(request, *ptr, aggregate->nod_arg[e_agg_group], FALSE))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 104,
gds_arg_gds, gds_field_ref_err,
/* invalid field reference */
@ -3922,7 +3913,7 @@ static NOD pass1_searched_case( REQ request, NOD input, USHORT proc_flag)
DEV_BLKCHK(input, dsql_type_nod);
DEV_BLKCHK(input->nod_arg[0], dsql_type_nod);
node = MAKE_node(nod_searched_case, 3);
node = MAKE_node(nod_searched_case, 2);
list = input->nod_arg[0];
@ -3947,6 +3938,14 @@ static NOD pass1_searched_case( REQ request, NOD input, USHORT proc_flag)
/* Set describer for output node */
MAKE_desc(&node->nod_desc, node);
/* Set parameter-types if parameters are there */
for (ptr = node->nod_arg[e_searched_case_search_conditions]->nod_arg,
end = ptr + node->nod_arg[e_searched_case_search_conditions]->nod_count;
ptr < end; ptr++)
{
set_parameter_type(*ptr, node, FALSE);
}
return node;
}
@ -4046,6 +4045,15 @@ static NOD pass1_simple_case( REQ request, NOD input, USHORT proc_flag)
/* Set describer for output node */
MAKE_desc(&node->nod_desc, node);
/* Set parameter-types if parameters are there */
set_parameter_type(node->nod_arg[e_simple_case_case_operand], node, FALSE);
for (ptr = node->nod_arg[e_simple_case_results]->nod_arg,
end = ptr + node->nod_arg[e_simple_case_results]->nod_count;
ptr < end; ptr++)
{
set_parameter_type(*ptr, node, FALSE);
}
return node;
}
@ -4545,7 +4553,7 @@ static NOD post_map( NOD node, CTX context)
/* Check to see if the item has already been posted */
for (map_ = context->ctx_map, count = 0; map_; map_ = map_->map_next, count++)
if (node_match(node, map_->map_node))
if (node_match(node, map_->map_node, FALSE))
break;
if (!map_) {

View File

@ -19,7 +19,7 @@
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
* $Id: show.epp,v 1.5 2002-06-29 13:39:11 skywalker Exp $
* $Id: show.epp,v 1.6 2002-08-11 08:04:54 dimitr Exp $
* Revision 1.2 2000/11/19 07:02:49 fsg
* Change in show.e to use CHARACTER_LENGTH instead of FIELD_LENGTH in
* SHOW PROCEDURE
@ -135,7 +135,7 @@ extern "C" CONST SQLTYPES Column_types[] = {
{blr_sql_time, "TIME"}, /* NTX: keyword */
{blr_sql_date, "DATE"}, /* NTX: keyword */
{blr_timestamp, "TIMESTAMP"}, /* NTX: keyword */
{blr_int64, "INT64"}, /* NTX: keyword */
{blr_int64, "BIGINT"}, /* NTX: keyword */
{0, ""}
};

View File

@ -31,6 +31,8 @@
* and complain if the grantee ROLE doesn't exist.
* 2001.10.06 Claudio Valderrama: Forbid "NONE" from role-related operations.
* Honor explicit USER keyword in GRANTs and REVOKEs.
*
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
*/
#include "firebird.h"
@ -409,6 +411,10 @@ TEXT * function_name, TEXT * procedure_name)
DYN_modify_relation(gbl, ptr);
break;
case gds_dyn_mod_view:
DYN_modify_view(gbl, ptr);
break;
case gds_dyn_delete_rel:
DYN_delete_relation(gbl, ptr, relation_name);
break;

View File

@ -30,7 +30,7 @@
* indexes that support unique constraints or primary keys.
* 26-Sep-2001 Paul Beach - External File Directory Config. Parameter
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
*
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
*/
#include "firebird.h"
@ -4171,8 +4171,9 @@ void DYN_define_view_relation( GBL gbl, UCHAR ** ptr, TEXT * view)
TDBB tdbb = GET_THREAD_DATA;
DBB dbb = tdbb->tdbb_database;
VOLATILE BLK request;
VOLATILE BLK request, old_request;
UCHAR verb;
VOLATILE SSHORT id, old_id;
MET_exact_name(view);
if (!view[0])
@ -4180,11 +4181,31 @@ void DYN_define_view_relation( GBL gbl, UCHAR ** ptr, TEXT * view)
/* msg 212: "Zero length identifiers not allowed" */
request = (BLK) CMP_find_request(tdbb, drq_s_view_rels, DYN_REQUESTS);
id = drq_s_view_rels;
bool b_ending_store = false;
try {
old_request = request, old_id = id;
request = (BLK) CMP_find_request(tdbb, drq_e_view_rels, DYN_REQUESTS);
id = drq_e_view_rels;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS WITH VRL.RDB$VIEW_NAME EQ view
if (!DYN_REQUEST(drq_e_view_rels))
DYN_REQUEST(drq_e_view_rels) = request;
ERASE VRL;
END_FOR;
if (!DYN_REQUEST(drq_e_view_rels))
DYN_REQUEST(drq_e_view_rels) = request;
request = old_request, id = old_id;
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS
strcpy(VRL.RDB$VIEW_NAME, view);
@ -4221,9 +4242,17 @@ void DYN_define_view_relation( GBL gbl, UCHAR ** ptr, TEXT * view)
}
catch (std::exception&) {
if (b_ending_store) {
DYN_rundown_request(request, drq_s_view_rels);
DYN_error_punt(TRUE, 34, NULL, NULL, NULL, NULL, NULL);
/* msg 34: "STORE RDB$VIEW_RELATIONS failed" */
DYN_rundown_request(request, id);
if (id == drq_s_view_rels)
{
DYN_error_punt(TRUE, 34, NULL, NULL, NULL, NULL, NULL);
/* msg 34: "STORE RDB$VIEW_RELATIONS failed" */
}
else if (id == drq_e_view_rels)
{
DYN_error_punt(TRUE, 59, NULL, NULL, NULL, NULL, NULL);
/* msg 59: "ERASE RDB$VIEW_RELATIONS failed" */
}
}
throw;
}

View File

@ -34,6 +34,7 @@ extern void DYN_modify_relation(GBL, UCHAR **);
extern void DYN_modify_trigger(GBL, UCHAR **);
extern void DYN_modify_trigger_msg(GBL, UCHAR **, TEXT *);
extern void DYN_modify_sql_field(GBL, UCHAR**, TEXT*, TEXT*);
extern void DYN_modify_view(GBL, UCHAR **);
#endif /* _JRD_DYN_MD_PROTO_H_ */

View File

@ -33,7 +33,7 @@
* 2001.10.08 Claudio Valderrama: put a comment with suggested code to hide
* special non-system triggers from user manipulation.
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
*
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
*/
#include "firebird.h"
@ -1750,6 +1750,111 @@ void DYN_modify_trigger_msg( GBL gbl, UCHAR ** ptr, TEXT * trigger_name)
}
void DYN_modify_view( GBL gbl, UCHAR ** ptr)
{
/**************************************
*
* D Y N _ m o d i f y _ v i e w
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
TDBB tdbb;
DBB dbb;
BLK request;
UCHAR verb;
USHORT found;
TEXT view_name[32];
tdbb = GET_THREAD_DATA;
dbb = tdbb->tdbb_database;
view_name[0] = 0;
GET_STRING(ptr, view_name);
MET_exact_name(view_name);
if (!view_name[0])
DYN_error_punt(FALSE, 212, NULL, NULL, NULL, NULL, NULL);
/* msg 212: "Zero length identifiers not allowed" */
try {
request = (BLK) CMP_find_request(tdbb, drq_m_relation, DYN_REQUESTS);
found = FALSE;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
VRL IN RDB$VIEW_RELATIONS CROSS REL IN RDB$RELATIONS
WITH VRL.RDB$VIEW_NAME EQ REL.RDB$RELATION_NAME AND
VRL.RDB$VIEW_NAME EQ view_name
if (!DYN_REQUEST(drq_m_relation))
DYN_REQUEST(drq_m_relation) = request;
found = TRUE;
MODIFY REL
REL.RDB$SYSTEM_FLAG.NULL = TRUE;
REL.RDB$VIEW_BLR.NULL = TRUE;
REL.RDB$VIEW_SOURCE.NULL = TRUE;
REL.RDB$SECURITY_CLASS.NULL = TRUE;
while ((verb = *(*ptr)++) != gds_dyn_end)
switch (verb)
{
case gds_dyn_system_flag:
REL.RDB$SYSTEM_FLAG = DYN_get_number(ptr);
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case gds_dyn_view_blr:
DYN_put_blr_blob(gbl, ptr, &REL.RDB$VIEW_BLR);
REL.RDB$VIEW_BLR.NULL = FALSE;
break;
case gds_dyn_view_source:
DYN_put_text_blob(gbl, ptr, &REL.RDB$VIEW_SOURCE);
REL.RDB$VIEW_SOURCE.NULL = FALSE;
break;
#if (defined JPN_SJIS || defined JPN_EUC)
case gds_dyn_view_source2:
DYN_put_text_blob2(gbl, ptr, &REL.RDB$VIEW_SOURCE);
REL.RDB$VIEW_SOURCE.NULL = FALSE;
break;
#endif
case gds_dyn_security_class:
GET_STRING(ptr, REL.RDB$SECURITY_CLASS);
REL.RDB$SECURITY_CLASS.NULL = FALSE;
break;
default:
--(*ptr);
DYN_execute(gbl, ptr, REL.RDB$RELATION_NAME, (TEXT*)NULL_PTR,
(TEXT*)NULL_PTR, (TEXT*)NULL_PTR, (TEXT*)NULL_PTR);
}
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_relation))
DYN_REQUEST(drq_m_relation) = request;
}
catch (...) {
DYN_rundown_request(request, -1);
DYN_error_punt(TRUE, 99, NULL, NULL, NULL, NULL, NULL);
/* msg 99: "MODIFY RDB$RELATIONS failed" */
}
if (!found) {
DYN_error_punt(FALSE, 61, NULL, NULL, NULL, NULL, NULL);
/* msg 61: "Relation not found" */
}
}
static void drop_cache( GBL gbl)
{
/**************************************