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.
|
2008-09-27 11:51:53 +02:00
|
|
|
* 2002.07.30 Arno Brinkman:
|
2002-08-03 17:27:20 +02:00
|
|
|
* COALESCE, CASE support added
|
2008-09-27 11:51:53 +02:00
|
|
|
* procedure MAKE_desc_from_list added
|
2003-01-15 13:00:33 +01:00
|
|
|
* 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
|
|
|
*/
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "../dsql/dsql.h"
|
2010-02-13 21:29:29 +01:00
|
|
|
#include "../dsql/Nodes.h"
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
#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"
|
2005-06-10 04:03:08 +02:00
|
|
|
#include "../dsql/utld_proto.h"
|
2010-04-15 16:40:27 +02:00
|
|
|
#include "../dsql/DSqlDataTypeUtil.h"
|
2006-08-10 04:53:16 +02:00
|
|
|
#include "../jrd/DataTypeUtil.h"
|
2011-01-09 22:58:56 +01:00
|
|
|
#include "../jrd/RecordSourceNodes.h"
|
2008-02-28 14:48:16 +01:00
|
|
|
#include "../jrd/jrd.h"
|
2005-09-14 20:09:40 +02:00
|
|
|
#include "../jrd/ods.h"
|
|
|
|
#include "../jrd/ini.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/dsc_proto.h"
|
2008-07-10 17:57:33 +02:00
|
|
|
#include "../common/cvt.h"
|
2005-05-28 00:45:31 +02:00
|
|
|
#include "../jrd/thread_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../yvalve/why_proto.h"
|
2002-12-03 14:37:06 +01:00
|
|
|
#include "../common/config/config.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;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-09-02 07:30:16 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
LiteralNode* MAKE_const_slong(SLONG value)
|
2007-10-17 16:35:31 +02:00
|
|
|
{
|
2008-02-28 14:48:16 +01:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
2007-10-17 16:35:31 +02:00
|
|
|
|
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);
|
2007-10-17 16:35:31 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
return literal;
|
2012-03-25 03:08:55 +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
|
|
|
MAKE_constant
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a constant node.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param constant
|
|
|
|
@param numeric_flag
|
|
|
|
|
|
|
|
**/
|
2013-03-13 03:15:38 +01:00
|
|
|
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());
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
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;
|
2003-11-01 11:26:43 +01:00
|
|
|
// Scale has no use for double
|
2013-03-13 03:15:38 +01:00
|
|
|
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);
|
2013-03-13 03:15:38 +01:00
|
|
|
literal->litDesc.dsc_address = (UCHAR*) str;
|
2010-10-24 02:26:00 +02:00
|
|
|
literal->litDesc.dsc_ttype() = ttype_ascii;
|
2003-11-01 11:26:43 +01:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
case CONSTANT_SINT64:
|
|
|
|
{
|
2010-10-24 02:26:00 +02:00
|
|
|
// We convert the string to an int64.
|
|
|
|
|
|
|
|
literal->litDesc.dsc_dtype = dtype_int64;
|
|
|
|
literal->litDesc.dsc_length = sizeof(SINT64);
|
|
|
|
literal->litDesc.dsc_scale = 0;
|
|
|
|
literal->litDesc.dsc_sub_type = 0;
|
|
|
|
literal->litDesc.dsc_address = (UCHAR*) FB_NEW(*tdbb->getDefaultPool()) SINT64;
|
2003-11-01 11:26:43 +01:00
|
|
|
|
2008-02-27 17:00:31 +01:00
|
|
|
// Now convert the string to an int64. We can omit testing for
|
|
|
|
// overflow, because we would never have gotten here if yylex
|
|
|
|
// hadn't recognized the string as a valid 64-bit integer value.
|
|
|
|
// We *might* have "9223372936854775808", which works an an int64
|
|
|
|
// only if preceded by a '-', but that issue is handled in GEN_expr,
|
|
|
|
// and need not be addressed here.
|
2003-11-01 11:26:43 +01:00
|
|
|
|
2008-02-27 17:00:31 +01:00
|
|
|
// Recent change to support hex numeric constants means the input
|
|
|
|
// string now can be X8000000000000000, for example.
|
|
|
|
// Hex constants coming through this code are guaranteed to be
|
|
|
|
// valid - they start with X and contains only 0-9, A-F.
|
|
|
|
// And, they will fit in a SINT64 without overflow.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2008-02-27 17:00:31 +01:00
|
|
|
SINT64 value = 0;
|
2013-03-13 03:15:38 +01:00
|
|
|
const UCHAR* p = reinterpret_cast<const UCHAR*>(str);
|
2003-12-22 11:00:59 +01:00
|
|
|
|
2008-02-27 17:00:31 +01:00
|
|
|
if (*p == 'X')
|
|
|
|
{
|
|
|
|
// oh no, a hex string!
|
2010-11-09 16:03:33 +01:00
|
|
|
++p; // skip the 'X' part.
|
2008-02-27 17:00:31 +01:00
|
|
|
UCHAR byte = 0;
|
2013-03-13 03:15:38 +01:00
|
|
|
bool nibble = ((strlen(str) - 1) & 1);
|
2008-02-27 17:00:31 +01:00
|
|
|
SSHORT c;
|
|
|
|
|
|
|
|
// hex string is already upper-cased
|
2008-06-05 13:02:42 +02:00
|
|
|
while (isdigit(*p) || ((*p >= 'A') && (*p <= 'F')))
|
2008-02-27 17:00:31 +01:00
|
|
|
{
|
|
|
|
// Now convert the character to a nibble
|
|
|
|
if (*p >= 'A')
|
|
|
|
c = (*p - 'A') + 10;
|
|
|
|
else
|
|
|
|
c = (*p - '0');
|
|
|
|
|
|
|
|
if (nibble)
|
|
|
|
{
|
|
|
|
byte = (byte << 4) + (UCHAR) c;
|
2008-06-05 13:02:42 +02:00
|
|
|
nibble = false;
|
2008-02-27 17:00:31 +01:00
|
|
|
value = (value << 8) + byte;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
byte = c;
|
2008-06-05 13:02:42 +02:00
|
|
|
nibble = true;
|
2008-02-27 17:00:31 +01:00
|
|
|
}
|
|
|
|
|
2010-11-09 16:03:33 +01:00
|
|
|
++p;
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
|
|
|
|
2008-02-27 17:00:31 +01:00
|
|
|
// if value is negative, then GEN_constant (from dsql/gen.cpp)
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
// is going to want 2 nodes: NegateNode (to hold the minus)
|
2010-10-24 02:26:00 +02:00
|
|
|
// and LiteralNode as a child to hold the value.
|
2008-02-27 17:00:31 +01:00
|
|
|
if (value < 0)
|
|
|
|
{
|
|
|
|
value = -value;
|
2010-10-24 02:26:00 +02:00
|
|
|
*(SINT64*) literal->litDesc.dsc_address = value;
|
2012-04-25 03:42:47 +02:00
|
|
|
return FB_NEW(*tdbb->getDefaultPool()) NegateNode(*tdbb->getDefaultPool(), literal);
|
2008-02-27 17:00:31 +01:00
|
|
|
}
|
|
|
|
else
|
2010-10-24 02:26:00 +02:00
|
|
|
*(SINT64*) literal->litDesc.dsc_address = value;
|
2008-02-27 17:00:31 +01:00
|
|
|
} // hex constant
|
|
|
|
else
|
|
|
|
{
|
2010-10-24 02:26:00 +02:00
|
|
|
// Good old-fashioned base-10 number from the lexer.
|
|
|
|
// We convert the string to an int64.
|
2008-02-27 17:00:31 +01:00
|
|
|
|
|
|
|
while (isdigit(*p))
|
|
|
|
value = 10 * value + (*(p++) - '0');
|
|
|
|
|
|
|
|
if (*p++ == '.')
|
|
|
|
{
|
|
|
|
while (isdigit(*p))
|
|
|
|
{
|
|
|
|
value = 10 * value + (*p++ - '0');
|
2010-10-24 02:26:00 +02:00
|
|
|
literal->litDesc.dsc_scale--;
|
2008-02-27 17:00:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-24 02:26:00 +02:00
|
|
|
*(FB_UINT64*) (literal->litDesc.dsc_address) = value;
|
2008-02-27 17:00:31 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-02-27 17:00:31 +01:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
case CONSTANT_DATE:
|
|
|
|
case CONSTANT_TIME:
|
|
|
|
case CONSTANT_TIMESTAMP:
|
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
// Setup the constant's descriptor
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (numeric_flag)
|
|
|
|
{
|
2003-11-01 11:26:43 +01:00
|
|
|
case CONSTANT_DATE:
|
2010-10-24 02:26:00 +02:00
|
|
|
literal->litDesc.dsc_dtype = dtype_sql_date;
|
2003-11-01 11:26:43 +01:00
|
|
|
break;
|
|
|
|
case CONSTANT_TIME:
|
2010-10-24 02:26:00 +02:00
|
|
|
literal->litDesc.dsc_dtype = dtype_sql_time;
|
2003-11-01 11:26:43 +01:00
|
|
|
break;
|
|
|
|
case CONSTANT_TIMESTAMP:
|
2010-10-24 02:26:00 +02:00
|
|
|
literal->litDesc.dsc_dtype = dtype_timestamp;
|
2003-11-01 11:26:43 +01:00
|
|
|
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
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// Set up a descriptor to point to the string
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsc tmp;
|
|
|
|
tmp.dsc_dtype = dtype_text;
|
|
|
|
tmp.dsc_scale = 0;
|
|
|
|
tmp.dsc_flags = 0;
|
2004-05-21 08:16:17 +02:00
|
|
|
tmp.dsc_ttype() = ttype_ascii;
|
2013-03-13 03:15:38 +01:00
|
|
|
tmp.dsc_length = static_cast<USHORT>(strlen(str));
|
|
|
|
tmp.dsc_address = (UCHAR*) str;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-27 11:51:53 +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);
|
2003-11-01 11:26:43 +01:00
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-12-18 03:17:06 +01:00
|
|
|
case CONSTANT_BOOLEAN:
|
2013-03-13 03:15:38 +01:00
|
|
|
literal->litDesc.makeBoolean((UCHAR*) str);
|
2010-12-18 03:17:06 +01:00
|
|
|
break;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
default:
|
2012-12-25 18:34:50 +01:00
|
|
|
fb_assert(false);
|
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
|
|
|
return literal;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2004-09-05 09:23:42 +02:00
|
|
|
MAKE_str_constant
|
2008-09-27 11:51:53 +02:00
|
|
|
|
|
|
|
@brief Make a constant node when the
|
2003-02-15 04:01:51 +01:00
|
|
|
character set ID is already known.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param constant
|
|
|
|
@param character_set
|
|
|
|
|
|
|
|
**/
|
2012-12-25 18:34:50 +01:00
|
|
|
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
|
|
|
|
2012-12-25 18:34:50 +01: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;
|
2012-12-25 18:34:50 +01:00
|
|
|
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
|
|
|
|
2004-09-05 09:23: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)
|
2004-09-05 09:23:42 +02:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
MAKE_desc_from_field
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Compute a DSC from a field's description information.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@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();
|
2012-12-05 03:07:37 +01:00
|
|
|
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())
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
2009-11-28 20:39:23 +01:00
|
|
|
desc->setTextType(INTL_CS_COLL_TO_TTYPE(
|
2012-12-05 03:07:37 +01:00
|
|
|
field->charSetId, field->collationId));
|
2005-05-28 00:45:31 +02: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
|
|
|
MAKE_desc_from_list
|
2008-09-27 11:51:53 +02:00
|
|
|
|
|
|
|
@brief Make a descriptor from a list of values
|
2003-08-25 00:15:23 +02:00
|
|
|
according to the sql-standard.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param desc
|
|
|
|
@param node
|
2003-08-28 01:00:43 +02:00
|
|
|
@param expression_name
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
**/
|
2012-04-25 03:42:47 +02:00
|
|
|
void MAKE_desc_from_list(DsqlCompilerScratch* dsqlScratch, dsc* desc, ValueListNode* node,
|
2010-11-01 01:42:12 +01:00
|
|
|
const TEXT* expression_name)
|
2002-08-03 17:27:20 +02:00
|
|
|
{
|
2012-05-03 18:43:29 +02:00
|
|
|
NestConst<ValueExprNode>* p = node->items.begin();
|
|
|
|
NestConst<ValueExprNode>* end = node->items.end();
|
2002-08-03 17:27:20 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
Array<const dsc*> args;
|
2003-08-25 00:15:23 +02:00
|
|
|
|
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;
|
2002-08-03 17:27:20 +02:00
|
|
|
}
|
|
|
|
|
2009-12-20 22:01:10 +01:00
|
|
|
DSqlDataTypeUtil(dsqlScratch).makeFromList(desc, expression_name, args.getCount(), args.begin());
|
2002-08-03 17:27:20 +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
|
|
|
MAKE_field
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make up a field node.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@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
|
|
|
|
2011-02-12 21:35:22 +01: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
|
|
|
|
2012-12-05 03:07:37 +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);
|
2012-12-05 03:07:37 +01:00
|
|
|
node->nodDesc.dsc_dtype = static_cast<UCHAR>(field->elementDtype);
|
|
|
|
node->nodDesc.dsc_length = field->elementLength;
|
2009-04-18 16:13:26 +02:00
|
|
|
|
2012-12-05 03:07:37 +01:00
|
|
|
// node->nodDesc.dsc_scale = 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
|
|
|
|
{
|
2012-04-25 03:42:47 +02:00
|
|
|
node->nodDesc.dsc_dtype = dtype_array;
|
|
|
|
node->nodDesc.dsc_length = sizeof(ISC_QUAD);
|
2012-12-05 03:07:37 +01:00
|
|
|
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
|
|
|
|
{
|
2006-09-10 11:05:40 +02:00
|
|
|
if (indices)
|
|
|
|
{
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_only_can_subscript_array) << Arg::Str(field->fld_name));
|
2006-09-10 11:05:40 +02:00
|
|
|
}
|
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
MAKE_desc_from_field(&node->nodDesc, field);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-12-05 03:07:37 +01: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
|
|
|
|
2009-11-28 17:39:54 +01:00
|
|
|
// UNICODE_FSS_HACK
|
2006-10-07 19:06:59 +02:00
|
|
|
// check if the field is a system domain and the type is CHAR/VARCHAR CHARACTER SET UNICODE_FSS
|
2012-12-05 03:07:37 +01:00
|
|
|
if ((field->flags & FLD_system) && node->nodDesc.dsc_dtype <= dtype_varying &&
|
2012-04-25 03:42:47 +02:00
|
|
|
INTL_GET_CHARSET(&node->nodDesc) == CS_METADATA)
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
2005-09-14 20:09:40 +02:00
|
|
|
USHORT adjust = 0;
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
if (node->nodDesc.dsc_dtype == dtype_varying)
|
2005-09-14 20:09:40 +02:00
|
|
|
adjust = sizeof(USHORT);
|
2012-04-25 03:42:47 +02:00
|
|
|
else if (node->nodDesc.dsc_dtype == dtype_cstring)
|
2005-09-14 20:09:40 +02:00
|
|
|
adjust = 1;
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2012-04-25 03:42:47 +02:00
|
|
|
node->nodDesc.dsc_length -= adjust;
|
|
|
|
node->nodDesc.dsc_length *= 3;
|
|
|
|
node->nodDesc.dsc_length += adjust;
|
2005-05-28 00:45:31 +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-09-27 11:51:53 +02:00
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
MAKE_field_name
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
@brief Make up a field name node.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
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
|
|
|
{
|
2012-03-25 03:08:55 +02: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
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
MAKE_parameter
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generate a parameter block for a message. If requested,
|
|
|
|
set up for a null flag as well.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param message
|
|
|
|
@param sqlda_flag
|
|
|
|
@param null_flag
|
|
|
|
@param sqlda_index
|
2005-09-02 07:30:16 +02:00
|
|
|
@param node
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
**/
|
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)
|
|
|
|
{
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
|
|
|
|
Arg::Gds(isc_badmsgnum));
|
2005-05-12 19:46:31 +02:00
|
|
|
}
|
2008-09-27 11:51:53 +02:00
|
|
|
|
|
|
|
if (sqlda_flag && sqlda_index && sqlda_index <= message->msg_index)
|
2002-12-03 14:48:18 +01:00
|
|
|
{
|
2009-12-19 19:50:38 +01:00
|
|
|
// This parameter is possibly already here. Look for it.
|
|
|
|
for (size_t i = 0; i < message->msg_parameters.getCount(); ++i)
|
2009-11-16 10:18:24 +01:00
|
|
|
{
|
2009-12-19 19:50:38 +01:00
|
|
|
dsql_par* temp = message->msg_parameters[i];
|
|
|
|
|
2002-11-24 16:22:03 +01:00
|
|
|
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
|
|
|
|
2009-12-23 01:57:08 +01:00
|
|
|
dsql_par* parameter = FB_NEW(*tdbb->getDefaultPool()) dsql_par(*tdbb->getDefaultPool());
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter->par_message = message;
|
2009-12-19 19:50:38 +01:00
|
|
|
message->msg_parameters.insert(0, parameter);
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter->par_parameter = message->msg_parameter++;
|
2005-09-02 07:30:16 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter->par_rel_name = NULL;
|
|
|
|
parameter->par_owner_name = NULL;
|
2005-01-23 16:53:36 +01:00
|
|
|
parameter->par_rel_alias = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-02-13 21:29:29 +01:00
|
|
|
if (node)
|
|
|
|
MAKE_parameter_names(parameter, node);
|
2005-09-02 07:30:16 +02:00
|
|
|
|
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)
|
|
|
|
{
|
2002-11-24 16:22:03 +01:00
|
|
|
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 {
|
2002-11-24 16:22:03 +01:00
|
|
|
parameter->par_index = ++message->msg_index;
|
|
|
|
}
|
|
|
|
}
|
2008-09-27 11:51:53 +02:00
|
|
|
|
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)
|
|
|
|
{
|
2005-09-02 07:30:16 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-09-02 07:30:16 +02:00
|
|
|
/**
|
|
|
|
|
2010-02-13 21:29:29 +01:00
|
|
|
MAKE_parameter_names
|
2005-09-02 07:30:16 +02:00
|
|
|
|
|
|
|
@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)
|
2005-09-02 07:30:16 +02:00
|
|
|
{
|
|
|
|
fb_assert(parameter && item);
|
2012-04-25 03:42:47 +02:00
|
|
|
item->setParameterName(parameter);
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|