8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 00:43:03 +01:00
firebird-mirror/src/dsql/gen.cpp

3155 lines
76 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Dynamic SQL runtime support
2003-10-05 08:27:16 +02:00
* MODULE: gen.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Routines to generate BLR.
*
* 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.
2002-06-29 08:56:51 +02:00
* Contributor(s): ______________________________________
* 2001.6.21 Claudio Valderrama: BREAK and SUBSTRING.
* 2001.07.28 John Bellardo: Added code to generate blr_skip.
* 2002.07.30 Arno Brinkman: Added code, procedures to generate COALESCE, CASE
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
* 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
* 2003.10.05 Dmitry Yemanov: Added support for explicit cursors in PSQL
* 2004.01.16 Vlad Horsun: Added support for default parameters and
* EXECUTE BLOCK statement
2007-04-13 03:37:44 +02:00
* Adriano dos Santos Fernandes
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
#include <stdio.h>
#include "../dsql/dsql.h"
2008-02-28 14:48:16 +01:00
#include "../dsql/node.h"
#include "../dsql/StmtNodes.h"
2003-11-08 00:27:24 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/align.h"
2005-05-28 00:45:31 +02:00
#include "../jrd/constants.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/intl.h"
2008-02-28 14:48:16 +01:00
#include "../jrd/jrd.h"
#include "../jrd/val.h"
2001-05-23 15:26:42 +02:00
#include "../dsql/ddl_proto.h"
#include "../dsql/errd_proto.h"
#include "../dsql/gen_proto.h"
#include "../dsql/make_proto.h"
#include "../dsql/metd_proto.h"
#include "../dsql/misc_func.h"
#include "../dsql/utld_proto.h"
2005-05-28 00:45:31 +02:00
#include "../jrd/thread_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/dsc_proto.h"
#include "../jrd/why_proto.h"
#include "gen/iberror.h"
2001-05-23 15:26:42 +02:00
2008-02-28 14:48:16 +01:00
using namespace Jrd;
using namespace Dsql;
static void gen_aggregate(CompiledStatement*, const dsql_nod*);
static void gen_cast(CompiledStatement*, const dsql_nod*);
static void gen_coalesce(CompiledStatement*, const dsql_nod*);
static void gen_constant(CompiledStatement*, const dsc*, bool);
static void gen_constant(CompiledStatement*, dsql_nod*, bool);
static void gen_descriptor(CompiledStatement*, const dsc*, bool);
static void gen_error_condition(CompiledStatement*, const dsql_nod*);
static void gen_exec_stmt(CompiledStatement* statement, const dsql_nod* node);
static void gen_field(CompiledStatement*, const dsql_ctx*, const dsql_fld*, dsql_nod*);
static void gen_for_select(CompiledStatement*, const dsql_nod*);
static void gen_gen_id(CompiledStatement*, const dsql_nod*);
static void gen_join_rse(CompiledStatement*, const dsql_nod*);
static void gen_map(CompiledStatement*, dsql_map*);
static inline void gen_optional_expr(CompiledStatement*, const UCHAR code, dsql_nod*);
static void gen_parameter(CompiledStatement*, const dsql_par*);
static void gen_plan(CompiledStatement*, const dsql_nod*);
static void gen_relation(CompiledStatement*, dsql_ctx*);
static void gen_rse(CompiledStatement*, const dsql_nod*);
static void gen_searched_case(CompiledStatement*, const dsql_nod*);
static void gen_select(CompiledStatement*, dsql_nod*);
static void gen_simple_case(CompiledStatement*, const dsql_nod*);
static void gen_sort(CompiledStatement*, dsql_nod*);
static void gen_statement(CompiledStatement*, const dsql_nod*);
static void gen_sys_function(CompiledStatement*, const dsql_nod*);
static void gen_table_lock(CompiledStatement*, const dsql_nod*, USHORT);
static void gen_udf(CompiledStatement*, const dsql_nod*);
static void gen_union(CompiledStatement*, const dsql_nod*);
static void stuff_context(CompiledStatement*, const dsql_ctx*);
static void stuff_cstring(CompiledStatement*, const char*);
static void stuff_meta_string(CompiledStatement*, const char*);
static void stuff_string(CompiledStatement*, const char*, int);
static void stuff_string(CompiledStatement* statement, const Firebird::MetaName& name);
static void stuff_word(CompiledStatement*, USHORT);
2001-05-23 15:26:42 +02:00
// STUFF is defined in dsql.h for use in common with ddl.c
2001-05-23 15:26:42 +02:00
// The following are passed as the third argument to gen_constant
2003-09-28 02:36:28 +02:00
const bool NEGATE_VALUE = true;
const bool USE_VALUE = false;
2001-05-23 15:26:42 +02:00
/**
GEN_expr
@brief Generate blr for an arbitrary expression.
@param statement
@param node
**/
void GEN_expr( CompiledStatement* statement, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
UCHAR blr_operator;
dsql_ctx* context;
dsql_map* map;
2004-02-02 12:02:12 +01:00
dsql_var* variable;
2001-05-23 15:26:42 +02:00
switch (node->nod_type) {
case nod_alias:
GEN_expr(statement, node->nod_arg[e_alias_value]);
2001-05-23 15:26:42 +02:00
return;
case nod_aggregate:
gen_aggregate(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_constant:
gen_constant(statement, node, USE_VALUE);
2001-05-23 15:26:42 +02:00
return;
case nod_derived_field:
GEN_expr(statement, node->nod_arg[e_derived_field_value]);
return;
2001-05-23 15:26:42 +02:00
case nod_extract:
stuff(statement, blr_extract);
stuff(statement, node->nod_arg[e_extract_part]->getSlong());
GEN_expr(statement, node->nod_arg[e_extract_value]);
2001-05-23 15:26:42 +02:00
return;
case nod_strlen:
stuff(statement, blr_strlen);
stuff(statement, node->nod_arg[e_strlen_type]->getSlong());
GEN_expr(statement, node->nod_arg[e_strlen_value]);
2005-05-28 00:45:31 +02:00
return;
2001-05-23 15:26:42 +02:00
case nod_dbkey:
node = node->nod_arg[0];
context = (dsql_ctx*) node->nod_arg[e_rel_context];
stuff(statement, blr_dbkey);
stuff_context(statement, context);
2001-05-23 15:26:42 +02:00
return;
case nod_rec_version:
node = node->nod_arg[0];
context = (dsql_ctx*) node->nod_arg[e_rel_context];
stuff(statement, blr_record_version);
stuff_context(statement, context);
2001-05-23 15:26:42 +02:00
return;
case nod_dom_value:
stuff(statement, blr_fid);
stuff(statement, 0); // Context
stuff_word(statement, 0); // Field id
2001-05-23 15:26:42 +02:00
return;
case nod_field:
gen_field(statement,
(dsql_ctx*) node->nod_arg[e_fld_context],
(dsql_fld*) node->nod_arg[e_fld_field],
2001-05-23 15:26:42 +02:00
node->nod_arg[e_fld_indices]);
return;
case nod_user_name:
stuff(statement, blr_user_name);
2001-05-23 15:26:42 +02:00
return;
case nod_current_time:
if (node->nod_arg[0]) {
const dsql_nod* const_node = node->nod_arg[0];
fb_assert(const_node->nod_type == nod_constant);
const int precision = (int) const_node->getSlong();
stuff(statement, blr_current_time2);
stuff(statement, precision);
}
else {
stuff(statement, blr_current_time);
}
2001-05-23 15:26:42 +02:00
return;
case nod_current_timestamp:
if (node->nod_arg[0]) {
const dsql_nod* const_node = node->nod_arg[0];
fb_assert(const_node->nod_type == nod_constant);
const int precision = (int) const_node->getSlong();
stuff(statement, blr_current_timestamp2);
stuff(statement, precision);
}
else {
stuff(statement, blr_current_timestamp);
}
2001-05-23 15:26:42 +02:00
return;
case nod_current_date:
stuff(statement, blr_current_date);
2001-05-23 15:26:42 +02:00
return;
2007-04-12 17:56:34 +02:00
case nod_current_role:
stuff(statement, blr_current_role);
2007-04-12 17:56:34 +02:00
return;
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
case nod_udf:
gen_udf(statement, node);
2001-05-23 15:26:42 +02:00
return;
2007-04-12 17:56:34 +02:00
case nod_sys_function:
gen_sys_function(statement, node);
2007-04-12 17:56:34 +02:00
return;
2001-05-23 15:26:42 +02:00
case nod_variable:
2004-02-02 12:02:12 +01:00
variable = (dsql_var*) node->nod_arg[e_var_variable];
if (variable->var_type == VAR_input) {
stuff(statement, blr_parameter2);
stuff(statement, variable->var_msg_number);
stuff_word(statement, variable->var_msg_item);
stuff_word(statement, variable->var_msg_item + 1);
2001-05-23 15:26:42 +02:00
}
else {
stuff(statement, blr_variable);
stuff_word(statement, variable->var_variable_number);
2001-05-23 15:26:42 +02:00
}
return;
case nod_join:
gen_join_rse(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_map:
map = (dsql_map*) node->nod_arg[e_map_map];
context = (dsql_ctx*) node->nod_arg[e_map_context];
stuff(statement, blr_fid);
stuff_context(statement, context);
stuff_word(statement, map->map_position);
2001-05-23 15:26:42 +02:00
return;
case nod_parameter:
gen_parameter(statement, (dsql_par*) node->nod_arg[e_par_parameter]);
2001-05-23 15:26:42 +02:00
return;
case nod_relation:
gen_relation(statement, (dsql_ctx*) node->nod_arg[e_rel_context]);
2001-05-23 15:26:42 +02:00
return;
case nod_rse:
gen_rse(statement, node);
2001-05-23 15:26:42 +02:00
return;
2003-08-15 01:34:37 +02:00
case nod_derived_table:
gen_rse(statement, node->nod_arg[e_derived_table_rse]);
2003-08-15 01:34:37 +02:00
return;
2001-05-23 15:26:42 +02:00
case nod_exists:
stuff(statement, blr_any);
gen_rse(statement, node->nod_arg[0]);
2001-05-23 15:26:42 +02:00
return;
case nod_singular:
stuff(statement, blr_unique);
gen_rse(statement, node->nod_arg[0]);
2001-05-23 15:26:42 +02:00
return;
case nod_agg_count:
if (node->nod_count)
blr_operator = (node->nod_flags & NOD_AGG_DISTINCT) ?
blr_agg_count_distinct : blr_agg_count2;
2001-05-23 15:26:42 +02:00
else
blr_operator = blr_agg_count;
2001-05-23 15:26:42 +02:00
break;
case nod_agg_min:
blr_operator = blr_agg_min;
2001-05-23 15:26:42 +02:00
break;
case nod_agg_max:
blr_operator = blr_agg_max;
2001-05-23 15:26:42 +02:00
break;
case nod_agg_average:
blr_operator = (node->nod_flags & NOD_AGG_DISTINCT) ?
blr_agg_average_distinct : blr_agg_average;
2001-05-23 15:26:42 +02:00
break;
case nod_agg_total:
blr_operator = (node->nod_flags & NOD_AGG_DISTINCT) ?
blr_agg_total_distinct : blr_agg_total;
2001-05-23 15:26:42 +02:00
break;
case nod_agg_average2:
blr_operator = (node->nod_flags & NOD_AGG_DISTINCT) ?
2001-05-23 15:26:42 +02:00
blr_agg_average_distinct : blr_agg_average;
break;
case nod_agg_total2:
blr_operator = (node->nod_flags & NOD_AGG_DISTINCT) ?
2001-05-23 15:26:42 +02:00
blr_agg_total_distinct : blr_agg_total;
break;
case nod_agg_list:
blr_operator = (node->nod_flags & NOD_AGG_DISTINCT) ?
blr_agg_list_distinct : blr_agg_list;
break;
2001-05-23 15:26:42 +02:00
case nod_and:
blr_operator = blr_and;
2001-05-23 15:26:42 +02:00
break;
case nod_or:
blr_operator = blr_or;
2001-05-23 15:26:42 +02:00
break;
case nod_not:
blr_operator = blr_not;
2001-05-23 15:26:42 +02:00
break;
case nod_eql_all:
case nod_eql_any:
case nod_eql:
blr_operator = blr_eql;
2001-05-23 15:26:42 +02:00
break;
case nod_equiv:
blr_operator = blr_equiv;
break;
2001-05-23 15:26:42 +02:00
case nod_neq_all:
case nod_neq_any:
case nod_neq:
blr_operator = blr_neq;
2001-05-23 15:26:42 +02:00
break;
case nod_gtr_all:
case nod_gtr_any:
case nod_gtr:
blr_operator = blr_gtr;
2001-05-23 15:26:42 +02:00
break;
case nod_leq_all:
case nod_leq_any:
case nod_leq:
blr_operator = blr_leq;
2001-05-23 15:26:42 +02:00
break;
case nod_geq_all:
case nod_geq_any:
case nod_geq:
blr_operator = blr_geq;
2001-05-23 15:26:42 +02:00
break;
case nod_lss_all:
case nod_lss_any:
case nod_lss:
blr_operator = blr_lss;
2001-05-23 15:26:42 +02:00
break;
case nod_between:
blr_operator = blr_between;
2001-05-23 15:26:42 +02:00
break;
case nod_containing:
blr_operator = blr_containing;
2001-05-23 15:26:42 +02:00
break;
2008-01-16 07:52:43 +01:00
case nod_similar:
stuff(statement, blr_similar);
GEN_expr(statement, node->nod_arg[e_similar_value]);
GEN_expr(statement, node->nod_arg[e_similar_pattern]);
2008-01-16 07:52:43 +01:00
if (node->nod_arg[e_similar_escape])
{
stuff(statement, 1);
GEN_expr(statement, node->nod_arg[e_similar_escape]);
2008-01-16 07:52:43 +01:00
}
else
stuff(statement, 0);
2008-01-16 07:52:43 +01:00
return;
2001-05-23 15:26:42 +02:00
case nod_starting:
blr_operator = blr_starting;
2001-05-23 15:26:42 +02:00
break;
case nod_missing:
blr_operator = blr_missing;
2001-05-23 15:26:42 +02:00
break;
case nod_like:
blr_operator = (node->nod_count == 2) ? blr_like : blr_ansi_like;
2001-05-23 15:26:42 +02:00
break;
case nod_add:
blr_operator = blr_add;
2001-05-23 15:26:42 +02:00
break;
case nod_subtract:
blr_operator = blr_subtract;
2001-05-23 15:26:42 +02:00
break;
case nod_multiply:
blr_operator = blr_multiply;
2001-05-23 15:26:42 +02:00
break;
case nod_negate:
{
dsql_nod* child = node->nod_arg[0];
2001-05-23 15:26:42 +02:00
if (child->nod_type == nod_constant &&
DTYPE_IS_NUMERIC(child->nod_desc.dsc_dtype))
{
gen_constant(statement, child, NEGATE_VALUE);
2001-05-23 15:26:42 +02:00
return;
}
}
blr_operator = blr_negate;
2001-05-23 15:26:42 +02:00
break;
case nod_divide:
blr_operator = blr_divide;
2001-05-23 15:26:42 +02:00
break;
case nod_add2:
blr_operator = blr_add;
2001-05-23 15:26:42 +02:00
break;
case nod_subtract2:
blr_operator = blr_subtract;
2001-05-23 15:26:42 +02:00
break;
case nod_multiply2:
blr_operator = blr_multiply;
2001-05-23 15:26:42 +02:00
break;
case nod_divide2:
blr_operator = blr_divide;
2001-05-23 15:26:42 +02:00
break;
case nod_concatenate:
blr_operator = blr_concatenate;
2001-05-23 15:26:42 +02:00
break;
case nod_null:
blr_operator = blr_null;
2001-05-23 15:26:42 +02:00
break;
case nod_any:
blr_operator = blr_any;
2001-05-23 15:26:42 +02:00
break;
case nod_ansi_any:
blr_operator = blr_ansi_any;
2001-05-23 15:26:42 +02:00
break;
case nod_ansi_all:
blr_operator = blr_ansi_all;
2001-05-23 15:26:42 +02:00
break;
case nod_via:
blr_operator = blr_via;
2001-05-23 15:26:42 +02:00
break;
case nod_internal_info:
blr_operator = blr_internal_info;
break;
2001-05-23 15:26:42 +02:00
case nod_upcase:
blr_operator = blr_upcase;
2001-05-23 15:26:42 +02:00
break;
2005-05-28 00:45:31 +02:00
case nod_lowcase:
blr_operator = blr_lowcase;
break;
2002-06-29 08:56:51 +02:00
case nod_substr:
blr_operator = blr_substring;
2002-06-29 08:56:51 +02:00
break;
2001-05-23 15:26:42 +02:00
case nod_cast:
gen_cast(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_gen_id:
case nod_gen_id2:
gen_gen_id(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_coalesce:
gen_coalesce(statement, node);
return;
case nod_simple_case:
gen_simple_case(statement, node);
return;
case nod_searched_case:
gen_searched_case(statement, node);
return;
2001-05-23 15:26:42 +02:00
case nod_average:
//case nod_count:
2001-05-23 15:26:42 +02:00
case nod_from:
case nod_max:
case nod_min:
case nod_total:
switch (node->nod_type) {
case nod_average:
blr_operator = blr_average;
2001-05-23 15:26:42 +02:00
break;
//case nod_count:
// blr_operator = blr_count;
// count2
// blr_operator = node->nod_arg[0]->nod_arg[e_rse_items] ? blr_count2 : blr_count;
// break;
2001-05-23 15:26:42 +02:00
case nod_from:
blr_operator = blr_from;
2001-05-23 15:26:42 +02:00
break;
case nod_max:
blr_operator = blr_maximum;
2001-05-23 15:26:42 +02:00
break;
case nod_min:
blr_operator = blr_minimum;
2001-05-23 15:26:42 +02:00
break;
case nod_total:
blr_operator = blr_total;
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
stuff(statement, blr_operator);
gen_rse(statement, node->nod_arg[0]);
if (blr_operator != blr_count)
GEN_expr(statement, node->nod_arg[0]->nod_arg[e_rse_items]);
2001-05-23 15:26:42 +02:00
return;
2005-05-28 00:45:31 +02:00
case nod_trim:
stuff(statement, blr_trim);
stuff(statement, node->nod_arg[e_trim_specification]->getSlong());
2005-05-28 00:45:31 +02:00
if (node->nod_arg[e_trim_characters])
{
stuff(statement, blr_trim_characters);
GEN_expr(statement, node->nod_arg[e_trim_characters]);
2005-05-28 00:45:31 +02:00
}
else
stuff(statement, blr_trim_spaces);
2005-05-28 00:45:31 +02:00
GEN_expr(statement, node->nod_arg[e_trim_value]);
2005-05-28 00:45:31 +02:00
return;
2001-05-23 15:26:42 +02:00
default:
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 901,
isc_arg_gds, isc_dsql_internal_err,
isc_arg_gds, isc_expression_eval_err,
// expression evaluation not supported
isc_arg_end);
2001-05-23 15:26:42 +02:00
}
stuff(statement, blr_operator);
2001-05-23 15:26:42 +02:00
dsql_nod* const* ptr = node->nod_arg;
for (const dsql_nod* const* const end = ptr + node->nod_count;
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
}
2001-05-23 15:26:42 +02:00
/* Check whether the node we just processed is for a dialect 3
operation which gives a different result than the corresponding
operation in dialect 1. If it is, and if the client dialect is 2,
issue a warning about the difference. */
if (node->nod_type == nod_add2 ||
node->nod_type == nod_subtract2 ||
node->nod_type == nod_multiply2 ||
node->nod_type == nod_divide2 ||
node->nod_type == nod_agg_total2 ||
node->nod_type == nod_agg_average2)
{
dsc desc;
const char* s = 0;
2001-05-23 15:26:42 +02:00
char message_buf[8];
MAKE_desc(statement, &desc, node, NULL);
2001-05-23 15:26:42 +02:00
if ((node->nod_flags & NOD_COMP_DIALECT) &&
(statement->req_client_dialect == SQL_DIALECT_V6_TRANSITION))
{
2001-05-23 15:26:42 +02:00
switch (node->nod_type) {
case nod_add2:
s = "add";
break;
case nod_subtract2:
s = "subtract";
break;
case nod_multiply2:
s = "multiply";
break;
case nod_divide2:
s = "divide";
break;
case nod_agg_total2:
s = "sum";
break;
case nod_agg_average2:
s = "avg";
break;
default:
sprintf(message_buf, "blr %d", (int) blr_operator);
2001-05-23 15:26:42 +02:00
s = message_buf;
}
ERRD_post_warning(isc_dsql_dialect_warning_expr,
2003-11-08 00:27:24 +01:00
isc_arg_string, s, isc_arg_end);
2001-05-23 15:26:42 +02:00
}
}
}
/**
GEN_port
@brief Generate a port from a message. Feel free to rearrange the
order of parameters.
@param statement
@param message
**/
void GEN_port(CompiledStatement* statement, dsql_msg* message)
2001-05-23 15:26:42 +02:00
{
2008-02-28 14:48:16 +01:00
thread_db* tdbb = JRD_get_thread_data();
Attachment* att = tdbb->getAttachment();
2001-05-23 15:26:42 +02:00
// if (statement->req_blr_string) {
stuff(statement, blr_message);
stuff(statement, message->msg_number);
stuff_word(statement, message->msg_parameter);
// }
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
dsql_par* parameter;
ULONG offset = 0;
USHORT number = 0;
for (parameter = message->msg_parameters; parameter;
parameter = parameter->par_next)
{
2001-05-23 15:26:42 +02:00
parameter->par_parameter = number++;
2007-07-08 10:43:30 +02:00
const USHORT fromCharSet = parameter->par_desc.getCharSet();
const USHORT toCharSet = (fromCharSet == CS_NONE || fromCharSet == CS_BINARY) ?
fromCharSet : att->att_charset;
if (parameter->par_desc.dsc_dtype <= dtype_any_text &&
att->att_charset != CS_NONE && att->att_charset != CS_BINARY)
2005-05-28 00:45:31 +02:00
{
USHORT adjust = 0;
2005-05-28 00:45:31 +02:00
if (parameter->par_desc.dsc_dtype == dtype_varying)
adjust = sizeof(USHORT);
2005-05-28 00:45:31 +02:00
else if (parameter->par_desc.dsc_dtype == dtype_cstring)
adjust = 1;
parameter->par_desc.dsc_length -= adjust;
2005-05-28 00:45:31 +02:00
USHORT fromCharSetBPC = METD_get_charset_bpc(statement, fromCharSet);
USHORT toCharSetBPC = METD_get_charset_bpc(statement, toCharSet);
2005-05-28 00:45:31 +02:00
INTL_ASSIGN_TTYPE(&parameter->par_desc, INTL_CS_COLL_TO_TTYPE(toCharSet,
(fromCharSet == toCharSet ? INTL_GET_COLLATE(&parameter->par_desc) : 0)));
2005-05-28 00:45:31 +02:00
parameter->par_desc.dsc_length =
UTLD_char_length_to_byte_length(parameter->par_desc.dsc_length / fromCharSetBPC, toCharSetBPC);
2005-05-28 00:45:31 +02:00
parameter->par_desc.dsc_length += adjust;
2005-05-28 00:45:31 +02:00
}
else if (ENCODE_ODS(statement->req_dbb->dbb_ods_version,
statement->req_dbb->dbb_minor_version) >= ODS_11_1 &&
2007-07-08 10:43:30 +02:00
parameter->par_desc.dsc_dtype == dtype_blob &&
parameter->par_desc.dsc_sub_type == isc_blob_text &&
att->att_charset != CS_NONE &&
att->att_charset != CS_BINARY)
{
if (fromCharSet != toCharSet)
parameter->par_desc.setTextType(toCharSet);
}
2005-05-28 00:45:31 +02:00
2001-05-23 15:26:42 +02:00
/* For older clients - generate an error should they try and
access data types which did not exist in the older dialect */
if (statement->req_client_dialect <= SQL_DIALECT_V5)
2001-05-23 15:26:42 +02:00
switch (parameter->par_desc.dsc_dtype) {
/* In V6.0 - older clients, which we distinguish by
their use of SQL DIALECT 0 or 1, are forbidden
from selecting values of new datatypes */
case dtype_sql_date:
case dtype_sql_time:
case dtype_int64:
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
isc_arg_gds, isc_dsql_datatype_err,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) statement->req_client_dialect,
2003-11-08 00:27:24 +01:00
isc_arg_string,
DSC_dtype_tostring(parameter->par_desc.dsc_dtype),
isc_arg_end);
break;
default:
// No special action for other data types
break;
}
const USHORT align = type_alignments[parameter->par_desc.dsc_dtype];
2001-05-23 15:26:42 +02:00
if (align)
offset = FB_ALIGN(offset, align);
parameter->par_desc.dsc_address = (UCHAR*)(IPTR) offset;
offset += parameter->par_desc.dsc_length;
// if (statement->req_blr_string)
gen_descriptor(statement, &parameter->par_desc, false);
2001-05-23 15:26:42 +02:00
}
if (offset > MAX_FORMAT_SIZE) {
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -204,
2006-07-21 06:15:40 +02:00
isc_arg_gds, isc_imp_exc,
isc_arg_gds, isc_blktoobig,
isc_arg_end);
}
message->msg_length = (USHORT) offset;
// Allocate buffer for message
const ULONG new_len = message->msg_length + DOUBLE_ALIGN - 1;
2008-02-28 14:48:16 +01:00
dsql_str* buffer = FB_NEW_RPT(*tdbb->getDefaultPool(), new_len) dsql_str;
2008-03-01 16:08:11 +01:00
message->msg_buffer = (UCHAR *) FB_ALIGN((U_IPTR) buffer->str_data, DOUBLE_ALIGN);
2001-05-23 15:26:42 +02:00
// Relocate parameter descriptors to point direction into message buffer
2001-05-23 15:26:42 +02:00
for (parameter = message->msg_parameters; parameter;
parameter = parameter->par_next)
{
parameter->par_desc.dsc_address = message->msg_buffer +
(IPTR)parameter->par_desc.dsc_address;
}
2001-05-23 15:26:42 +02:00
}
/**
GEN_request
@brief Generate complete blr for a statement.
@param statement
@param node
**/
void GEN_request( CompiledStatement* statement, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
if (statement->req_type == REQ_CREATE_DB ||
statement->req_type == REQ_DDL)
2008-02-28 14:48:16 +01:00
{
DDL_generate(statement, node);
2001-05-23 15:26:42 +02:00
return;
}
if (statement->req_flags & REQ_blr_version4)
stuff(statement, blr_version4);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_version5);
if (statement->req_type == REQ_SAVEPOINT)
{
// Do not generate BEGIN..END block around savepoint statement
// to avoid breaking of savepoint logic
statement->req_send = NULL;
statement->req_receive = NULL;
GEN_statement(statement, node);
}
else
{
stuff(statement, blr_begin);
2001-05-23 15:26:42 +02:00
switch (statement->req_type)
2004-10-26 09:21:47 +02:00
{
2008-01-16 07:52:43 +01:00
case REQ_SELECT:
case REQ_SELECT_UPD:
case REQ_EMBED_SELECT:
gen_select(statement, node);
2008-01-16 07:52:43 +01:00
break;
case REQ_EXEC_BLOCK:
case REQ_SELECT_BLOCK:
GEN_statement(statement, node);
2008-01-16 07:52:43 +01:00
break;
default:
{
dsql_msg* message = statement->req_send;
2008-01-16 07:52:43 +01:00
if (!message->msg_parameter)
statement->req_send = NULL;
2008-01-16 07:52:43 +01:00
else {
GEN_port(statement, message);
stuff(statement, blr_receive);
stuff(statement, message->msg_number);
2008-01-16 07:52:43 +01:00
}
message = statement->req_receive;
2008-01-16 07:52:43 +01:00
if (!message->msg_parameter)
statement->req_receive = NULL;
2008-01-16 07:52:43 +01:00
else
GEN_port(statement, message);
GEN_statement(statement, node);
2001-05-23 15:26:42 +02:00
}
}
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
}
stuff(statement, blr_eoc);
2001-05-23 15:26:42 +02:00
}
/**
GEN_start_transaction
@brief Generate tpb for set transaction. Use blr string of statement.
If a value is not specified, default is not STUFF'ed, let the
engine handle it.
Do not allow an option to be specified more than once.
@param statement
@param tran_node
**/
void GEN_start_transaction( CompiledStatement* statement, const dsql_nod* tran_node)
2001-05-23 15:26:42 +02:00
{
SSHORT count = tran_node->nod_count;
2001-05-23 15:26:42 +02:00
if (!count)
return;
const dsql_nod* node = tran_node->nod_arg[0];
2001-05-23 15:26:42 +02:00
if (!node)
return;
// Find out isolation level - if specified. This is required for
// specifying the correct lock level in reserving clause.
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
USHORT lock_level = isc_tpb_shared;
2001-05-23 15:26:42 +02:00
if (count = node->nod_count) {
while (count--) {
const dsql_nod* ptr = node->nod_arg[count];
2001-05-23 15:26:42 +02:00
2008-06-06 04:25:35 +02:00
if (!ptr || ptr->nod_type != nod_isolation)
2001-05-23 15:26:42 +02:00
continue;
lock_level = (ptr->nod_flags & NOD_CONSISTENCY) ?
2003-11-08 00:27:24 +01:00
isc_tpb_protected : isc_tpb_shared;
2001-05-23 15:26:42 +02:00
}
}
bool sw_access = false, sw_wait = false, sw_isolation = false,
sw_reserve = false, sw_lock_timeout = false;
int misc_flags = 0;
// Stuff some version info.
2001-05-23 15:26:42 +02:00
if (count = node->nod_count)
stuff(statement, isc_tpb_version1);
2001-05-23 15:26:42 +02:00
while (count--)
{
const dsql_nod* ptr = node->nod_arg[count];
2001-05-23 15:26:42 +02:00
if (!ptr)
continue;
switch (ptr->nod_type) {
case nod_access:
if (sw_access)
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_dup_option, isc_arg_end);
2001-05-23 15:26:42 +02:00
sw_access = true;
2001-05-23 15:26:42 +02:00
if (ptr->nod_flags & NOD_READ_ONLY)
stuff(statement, isc_tpb_read);
2001-05-23 15:26:42 +02:00
else
stuff(statement, isc_tpb_write);
2001-05-23 15:26:42 +02:00
break;
case nod_wait:
if (sw_wait)
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_dup_option, isc_arg_end);
2001-05-23 15:26:42 +02:00
sw_wait = true;
2001-05-23 15:26:42 +02:00
if (ptr->nod_flags & NOD_NO_WAIT)
stuff(statement, isc_tpb_nowait);
2001-05-23 15:26:42 +02:00
else
stuff(statement, isc_tpb_wait);
2001-05-23 15:26:42 +02:00
break;
case nod_isolation:
if (sw_isolation)
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_dup_option, isc_arg_end);
2001-05-23 15:26:42 +02:00
sw_isolation = true;
2001-05-23 15:26:42 +02:00
if (ptr->nod_flags & NOD_CONCURRENCY)
stuff(statement, isc_tpb_concurrency);
2001-05-23 15:26:42 +02:00
else if (ptr->nod_flags & NOD_CONSISTENCY)
stuff(statement, isc_tpb_consistency);
2001-05-23 15:26:42 +02:00
else {
stuff(statement, isc_tpb_read_committed);
2001-05-23 15:26:42 +02:00
if ((ptr->nod_count) && (ptr->nod_arg[0]) &&
2004-10-26 09:21:47 +02:00
(ptr->nod_arg[0]->nod_type == nod_version))
{
2001-05-23 15:26:42 +02:00
if (ptr->nod_arg[0]->nod_flags & NOD_VERSION)
stuff(statement, isc_tpb_rec_version);
2001-05-23 15:26:42 +02:00
else
stuff(statement, isc_tpb_no_rec_version);
2001-05-23 15:26:42 +02:00
}
else
stuff(statement, isc_tpb_no_rec_version);
2001-05-23 15:26:42 +02:00
}
break;
case nod_reserve:
{
if (sw_reserve)
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_dup_option, isc_arg_end);
sw_reserve = true;
const dsql_nod* reserve = ptr->nod_arg[0];
if (reserve) {
const dsql_nod* const* temp = reserve->nod_arg;
for (const dsql_nod* const* end = temp + reserve->nod_count;
temp < end; temp++)
{
gen_table_lock(statement, *temp, lock_level);
}
}
break;
}
case nod_tra_misc:
if (misc_flags & ptr->nod_flags)
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_dup_option, isc_arg_end);
misc_flags |= ptr->nod_flags;
if (ptr->nod_flags & NOD_NO_AUTO_UNDO)
stuff(statement, isc_tpb_no_auto_undo);
else if (ptr->nod_flags & NOD_IGNORE_LIMBO)
stuff(statement, isc_tpb_ignore_limbo);
else if (ptr->nod_flags & NOD_RESTART_REQUESTS)
stuff(statement, isc_tpb_restart_requests);
break;
case nod_lock_timeout:
if (sw_lock_timeout)
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_dup_option, isc_arg_end);
sw_lock_timeout = true;
if (ptr->nod_count == 1 && ptr->nod_arg[0]->nod_type == nod_constant)
{
const int lck_timeout = (int) ptr->nod_arg[0]->getSlong();
stuff(statement, isc_tpb_lock_timeout);
stuff(statement, 2);
stuff_word(statement, lck_timeout);
}
break;
2001-05-23 15:26:42 +02:00
default:
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_dsql_tran_err, isc_arg_end);
2001-05-23 15:26:42 +02:00
}
}
}
/**
GEN_statement
@brief Generate blr for an arbitrary expression.
@param statement
@param node
**/
void GEN_statement( CompiledStatement* statement, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
dsql_nod* temp;
dsql_nod** ptr;
const dsql_nod* const* end;
2003-11-10 10:16:38 +01:00
dsql_str* string;
2001-05-23 15:26:42 +02:00
switch (node->nod_type) {
case nod_assign:
stuff(statement, blr_assignment);
GEN_expr(statement, node->nod_arg[0]);
GEN_expr(statement, node->nod_arg[1]);
2001-05-23 15:26:42 +02:00
return;
case nod_block:
stuff(statement, blr_block);
GEN_statement(statement, node->nod_arg[e_blk_action]);
2001-05-23 15:26:42 +02:00
if (node->nod_count > 1) {
temp = node->nod_arg[e_blk_errs];
for (ptr = temp->nod_arg, end = ptr + temp->nod_count;
ptr < end; ptr++)
{
GEN_statement(statement, *ptr);
}
2001-05-23 15:26:42 +02:00
}
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
return;
case nod_exec_block:
DDL_gen_block(statement, node);
return;
case nod_class_node:
reinterpret_cast<StmtNode*>(node->nod_arg[0])->genBlr();
2008-01-16 07:52:43 +01:00
return;
2001-05-23 15:26:42 +02:00
case nod_for_select:
gen_for_select(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_set_generator:
case nod_set_generator2:
stuff(statement, blr_set_generator);
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[e_gen_id_name];
stuff_cstring(statement, string->str_data);
GEN_expr(statement, node->nod_arg[e_gen_id_value]);
2001-05-23 15:26:42 +02:00
return;
case nod_if:
stuff(statement, blr_if);
GEN_expr(statement, node->nod_arg[e_if_condition]);
GEN_statement(statement, node->nod_arg[e_if_true]);
2001-05-23 15:26:42 +02:00
if (node->nod_arg[e_if_false])
GEN_statement(statement, node->nod_arg[e_if_false]);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
return;
case nod_list:
stuff(statement, blr_begin);
2001-05-23 15:26:42 +02:00
for (ptr = node->nod_arg, end = ptr + node->nod_count; ptr < end;
ptr++)
{
GEN_statement(statement, *ptr);
}
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
return;
case nod_erase:
case nod_erase_current:
2001-05-23 15:26:42 +02:00
case nod_modify:
case nod_modify_current:
case nod_store:
case nod_exec_procedure:
gen_statement(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_on_error:
stuff(statement, blr_error_handler);
2001-05-23 15:26:42 +02:00
temp = node->nod_arg[e_err_errs];
stuff_word(statement, temp->nod_count);
2001-05-23 15:26:42 +02:00
for (ptr = temp->nod_arg, end = ptr + temp->nod_count; ptr < end;
ptr++)
{
gen_error_condition(statement, *ptr);
}
GEN_statement(statement, node->nod_arg[e_err_action]);
2001-05-23 15:26:42 +02:00
return;
case nod_post:
if ( (temp = node->nod_arg[e_pst_argument]) ) {
stuff(statement, blr_post_arg);
GEN_expr(statement, node->nod_arg[e_pst_event]);
GEN_expr(statement, temp);
}
else {
stuff(statement, blr_post);
GEN_expr(statement, node->nod_arg[e_pst_event]);
}
2001-05-23 15:26:42 +02:00
return;
2002-04-04 15:53:20 +02:00
case nod_exec_sql:
stuff(statement, blr_exec_sql);
GEN_expr(statement, node->nod_arg[e_exec_sql_stmnt]);
return;
case nod_exec_into:
if (node->nod_arg[e_exec_into_block]) {
stuff(statement, blr_label);
stuff(statement, (int) (IPTR) node->nod_arg[e_exec_into_label]->nod_arg[e_label_number]);
}
stuff(statement, blr_exec_into);
temp = node->nod_arg[e_exec_into_list];
stuff_word(statement, temp->nod_count);
GEN_expr(statement, node->nod_arg[e_exec_into_stmnt]);
if (node->nod_arg[e_exec_into_block]) {
stuff(statement, 0); // Non-singleton
GEN_statement(statement, node->nod_arg[e_exec_into_block]);
}
else
stuff(statement, 1); // Singleton
for (ptr = temp->nod_arg, end = ptr + temp->nod_count;
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
}
2002-04-04 15:53:20 +02:00
return;
case nod_exec_stmt:
gen_exec_stmt(statement, node);
return;
2002-04-04 15:53:20 +02:00
2001-05-23 15:26:42 +02:00
case nod_return:
2005-06-13 14:45:42 +02:00
if ( (temp = node->nod_arg[e_rtn_procedure]) )
{
if (temp->nod_type == nod_exec_block)
GEN_return(statement, temp->nod_arg[e_exe_blk_outputs], false);
else
GEN_return(statement, temp->nod_arg[e_prc_outputs], false);
}
2001-05-23 15:26:42 +02:00
return;
case nod_exit:
stuff(statement, blr_leave);
stuff(statement, 0);
2001-05-23 15:26:42 +02:00
return;
2006-06-02 10:03:22 +02:00
case nod_breakleave:
stuff(statement, blr_leave);
stuff(statement, (int) (IPTR) node->nod_arg[e_breakleave_label]->nod_arg[e_label_number]);
2006-06-02 10:03:22 +02:00
return;
2001-05-23 15:26:42 +02:00
case nod_abort:
stuff(statement, blr_leave);
stuff(statement, (int) (IPTR) node->nod_arg[e_abrt_number]);
2001-05-23 15:26:42 +02:00
return;
case nod_start_savepoint:
stuff(statement, blr_start_savepoint);
2001-05-23 15:26:42 +02:00
return;
case nod_end_savepoint:
stuff(statement, blr_end_savepoint);
2001-05-23 15:26:42 +02:00
return;
case nod_user_savepoint:
stuff(statement, blr_user_savepoint);
stuff(statement, blr_savepoint_set);
stuff_cstring(statement, ((dsql_str*)node->nod_arg[e_sav_name])->str_data);
return;
case nod_release_savepoint:
stuff(statement, blr_user_savepoint);
if (node->nod_arg[1]) {
stuff(statement, blr_savepoint_release_single);
}
else {
stuff(statement, blr_savepoint_release);
}
stuff_cstring(statement, ((dsql_str*)node->nod_arg[e_sav_name])->str_data);
return;
case nod_undo_savepoint:
stuff(statement, blr_user_savepoint);
stuff(statement, blr_savepoint_undo);
stuff_cstring(statement, ((dsql_str*)node->nod_arg[e_sav_name])->str_data);
return;
2001-05-23 15:26:42 +02:00
case nod_exception_stmt:
stuff(statement, blr_abort);
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[e_xcps_name];
2003-10-01 20:11:23 +02:00
temp = node->nod_arg[e_xcps_msg];
/* if exception name is undefined,
it means we have re-initiate semantics here,
so blr_raise verb should be generated */
if (!string)
{
stuff(statement, blr_raise);
return;
}
/* if exception value is defined,
it means we have user-defined exception message here,
so blr_exception_msg verb should be generated */
if (temp)
{
stuff(statement, blr_exception_msg);
}
/* otherwise go usual way,
i.e. generate blr_exception */
else
{
stuff(statement, blr_exception);
}
if (!string->delimited_id)
{
ULONG id_length = string->str_length;
for (TEXT* p = string->str_data; *p && id_length; ++p, --id_length)
{
2001-05-23 15:26:42 +02:00
*p = UPPER(*p);
}
}
stuff_cstring(statement, string->str_data);
/* if exception value is defined,
generate appropriate BLR verbs */
if (temp)
{
GEN_expr(statement, temp);
}
2001-05-23 15:26:42 +02:00
return;
case nod_while:
stuff(statement, blr_label);
stuff(statement, (int) (IPTR) node->nod_arg[e_while_label]->nod_arg[e_label_number]);
stuff(statement, blr_loop);
stuff(statement, blr_begin);
stuff(statement, blr_if);
GEN_expr(statement, node->nod_arg[e_while_cond]);
GEN_statement(statement, node->nod_arg[e_while_action]);
stuff(statement, blr_leave);
stuff(statement, (int) (IPTR) node->nod_arg[e_while_label]->nod_arg[e_label_number]);
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
return;
case nod_sqlcode:
case nod_gdscode:
stuff(statement, blr_abort);
gen_error_condition(statement, node);
2001-05-23 15:26:42 +02:00
return;
case nod_cursor:
stuff(statement, blr_dcl_cursor);
stuff_word(statement, (int) (IPTR) node->nod_arg[e_cur_number]);
GEN_expr(statement, node->nod_arg[e_cur_rse]);
temp = node->nod_arg[e_cur_rse]->nod_arg[e_rse_items];
stuff_word(statement, temp->nod_count);
ptr = temp->nod_arg;
end = ptr + temp->nod_count;
while (ptr < end) {
GEN_expr(statement, *ptr++);
}
return;
case nod_cursor_open:
case nod_cursor_close:
case nod_cursor_fetch:
{
// op-code
stuff(statement, blr_cursor_stmt);
if (node->nod_type == nod_cursor_open)
stuff(statement, blr_cursor_open);
else if (node->nod_type == nod_cursor_close)
stuff(statement, blr_cursor_close);
else
stuff(statement, blr_cursor_fetch);
// cursor reference
dsql_nod* cursor = node->nod_arg[e_cur_stmt_id];
stuff_word(statement, (int) (IPTR) cursor->nod_arg[e_cur_number]);
// preliminary navigation
dsql_nod* seek = node->nod_arg[e_cur_stmt_seek];
if (seek) {
stuff(statement, blr_seek);
GEN_expr(statement, seek->nod_arg[0]);
GEN_expr(statement, seek->nod_arg[1]);
}
// assignment
dsql_nod* list_into = node->nod_arg[e_cur_stmt_into];
if (list_into) {
dsql_nod* list = cursor->nod_arg[e_cur_rse]->nod_arg[e_rse_items];
if (list->nod_count != list_into->nod_count)
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 313,
isc_arg_gds, isc_dsql_count_mismatch, isc_arg_end);
stuff(statement, blr_begin);
ptr = list->nod_arg;
end = ptr + list->nod_count;
dsql_nod** ptr_to = list_into->nod_arg;
while (ptr < end) {
stuff(statement, blr_assignment);
GEN_expr(statement, *ptr++);
GEN_expr(statement, *ptr_to++);
}
stuff(statement, blr_end);
}
}
return;
case nod_src_info:
statement->put_debug_src_info(node->nod_line, node->nod_column);
GEN_statement(statement, node->nod_arg[e_src_info_stmt]);
return;
2001-05-23 15:26:42 +02:00
default:
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 901,
isc_arg_gds, isc_dsql_internal_err,
isc_arg_gds, isc_node_err, // gen.c: node not supported
isc_arg_end);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_aggregate
@brief Generate blr for a relation reference.
@param
@param
**/
static void gen_aggregate( CompiledStatement* statement, const dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
const dsql_ctx* context = (dsql_ctx*) node->nod_arg[e_agg_context];
stuff(statement, blr_aggregate);
stuff_context(statement, context);
gen_rse(statement, node->nod_arg[e_agg_rse]);
2001-05-23 15:26:42 +02:00
// Handle GROUP BY clause
2001-05-23 15:26:42 +02:00
stuff(statement, blr_group_by);
2001-05-23 15:26:42 +02:00
dsql_nod* list = node->nod_arg[e_agg_group];
if (list != NULL) {
stuff(statement, list->nod_count);
dsql_nod** ptr = list->nod_arg;
for (const dsql_nod* const* end = ptr + list->nod_count; ptr < end;
2001-05-23 15:26:42 +02:00
ptr++)
{
GEN_expr(statement, *ptr);
}
2001-05-23 15:26:42 +02:00
}
else
stuff(statement, 0);
2001-05-23 15:26:42 +02:00
// Generate value map
2001-05-23 15:26:42 +02:00
gen_map(statement, context->ctx_map);
2001-05-23 15:26:42 +02:00
}
/**
gen_cast
@brief Generate BLR for a data-type cast operation
@param statement
@param node
**/
static void gen_cast( CompiledStatement* statement, const dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
stuff(statement, blr_cast);
const dsql_fld* field = (dsql_fld*) node->nod_arg[e_cast_target];
DDL_put_field_dtype(statement, field, true);
GEN_expr(statement, node->nod_arg[e_cast_source]);
2001-05-23 15:26:42 +02:00
}
/**
gen_coalesce
@brief Generate BLR for coalesce function
Generate the blr values, begin with a cast and then :
blr_value_if
blr_missing
blr for expression 1
blr_value_if
blr_missing
blr for expression n-1
expression n
blr for expression n-1
@param statement
@param node
**/
static void gen_coalesce( CompiledStatement* statement, const dsql_nod* node)
{
// blr_value_if is used for building the coalesce function
dsql_nod* list = node->nod_arg[0];
stuff(statement, blr_cast);
gen_descriptor(statement, &node->nod_desc, true);
dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + (list->nod_count - 1);
ptr < end; ptr++)
{
// IF (expression IS NULL) THEN
stuff(statement, blr_value_if);
stuff(statement, blr_missing);
GEN_expr(statement, *ptr);
}
// Return values
list = node->nod_arg[1];
const dsql_nod* const* const begin = list->nod_arg;
ptr = list->nod_arg + list->nod_count;
// if all expressions are NULL return NULL
for (ptr--; ptr >= begin; ptr--)
{
GEN_expr(statement, *ptr);
}
}
/**
gen_constant
@brief Generate BLR for a constant.
@param statement
@param desc
@param negate_value
**/
static void gen_constant( CompiledStatement* statement, const dsc* desc, bool negate_value)
2001-05-23 15:26:42 +02:00
{
SLONG value;
SINT64 i64value;
DSC tmp_desc;
stuff(statement, blr_literal);
2001-05-23 15:26:42 +02:00
const UCHAR* p = desc->dsc_address;
2001-05-23 15:26:42 +02:00
switch (desc->dsc_dtype) {
case dtype_short:
gen_descriptor(statement, desc, true);
2001-05-23 15:26:42 +02:00
value = *(SSHORT *) p;
if (negate_value)
value = -value;
stuff_word(statement, value);
2001-05-23 15:26:42 +02:00
break;
case dtype_long:
gen_descriptor(statement, desc, true);
2001-05-23 15:26:42 +02:00
value = *(SLONG *) p;
if (negate_value)
value = -value;
//printf("gen.cpp = %p %d\n", *((void**)p), value);
stuff_word(statement, value);
stuff_word(statement, value >> 16);
2001-05-23 15:26:42 +02:00
break;
case dtype_sql_time:
case dtype_sql_date:
gen_descriptor(statement, desc, true);
2001-05-23 15:26:42 +02:00
value = *(SLONG *) p;
stuff_word(statement, value);
stuff_word(statement, value >> 16);
2001-05-23 15:26:42 +02:00
break;
case dtype_double:
{
/* this is used for approximate/large numeric literal
which is transmitted to the engine as a string.
*/
gen_descriptor(statement, desc, true);
// Length of string literal, cast because it could be > 127 bytes.
2008-05-28 04:11:00 +02:00
const USHORT l = (USHORT)(UCHAR) desc->dsc_scale;
if (negate_value) {
stuff_word(statement, l + 1);
stuff(statement, '-');
}
else {
stuff_word(statement, l);
}
2001-05-23 15:26:42 +02:00
if (l)
statement->append_raw_string(p, l);
}
2001-05-23 15:26:42 +02:00
break;
case dtype_int64:
i64value = *(SINT64 *) p;
if (negate_value)
i64value = -i64value;
else if (i64value == MIN_SINT64) {
/* UH OH!
* yylex correctly recognized the digits as the most-negative
* possible INT64 value, but unfortunately, there was no
* preceding '-' (a fact which the lexer could not know).
* The value is too big for a positive INT64 value, and it
* didn't contain an exponent so it's not a valid DOUBLE
* PRECISION literal either, so we have to bounce it.
*/
ERRD_post(isc_sqlerr,
2003-11-08 00:27:24 +01:00
isc_arg_number, (SLONG) - 104,
isc_arg_gds, isc_arith_except,
isc_arg_gds, isc_numeric_out_of_range,
isc_arg_end);
2001-05-23 15:26:42 +02:00
}
/* We and the lexer both agree that this is an SINT64 constant,
* and if the value needed to be negated, it already has been.
* If the value will fit into a 32-bit signed integer, generate
* it that way, else as an INT64.
*/
if ((i64value >= (SINT64) MIN_SLONG) &&
(i64value <= (SINT64) MAX_SLONG))
{
stuff(statement, blr_long);
stuff(statement, desc->dsc_scale);
stuff_word(statement, i64value);
stuff_word(statement, i64value >> 16);
2001-05-23 15:26:42 +02:00
break;
}
else {
stuff(statement, blr_int64);
stuff(statement, desc->dsc_scale);
stuff_word(statement, i64value);
stuff_word(statement, i64value >> 16);
stuff_word(statement, i64value >> 32);
stuff_word(statement, i64value >> 48);
2001-05-23 15:26:42 +02:00
}
break;
case dtype_quad:
case dtype_blob:
case dtype_array:
case dtype_timestamp:
gen_descriptor(statement, desc, true);
2001-05-23 15:26:42 +02:00
value = *(SLONG *) p;
stuff_word(statement, value);
stuff_word(statement, value >> 16);
2001-05-23 15:26:42 +02:00
value = *(SLONG *) (p + 4);
stuff_word(statement, value);
stuff_word(statement, value >> 16);
2001-05-23 15:26:42 +02:00
break;
case dtype_text:
{
const USHORT length = desc->dsc_length;
gen_descriptor(statement, desc, true);
if (length)
statement->append_raw_string(p, length);
}
break;
2001-05-23 15:26:42 +02:00
default:
// gen_constant: datatype not understood
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 103,
isc_arg_gds, isc_dsql_constant_err, isc_arg_end);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_constant
@brief Generate BLR for a constant.
@param statement
@param node
@param negate_value
**/
static void gen_constant( CompiledStatement* statement, dsql_nod* node, bool negate_value)
{
if (node->nod_desc.dsc_dtype == dtype_text)
node->nod_desc.dsc_length = ((dsql_str*) node->nod_arg[0])->str_length;
gen_constant(statement, &node->nod_desc, negate_value);
}
/**
gen_descriptor
@brief Generate a blr descriptor from an internal descriptor.
@param statement
@param desc
@param texttype
**/
static void gen_descriptor( CompiledStatement* statement, const dsc* desc, bool texttype)
2001-05-23 15:26:42 +02:00
{
switch (desc->dsc_dtype) {
case dtype_text:
if (texttype || desc->dsc_ttype() == ttype_binary || desc->dsc_ttype() == ttype_none) {
stuff(statement, blr_text2);
stuff_word(statement, desc->dsc_ttype());
2001-05-23 15:26:42 +02:00
}
else {
stuff(statement, blr_text2); // automatic transliteration
stuff_word(statement, ttype_dynamic);
2001-05-23 15:26:42 +02:00
}
stuff_word(statement, desc->dsc_length);
2001-05-23 15:26:42 +02:00
break;
case dtype_varying:
if (texttype || desc->dsc_ttype() == ttype_binary || desc->dsc_ttype() == ttype_none) {
stuff(statement, blr_varying2);
stuff_word(statement, desc->dsc_ttype());
2001-05-23 15:26:42 +02:00
}
else {
stuff(statement, blr_varying2); // automatic transliteration
stuff_word(statement, ttype_dynamic);
2001-05-23 15:26:42 +02:00
}
stuff_word(statement, desc->dsc_length - sizeof(USHORT));
2001-05-23 15:26:42 +02:00
break;
case dtype_short:
stuff(statement, blr_short);
stuff(statement, desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_long:
stuff(statement, blr_long);
stuff(statement, desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_quad:
stuff(statement, blr_quad);
stuff(statement, desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_int64:
stuff(statement, blr_int64);
stuff(statement, desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_real:
stuff(statement, blr_float);
2001-05-23 15:26:42 +02:00
break;
case dtype_double:
stuff(statement, blr_double);
2001-05-23 15:26:42 +02:00
break;
case dtype_sql_date:
stuff(statement, blr_sql_date);
2001-05-23 15:26:42 +02:00
break;
case dtype_sql_time:
stuff(statement, blr_sql_time);
2001-05-23 15:26:42 +02:00
break;
case dtype_timestamp:
stuff(statement, blr_timestamp);
2001-05-23 15:26:42 +02:00
break;
case dtype_array:
stuff(statement, blr_quad);
stuff(statement, 0);
2001-05-23 15:26:42 +02:00
break;
case dtype_blob:
stuff(statement, blr_blob2);
stuff_word(statement, desc->dsc_sub_type);
stuff_word(statement, desc->getTextType());
break;
2001-05-23 15:26:42 +02:00
default:
// don't understand dtype
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
isc_arg_gds, isc_dsql_datatype_err, isc_arg_end);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_error_condition
@brief Generate blr for an error condtion
@param statement
@param node
**/
static void gen_error_condition( CompiledStatement* statement, const dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
2003-11-10 10:16:38 +01:00
const dsql_str* string;
2001-05-23 15:26:42 +02:00
switch (node->nod_type) {
case nod_sqlcode:
stuff(statement, blr_sql_code);
stuff_word(statement, (USHORT)(IPTR) node->nod_arg[0]);
2001-05-23 15:26:42 +02:00
return;
case nod_gdscode:
stuff(statement, blr_gds_code);
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
stuff_cstring(statement, string->str_data);
2001-05-23 15:26:42 +02:00
return;
case nod_exception:
stuff(statement, blr_exception);
2003-11-10 10:16:38 +01:00
string = (dsql_str*) node->nod_arg[0];
stuff_cstring(statement, string->str_data);
2001-05-23 15:26:42 +02:00
return;
case nod_default:
stuff(statement, blr_default_code);
2001-05-23 15:26:42 +02:00
return;
default:
2003-11-04 00:59:24 +01:00
fb_assert(false);
2001-05-23 15:26:42 +02:00
return;
}
}
/**
gen_exec_stmt
@brief Generate blr for the EXECUTE STATEMENT clause
@param statement
@param node
**/
static void gen_exec_stmt(CompiledStatement* statement, const dsql_nod* node)
{
if (node->nod_arg[e_exec_stmt_proc_block])
{
stuff(statement, blr_label);
stuff(statement, (int)(IPTR) node->nod_arg[e_exec_stmt_label]->nod_arg[e_label_number]);
}
stuff(statement, blr_exec_stmt);
// counts of input and output parameters
2008-06-13 03:42:58 +02:00
const dsql_nod* temp = node->nod_arg[e_exec_stmt_inputs];
if (temp)
{
stuff(statement, blr_exec_stmt_inputs);
stuff_word(statement, temp->nod_count);
}
temp = node->nod_arg[e_exec_stmt_outputs];
if (temp)
{
stuff(statement, blr_exec_stmt_outputs);
stuff_word(statement, temp->nod_count);
}
// query expression
stuff(statement, blr_exec_stmt_sql);
GEN_expr(statement, node->nod_arg[e_exec_stmt_sql]);
// proc block body
dsql_nod* temp2 = node->nod_arg[e_exec_stmt_proc_block];
if (temp2)
{
stuff(statement, blr_exec_stmt_proc_block);
GEN_statement(statement, temp2);
}
// external data source, user and password
gen_optional_expr(statement, blr_exec_stmt_data_src, node->nod_arg[e_exec_stmt_data_src]);
gen_optional_expr(statement, blr_exec_stmt_user, node->nod_arg[e_exec_stmt_user]);
gen_optional_expr(statement, blr_exec_stmt_pwd, node->nod_arg[e_exec_stmt_pwd]);
// statement's transaction behavior
temp = node->nod_arg[e_exec_stmt_tran];
if (temp)
{
stuff(statement, blr_exec_stmt_tran_clone); // transaction parameters equal to current transaction
stuff(statement, (UCHAR)(IPTR) temp->nod_flags);
}
// inherit caller's privileges ?
if (node->nod_arg[e_exec_stmt_privs]) {
stuff(statement, blr_exec_stmt_privs);
}
// inputs
temp = node->nod_arg[e_exec_stmt_inputs];
if (temp)
{
const dsql_nod* const* ptr = temp->nod_arg;
const bool haveNames = ((*ptr)->nod_arg[e_named_param_name] != 0);
if (haveNames)
stuff(statement, blr_exec_stmt_in_params2);
else
stuff(statement, blr_exec_stmt_in_params);
for (const dsql_nod* const* end = ptr + temp->nod_count; ptr < end; ptr++)
{
if (haveNames)
{
const dsql_str* name = (dsql_str*) (*ptr)->nod_arg[e_named_param_name];
stuff_cstring(statement, name->str_data);
}
GEN_expr(statement, (*ptr)->nod_arg[e_named_param_expr]);
}
}
// outputs
temp = node->nod_arg[e_exec_stmt_outputs];
if (temp)
{
stuff(statement, blr_exec_stmt_out_params);
for (size_t i = 0; i < temp->nod_count; ++i) {
GEN_expr(statement, temp->nod_arg[i]);
}
}
stuff(statement, blr_end);
}
/**
gen_field
@brief Generate blr for a field - field id's
are preferred but not for trigger or view blr.
@param statement
@param context
@param field
@param indices
**/
static void gen_field( CompiledStatement* statement, const dsql_ctx* context,
const dsql_fld* field, dsql_nod* indices)
2001-05-23 15:26:42 +02:00
{
/* For older clients - generate an error should they try and
* access data types which did not exist in the older dialect */
if (statement->req_client_dialect <= SQL_DIALECT_V5) {
2001-05-23 15:26:42 +02:00
switch (field->fld_dtype) {
case dtype_sql_date:
case dtype_sql_time:
case dtype_int64:
2003-11-08 00:27:24 +01:00
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 804,
isc_arg_gds, isc_dsql_datatype_err,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) statement->req_client_dialect,
2003-11-08 00:27:24 +01:00
isc_arg_string,
2008-07-01 03:12:02 +02:00
DSC_dtype_tostring(static_cast<UCHAR>(field->fld_dtype)),
isc_arg_end);
2001-05-23 15:26:42 +02:00
break;
default:
// No special action for other data types
2001-05-23 15:26:42 +02:00
break;
}
}
if (indices)
stuff(statement, blr_index);
2001-05-23 15:26:42 +02:00
if (DDL_ids(statement)) {
stuff(statement, blr_fid);
stuff_context(statement, context);
stuff_word(statement, field->fld_id);
2001-05-23 15:26:42 +02:00
}
else {
stuff(statement, blr_field);
stuff_context(statement, context);
stuff_string(statement, field->fld_name);
2001-05-23 15:26:42 +02:00
}
if (indices) {
stuff(statement, indices->nod_count);
dsql_nod** ptr = indices->nod_arg;
for (const dsql_nod* const* end = ptr + indices->nod_count;
2001-05-23 15:26:42 +02:00
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
}
2001-05-23 15:26:42 +02:00
}
}
/**
gen_for_select
@brief Generate BLR for a SELECT statement.
@param statement
@param for_select
**/
static void gen_for_select( CompiledStatement* statement, const dsql_nod* for_select)
2001-05-23 15:26:42 +02:00
{
dsql_nod* rse = for_select->nod_arg[e_flp_select];
2001-05-23 15:26:42 +02:00
2006-06-02 10:03:22 +02:00
// CVC: Only put a label if this is not singular; otherwise,
// what loop is the user trying to abandon?
if (for_select->nod_arg[e_flp_action]) {
stuff(statement, blr_label);
stuff(statement, (int) (IPTR) for_select->nod_arg[e_flp_label]->nod_arg[e_label_number]);
2006-06-02 10:03:22 +02:00
}
2002-06-29 08:56:51 +02:00
// Generate FOR loop
2001-05-23 15:26:42 +02:00
stuff(statement, blr_for);
2001-05-23 15:26:42 +02:00
if (!for_select->nod_arg[e_flp_action])
2003-10-01 20:11:23 +02:00
{
stuff(statement, blr_singular);
2003-10-01 20:11:23 +02:00
}
gen_rse(statement, rse);
stuff(statement, blr_begin);
2001-05-23 15:26:42 +02:00
// Build body of FOR loop
2001-05-23 15:26:42 +02:00
// Handle write locks
dsql_nod* streams = rse->nod_arg[e_rse_streams];
dsql_ctx* context = NULL;
if (!rse->nod_arg[e_rse_reduced] && streams->nod_count == 1) {
dsql_nod* item = streams->nod_arg[0];
if (item && (item->nod_type == nod_relation))
context = (dsql_ctx*) item->nod_arg[e_rel_context];
}
dsql_nod* list = rse->nod_arg[e_rse_items];
dsql_nod* list_to = for_select->nod_arg[e_flp_into];
2006-09-14 04:05:32 +02:00
if (list_to)
{
2006-09-14 04:05:32 +02:00
if (list->nod_count != list_to->nod_count)
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) - 313,
isc_arg_gds, isc_dsql_count_mismatch, isc_arg_end);
2006-09-14 04:05:32 +02:00
dsql_nod** ptr = list->nod_arg;
dsql_nod** ptr_to = list_to->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end;
ptr++, ptr_to++)
{
stuff(statement, blr_assignment);
GEN_expr(statement, *ptr);
GEN_expr(statement, *ptr_to);
2006-09-14 04:05:32 +02:00
}
2001-05-23 15:26:42 +02:00
}
2006-09-14 04:05:32 +02:00
2001-05-23 15:26:42 +02:00
if (for_select->nod_arg[e_flp_action])
GEN_statement(statement, for_select->nod_arg[e_flp_action]);
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
}
/**
gen_gen_id
@brief Generate BLR for gen_id
@param statement
@param node
**/
static void gen_gen_id( CompiledStatement* statement, const dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
stuff(statement, blr_gen_id);
2003-11-10 10:16:38 +01:00
const dsql_str* string = (dsql_str*) node->nod_arg[e_gen_id_name];
stuff_cstring(statement, string->str_data);
GEN_expr(statement, node->nod_arg[e_gen_id_value]);
2001-05-23 15:26:42 +02:00
}
/**
gen_join_rse
@brief Generate a record selection expression
with an explicit join type.
@param statement
@param rse
**/
static void gen_join_rse( CompiledStatement* statement, const dsql_nod* rse)
2001-05-23 15:26:42 +02:00
{
stuff(statement, blr_rs_stream);
stuff(statement, 2);
2001-05-23 15:26:42 +02:00
GEN_expr(statement, rse->nod_arg[e_join_left_rel]);
GEN_expr(statement, rse->nod_arg[e_join_rght_rel]);
2001-05-23 15:26:42 +02:00
const dsql_nod* node = rse->nod_arg[e_join_type];
2001-05-23 15:26:42 +02:00
if (node->nod_type != nod_join_inner) {
stuff(statement, blr_join_type);
2001-05-23 15:26:42 +02:00
if (node->nod_type == nod_join_left)
stuff(statement, blr_left);
2001-05-23 15:26:42 +02:00
else if (node->nod_type == nod_join_right)
stuff(statement, blr_right);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_full);
2001-05-23 15:26:42 +02:00
}
if (rse->nod_arg[e_join_boolean])
{
stuff(statement, blr_boolean);
GEN_expr(statement, rse->nod_arg[e_join_boolean]);
}
2001-05-23 15:26:42 +02:00
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
}
/**
gen_map
@brief Generate a value map for a record selection expression.
@param statement
@param map
**/
static void gen_map( CompiledStatement* statement, dsql_map* map)
2001-05-23 15:26:42 +02:00
{
USHORT count = 0;
dsql_map* temp;
2001-05-23 15:26:42 +02:00
for (temp = map; temp; temp = temp->map_next)
temp->map_position = count++;
stuff(statement, blr_map);
stuff_word(statement, count);
2001-05-23 15:26:42 +02:00
for (temp = map; temp; temp = temp->map_next) {
stuff_word(statement, temp->map_position);
GEN_expr(statement, temp->map_node);
2001-05-23 15:26:42 +02:00
}
}
static void gen_optional_expr(CompiledStatement* statement, const UCHAR code, dsql_nod* node)
{
if (node)
{
stuff(statement, code);
GEN_expr(statement, node);
}
}
2001-05-23 15:26:42 +02:00
/**
gen_parameter
@brief Generate a parameter reference.
@param statement
@param parameter
**/
static void gen_parameter( CompiledStatement* statement, const dsql_par* parameter)
2001-05-23 15:26:42 +02:00
{
const dsql_msg* message = parameter->par_message;
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
const dsql_par* null = parameter->par_null;
if (null != NULL) {
stuff(statement, blr_parameter2);
stuff(statement, message->msg_number);
stuff_word(statement, parameter->par_parameter);
stuff_word(statement, null->par_parameter);
2001-05-23 15:26:42 +02:00
return;
}
stuff(statement, blr_parameter);
stuff(statement, message->msg_number);
stuff_word(statement, parameter->par_parameter);
2001-05-23 15:26:42 +02:00
}
/**
gen_plan
@brief Generate blr for an access plan expression.
@param statement
@param plan_expression
**/
static void gen_plan( CompiledStatement* statement, const dsql_nod* plan_expression)
2001-05-23 15:26:42 +02:00
{
// stuff the join type
2001-05-23 15:26:42 +02:00
const dsql_nod* list = plan_expression->nod_arg[1];
2001-05-23 15:26:42 +02:00
if (list->nod_count > 1) {
if (plan_expression->nod_arg[0])
stuff(statement, blr_merge);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_join);
stuff(statement, list->nod_count);
2001-05-23 15:26:42 +02:00
}
// stuff one or more plan items
2001-05-23 15:26:42 +02:00
const dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end;
ptr++)
{
const dsql_nod* node = *ptr;
2001-05-23 15:26:42 +02:00
if (node->nod_type == nod_plan_expr) {
gen_plan(statement, node);
2001-05-23 15:26:42 +02:00
continue;
}
// if we're here, it must be a nod_plan_item
2001-05-23 15:26:42 +02:00
stuff(statement, blr_retrieve);
2001-05-23 15:26:42 +02:00
/* stuff the relation--the relation id itself is redundant except
when there is a need to differentiate the base tables of views */
const dsql_nod* arg = node->nod_arg[0];
gen_relation(statement, (dsql_ctx*) arg->nod_arg[e_rel_context]);
2001-05-23 15:26:42 +02:00
// now stuff the access method for this stream
2003-11-10 10:16:38 +01:00
const dsql_str* index_string;
2001-05-23 15:26:42 +02:00
arg = node->nod_arg[1];
switch (arg->nod_type) {
case nod_natural:
stuff(statement, blr_sequential);
2001-05-23 15:26:42 +02:00
break;
case nod_index_order:
stuff(statement, blr_navigational);
2003-11-10 10:16:38 +01:00
index_string = (dsql_str*) arg->nod_arg[0];
stuff_cstring(statement, index_string->str_data);
if (!arg->nod_arg[1])
break;
// dimitr: FALL INTO, if the plan item is ORDER ... INDEX (...)
2001-05-23 15:26:42 +02:00
case nod_index:
{
stuff(statement, blr_indices);
arg = (arg->nod_type == nod_index) ?
arg->nod_arg[0] : arg->nod_arg[1];
stuff(statement, arg->nod_count);
const dsql_nod* const* ptr2 = arg->nod_arg;
for (const dsql_nod* const* const end2 = ptr2 + arg->nod_count;
ptr2 < end2; ptr2++)
{
2003-11-10 10:16:38 +01:00
index_string = (dsql_str*) * ptr2;
stuff_cstring(statement, index_string->str_data);
}
break;
2001-05-23 15:26:42 +02:00
}
default:
2003-11-04 00:59:24 +01:00
fb_assert(false);
2001-05-23 15:26:42 +02:00
break;
}
}
}
/**
gen_relation
@brief Generate blr for a relation reference.
@param statement
@param context
**/
static void gen_relation( CompiledStatement* statement, dsql_ctx* context)
2001-05-23 15:26:42 +02:00
{
const dsql_rel* relation = context->ctx_relation;
const dsql_prc* procedure = context->ctx_procedure;
2001-05-23 15:26:42 +02:00
2007-05-27 02:37:39 +02:00
// if this is a trigger or procedure, don't want relation id used
2001-05-23 15:26:42 +02:00
if (relation) {
if (DDL_ids(statement)) {
2001-05-23 15:26:42 +02:00
if (context->ctx_alias)
stuff(statement, blr_rid2);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_rid);
stuff_word(statement, relation->rel_id);
2001-05-23 15:26:42 +02:00
}
else {
if (context->ctx_alias)
stuff(statement, blr_relation2);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_relation);
stuff_meta_string(statement, relation->rel_name.c_str());
2001-05-23 15:26:42 +02:00
}
if (context->ctx_alias)
stuff_meta_string(statement, context->ctx_alias);
stuff_context(statement, context);
2001-05-23 15:26:42 +02:00
}
2003-08-20 01:34:23 +02:00
else if (procedure) {
if (DDL_ids(statement)) {
stuff(statement, blr_pid);
stuff_word(statement, procedure->prc_id);
2001-05-23 15:26:42 +02:00
}
else {
stuff(statement, blr_procedure);
stuff_meta_string(statement, procedure->prc_name.c_str());
2001-05-23 15:26:42 +02:00
}
stuff_context(statement, context);
dsql_nod* inputs = context->ctx_proc_inputs;
if (inputs) {
stuff_word(statement, inputs->nod_count);
dsql_nod* const* ptr = inputs->nod_arg;
for (const dsql_nod* const* const end = ptr + inputs->nod_count;
2001-05-23 15:26:42 +02:00
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
}
}
else
stuff_word(statement, 0);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_return
@brief Generate blr for a procedure return.
@param statement
@param procedure
@param eos_flag
**/
void GEN_return( CompiledStatement* statement, const dsql_nod* parameters, bool eos_flag)
2001-05-23 15:26:42 +02:00
{
if (!eos_flag)
stuff(statement, blr_begin);
stuff(statement, blr_send);
stuff(statement, 1);
stuff(statement, blr_begin);
USHORT outputs = 0;
if (parameters) {
const dsql_nod* const* ptr = parameters->nod_arg;
for (const dsql_nod* const* const end = ptr + parameters->nod_count;
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
outputs++;
const dsql_nod* parameter = *ptr;
2004-02-02 12:02:12 +01:00
const dsql_var* variable = (dsql_var*) parameter->nod_arg[e_var_variable];
stuff(statement, blr_assignment);
stuff(statement, blr_variable);
stuff_word(statement, variable->var_variable_number);
stuff(statement, blr_parameter2);
stuff(statement, variable->var_msg_number);
stuff_word(statement, variable->var_msg_item);
stuff_word(statement, variable->var_msg_item + 1);
}
}
stuff(statement, blr_assignment);
stuff(statement, blr_literal);
stuff(statement, blr_short);
stuff(statement, 0);
2001-05-23 15:26:42 +02:00
if (eos_flag)
stuff_word(statement, 0);
2001-05-23 15:26:42 +02:00
else
stuff_word(statement, 1);
stuff(statement, blr_parameter);
stuff(statement, 1);
stuff_word(statement, 2 * outputs);
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
if (!eos_flag) {
stuff(statement, blr_stall);
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_rse
@brief Generate a record selection expression.
@param statement
@param rse
**/
static void gen_rse( CompiledStatement* statement, const dsql_nod* rse)
2001-05-23 15:26:42 +02:00
{
if (rse->nod_flags & NOD_SELECT_EXPR_SINGLETON)
2003-10-05 08:27:16 +02:00
{
stuff(statement, blr_singular);
2003-10-05 08:27:16 +02:00
}
2001-05-23 15:26:42 +02:00
stuff(statement, blr_rse);
2001-05-23 15:26:42 +02:00
dsql_nod* list = rse->nod_arg[e_rse_streams];
2001-05-23 15:26:42 +02:00
// Handle source streams
2001-05-23 15:26:42 +02:00
if (list->nod_type == nod_union) {
stuff(statement, 1);
gen_union(statement, rse);
2001-05-23 15:26:42 +02:00
}
else if (list->nod_type == nod_list) {
stuff(statement, list->nod_count);
dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count;
ptr < end; ptr++)
{
dsql_nod* node = *ptr;
2001-05-23 15:26:42 +02:00
if (node->nod_type == nod_relation ||
node->nod_type == nod_aggregate ||
node->nod_type == nod_join)
{
GEN_expr(statement, node);
2003-08-15 01:34:37 +02:00
}
else if (node->nod_type == nod_derived_table) {
GEN_expr(statement, node->nod_arg[e_derived_table_rse]);
2003-08-15 01:34:37 +02:00
}
2001-05-23 15:26:42 +02:00
}
}
else {
stuff(statement, 1);
GEN_expr(statement, list);
2001-05-23 15:26:42 +02:00
}
if (rse->nod_arg[e_rse_lock])
stuff(statement, blr_writelock);
dsql_nod* node;
2001-05-23 15:26:42 +02:00
if ((node = rse->nod_arg[e_rse_first]) != NULL) {
stuff(statement, blr_first);
GEN_expr(statement, node);
2001-05-23 15:26:42 +02:00
}
2006-06-02 10:03:22 +02:00
if ((node = rse->nod_arg[e_rse_skip]) != NULL) {
stuff(statement, blr_skip);
GEN_expr (statement, node);
2006-06-02 10:03:22 +02:00
}
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
if ((node = rse->nod_arg[e_rse_boolean]) != NULL) {
stuff(statement, blr_boolean);
GEN_expr(statement, node);
2001-05-23 15:26:42 +02:00
}
if ((list = rse->nod_arg[e_rse_sort]) != NULL)
gen_sort(statement, list);
2001-05-23 15:26:42 +02:00
if ((list = rse->nod_arg[e_rse_reduced]) != NULL) {
stuff(statement, blr_project);
stuff(statement, list->nod_count);
dsql_nod** ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count;
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
}
2001-05-23 15:26:42 +02:00
}
// if the user specified an access plan to use, add it here
2001-05-23 15:26:42 +02:00
if ((node = rse->nod_arg[e_rse_plan]) != NULL) {
stuff(statement, blr_plan);
gen_plan(statement, node);
2001-05-23 15:26:42 +02:00
}
#ifdef SCROLLABLE_CURSORS
/* generate a statement to be executed if the user scrolls
in a direction other than forward; a message is sent outside
the normal send/receive protocol to specify the direction
and offset to scroll; note that we do this only on a SELECT
type statement and only when talking to a 4.1 engine or greater */
if (statement->req_type == REQ_SELECT &&
statement->req_dbb->dbb_base_level >= 5)
{
stuff(statement, blr_receive);
stuff(statement, statement->req_async->msg_number);
stuff(statement, blr_seek);
const dsql_par* parameter = statement->req_async->msg_parameters;
gen_parameter(statement, parameter->par_next);
gen_parameter(statement, parameter);
2001-05-23 15:26:42 +02:00
}
#endif
stuff(statement, blr_end);
2001-05-23 15:26:42 +02:00
}
/**
gen_searched_case
@brief Generate BLR for CASE function (searched)
@param statement
@param node
**/
static void gen_searched_case( CompiledStatement* statement, const dsql_nod* node)
{
// blr_value_if is used for building the case expression
stuff(statement, blr_cast);
gen_descriptor(statement, &node->nod_desc, true);
const SSHORT count =
node->nod_arg[e_searched_case_search_conditions]->nod_count;
dsql_nod* boolean_list = node->nod_arg[e_searched_case_search_conditions];
dsql_nod* results_list = node->nod_arg[e_searched_case_results];
dsql_nod* const* bptr = boolean_list->nod_arg;
dsql_nod* const* rptr = results_list->nod_arg;
for (const dsql_nod* const* const end = bptr + count; bptr < end;
bptr++, rptr++)
{
stuff(statement, blr_value_if);
GEN_expr(statement, *bptr);
GEN_expr(statement, *rptr);
}
// else_result
GEN_expr(statement, node->nod_arg[e_searched_case_results]->nod_arg[count]);
}
/**
gen_select
@brief Generate BLR for a SELECT statement.
@param statement
@param rse
**/
static void gen_select( CompiledStatement* statement, dsql_nod* rse)
2001-05-23 15:26:42 +02:00
{
const dsql_rel* relation;
dsql_ctx* context;
fb_assert(rse->nod_type == nod_rse);
2001-05-23 15:26:42 +02:00
// Set up parameter for things in the select list
const dsql_nod* list = rse->nod_arg[e_rse_items];
dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end;
ptr++)
{
dsql_par* parameter =
MAKE_parameter(statement->req_receive, true, true, 0, *ptr);
parameter->par_node = *ptr;
MAKE_desc(statement, &parameter->par_desc, *ptr, NULL);
}
2001-05-23 15:26:42 +02:00
// Set up parameter to handle EOF
2001-05-23 15:26:42 +02:00
dsql_par* parameter_eof =
MAKE_parameter(statement->req_receive, false, false, 0, NULL);
statement->req_eof = parameter_eof;
parameter_eof->par_desc.dsc_dtype = dtype_short;
parameter_eof->par_desc.dsc_scale = 0;
parameter_eof->par_desc.dsc_length = sizeof(SSHORT);
// Save DBKEYs for possible update later
2001-05-23 15:26:42 +02:00
list = rse->nod_arg[e_rse_streams];
if (!rse->nod_arg[e_rse_reduced]) {
2006-08-17 14:08:49 +02:00
dsql_nod* const* ptr2 = list->nod_arg;
for (const dsql_nod* const* const end2 = ptr2 + list->nod_count;
ptr2 < end2; ptr2++)
{
2006-08-17 14:08:49 +02:00
dsql_nod* item = *ptr2;
if (item && item->nod_type == nod_relation) {
context = (dsql_ctx*) item->nod_arg[e_rel_context];
2001-05-23 15:26:42 +02:00
if (relation = context->ctx_relation) {
// Set up dbkey
2004-02-02 12:02:12 +01:00
dsql_par* parameter =
MAKE_parameter(statement->req_receive,
false, false, 0, NULL);
2001-05-23 15:26:42 +02:00
parameter->par_dbkey_ctx = context;
parameter->par_desc.dsc_dtype = dtype_text;
parameter->par_desc.dsc_ttype() = ttype_binary;
2001-05-23 15:26:42 +02:00
parameter->par_desc.dsc_length =
relation->rel_dbkey_length;
// Set up record version - for post v33 databases
2001-05-23 15:26:42 +02:00
parameter =
MAKE_parameter(statement->req_receive, false,
false, 0, NULL);
parameter->par_rec_version_ctx = context;
parameter->par_desc.dsc_dtype = dtype_text;
parameter->par_desc.dsc_ttype() = ttype_binary;
parameter->par_desc.dsc_length =
relation->rel_dbkey_length / 2;
2001-05-23 15:26:42 +02:00
}
}
}
2001-05-23 15:26:42 +02:00
}
#ifdef SCROLLABLE_CURSORS
/* define the parameters for the scrolling message--offset and direction,
in that order to make it easier to generate the statement */
2001-05-23 15:26:42 +02:00
if (statement->req_type == REQ_SELECT &&
statement->req_dbb->dbb_base_level >= 5)
{
dsql_par* parameter =
MAKE_parameter(statement->req_async, false, false, 0, NULL);
2001-05-23 15:26:42 +02:00
parameter->par_desc.dsc_dtype = dtype_short;
parameter->par_desc.dsc_length = sizeof(USHORT);
parameter->par_desc.dsc_scale = 0;
parameter->par_desc.dsc_flags = 0;
parameter->par_desc.dsc_sub_type = 0;
parameter =
MAKE_parameter(statement->req_async, false, false, 0, NULL);
2001-05-23 15:26:42 +02:00
parameter->par_desc.dsc_dtype = dtype_long;
parameter->par_desc.dsc_length = sizeof(ULONG);
parameter->par_desc.dsc_scale = 0;
parameter->par_desc.dsc_flags = 0;
parameter->par_desc.dsc_sub_type = 0;
}
#endif
// Generate definitions for the messages
2001-05-23 15:26:42 +02:00
GEN_port(statement, statement->req_receive);
dsql_msg* message = statement->req_send;
2001-05-23 15:26:42 +02:00
if (message->msg_parameter)
GEN_port(statement, message);
2001-05-23 15:26:42 +02:00
else
statement->req_send = NULL;
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
if (statement->req_type == REQ_SELECT &&
statement->req_dbb->dbb_base_level >= 5)
GEN_port(statement, statement->req_async);
2001-05-23 15:26:42 +02:00
#endif
// If there is a send message, build a RECEIVE
2001-05-23 15:26:42 +02:00
if ((message = statement->req_send) != NULL) {
stuff(statement, blr_receive);
stuff(statement, message->msg_number);
2001-05-23 15:26:42 +02:00
}
// Generate FOR loop
2001-05-23 15:26:42 +02:00
message = statement->req_receive;
2001-05-23 15:26:42 +02:00
stuff(statement, blr_for);
stuff(statement, blr_stall);
gen_rse(statement, rse);
stuff(statement, blr_send);
stuff(statement, message->msg_number);
stuff(statement, blr_begin);
2001-05-23 15:26:42 +02:00
// Build body of FOR loop
2001-05-23 15:26:42 +02:00
SSHORT constant;
dsc constant_desc;
constant_desc.dsc_dtype = dtype_short;
constant_desc.dsc_scale = 0;
constant_desc.dsc_sub_type = 0;
constant_desc.dsc_flags = 0;
constant_desc.dsc_length = sizeof(SSHORT);
constant_desc.dsc_address = (UCHAR*) & constant;
// Add invalid usage here
stuff(statement, blr_assignment);
2001-05-23 15:26:42 +02:00
constant = 1;
gen_constant(statement, &constant_desc, USE_VALUE);
gen_parameter(statement, statement->req_eof);
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
for (dsql_par* parameter = message->msg_parameters; parameter;
2004-10-26 09:21:47 +02:00
parameter = parameter->par_next)
{
2001-05-23 15:26:42 +02:00
if (parameter->par_node) {
stuff(statement, blr_assignment);
GEN_expr(statement, parameter->par_node);
gen_parameter(statement, parameter);
2001-05-23 15:26:42 +02:00
}
if (context = parameter->par_dbkey_ctx) {
stuff(statement, blr_assignment);
stuff(statement, blr_dbkey);
stuff_context(statement, context);
gen_parameter(statement, parameter);
2001-05-23 15:26:42 +02:00
}
if (context = parameter->par_rec_version_ctx) {
stuff(statement, blr_assignment);
stuff(statement, blr_record_version);
stuff_context(statement, context);
gen_parameter(statement, parameter);
2001-05-23 15:26:42 +02:00
}
}
stuff(statement, blr_end);
stuff(statement, blr_send);
stuff(statement, message->msg_number);
stuff(statement, blr_assignment);
2001-05-23 15:26:42 +02:00
constant = 0;
gen_constant(statement, &constant_desc, USE_VALUE);
gen_parameter(statement, statement->req_eof);
2001-05-23 15:26:42 +02:00
}
/**
gen_simple_case
@brief Generate BLR for CASE function (simple)
@param statement
@param node
**/
static void gen_simple_case( CompiledStatement* statement, const dsql_nod* node)
{
// blr_value_if is used for building the case expression
stuff(statement, blr_cast);
gen_descriptor(statement, &node->nod_desc, true);
SSHORT count = node->nod_arg[e_simple_case_when_operands]->nod_count;
dsql_nod* when_list = node->nod_arg[e_simple_case_when_operands];
dsql_nod* results_list = node->nod_arg[e_simple_case_results];
dsql_nod* const* wptr = when_list->nod_arg;
dsql_nod* const* rptr = results_list->nod_arg;
for (const dsql_nod* const* const end = wptr + count; wptr < end;
wptr++, rptr++)
{
stuff(statement, blr_value_if);
stuff(statement, blr_eql);
GEN_expr(statement, node->nod_arg[e_simple_case_case_operand]);
GEN_expr(statement, *wptr);
GEN_expr(statement, *rptr);
}
// else_result
GEN_expr(statement, node->nod_arg[e_simple_case_results]->nod_arg[count]);
}
/**
gen_sort
@brief Generate a sort clause.
@param statement
@param list
**/
static void gen_sort( CompiledStatement* statement, dsql_nod* list)
2001-05-23 15:26:42 +02:00
{
stuff(statement, blr_sort);
stuff(statement, list->nod_count);
2001-05-23 15:26:42 +02:00
dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end;
ptr++)
{
dsql_nod* nulls_placement = (*ptr)->nod_arg[e_order_nulls];
if (nulls_placement) {
switch (nulls_placement->getSlong()) {
case NOD_NULLS_FIRST:
stuff(statement, blr_nullsfirst);
break;
case NOD_NULLS_LAST:
stuff(statement, blr_nullslast);
break;
}
}
2002-09-10 20:28:23 +02:00
if ((*ptr)->nod_arg[e_order_flag])
stuff(statement, blr_descending);
2001-05-23 15:26:42 +02:00
else
stuff(statement, blr_ascending);
GEN_expr(statement, (*ptr)->nod_arg[e_order_field]);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_statement
@brief Generate BLR for DML statements.
@param statement
@param node
**/
static void gen_statement(CompiledStatement* statement, const dsql_nod* node)
{
dsql_nod* rse = NULL;
const dsql_msg* message = NULL;
bool send_before_for = !(statement->req_flags & REQ_dsql_upd_or_ins);
switch (node->nod_type) {
case nod_store:
rse = node->nod_arg[e_sto_rse];
break;
case nod_modify:
rse = node->nod_arg[e_mod_rse];
break;
case nod_erase:
rse = node->nod_arg[e_era_rse];
break;
default:
send_before_for = false;
break;
}
if (statement->req_type == REQ_EXEC_PROCEDURE && send_before_for)
{
if ((message = statement->req_receive))
{
stuff(statement, blr_send);
stuff(statement, message->msg_number);
}
}
if (rse) {
stuff(statement, blr_for);
GEN_expr(statement, rse);
}
if (statement->req_type == REQ_EXEC_PROCEDURE)
{
if ((message = statement->req_receive))
{
stuff(statement, blr_begin);
if (!send_before_for)
{
stuff(statement, blr_send);
stuff(statement, message->msg_number);
}
2006-09-03 03:09:23 +02:00
}
}
dsql_nod* temp;
dsql_ctx* context;
dsql_str* name;
switch (node->nod_type) {
case nod_store:
stuff(statement, node->nod_arg[e_sto_return] ? blr_store2 : blr_store);
GEN_expr(statement, node->nod_arg[e_sto_relation]);
GEN_statement(statement, node->nod_arg[e_sto_statement]);
if (node->nod_arg[e_sto_return]) {
GEN_statement(statement, node->nod_arg[e_sto_return]);
}
break;
case nod_modify:
stuff(statement, node->nod_arg[e_mod_return] ? blr_modify2 : blr_modify);
temp = node->nod_arg[e_mod_source];
context = (dsql_ctx*) temp->nod_arg[e_rel_context];
stuff_context(statement, context);
temp = node->nod_arg[e_mod_update];
context = (dsql_ctx*) temp->nod_arg[e_rel_context];
stuff_context(statement, context);
GEN_statement(statement, node->nod_arg[e_mod_statement]);
if (node->nod_arg[e_mod_return]) {
GEN_statement(statement, node->nod_arg[e_mod_return]);
}
break;
case nod_modify_current:
stuff(statement, node->nod_arg[e_mdc_return] ? blr_modify2 : blr_modify);
context = (dsql_ctx*) node->nod_arg[e_mdc_context];
stuff_context(statement, context);
temp = node->nod_arg[e_mdc_update];
context = (dsql_ctx*) temp->nod_arg[e_rel_context];
stuff_context(statement, context);
GEN_statement(statement, node->nod_arg[e_mdc_statement]);
if (node->nod_arg[e_mdc_return]) {
GEN_statement(statement, node->nod_arg[e_mdc_return]);
}
break;
case nod_erase:
temp = node->nod_arg[e_era_relation];
context = (dsql_ctx*) temp->nod_arg[e_rel_context];
if (node->nod_arg[e_era_return]) {
stuff(statement, blr_begin);
GEN_statement(statement, node->nod_arg[e_era_return]);
stuff(statement, blr_erase);
stuff_context(statement, context);
stuff(statement, blr_end);
}
else {
stuff(statement, blr_erase);
stuff_context(statement, context);
}
break;
case nod_erase_current:
context = (dsql_ctx*) node->nod_arg[e_erc_context];
if (node->nod_arg[e_erc_return]) {
stuff(statement, blr_begin);
GEN_statement(statement, node->nod_arg[e_erc_return]);
stuff(statement, blr_erase);
stuff_context(statement, context);
stuff(statement, blr_end);
}
else {
stuff(statement, blr_erase);
stuff_context(statement, context);
}
break;
case nod_exec_procedure:
stuff(statement, blr_exec_proc);
name = (dsql_str*) node->nod_arg[e_exe_procedure];
stuff_meta_string(statement, name->str_data);
// Input parameters
if ( (temp = node->nod_arg[e_exe_inputs]) ) {
stuff_word(statement, temp->nod_count);
dsql_nod** ptr = temp->nod_arg;
const dsql_nod* const* end = ptr + temp->nod_count;
while (ptr < end)
{
GEN_expr(statement, *ptr++);
}
}
else {
stuff_word(statement, 0);
}
// Output parameters
if ( ( temp = node->nod_arg[e_exe_outputs]) ) {
stuff_word(statement, temp->nod_count);
dsql_nod** ptr = temp->nod_arg;
const dsql_nod* const* end = ptr + temp->nod_count;
while (ptr < end)
{
GEN_expr(statement, *ptr++);
}
}
else {
stuff_word(statement, 0);
}
break;
default:
fb_assert(false);
}
if (message) {
stuff(statement, blr_end);
}
}
2007-04-12 17:56:34 +02:00
/**
gen_sys_function
@brief Generate a system defined function.
@param statement
2007-04-12 17:56:34 +02:00
@param node
**/
static void gen_sys_function(CompiledStatement* statement, const dsql_nod* node)
2007-04-12 17:56:34 +02:00
{
stuff(statement, blr_sys_function);
stuff_cstring(statement, ((dsql_str*) node->nod_arg[e_sysfunc_name])->str_data);
2007-04-12 17:56:34 +02:00
const dsql_nod* list;
2007-04-15 13:25:23 +02:00
if ((node->nod_count == e_sysfunc_args + 1) && (list = node->nod_arg[e_sysfunc_args]))
2007-04-13 03:37:44 +02:00
{
stuff(statement, list->nod_count);
2007-04-12 17:56:34 +02:00
dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count;
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
2007-04-12 17:56:34 +02:00
}
}
else
stuff(statement, 0);
2007-04-12 17:56:34 +02:00
}
/**
gen_table_lock
@brief Generate tpb for table lock.
If lock level is specified, it overrrides the transaction lock level.
@param statement
@param tbl_lock
@param lock_level
**/
static void gen_table_lock( CompiledStatement* statement, const dsql_nod* tbl_lock,
USHORT lock_level)
2001-05-23 15:26:42 +02:00
{
2008-06-03 08:14:59 +02:00
if (!tbl_lock || tbl_lock->nod_type != nod_table_lock)
2001-05-23 15:26:42 +02:00
return;
const dsql_nod* tbl_names = tbl_lock->nod_arg[e_lock_tables];
SSHORT flags = 0;
2001-05-23 15:26:42 +02:00
if (tbl_lock->nod_arg[e_lock_mode])
flags = tbl_lock->nod_arg[e_lock_mode]->nod_flags;
if (flags & NOD_PROTECTED)
2003-11-08 00:27:24 +01:00
lock_level = isc_tpb_protected;
2001-05-23 15:26:42 +02:00
else if (flags & NOD_SHARED)
2003-11-08 00:27:24 +01:00
lock_level = isc_tpb_shared;
2001-05-23 15:26:42 +02:00
const USHORT lock_mode = (flags & NOD_WRITE) ?
2003-11-08 00:27:24 +01:00
isc_tpb_lock_write : isc_tpb_lock_read;
2001-05-23 15:26:42 +02:00
2006-06-02 10:03:22 +02:00
const dsql_nod* const* ptr = tbl_names->nod_arg;
for (const dsql_nod* const* const end = ptr + tbl_names->nod_count;
ptr < end; ptr++)
{
2001-05-23 15:26:42 +02:00
if ((*ptr)->nod_type != nod_relation_name)
continue;
stuff(statement, lock_mode);
2001-05-23 15:26:42 +02:00
// stuff table name
2003-11-10 10:16:38 +01:00
const dsql_str* temp = (dsql_str*) ((*ptr)->nod_arg[e_rln_name]);
stuff_cstring(statement, reinterpret_cast<const char*>(temp->str_data));
2001-05-23 15:26:42 +02:00
stuff(statement, lock_level);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_udf
@brief Generate a user defined function.
@param statement
@param node
**/
static void gen_udf( CompiledStatement* statement, const dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
2003-11-10 10:16:38 +01:00
const dsql_udf* userFunc = (dsql_udf*) node->nod_arg[0];
stuff(statement, blr_function);
stuff_string(statement, userFunc->udf_name);
2001-05-23 15:26:42 +02:00
const dsql_nod* list;
2001-05-23 15:26:42 +02:00
if ((node->nod_count == 2) && (list = node->nod_arg[1])) {
stuff(statement, list->nod_count);
dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + list->nod_count;
ptr < end; ptr++)
{
GEN_expr(statement, *ptr);
}
2001-05-23 15:26:42 +02:00
}
else
stuff(statement, 0);
2001-05-23 15:26:42 +02:00
}
/**
gen_union
@brief Generate a union of substreams.
@param statement
@param union_node
**/
static void gen_union( CompiledStatement* statement, const dsql_nod* union_node)
2001-05-23 15:26:42 +02:00
{
if (union_node->nod_arg[0]->nod_flags & NOD_UNION_RECURSIVE) {
stuff(statement, blr_recurse);
}
else {
stuff(statement, blr_union);
}
2001-05-23 15:26:42 +02:00
2003-11-10 10:16:38 +01:00
// Obtain the context for UNION from the first dsql_map* node
dsql_nod* items = union_node->nod_arg[e_rse_items];
dsql_nod* map_item = items->nod_arg[0];
// AB: First item could be a virtual field generated by derived table.
if (map_item->nod_type == nod_derived_field) {
2003-08-15 01:34:37 +02:00
map_item = map_item->nod_arg[e_alias_value];
}
dsql_ctx* union_context = (dsql_ctx*) map_item->nod_arg[e_map_context];
stuff_context(statement, union_context);
// secondary context number must be present once in generated blr
union_context->ctx_flags &= ~CTX_recursive;
2001-05-23 15:26:42 +02:00
dsql_nod* streams = union_node->nod_arg[e_rse_streams];
stuff(statement, streams->nod_count); // number of substreams
2001-05-23 15:26:42 +02:00
2006-06-02 10:03:22 +02:00
dsql_nod** ptr = streams->nod_arg;
for (const dsql_nod* const* const end = ptr + streams->nod_count; ptr < end;
ptr++)
{
dsql_nod* sub_rse = *ptr;
gen_rse(statement, sub_rse);
2001-05-23 15:26:42 +02:00
items = sub_rse->nod_arg[e_rse_items];
stuff(statement, blr_map);
stuff_word(statement, items->nod_count);
USHORT count = 0;
dsql_nod** iptr = items->nod_arg;
for (const dsql_nod* const* const iend = iptr + items->nod_count;
iptr < iend; iptr++)
{
stuff_word(statement, count);
GEN_expr(statement, *iptr);
2001-05-23 15:26:42 +02:00
count++;
}
}
}
/**
stuff_context
@brief Write a context number into the BLR buffer.
Check for possible overflow.
@param statement
@param context
**/
static void stuff_context(CompiledStatement* statement, const dsql_ctx* context)
{
if (context->ctx_context > MAX_UCHAR) {
ERRD_post(isc_too_many_contexts, isc_arg_end);
}
stuff(statement, context->ctx_context);
if (context->ctx_flags & CTX_recursive)
{
if (context->ctx_recursive > MAX_UCHAR) {
ERRD_post(isc_too_many_contexts, isc_arg_end);
}
stuff(statement, context->ctx_recursive);
}
}
/**
stuff_cstring
@brief Write out a string with one byte of length.
@param statement
@param string
**/
static void stuff_cstring(CompiledStatement* statement, const char* string)
2001-05-23 15:26:42 +02:00
{
stuff_string(statement, string, strlen(string));
}
/**
stuff_meta_string
@brief Write out a string in metadata charset with one byte of length.
@param statement
@param string
**/
static void stuff_meta_string(CompiledStatement* statement, const char* string)
{
statement->append_meta_string(string);
}
/**
stuff_string
@brief Write out a string with one byte of length.
@param statement
@param string
**/
static void stuff_string(CompiledStatement* statement, const char* string, int len)
{
fb_assert(len >= 0 && len <= 255);
stuff(statement, len);
statement->append_raw_string(string, len);
2001-05-23 15:26:42 +02:00
}
static void stuff_string(CompiledStatement* statement, const Firebird::MetaName& name)
2008-01-16 07:52:43 +01:00
{
stuff_string(statement, name.c_str(), name.length());
2008-01-16 07:52:43 +01:00
}
/**
stuff_word
@brief Cram a word into the blr buffer. If the buffer is getting
ready to overflow, expand it.
@param statement
@param word
**/
static void stuff_word( CompiledStatement* statement, USHORT word)
2001-05-23 15:26:42 +02:00
{
stuff(statement, word);
stuff(statement, word >> 8);
2001-05-23 15:26:42 +02:00
}