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

774 lines
20 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/DdlNodes.h"
2010-10-24 02:26:00 +02:00
#include "../dsql/ExprNodes.h"
#include "../dsql/StmtNodes.h"
#include "../jrd/RecordSourceNodes.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/utld_proto.h"
2005-05-28 00:45:31 +02:00
#include "../jrd/thread_proto.h"
2010-10-12 10:02:57 +02:00
#include "../common/dsc_proto.h"
#include "../yvalve/why_proto.h"
#include "gen/iberror.h"
#include "../common/StatusArg.h"
2001-05-23 15:26:42 +02:00
2008-02-28 14:48:16 +01:00
using namespace Jrd;
using namespace Dsql;
using namespace Firebird;
2008-02-28 14:48:16 +01:00
static void gen_plan(DsqlCompilerScratch*, const dsql_nod*);
static void gen_union(DsqlCompilerScratch*, const dsql_nod*);
2001-05-23 15:26:42 +02:00
void GEN_hidden_variables(DsqlCompilerScratch* dsqlScratch)
{
/**************************************
*
* G E N _ h i d d e n _ v a r i a b l e s
*
**************************************
*
* Function
* Emit BLR for hidden variables.
*
**************************************/
if (dsqlScratch->hiddenVariables.isEmpty())
return;
for (Array<dsql_var*>::const_iterator i = dsqlScratch->hiddenVariables.begin();
i != dsqlScratch->hiddenVariables.end();
++i)
{
const dsql_var* var = *i;
dsqlScratch->appendUChar(blr_dcl_variable);
dsqlScratch->appendUShort(var->number);
GEN_descriptor(dsqlScratch, &var->desc, true);
}
// Clear it for GEN_expr not regenerate them.
dsqlScratch->hiddenVariables.clear();
}
/**
GEN_expr
@brief Generate blr for an arbitrary expression.
@param dsqlScratch
@param node
**/
void GEN_expr(DsqlCompilerScratch* dsqlScratch, dsql_nod* node)
2001-05-23 15:26:42 +02:00
{
2011-02-18 01:52:10 +01:00
if (node->nod_type == nod_class_exprnode)
2009-01-06 06:53:34 +01:00
{
2011-02-18 01:52:10 +01:00
ExprNode* exprNode = reinterpret_cast<ExprNode*>(node->nod_arg[0]);
if (exprNode->is<RseNode>())
{
2011-02-18 01:52:10 +01:00
GEN_rse(dsqlScratch, node);
return;
}
2011-02-18 01:52:10 +01:00
exprNode->genBlr(dsqlScratch);
2011-02-18 01:52:10 +01: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.
2011-02-18 01:52:10 +01:00
// ASF: Shouldn't we check nod_gen_id2 too?
2011-02-18 01:52:10 +01:00
if (exprNode->dsqlCompatDialectVerb &&
dsqlScratch->clientDialect == SQL_DIALECT_V6_TRANSITION)
{
dsc desc;
MAKE_desc(dsqlScratch, &desc, node);
2011-02-18 01:52:10 +01:00
if (desc.dsc_dtype == dtype_int64)
{
2011-02-18 01:52:10 +01:00
ERRD_post_warning(
Arg::Warning(isc_dsql_dialect_warning_expr) <<
Arg::Str(exprNode->dsqlCompatDialectVerb));
}
}
2011-02-18 01:52:10 +01:00
}
else
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_internal_err) <<
// expression evaluation not supported
Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_dsql_eval_unknode) << Arg::Num(node->nod_type));
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 dsqlScratch
@param message
**/
void GEN_port(DsqlCompilerScratch* dsqlScratch, 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();
2001-05-23 15:26:42 +02:00
dsqlScratch->appendUChar(blr_message);
dsqlScratch->appendUChar(message->msg_number);
dsqlScratch->appendUShort(message->msg_parameter);
2001-05-23 15:26:42 +02:00
ULONG offset = 0;
for (size_t i = 0; i < message->msg_parameters.getCount(); ++i)
{
dsql_par* parameter = message->msg_parameters[i];
parameter->par_parameter = (USHORT) i;
2001-05-23 15:26:42 +02:00
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 : tdbb->getCharSet();
if (parameter->par_desc.dsc_dtype <= dtype_any_text &&
tdbb->getCharSet() != CS_NONE && tdbb->getCharSet() != 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
const USHORT fromCharSetBPC = METD_get_charset_bpc(dsqlScratch->getTransaction(), fromCharSet);
const USHORT toCharSetBPC = METD_get_charset_bpc(dsqlScratch->getTransaction(), toCharSet);
2005-05-28 00:45:31 +02:00
2009-11-28 20:39:23 +01:00
parameter->par_desc.setTextType(INTL_CS_COLL_TO_TTYPE(toCharSet,
(fromCharSet == toCharSet ? INTL_GET_COLLATE(&parameter->par_desc) : 0)));
2012-03-17 03:26:59 +01:00
parameter->par_desc.dsc_length = UTLD_char_length_to_byte_length(
parameter->par_desc.dsc_length / fromCharSetBPC, toCharSetBPC, adjust);
2005-05-28 00:45:31 +02:00
parameter->par_desc.dsc_length += adjust;
2005-05-28 00:45:31 +02:00
}
else if (parameter->par_desc.dsc_dtype == dtype_blob &&
2007-07-08 10:43:30 +02:00
parameter->par_desc.dsc_sub_type == isc_blob_text &&
tdbb->getCharSet() != CS_NONE && tdbb->getCharSet() != CS_BINARY)
{
if (fromCharSet != toCharSet)
parameter->par_desc.setTextType(toCharSet);
}
2005-05-28 00:45:31 +02:00
2009-04-18 16:13:26 +02:00
// For older clients - generate an error should they try and
// access data types which did not exist in the older dialect
if (dsqlScratch->clientDialect <= SQL_DIALECT_V5)
{
2009-01-06 06:53:34 +01:00
switch (parameter->par_desc.dsc_dtype)
{
2009-04-18 16:13:26 +02:00
// 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:
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
Arg::Gds(isc_dsql_datatype_err) <<
2009-01-06 06:53:34 +01:00
Arg::Gds(isc_sql_dialect_datatype_unsupport) <<
Arg::Num(dsqlScratch->clientDialect) <<
2009-01-06 06:53:34 +01:00
Arg::Str(DSC_dtype_tostring(parameter->par_desc.dsc_dtype)));
break;
default:
// No special action for other data types
break;
}
}
2009-01-07 10:30:57 +01:00
if (parameter->par_desc.dsc_dtype == dtype_text && parameter->par_index != 0)
{
// We should convert par_desc from text to varying so the user can receive it with
// correct length when requesting it as varying. See CORE-2606.
// But we flag it to describe as text.
parameter->par_is_text = true;
parameter->par_desc.dsc_dtype = dtype_varying;
parameter->par_desc.dsc_length += sizeof(USHORT);
}
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;
GEN_descriptor(dsqlScratch, &parameter->par_desc, true);
2001-05-23 15:26:42 +02:00
}
if (offset > MAX_MESSAGE_SIZE)
2009-11-16 10:18:24 +01:00
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_imp_exc) <<
Arg::Gds(isc_blktoobig));
}
message->msg_length = offset;
dsqlScratch->ports.add(message);
2001-05-23 15:26:42 +02:00
}
2012-02-20 03:02:04 +01:00
// Generate complete blr for a dsqlScratch.
void GEN_request(DsqlCompilerScratch* scratch, DmlNode* node)
2001-05-23 15:26:42 +02:00
{
DsqlCompiledStatement* statement = scratch->getStatement();
if (statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4)
scratch->appendUChar(blr_version4);
2001-05-23 15:26:42 +02:00
else
scratch->appendUChar(blr_version5);
if (statement->getType() == DsqlCompiledStatement::TYPE_SAVEPOINT)
{
// Do not generate BEGIN..END block around savepoint statement
// to avoid breaking of savepoint logic
statement->setSendMsg(NULL);
statement->setReceiveMsg(NULL);
2012-02-20 03:02:04 +01:00
node->genBlr(scratch);
}
else
{
2012-01-19 05:54:39 +01:00
const bool block = statement->getType() == DsqlCompiledStatement::TYPE_EXEC_BLOCK ||
statement->getType() == DsqlCompiledStatement::TYPE_SELECT_BLOCK;
// To parse sub-routines messages, they must not have that begin...end pair.
// And since it appears to be unnecessary for execute block too, do not generate them.
if (!block)
scratch->appendUChar(blr_begin);
2001-05-23 15:26:42 +02:00
GEN_hidden_variables(scratch);
switch (statement->getType())
2004-10-26 09:21:47 +02:00
{
case DsqlCompiledStatement::TYPE_SELECT:
case DsqlCompiledStatement::TYPE_SELECT_UPD:
case DsqlCompiledStatement::TYPE_EXEC_BLOCK:
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
2012-02-20 03:02:04 +01:00
node->genBlr(scratch);
2008-01-16 07:52:43 +01:00
break;
default:
{
dsql_msg* message = statement->getSendMsg();
2008-01-16 07:52:43 +01:00
if (!message->msg_parameter)
statement->setSendMsg(NULL);
2009-11-16 10:18:24 +01:00
else
{
GEN_port(scratch, message);
scratch->appendUChar(blr_receive);
scratch->appendUChar(message->msg_number);
2008-01-16 07:52:43 +01:00
}
message = statement->getReceiveMsg();
2008-01-16 07:52:43 +01:00
if (!message->msg_parameter)
statement->setReceiveMsg(NULL);
2008-01-16 07:52:43 +01:00
else
GEN_port(scratch, message);
2012-02-20 03:02:04 +01:00
node->genBlr(scratch);
2001-05-23 15:26:42 +02:00
}
}
if (!block)
scratch->appendUChar(blr_end);
2001-05-23 15:26:42 +02:00
}
scratch->appendUChar(blr_eoc);
2001-05-23 15:26:42 +02:00
}
/**
GEN_descriptor
@brief Generate a blr descriptor from an internal descriptor.
@param dsqlScratch
@param desc
@param texttype
**/
void GEN_descriptor( DsqlCompilerScratch* dsqlScratch, const dsc* desc, bool texttype)
2001-05-23 15:26:42 +02:00
{
2009-01-06 06:53:34 +01:00
switch (desc->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_text:
2009-11-16 10:18:24 +01:00
if (texttype || desc->dsc_ttype() == ttype_binary || desc->dsc_ttype() == ttype_none)
{
dsqlScratch->appendUChar(blr_text2);
dsqlScratch->appendUShort(desc->dsc_ttype());
2001-05-23 15:26:42 +02:00
}
2009-11-16 10:18:24 +01:00
else
{
dsqlScratch->appendUChar(blr_text2); // automatic transliteration
dsqlScratch->appendUShort(ttype_dynamic);
2001-05-23 15:26:42 +02:00
}
dsqlScratch->appendUShort(desc->dsc_length);
2001-05-23 15:26:42 +02:00
break;
case dtype_varying:
2009-11-16 10:18:24 +01:00
if (texttype || desc->dsc_ttype() == ttype_binary || desc->dsc_ttype() == ttype_none)
{
dsqlScratch->appendUChar(blr_varying2);
dsqlScratch->appendUShort(desc->dsc_ttype());
2001-05-23 15:26:42 +02:00
}
2009-11-16 10:18:24 +01:00
else
{
dsqlScratch->appendUChar(blr_varying2); // automatic transliteration
dsqlScratch->appendUShort(ttype_dynamic);
2001-05-23 15:26:42 +02:00
}
dsqlScratch->appendUShort(desc->dsc_length - sizeof(USHORT));
2001-05-23 15:26:42 +02:00
break;
case dtype_short:
dsqlScratch->appendUChar(blr_short);
dsqlScratch->appendUChar(desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_long:
dsqlScratch->appendUChar(blr_long);
dsqlScratch->appendUChar(desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_quad:
dsqlScratch->appendUChar(blr_quad);
dsqlScratch->appendUChar(desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_int64:
dsqlScratch->appendUChar(blr_int64);
dsqlScratch->appendUChar(desc->dsc_scale);
2001-05-23 15:26:42 +02:00
break;
case dtype_real:
dsqlScratch->appendUChar(blr_float);
2001-05-23 15:26:42 +02:00
break;
case dtype_double:
dsqlScratch->appendUChar(blr_double);
2001-05-23 15:26:42 +02:00
break;
case dtype_sql_date:
dsqlScratch->appendUChar(blr_sql_date);
2001-05-23 15:26:42 +02:00
break;
case dtype_sql_time:
dsqlScratch->appendUChar(blr_sql_time);
2001-05-23 15:26:42 +02:00
break;
case dtype_timestamp:
dsqlScratch->appendUChar(blr_timestamp);
2001-05-23 15:26:42 +02:00
break;
case dtype_array:
dsqlScratch->appendUChar(blr_quad);
dsqlScratch->appendUChar(0);
2001-05-23 15:26:42 +02:00
break;
case dtype_blob:
dsqlScratch->appendUChar(blr_blob2);
dsqlScratch->appendUShort(desc->dsc_sub_type);
dsqlScratch->appendUShort(desc->getTextType());
break;
2010-12-18 03:17:06 +01:00
case dtype_boolean:
dsqlScratch->appendUChar(blr_bool);
break;
2001-05-23 15:26:42 +02:00
default:
// don't understand dtype
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
Arg::Gds(isc_dsql_datatype_err));
2001-05-23 15:26:42 +02:00
}
}
2010-10-09 03:57:37 +02:00
// Generate a parameter reference.
void GEN_parameter( DsqlCompilerScratch* dsqlScratch, 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;
2009-11-16 10:18:24 +01:00
if (null != NULL)
{
dsqlScratch->appendUChar(blr_parameter2);
dsqlScratch->appendUChar(message->msg_number);
dsqlScratch->appendUShort(parameter->par_parameter);
dsqlScratch->appendUShort(null->par_parameter);
2001-05-23 15:26:42 +02:00
return;
}
dsqlScratch->appendUChar(blr_parameter);
dsqlScratch->appendUChar(message->msg_number);
dsqlScratch->appendUShort(parameter->par_parameter);
2001-05-23 15:26:42 +02:00
}
/**
gen_plan
@brief Generate blr for an access plan expression.
@param dsqlScratch
@param plan_expression
**/
static void gen_plan( DsqlCompilerScratch* dsqlScratch, const dsql_nod* plan_expression)
2001-05-23 15:26:42 +02:00
{
2009-04-18 16:13:26 +02:00
// stuff the join type
2001-05-23 15:26:42 +02:00
const dsql_nod* list = plan_expression->nod_arg[0];
2009-11-16 10:18:24 +01:00
if (list->nod_count > 1)
{
dsqlScratch->appendUChar(blr_join);
dsqlScratch->appendUChar(list->nod_count);
2001-05-23 15:26:42 +02:00
}
2009-04-18 16:13:26 +02:00
// stuff one or more plan items
2001-05-23 15:26:42 +02:00
const dsql_nod* const* ptr = list->nod_arg;
2009-01-06 06:53:34 +01:00
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
const dsql_nod* node = *ptr;
2009-11-16 10:18:24 +01:00
if (node->nod_type == nod_plan_expr)
{
gen_plan(dsqlScratch, 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
dsqlScratch->appendUChar(blr_retrieve);
2001-05-23 15:26:42 +02:00
2009-04-18 16:13:26 +02:00
// stuff the relation--the relation id itself is redundant except
// when there is a need to differentiate the base tables of views
2001-05-23 15:26:42 +02:00
/*const*/ dsql_nod* arg = node->nod_arg[0];
reinterpret_cast<RecordSourceNode*>(arg->nod_arg[0])->genBlr(dsqlScratch);
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];
2009-01-06 06:53:34 +01:00
switch (arg->nod_type)
{
2001-05-23 15:26:42 +02:00
case nod_natural:
dsqlScratch->appendUChar(blr_sequential);
2001-05-23 15:26:42 +02:00
break;
case nod_index_order:
dsqlScratch->appendUChar(blr_navigational);
2003-11-10 10:16:38 +01:00
index_string = (dsql_str*) arg->nod_arg[0];
dsqlScratch->appendNullString(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:
{
dsqlScratch->appendUChar(blr_indices);
2009-01-06 06:53:34 +01:00
arg = (arg->nod_type == nod_index) ? arg->nod_arg[0] : arg->nod_arg[1];
dsqlScratch->appendUChar(arg->nod_count);
const dsql_nod* const* ptr2 = arg->nod_arg;
2009-01-06 06:53:34 +01:00
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;
dsqlScratch->appendNullString(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_rse
@brief Generate a record selection expression.
@param dsqlScratch
@param rse
**/
void GEN_rse( DsqlCompilerScratch* dsqlScratch, const dsql_nod* rseNod)
2001-05-23 15:26:42 +02:00
{
const RseNode* rse = ExprNode::as<RseNode>(rseNod);
if (rseNod->nod_flags & NOD_SELECT_EXPR_SINGLETON)
dsqlScratch->appendUChar(blr_singular);
2001-05-23 15:26:42 +02:00
if (rse->dsqlExplicitJoin)
{
dsqlScratch->appendUChar(blr_rs_stream);
fb_assert(rse->dsqlStreams->nod_count == 2);
}
else
dsqlScratch->appendUChar(blr_rse);
2001-05-23 15:26:42 +02:00
dsql_nod* list = rse->dsqlStreams;
2001-05-23 15:26:42 +02:00
2009-04-18 16:13:26 +02:00
// Handle source streams
2001-05-23 15:26:42 +02:00
if (ExprNode::is<UnionSourceNode>(list))
2009-11-16 10:18:24 +01:00
{
dsqlScratch->appendUChar(1);
gen_union(dsqlScratch, rseNod);
2001-05-23 15:26:42 +02:00
}
2009-01-06 06:53:34 +01:00
else if (list->nod_type == nod_list)
{
dsqlScratch->appendUChar(list->nod_count);
dsql_nod* const* ptr = list->nod_arg;
2009-01-06 06:53:34 +01:00
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
dsql_nod* node = *ptr;
2009-01-06 06:53:34 +01:00
switch (node->nod_type)
{
case nod_class_exprnode:
GEN_expr(dsqlScratch, node);
2009-01-06 06:53:34 +01:00
break;
2003-08-15 01:34:37 +02:00
}
2001-05-23 15:26:42 +02:00
}
}
2009-11-16 10:18:24 +01:00
else
{
dsqlScratch->appendUChar(1);
GEN_expr(dsqlScratch, list);
2001-05-23 15:26:42 +02:00
}
if (rse->flags & RseNode::FLAG_WRITELOCK)
dsqlScratch->appendUChar(blr_writelock);
dsql_nod* node;
if ((node = rse->dsqlFirst))
2009-11-16 10:18:24 +01:00
{
dsqlScratch->appendUChar(blr_first);
GEN_expr(dsqlScratch, node);
2001-05-23 15:26:42 +02:00
}
if ((node = rse->dsqlSkip))
2009-11-16 10:18:24 +01:00
{
dsqlScratch->appendUChar(blr_skip);
2010-01-20 08:34:31 +01:00
GEN_expr(dsqlScratch, node);
2006-06-02 10:03:22 +02:00
}
2002-06-29 08:56:51 +02:00
if (rse->rse_jointype != blr_inner)
{
dsqlScratch->appendUChar(blr_join_type);
dsqlScratch->appendUChar(rse->rse_jointype);
}
if ((node = rse->dsqlWhere))
2009-11-16 10:18:24 +01:00
{
dsqlScratch->appendUChar(blr_boolean);
GEN_expr(dsqlScratch, node);
2001-05-23 15:26:42 +02:00
}
if ((list = rse->dsqlOrder))
GEN_sort(dsqlScratch, list);
2001-05-23 15:26:42 +02:00
if ((list = rse->dsqlDistinct))
2009-11-16 10:18:24 +01:00
{
dsqlScratch->appendUChar(blr_project);
dsqlScratch->appendUChar(list->nod_count);
dsql_nod** ptr = list->nod_arg;
2009-01-06 06:53:34 +01:00
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
GEN_expr(dsqlScratch, *ptr);
2001-05-23 15:26:42 +02:00
}
2009-04-18 16:13:26 +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->dsqlPlan) != NULL)
2009-11-16 10:18:24 +01:00
{
dsqlScratch->appendUChar(blr_plan);
gen_plan(dsqlScratch, node);
2001-05-23 15:26:42 +02:00
}
dsqlScratch->appendUChar(blr_end);
2001-05-23 15:26:42 +02:00
}
// Generate a sort clause.
void GEN_sort(DsqlCompilerScratch* dsqlScratch, dsql_nod* list)
2001-05-23 15:26:42 +02:00
{
dsqlScratch->appendUChar(blr_sort);
dsqlScratch->appendUChar(list->nod_count);
2001-05-23 15:26:42 +02:00
dsql_nod* const* ptr = list->nod_arg;
2009-01-06 06:53:34 +01:00
for (const dsql_nod* const* const end = ptr + list->nod_count; ptr < end; ptr++)
{
dsql_nod* nulls_placement = (*ptr)->nod_arg[e_order_nulls];
2010-10-24 02:26:00 +02:00
2009-01-06 06:53:34 +01:00
if (nulls_placement)
{
2010-10-24 02:26:00 +02:00
switch (ExprNode::as<LiteralNode>(nulls_placement)->getSlong())
2009-01-06 06:53:34 +01:00
{
case NOD_NULLS_FIRST:
dsqlScratch->appendUChar(blr_nullsfirst);
break;
case NOD_NULLS_LAST:
dsqlScratch->appendUChar(blr_nullslast);
break;
}
}
2002-09-10 20:28:23 +02:00
if ((*ptr)->nod_arg[e_order_flag])
dsqlScratch->appendUChar(blr_descending);
2001-05-23 15:26:42 +02:00
else
dsqlScratch->appendUChar(blr_ascending);
GEN_expr(dsqlScratch, (*ptr)->nod_arg[e_order_field]);
2001-05-23 15:26:42 +02:00
}
}
/**
gen_union
@brief Generate a union of substreams.
@param dsqlScratch
@param union_node
**/
static void gen_union( DsqlCompilerScratch* dsqlScratch, const dsql_nod* union_node)
2001-05-23 15:26:42 +02:00
{
const RseNode* unionRse = ExprNode::as<RseNode>(union_node);
if (unionRse->dsqlStreams->nod_flags & NOD_UNION_RECURSIVE)
dsqlScratch->appendUChar(blr_recurse);
else
dsqlScratch->appendUChar(blr_union);
2001-05-23 15:26:42 +02:00
2009-04-18 16:13:26 +02:00
// Obtain the context for UNION from the first dsql_map* node
dsql_nod* items = unionRse->dsqlSelectList;
dsql_nod* map_item = items->nod_arg[0];
// AB: First item could be a virtual field generated by derived table.
2011-04-02 06:24:20 +02:00
DerivedFieldNode* derivedField = ExprNode::as<DerivedFieldNode>(map_item);
2011-04-02 06:24:20 +02:00
if (derivedField)
map_item = derivedField->dsqlValue;
dsql_ctx* union_context = ExprNode::as<DsqlMapNode>(map_item)->context;
GEN_stuff_context(dsqlScratch, 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 = ExprNode::as<UnionSourceNode>(unionRse->dsqlStreams)->dsqlClauses;
dsqlScratch->appendUChar(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;
2009-01-06 06:53:34 +01:00
for (const dsql_nod* const* const end = ptr + streams->nod_count; ptr < end; ptr++)
{
dsql_nod* sub_rse = *ptr;
GEN_rse(dsqlScratch, sub_rse);
items = ExprNode::as<RseNode>(sub_rse)->dsqlSelectList;
dsqlScratch->appendUChar(blr_map);
dsqlScratch->appendUShort(items->nod_count);
USHORT count = 0;
dsql_nod** iptr = items->nod_arg;
2009-01-06 06:53:34 +01:00
for (const dsql_nod* const* const iend = iptr + items->nod_count; iptr < iend; iptr++)
{
dsqlScratch->appendUShort(count);
GEN_expr(dsqlScratch, *iptr);
2001-05-23 15:26:42 +02:00
count++;
}
}
}
// Write a context number into the BLR buffer. Check for possible overflow.
void GEN_stuff_context(DsqlCompilerScratch* dsqlScratch, const dsql_ctx* context)
{
if (context->ctx_context > MAX_UCHAR)
ERRD_post(Arg::Gds(isc_too_many_contexts));
dsqlScratch->appendUChar(context->ctx_context);
if (context->ctx_flags & CTX_recursive)
{
if (context->ctx_recursive > MAX_UCHAR)
ERRD_post(Arg::Gds(isc_too_many_contexts));
dsqlScratch->appendUChar(context->ctx_recursive);
}
}