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

495 lines
12 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: make.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Routines to make various blocks.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-06-29 08:56:51 +02:00
* 2001.11.21 Claudio Valderrama: Finally solved the mystery of DSQL
* not recognizing when a UDF returns NULL. This fixes SF bug #484399.
* See case nod_udf in MAKE_desc().
* 2001.02.23 Claudio Valderrama: Fix SF bug #518350 with substring()
* and text blobs containing charsets other than ASCII/NONE/BINARY.
* 2002.07.30 Arno Brinkman:
* COALESCE, CASE support added
* procedure MAKE_desc_from_list added
* 2003.01.25 Dmitry Yemanov: Fixed problem with concatenation which
* trashed RDB$FIELD_LENGTH in the system tables. This change may
* potentially interfere with the one made by Claudio one year ago.
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 <ctype.h>
#include <string.h>
#include "../dsql/dsql.h"
#include "../dsql/Nodes.h"
#include "../dsql/ExprNodes.h"
2003-11-08 00:27:24 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/intl.h"
#include "../jrd/constants.h"
#include "../jrd/align.h"
#include "../dsql/errd_proto.h"
#include "../dsql/make_proto.h"
2005-05-28 00:45:31 +02:00
#include "../dsql/metd_proto.h"
#include "../dsql/utld_proto.h"
#include "../dsql/DSqlDataTypeUtil.h"
#include "../jrd/DataTypeUtil.h"
#include "../jrd/RecordSourceNodes.h"
2008-02-28 14:48:16 +01:00
#include "../jrd/jrd.h"
#include "../jrd/ods.h"
#include "../jrd/ini.h"
2010-10-12 10:02:57 +02:00
#include "../common/dsc_proto.h"
#include "../common/cvt.h"
2010-10-12 10:02:57 +02:00
#include "../yvalve/why_proto.h"
#include "../common/config/config.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 Firebird;
2001-05-23 15:26:42 +02:00
static void adjustLength(dsc* desc)
{
USHORT adjust = 0;
if (desc->dsc_dtype == dtype_varying)
adjust = sizeof(USHORT);
else if (desc->dsc_dtype == dtype_cstring)
adjust = 1;
desc->dsc_length -= adjust;
desc->dsc_length *= 3;
desc->dsc_length += adjust;
}
2012-04-25 03:42:47 +02:00
LiteralNode* MAKE_const_slong(SLONG value)
{
2008-02-28 14:48:16 +01:00
thread_db* tdbb = JRD_get_thread_data();
2010-10-24 02:26:00 +02:00
SLONG* valuePtr = FB_NEW(*tdbb->getDefaultPool()) SLONG(value);
LiteralNode* literal = FB_NEW(*tdbb->getDefaultPool()) LiteralNode(*tdbb->getDefaultPool());
literal->litDesc.dsc_dtype = dtype_long;
literal->litDesc.dsc_length = sizeof(SLONG);
literal->litDesc.dsc_scale = 0;
literal->litDesc.dsc_sub_type = 0;
literal->litDesc.dsc_address = reinterpret_cast<UCHAR*>(valuePtr);
2012-04-25 03:42:47 +02:00
return literal;
}
LiteralNode* MAKE_const_sint64(SINT64 value, SCHAR scale)
{
thread_db* tdbb = JRD_get_thread_data();
SINT64* valuePtr = FB_NEW(*tdbb->getDefaultPool()) SINT64(value);
LiteralNode* literal = FB_NEW(*tdbb->getDefaultPool()) LiteralNode(*tdbb->getDefaultPool());
literal->litDesc.dsc_dtype = dtype_int64;
literal->litDesc.dsc_length = sizeof(SINT64);
literal->litDesc.dsc_scale = scale;
literal->litDesc.dsc_sub_type = 0;
literal->litDesc.dsc_address = reinterpret_cast<UCHAR*>(valuePtr);
return literal;
}
/**
MAKE_constant
@brief Make a constant node.
@param constant
@param numeric_flag
**/
ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag)
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-10-24 02:26:00 +02:00
LiteralNode* literal = FB_NEW(*tdbb->getDefaultPool()) LiteralNode(*tdbb->getDefaultPool());
switch (numeric_flag)
{
case CONSTANT_DOUBLE:
2009-04-18 16:13:26 +02:00
// This is a numeric value which is transported to the engine as
// a string. The engine will convert it. Use dtype_double so that
// the engine can distinguish it from an actual string.
// Note: Due to the size of dsc_scale we are limited to numeric
// constants of less than 256 bytes.
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_dtype = dtype_double;
// Scale has no use for double
literal->litDesc.dsc_scale = static_cast<signed char>(strlen(str));
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_sub_type = 0;
literal->litDesc.dsc_length = sizeof(double);
literal->litDesc.dsc_address = (UCHAR*) str;
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_ttype() = ttype_ascii;
break;
2001-05-23 15:26:42 +02:00
case CONSTANT_DATE:
case CONSTANT_TIME:
case CONSTANT_TIMESTAMP:
{
// Setup the constant's descriptor
2001-05-23 15:26:42 +02:00
2009-01-06 06:53:34 +01:00
switch (numeric_flag)
{
case CONSTANT_DATE:
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_dtype = dtype_sql_date;
break;
case CONSTANT_TIME:
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_dtype = dtype_sql_time;
break;
case CONSTANT_TIMESTAMP:
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_dtype = dtype_timestamp;
break;
}
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_sub_type = 0;
literal->litDesc.dsc_scale = 0;
literal->litDesc.dsc_length = type_lengths[literal->litDesc.dsc_dtype];
literal->litDesc.dsc_address =
FB_NEW(*tdbb->getDefaultPool()) UCHAR[literal->litDesc.dsc_length];
2001-05-23 15:26:42 +02:00
// Set up a descriptor to point to the string
2001-05-23 15:26:42 +02:00
dsc tmp;
tmp.dsc_dtype = dtype_text;
tmp.dsc_scale = 0;
tmp.dsc_flags = 0;
tmp.dsc_ttype() = ttype_ascii;
tmp.dsc_length = static_cast<USHORT>(strlen(str));
tmp.dsc_address = (UCHAR*) str;
2001-05-23 15:26:42 +02:00
// Now invoke the string_to_date/time/timestamp routines
2001-05-23 15:26:42 +02:00
2010-10-24 02:26:00 +02:00
CVT_move(&tmp, &literal->litDesc, ERRD_post);
break;
}
2001-05-23 15:26:42 +02:00
2010-12-18 03:17:06 +01:00
case CONSTANT_BOOLEAN:
literal->litDesc.makeBoolean((UCHAR*) str);
2010-12-18 03:17:06 +01:00
break;
default:
fb_assert(false);
break;
2001-05-23 15:26:42 +02:00
}
2012-04-25 03:42:47 +02:00
return literal;
2001-05-23 15:26:42 +02:00
}
/**
MAKE_str_constant
@brief Make a constant node when the
character set ID is already known.
@param constant
@param character_set
**/
LiteralNode* MAKE_str_constant(const IntlString* constant, SSHORT character_set)
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
const string& str = constant->getString();
2001-05-23 15:26:42 +02:00
2010-10-24 02:26:00 +02:00
LiteralNode* literal = FB_NEW(*tdbb->getDefaultPool()) LiteralNode(*tdbb->getDefaultPool());
literal->litDesc.dsc_dtype = dtype_text;
literal->litDesc.dsc_sub_type = 0;
literal->litDesc.dsc_scale = 0;
literal->litDesc.dsc_length = static_cast<USHORT>(str.length());
literal->litDesc.dsc_address = (UCHAR*) str.c_str();
2010-10-24 02:26:00 +02:00
literal->litDesc.dsc_ttype() = character_set;
literal->dsqlStr = constant;
2012-04-25 03:42:47 +02:00
return literal;
2001-05-23 15:26:42 +02:00
}
2012-02-10 04:06:22 +01:00
// Make a descriptor from input node.
2012-04-25 03:42:47 +02:00
void MAKE_desc(DsqlCompilerScratch* dsqlScratch, dsc* desc, ValueExprNode* node)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(node, dsql_type_nod);
2001-05-23 15:26:42 +02:00
// If we already know the datatype, don't worry about anything.
2012-04-25 03:42:47 +02:00
if (node->nodDesc.dsc_dtype)
{
2012-04-25 03:42:47 +02:00
*desc = node->nodDesc;
2001-05-23 15:26:42 +02:00
return;
}
2012-04-25 03:42:47 +02:00
node->make(dsqlScratch, desc);
2001-05-23 15:26:42 +02:00
}
/**
MAKE_desc_from_field
@brief Compute a DSC from a field's description information.
@param desc
@param field
**/
2003-10-05 08:27:16 +02:00
void MAKE_desc_from_field(dsc* desc, const dsql_fld* field)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(field, dsql_type_fld);
2001-05-23 15:26:42 +02:00
2012-04-25 03:42:47 +02:00
desc->clear();
desc->dsc_dtype = static_cast<UCHAR>(field->dtype);
desc->dsc_scale = static_cast<SCHAR>(field->scale);
desc->dsc_sub_type = field->subType;
desc->dsc_length = field->length;
desc->dsc_flags = (field->flags & FLD_nullable) ? DSC_nullable : 0;
2009-11-28 20:39:23 +01:00
if (desc->isText() || desc->isBlob())
desc->setTextType(INTL_CS_COLL_TO_TTYPE(field->charSetId, field->collationId));
// UNICODE_FSS_HACK
// check if the field is a system domain and CHARACTER SET is UNICODE_FSS
if (desc->isText() && (INTL_GET_CHARSET(desc) == CS_UNICODE_FSS) && (field->flags & FLD_system))
adjustLength(desc);
2001-05-23 15:26:42 +02:00
}
/**
MAKE_desc_from_list
@brief Make a descriptor from a list of values
according to the sql-standard.
@param desc
@param node
@param expression_name
**/
2012-04-25 03:42:47 +02:00
void MAKE_desc_from_list(DsqlCompilerScratch* dsqlScratch, dsc* desc, ValueListNode* node,
const TEXT* expression_name)
{
2012-05-03 18:43:29 +02:00
NestConst<ValueExprNode>* p = node->items.begin();
NestConst<ValueExprNode>* end = node->items.end();
2012-04-25 03:42:47 +02:00
Array<const dsc*> args;
2012-04-25 03:42:47 +02:00
while (p != end)
2007-04-12 17:56:34 +02:00
{
2012-04-25 03:42:47 +02:00
MAKE_desc(dsqlScratch, &(*p)->nodDesc, *p);
args.add(&(*p)->nodDesc);
++p;
}
DSqlDataTypeUtil(dsqlScratch).makeFromList(desc, expression_name, args.getCount(), args.begin());
}
/**
MAKE_field
@brief Make up a field node.
@param context
@param field
@param indices
**/
2012-04-25 03:42:47 +02:00
FieldNode* MAKE_field(dsql_ctx* context, dsql_fld* field, ValueListNode* indices)
2001-05-23 15:26:42 +02:00
{
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(context, dsql_type_ctx);
DEV_BLKCHK(field, dsql_type_fld);
2001-05-23 15:26:42 +02:00
thread_db* const tdbb = JRD_get_thread_data();
2011-02-18 01:52:10 +01:00
FieldNode* const node = FB_NEW(*tdbb->getDefaultPool()) FieldNode(
*tdbb->getDefaultPool(), context, field, indices);
2010-12-19 22:42:32 +01:00
if (field->dimensions)
2009-01-06 06:53:34 +01:00
{
2009-01-08 10:26:06 +01:00
if (indices)
{
2012-04-25 03:42:47 +02:00
MAKE_desc_from_field(&node->nodDesc, field);
node->nodDesc.dsc_dtype = static_cast<UCHAR>(field->elementDtype);
node->nodDesc.dsc_length = field->elementLength;
2009-04-18 16:13:26 +02:00
// node->nodDesc.dsc_scale = field->scale;
// node->nodDesc.dsc_sub_type = field->subType;
// UNICODE_FSS_HACK
// check if the field is a system domain and the type is CHAR/VARCHAR CHARACTER SET UNICODE_FSS
if ((field->flags & FLD_system) && node->nodDesc.dsc_dtype <= dtype_varying &&
INTL_GET_CHARSET(&node->nodDesc) == CS_METADATA)
{
adjustLength(&node->nodDesc);
}
2001-05-23 15:26:42 +02:00
}
2009-01-08 10:26:06 +01:00
else
{
2012-04-25 03:42:47 +02:00
node->nodDesc.dsc_dtype = dtype_array;
node->nodDesc.dsc_length = sizeof(ISC_QUAD);
node->nodDesc.dsc_scale = static_cast<SCHAR>(field->scale);
node->nodDesc.dsc_sub_type = field->subType;
2001-05-23 15:26:42 +02:00
}
}
2009-01-08 10:26:06 +01:00
else
{
if (indices)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
Arg::Gds(isc_dsql_only_can_subscript_array) << Arg::Str(field->fld_name));
}
2012-04-25 03:42:47 +02:00
MAKE_desc_from_field(&node->nodDesc, field);
2001-05-23 15:26:42 +02:00
}
if ((field->flags & FLD_nullable) || (context->ctx_flags & CTX_outer_join))
2012-04-25 03:42:47 +02:00
node->nodDesc.dsc_flags |= DSC_nullable;
2001-05-23 15:26:42 +02:00
2012-04-25 03:42:47 +02:00
return node;
2001-05-23 15:26:42 +02:00
}
2008-02-28 14:48:16 +01:00
/**
2008-02-28 14:48:16 +01:00
MAKE_field_name
2008-02-28 14:48:16 +01:00
@brief Make up a field name node.
2008-02-28 14:48:16 +01:00
@param field_name
**/
2012-04-25 03:42:47 +02:00
FieldNode* MAKE_field_name(const char* field_name)
2008-02-28 14:48:16 +01:00
{
thread_db* tdbb = JRD_get_thread_data();
FieldNode* fieldNode = FB_NEW(*tdbb->getDefaultPool()) FieldNode(*tdbb->getDefaultPool());
fieldNode->dsqlName = field_name;
2012-04-25 03:42:47 +02:00
return fieldNode;
2001-05-23 15:26:42 +02:00
}
/**
MAKE_parameter
@brief Generate a parameter block for a message. If requested,
set up for a null flag as well.
@param message
@param sqlda_flag
@param null_flag
@param sqlda_index
@param node
**/
2004-02-02 12:02:12 +01:00
dsql_par* MAKE_parameter(dsql_msg* message, bool sqlda_flag, bool null_flag,
2012-04-25 03:42:47 +02:00
USHORT sqlda_index, const ValueExprNode* node)
2001-05-23 15:26:42 +02:00
{
2009-11-16 10:18:24 +01:00
if (!message)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_badmsgnum));
}
if (sqlda_flag && sqlda_index && sqlda_index <= message->msg_index)
{
// This parameter is possibly already here. Look for it.
2014-07-17 20:48:46 +02:00
for (FB_SIZE_T i = 0; i < message->msg_parameters.getCount(); ++i)
2009-11-16 10:18:24 +01:00
{
dsql_par* temp = message->msg_parameters[i];
if (temp->par_index == sqlda_index)
return temp;
}
}
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
dsql_par* parameter = FB_NEW(*tdbb->getDefaultPool()) dsql_par(*tdbb->getDefaultPool());
2001-05-23 15:26:42 +02:00
parameter->par_message = message;
message->msg_parameters.insert(0, parameter);
2001-05-23 15:26:42 +02:00
parameter->par_parameter = message->msg_parameter++;
2001-05-23 15:26:42 +02:00
parameter->par_rel_name = NULL;
parameter->par_owner_name = NULL;
parameter->par_rel_alias = NULL;
2001-05-23 15:26:42 +02:00
if (node)
MAKE_parameter_names(parameter, node);
2009-04-18 16:13:26 +02:00
// If the parameter is used declared, set SQLDA index
2009-01-08 10:26:06 +01:00
if (sqlda_flag)
{
2009-11-16 10:18:24 +01:00
if (sqlda_index)
{
parameter->par_index = sqlda_index;
2003-12-22 11:00:59 +01:00
if (message->msg_index < sqlda_index)
message->msg_index = sqlda_index;
}
else {
parameter->par_index = ++message->msg_index;
}
}
2009-04-18 16:13:26 +02:00
// If a null handing has been requested, set up a null flag
2001-05-23 15:26:42 +02:00
2009-11-16 10:18:24 +01:00
if (null_flag)
{
dsql_par* null = MAKE_parameter(message, false, false, 0, NULL);
2003-10-05 08:27:16 +02:00
parameter->par_null = null;
2001-05-23 15:26:42 +02:00
null->par_desc.dsc_dtype = dtype_short;
null->par_desc.dsc_scale = 0;
null->par_desc.dsc_length = sizeof(SSHORT);
}
return parameter;
}
/**
MAKE_parameter_names
@brief Determine relation/column/alias names (if appropriate)
and store them in the given parameter.
@param parameter
@param item
**/
2012-04-25 03:42:47 +02:00
void MAKE_parameter_names(dsql_par* parameter, const ValueExprNode* item)
{
fb_assert(parameter && item);
2012-04-25 03:42:47 +02:00
item->setParameterName(parameter);
}