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.
|
2002-09-28 16:04:35 +02:00
|
|
|
* 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-29 21:20:44 +01:00
|
|
|
* 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks
|
|
|
|
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
|
2003-11-02 13:28:30 +01:00
|
|
|
* 2003.10.05 Dmitry Yemanov: Added support for explicit cursors in PSQL
|
2008-09-27 11:51:53 +02:00
|
|
|
* 2004.01.16 Vlad Horsun: Added support for default parameters and
|
2004-01-16 11:43:21 +01:00
|
|
|
* EXECUTE BLOCK statement
|
2007-04-13 03:37:44 +02:00
|
|
|
* Adriano dos Santos Fernandes
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "../dsql/dsql.h"
|
2009-10-21 02:42:38 +02:00
|
|
|
#include "../dsql/DdlNodes.h"
|
2010-10-24 02:26:00 +02:00
|
|
|
#include "../dsql/ExprNodes.h"
|
2008-05-19 15:47:48 +02:00
|
|
|
#include "../dsql/StmtNodes.h"
|
2011-01-09 22:58:56 +01:00
|
|
|
#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"
|
2006-07-20 11:57:04 +02:00
|
|
|
#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"
|
2005-06-10 04:03:08 +02:00
|
|
|
#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"
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "gen/iberror.h"
|
2008-08-15 13:21:47 +02:00
|
|
|
#include "../common/StatusArg.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
using namespace Jrd;
|
2008-08-15 13:21:47 +02:00
|
|
|
using namespace Firebird;
|
2008-02-28 14:48:16 +01:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
static void gen_plan(DsqlCompilerScratch*, const PlanNode*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
|
2011-02-06 19:13:12 +01:00
|
|
|
void GEN_hidden_variables(DsqlCompilerScratch* dsqlScratch)
|
2008-08-15 18:32:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G E N _ h i d d e n _ v a r i a b l e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Function
|
|
|
|
* Emit BLR for hidden variables.
|
|
|
|
*
|
|
|
|
**************************************/
|
2011-01-31 15:47:41 +01:00
|
|
|
if (dsqlScratch->hiddenVariables.isEmpty())
|
2008-09-01 15:18:02 +02:00
|
|
|
return;
|
|
|
|
|
2011-01-31 15:47:41 +01:00
|
|
|
for (Array<dsql_var*>::const_iterator i = dsqlScratch->hiddenVariables.begin();
|
|
|
|
i != dsqlScratch->hiddenVariables.end();
|
|
|
|
++i)
|
2008-08-15 18:32:42 +02:00
|
|
|
{
|
2011-01-31 15:47:41 +01:00
|
|
|
const dsql_var* var = *i;
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_dcl_variable);
|
2011-01-31 15:47:41 +01:00
|
|
|
dsqlScratch->appendUShort(var->number);
|
|
|
|
GEN_descriptor(dsqlScratch, &var->desc, true);
|
2008-08-15 18:32:42 +02:00
|
|
|
}
|
2008-09-01 15:18:02 +02:00
|
|
|
|
|
|
|
// Clear it for GEN_expr not regenerate them.
|
2011-01-31 15:47:41 +01:00
|
|
|
dsqlScratch->hiddenVariables.clear();
|
2008-08-15 18:32:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
GEN_expr
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generate blr for an arbitrary expression.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
2009-12-20 22:01:10 +01:00
|
|
|
@param dsqlScratch
|
2003-02-15 04:01:51 +01:00
|
|
|
@param node
|
|
|
|
|
|
|
|
**/
|
2012-04-25 03:42:47 +02:00
|
|
|
void GEN_expr(DsqlCompilerScratch* dsqlScratch, ExprNode* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2012-04-25 03:42:47 +02:00
|
|
|
RseNode* rseNode = node->as<RseNode>();
|
|
|
|
if (rseNode)
|
2009-01-06 06:53:34 +01:00
|
|
|
{
|
2012-04-25 03:42:47 +02:00
|
|
|
GEN_rse(dsqlScratch, rseNode);
|
|
|
|
return;
|
|
|
|
}
|
2011-02-18 01:52:10 +01:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
node->genBlr(dsqlScratch);
|
2011-01-09 22:58:56 +01:00
|
|
|
|
2012-04-25 03:42:47 +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.
|
2011-01-09 22:58:56 +01:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
// ASF: Shouldn't we check nod_gen_id2 too?
|
2010-09-17 05:15:32 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (node->kind == DmlNode::KIND_VALUE && node->dsqlCompatDialectVerb &&
|
|
|
|
dsqlScratch->clientDialect == SQL_DIALECT_V6_TRANSITION)
|
|
|
|
{
|
|
|
|
dsc desc;
|
|
|
|
MAKE_desc(dsqlScratch, &desc, static_cast<ValueExprNode*>(node));
|
2010-09-17 05:15:32 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (desc.dsc_dtype == dtype_int64)
|
2011-02-18 01:52:10 +01:00
|
|
|
{
|
2012-04-25 03:42:47 +02:00
|
|
|
ERRD_post_warning(
|
|
|
|
Arg::Warning(isc_dsql_dialect_warning_expr) <<
|
|
|
|
Arg::Str(node->dsqlCompatDialectVerb));
|
2010-02-13 21:29:29 +01:00
|
|
|
}
|
2011-02-18 01:52:10 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
GEN_port
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generate a port from a message. Feel free to rearrange the
|
|
|
|
order of parameters.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
2009-12-20 22:01:10 +01:00
|
|
|
@param dsqlScratch
|
2003-02-15 04:01:51 +01:00
|
|
|
@param message
|
|
|
|
|
|
|
|
**/
|
2009-12-20 22:01:10 +01:00
|
|
|
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
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_message);
|
|
|
|
dsqlScratch->appendUChar(message->msg_number);
|
|
|
|
dsqlScratch->appendUShort(message->msg_parameter);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2006-07-20 11:57:04 +02:00
|
|
|
ULONG offset = 0;
|
2009-12-19 19:50:38 +01:00
|
|
|
|
|
|
|
for (size_t i = 0; i < message->msg_parameters.getCount(); ++i)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2009-12-19 19:50:38 +01:00
|
|
|
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) ?
|
2009-10-21 02:42:38 +02:00
|
|
|
fromCharSet : tdbb->getCharSet();
|
2007-06-28 17:27:28 +02:00
|
|
|
|
|
|
|
if (parameter->par_desc.dsc_dtype <= dtype_any_text &&
|
2009-10-21 02:42:38 +02:00
|
|
|
tdbb->getCharSet() != CS_NONE && tdbb->getCharSet() != CS_BINARY)
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
2005-06-06 10:30:03 +02:00
|
|
|
USHORT adjust = 0;
|
2005-05-28 00:45:31 +02:00
|
|
|
if (parameter->par_desc.dsc_dtype == dtype_varying)
|
2005-06-06 10:30:03 +02:00
|
|
|
adjust = sizeof(USHORT);
|
2005-05-28 00:45:31 +02:00
|
|
|
else if (parameter->par_desc.dsc_dtype == dtype_cstring)
|
2005-06-06 10:30:03 +02:00
|
|
|
adjust = 1;
|
|
|
|
|
|
|
|
parameter->par_desc.dsc_length -= adjust;
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2009-12-20 22:01:10 +01: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,
|
2006-01-15 19:11:31 +01:00
|
|
|
(fromCharSet == toCharSet ? INTL_GET_COLLATE(¶meter->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
|
|
|
|
2005-06-06 10:30:03 +02:00
|
|
|
parameter->par_desc.dsc_length += adjust;
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
2009-11-27 03:33:40 +01: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 &&
|
2009-10-21 02:42:38 +02:00
|
|
|
tdbb->getCharSet() != CS_NONE && tdbb->getCharSet() != CS_BINARY)
|
2007-06-28 17:27:28 +02:00
|
|
|
{
|
|
|
|
if (fromCharSet != toCharSet)
|
|
|
|
parameter->par_desc.setTextType(toCharSet);
|
|
|
|
}
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2011-04-13 18:57:58 +02:00
|
|
|
if (parameter->par_desc.dsc_dtype == dtype_text && parameter->par_index != 0)
|
2011-04-05 02:31:58 +02:00
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
const USHORT align = type_alignments[parameter->par_desc.dsc_dtype];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (align)
|
2006-07-20 11:57:04 +02:00
|
|
|
offset = FB_ALIGN(offset, align);
|
|
|
|
parameter->par_desc.dsc_address = (UCHAR*)(IPTR) offset;
|
|
|
|
offset += parameter->par_desc.dsc_length;
|
2011-03-22 19:59:13 +01:00
|
|
|
GEN_descriptor(dsqlScratch, ¶meter->par_desc, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2011-01-28 19:50:27 +01:00
|
|
|
message->msg_length = offset;
|
2006-07-20 11:57:04 +02:00
|
|
|
|
2009-12-20 22:01:10 +01:00
|
|
|
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
|
|
|
{
|
2009-12-20 23:42:43 +01:00
|
|
|
DsqlCompiledStatement* statement = scratch->getStatement();
|
2009-12-20 22:01:10 +01:00
|
|
|
|
2012-04-12 11:02:13 +02:00
|
|
|
if (statement->getBlrVersion() == 4)
|
2010-06-17 03:18:40 +02:00
|
|
|
scratch->appendUChar(blr_version4);
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2010-06-17 03:18:40 +02:00
|
|
|
scratch->appendUChar(blr_version5);
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2009-12-23 01:57:08 +01:00
|
|
|
if (statement->getType() == DsqlCompiledStatement::TYPE_SAVEPOINT)
|
2002-10-29 21:20:44 +01:00
|
|
|
{
|
2009-12-20 23:42:43 +01:00
|
|
|
// Do not generate BEGIN..END block around savepoint statement
|
2002-10-29 21:20:44 +01:00
|
|
|
// to avoid breaking of savepoint logic
|
2009-12-22 16:36:10 +01:00
|
|
|
statement->setSendMsg(NULL);
|
|
|
|
statement->setReceiveMsg(NULL);
|
2012-02-20 03:02:04 +01:00
|
|
|
node->genBlr(scratch);
|
2008-09-27 11:51:53 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-19 05:54:39 +01:00
|
|
|
const bool block = statement->getType() == DsqlCompiledStatement::TYPE_EXEC_BLOCK ||
|
2011-10-03 00:11:41 +02:00
|
|
|
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
|
|
|
|
2011-02-06 19:13:12 +01:00
|
|
|
GEN_hidden_variables(scratch);
|
2008-08-15 18:32:42 +02:00
|
|
|
|
2009-12-23 01:57:08 +01:00
|
|
|
switch (statement->getType())
|
2004-10-26 09:21:47 +02:00
|
|
|
{
|
2009-12-23 01:57:08 +01: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:
|
|
|
|
{
|
2009-12-22 16:36:10 +01:00
|
|
|
dsql_msg* message = statement->getSendMsg();
|
2008-01-16 07:52:43 +01:00
|
|
|
if (!message->msg_parameter)
|
2009-12-22 16:36:10 +01:00
|
|
|
statement->setSendMsg(NULL);
|
2009-11-16 10:18:24 +01:00
|
|
|
else
|
|
|
|
{
|
2009-12-20 22:01:10 +01:00
|
|
|
GEN_port(scratch, message);
|
2010-06-17 03:18:40 +02:00
|
|
|
scratch->appendUChar(blr_receive);
|
|
|
|
scratch->appendUChar(message->msg_number);
|
2008-01-16 07:52:43 +01:00
|
|
|
}
|
2009-12-22 16:36:10 +01:00
|
|
|
message = statement->getReceiveMsg();
|
2008-01-16 07:52:43 +01:00
|
|
|
if (!message->msg_parameter)
|
2009-12-22 16:36:10 +01:00
|
|
|
statement->setReceiveMsg(NULL);
|
2008-01-16 07:52:43 +01:00
|
|
|
else
|
2009-12-20 22:01:10 +01:00
|
|
|
GEN_port(scratch, message);
|
2012-02-20 03:02:04 +01:00
|
|
|
node->genBlr(scratch);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-09-27 11:51:53 +02:00
|
|
|
}
|
2011-10-03 00:11:41 +02:00
|
|
|
|
|
|
|
if (!block)
|
|
|
|
scratch->appendUChar(blr_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
scratch->appendUChar(blr_eoc);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2008-08-15 18:32:42 +02:00
|
|
|
GEN_descriptor
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generate a blr descriptor from an internal descriptor.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
2009-12-20 22:01:10 +01:00
|
|
|
@param dsqlScratch
|
2003-02-15 04:01:51 +01:00
|
|
|
@param desc
|
|
|
|
@param texttype
|
|
|
|
|
|
|
|
**/
|
2009-12-20 22:01:10 +01:00
|
|
|
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)
|
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
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
|
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_text2); // automatic transliteration
|
|
|
|
dsqlScratch->appendUShort(ttype_dynamic);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2010-06-17 03:18:40 +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)
|
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
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
|
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_varying2); // automatic transliteration
|
|
|
|
dsqlScratch->appendUShort(ttype_dynamic);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUShort(desc->dsc_length - sizeof(USHORT));
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_short:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_short);
|
|
|
|
dsqlScratch->appendUChar(desc->dsc_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_long:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_long);
|
|
|
|
dsqlScratch->appendUChar(desc->dsc_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_quad:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_quad);
|
|
|
|
dsqlScratch->appendUChar(desc->dsc_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_int64:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_int64);
|
|
|
|
dsqlScratch->appendUChar(desc->dsc_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_real:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_float);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_double:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_double);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_sql_date:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_sql_date);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_sql_time:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_sql_time);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_timestamp:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_timestamp);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_array:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_quad);
|
|
|
|
dsqlScratch->appendUChar(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
2007-05-22 04:14:20 +02:00
|
|
|
case dtype_blob:
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_blob2);
|
|
|
|
dsqlScratch->appendUShort(desc->dsc_sub_type);
|
|
|
|
dsqlScratch->appendUShort(desc->getTextType());
|
2007-05-22 04:14:20 +02:00
|
|
|
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:
|
2008-09-27 11:51:53 +02:00
|
|
|
// don't understand dtype
|
2008-08-15 13:21:47 +02:00
|
|
|
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
|
|
|
{
|
2003-11-01 11:26:43 +01: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)
|
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_parameter);
|
|
|
|
dsqlScratch->appendUChar(message->msg_number);
|
|
|
|
dsqlScratch->appendUShort(parameter->par_parameter);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
// Generate blr for an access plan expression.
|
|
|
|
static void gen_plan(DsqlCompilerScratch* dsqlScratch, const PlanNode* planNode)
|
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
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
const Array<NestConst<PlanNode> >& list = planNode->subNodes;
|
|
|
|
|
2012-05-04 19:01:06 +02:00
|
|
|
if (list.getCount() > 1)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_join);
|
2012-04-25 03:42:47 +02:00
|
|
|
dsqlScratch->appendUChar(list.getCount());
|
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
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
for (const NestConst<PlanNode>* ptr = list.begin(); ptr != list.end(); ++ptr)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2012-04-25 03:42:47 +02:00
|
|
|
const PlanNode* node = *ptr;
|
|
|
|
|
|
|
|
if (node->subNodes.hasData())
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2009-12-20 22:01:10 +01:00
|
|
|
gen_plan(dsqlScratch, node);
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// if we're here, it must be a nod_plan_item
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_retrieve);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
// stuff the relation -- the relation id itself is redundant except
|
2009-04-18 16:13:26 +02:00
|
|
|
// when there is a need to differentiate the base tables of views
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
// ASF: node->dsqlRecordSourceNode may be NULL, and then a BLR error will happen.
|
|
|
|
// Example command: select * from (select * from t1) a plan (a natural);
|
|
|
|
if (node->dsqlRecordSourceNode)
|
|
|
|
node->dsqlRecordSourceNode->genBlr(dsqlScratch);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// now stuff the access method for this stream
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
unsigned delta = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
switch (node->accessType->type)
|
|
|
|
{
|
|
|
|
case PlanNode::AccessType::TYPE_SEQUENTIAL:
|
|
|
|
dsqlScratch->appendUChar(blr_sequential);
|
2003-09-14 17:37:05 +02:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
case PlanNode::AccessType::TYPE_NAVIGATIONAL:
|
|
|
|
dsqlScratch->appendUChar(blr_navigational);
|
|
|
|
dsqlScratch->appendNullString(node->accessType->items[0].indexName.c_str());
|
|
|
|
if (node->accessType->items.getCount() == 1)
|
|
|
|
break;
|
|
|
|
// dimitr: FALL INTO, if the plan item is ORDER ... INDEX (...)
|
|
|
|
// ASF: The first item of a TYPE_NAVIGATIONAL is not for blr_indices.
|
|
|
|
++delta;
|
|
|
|
|
|
|
|
case PlanNode::AccessType::TYPE_INDICES:
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_indices);
|
2012-04-25 03:42:47 +02:00
|
|
|
dsqlScratch->appendUChar(node->accessType->items.getCount() - delta);
|
|
|
|
|
|
|
|
const ObjectsArray<PlanNode::AccessItem>& items = node->accessType->items;
|
|
|
|
|
|
|
|
for (ObjectsArray<PlanNode::AccessItem>::const_iterator ptr2 = items.begin();
|
|
|
|
ptr2 != items.end();
|
|
|
|
++ptr2)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2012-04-25 03:42:47 +02:00
|
|
|
if (delta > 0)
|
|
|
|
--delta;
|
|
|
|
else
|
|
|
|
dsqlScratch->appendNullString(ptr2->indexName.c_str());
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
2012-04-25 03:42:47 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2010-02-22 17:00:49 +01:00
|
|
|
GEN_rse
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generate a record selection expression.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
2009-12-20 22:01:10 +01:00
|
|
|
@param dsqlScratch
|
2003-02-15 04:01:51 +01:00
|
|
|
@param rse
|
|
|
|
|
|
|
|
**/
|
2012-05-03 18:43:29 +02:00
|
|
|
void GEN_rse(DsqlCompilerScratch* dsqlScratch, RseNode* rse)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2012-04-07 05:03:28 +02:00
|
|
|
if (rse->dsqlFlags & RecordSourceNode::DFLAG_SINGLETON)
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_singular);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2011-01-22 21:40:04 +01:00
|
|
|
if (rse->dsqlExplicitJoin)
|
|
|
|
{
|
|
|
|
dsqlScratch->appendUChar(blr_rs_stream);
|
2012-05-03 18:43:29 +02:00
|
|
|
fb_assert(rse->dsqlStreams->items.getCount() == 2);
|
2011-01-22 21:40:04 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
dsqlScratch->appendUChar(blr_rse);
|
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
|
|
|
|
2012-05-03 18:43:29 +02:00
|
|
|
dsqlScratch->appendUChar(rse->dsqlStreams->items.getCount());
|
|
|
|
NestConst<RecordSourceNode>* ptr = rse->dsqlStreams->items.begin();
|
|
|
|
for (const NestConst<RecordSourceNode>* const end = rse->dsqlStreams->items.end(); ptr != end; ++ptr)
|
2012-04-25 03:42:47 +02:00
|
|
|
GEN_expr(dsqlScratch, *ptr);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2011-01-09 22:58:56 +01:00
|
|
|
if (rse->flags & RseNode::FLAG_WRITELOCK)
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_writelock);
|
2003-08-13 13:09:57 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (rse->dsqlFirst)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_first);
|
2012-04-25 03:42:47 +02:00
|
|
|
GEN_expr(dsqlScratch, rse->dsqlFirst);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (rse->dsqlSkip)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_skip);
|
2012-04-25 03:42:47 +02:00
|
|
|
GEN_expr(dsqlScratch, rse->dsqlSkip);
|
2006-06-02 10:03:22 +02:00
|
|
|
}
|
2002-06-29 08:56:51 +02:00
|
|
|
|
2011-01-22 21:40:04 +01:00
|
|
|
if (rse->rse_jointype != blr_inner)
|
|
|
|
{
|
|
|
|
dsqlScratch->appendUChar(blr_join_type);
|
|
|
|
dsqlScratch->appendUChar(rse->rse_jointype);
|
|
|
|
}
|
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (rse->dsqlWhere)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_boolean);
|
2012-04-25 03:42:47 +02:00
|
|
|
GEN_expr(dsqlScratch, rse->dsqlWhere);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (rse->dsqlOrder)
|
|
|
|
GEN_sort(dsqlScratch, rse->dsqlOrder);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (rse->dsqlDistinct)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_project);
|
2012-05-03 18:43:29 +02:00
|
|
|
dsqlScratch->appendUChar(rse->dsqlDistinct->items.getCount());
|
2011-01-09 22:58:56 +01:00
|
|
|
|
2012-05-03 18:43:29 +02:00
|
|
|
NestConst<ValueExprNode>* ptr = rse->dsqlDistinct->items.begin();
|
2011-01-09 22:58:56 +01:00
|
|
|
|
2012-05-03 18:43:29 +02:00
|
|
|
for (const NestConst<ValueExprNode>* const end = rse->dsqlDistinct->items.end(); ptr != end; ++ptr)
|
2009-12-20 22:01:10 +01:00
|
|
|
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
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (rse->rse_plan)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_plan);
|
2012-04-25 03:42:47 +02:00
|
|
|
gen_plan(dsqlScratch, rse->rse_plan);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-09 22:58:56 +01:00
|
|
|
// Generate a sort clause.
|
2012-04-25 03:42:47 +02:00
|
|
|
void GEN_sort(DsqlCompilerScratch* dsqlScratch, ValueListNode* list)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(blr_sort);
|
2012-05-03 18:43:29 +02:00
|
|
|
dsqlScratch->appendUChar(list->items.getCount());
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-05-03 18:43:29 +02:00
|
|
|
NestConst<ValueExprNode>* ptr = list->items.begin();
|
|
|
|
for (const NestConst<ValueExprNode>* const end = list->items.end(); ptr != end; ++ptr)
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2012-05-03 18:43:29 +02:00
|
|
|
OrderNode* orderNode = (*ptr)->as<OrderNode>();
|
2010-10-24 02:26:00 +02:00
|
|
|
|
2012-04-08 06:15:09 +02:00
|
|
|
switch (orderNode->nullsPlacement)
|
2009-01-06 06:53:34 +01:00
|
|
|
{
|
2012-04-08 06:15:09 +02:00
|
|
|
case OrderNode::NULLS_FIRST:
|
|
|
|
dsqlScratch->appendUChar(blr_nullsfirst);
|
|
|
|
break;
|
|
|
|
case OrderNode::NULLS_LAST:
|
|
|
|
dsqlScratch->appendUChar(blr_nullslast);
|
|
|
|
break;
|
2003-12-21 01:07:03 +01:00
|
|
|
}
|
2011-01-09 22:58:56 +01:00
|
|
|
|
2012-04-08 06:15:09 +02:00
|
|
|
dsqlScratch->appendUChar((orderNode->descending ? blr_descending : blr_ascending));
|
2012-05-03 18:43:29 +02:00
|
|
|
GEN_expr(dsqlScratch, orderNode->value);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-14 18:25:48 +01:00
|
|
|
// Write a context number into the BLR buffer. Check for possible overflow.
|
|
|
|
void GEN_stuff_context(DsqlCompilerScratch* dsqlScratch, const dsql_ctx* context)
|
2006-03-07 11:20:52 +01:00
|
|
|
{
|
2010-11-14 18:25:48 +01:00
|
|
|
if (context->ctx_context > MAX_UCHAR)
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_too_many_contexts));
|
2010-01-18 22:37:47 +01:00
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(context->ctx_context);
|
2007-07-21 23:28:56 +02:00
|
|
|
|
|
|
|
if (context->ctx_flags & CTX_recursive)
|
|
|
|
{
|
2010-11-14 18:25:48 +01:00
|
|
|
if (context->ctx_recursive > MAX_UCHAR)
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_too_many_contexts));
|
2010-11-14 18:25:48 +01:00
|
|
|
|
2010-06-17 03:18:40 +02:00
|
|
|
dsqlScratch->appendUChar(context->ctx_recursive);
|
2007-07-21 23:28:56 +02:00
|
|
|
}
|
2006-03-07 11:20:52 +01:00
|
|
|
}
|