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-12-24 03:51:06 +01:00
|
|
|
//This MUST be before any other includes
|
|
|
|
#ifdef DARWIN
|
|
|
|
#define _STLP_CCTYPE
|
|
|
|
#endif
|
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 <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "../dsql/dsql.h"
|
2008-02-28 14:48:16 +01:00
|
|
|
#include "../dsql/node.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/hsh_proto.h"
|
|
|
|
#include "../dsql/make_proto.h"
|
2005-05-28 00:45:31 +02:00
|
|
|
#include "../dsql/metd_proto.h"
|
2005-09-02 07:30:16 +02:00
|
|
|
#include "../dsql/misc_func.h"
|
2005-06-10 04:03:08 +02:00
|
|
|
#include "../dsql/utld_proto.h"
|
2006-08-10 04:53:16 +02:00
|
|
|
#include "../jrd/DataTypeUtil.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"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/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"
|
2005-08-21 17:52:30 +02:00
|
|
|
#include "../jrd/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;
|
|
|
|
using namespace Dsql;
|
2008-08-15 13:21:47 +02:00
|
|
|
using namespace Firebird;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-02-11 10:04:54 +01:00
|
|
|
/* Firebird provides transparent conversion from string to date in
|
2001-05-23 15:26:42 +02:00
|
|
|
* contexts where it makes sense. This macro checks a descriptor to
|
|
|
|
* see if it is something that *could* represent a date value
|
|
|
|
*/
|
2003-09-29 14:43:14 +02:00
|
|
|
static inline bool could_be_date(const dsc& d)
|
2003-09-28 02:36:28 +02:00
|
|
|
{
|
2003-09-29 14:43:14 +02:00
|
|
|
return DTYPE_IS_DATE(d.dsc_dtype) || (d.dsc_dtype <= dtype_any_text);
|
2003-09-28 02:36:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// One of d1, d2 is time, the other is date
|
2003-09-29 14:43:14 +02:00
|
|
|
static inline bool is_date_and_time(const dsc& d1, const dsc& d2)
|
2003-09-28 02:36:28 +02:00
|
|
|
{
|
2003-09-29 14:43:14 +02:00
|
|
|
return ((d1.dsc_dtype == dtype_sql_time) && (d2.dsc_dtype == dtype_sql_date)) ||
|
|
|
|
((d2.dsc_dtype == dtype_sql_time) && (d1.dsc_dtype == dtype_sql_date));
|
2003-09-28 02:36:28 +02:00
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2005-02-14 06:51:25 +01:00
|
|
|
static void make_null(dsc* const desc);
|
2005-09-02 07:30:16 +02:00
|
|
|
static void make_parameter_names(dsql_par*, const dsql_nod*);
|
|
|
|
|
|
|
|
|
2008-09-07 23:50:00 +02:00
|
|
|
static const char* DB_KEY_NAME = "DB_KEY";
|
2005-02-14 06:51:25 +01:00
|
|
|
|
2007-10-19 03:25:11 +02:00
|
|
|
|
2009-04-10 22:18:17 +02:00
|
|
|
dsql_nod* 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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(), 1) dsql_nod;
|
2007-10-17 16:35:31 +02:00
|
|
|
node->nod_type = nod_constant;
|
2009-04-10 22:18:17 +02:00
|
|
|
node->nod_flags = 0;
|
2007-10-17 16:35:31 +02:00
|
|
|
node->nod_desc.dsc_dtype = dtype_long;
|
|
|
|
node->nod_desc.dsc_length = sizeof(SLONG);
|
|
|
|
node->nod_desc.dsc_scale = 0;
|
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
|
|
|
node->nod_desc.dsc_address = (UCHAR*) node->nod_arg;
|
|
|
|
|
|
|
|
*((SLONG *) (node->nod_desc.dsc_address)) = value;
|
|
|
|
//printf("make.cpp %p %d\n", node->nod_arg[0], value);
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2001-12-24 03:51:06 +01: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
|
|
|
|
|
|
|
|
**/
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_nod* MAKE_constant(dsql_str* constant, 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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(),
|
2001-12-24 03:51:06 +01:00
|
|
|
(numeric_flag == CONSTANT_TIMESTAMP ||
|
2002-11-21 00:18:16 +01:00
|
|
|
numeric_flag == CONSTANT_SINT64) ? 2 : 1) dsql_nod;
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_type = nod_constant;
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
switch (numeric_flag)
|
|
|
|
{
|
2007-10-17 16:35:31 +02:00
|
|
|
/* case CONSTANT_SLONG:
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_desc.dsc_dtype = dtype_long;
|
|
|
|
node->nod_desc.dsc_length = sizeof(SLONG);
|
|
|
|
node->nod_desc.dsc_scale = 0;
|
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
2004-01-21 08:18:30 +01:00
|
|
|
node->nod_desc.dsc_address = (UCHAR*) node->nod_arg;
|
2007-10-17 16:35:31 +02:00
|
|
|
*((SLONG *) (node->nod_desc.dsc_address)) = (SLONG) (IPTR) constant;
|
2003-11-01 11:26:43 +01:00
|
|
|
break;
|
2007-10-17 16:35:31 +02:00
|
|
|
*/
|
2003-11-01 11:26:43 +01:00
|
|
|
case CONSTANT_DOUBLE:
|
2001-12-24 03:51:06 +01:00
|
|
|
DEV_BLKCHK(constant, dsql_type_str);
|
2001-05-23 15:26:42 +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
|
2008-09-27 11:51:53 +02:00
|
|
|
constants of less than 256 bytes.
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
node->nod_desc.dsc_dtype = dtype_double;
|
2003-11-01 11:26:43 +01:00
|
|
|
// Scale has no use for double
|
2005-02-14 06:51:25 +01:00
|
|
|
node->nod_desc.dsc_scale = static_cast<signed char>(constant->str_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
|
|
|
node->nod_desc.dsc_length = sizeof(double);
|
2004-01-21 08:18:30 +01:00
|
|
|
node->nod_desc.dsc_address = (UCHAR*) constant->str_data;
|
2004-05-21 08:16:17 +02:00
|
|
|
node->nod_desc.dsc_ttype() = ttype_ascii;
|
2003-11-01 11:26:43 +01:00
|
|
|
node->nod_arg[0] = (dsql_nod*) constant;
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
case CONSTANT_SINT64:
|
|
|
|
{
|
2008-02-27 17:00:31 +01:00
|
|
|
// We convert the string to an int64. We treat the two adjacent
|
|
|
|
// 32-bit words node->nod_arg[0] and node->nod_arg[1] as a
|
|
|
|
// 64-bit integer: if we ever port to a platform which requires
|
|
|
|
// 8-byte alignment of int64 data, we will have to force 8-byte
|
|
|
|
// alignment of node->nod_arg, which is now only guaranteed
|
|
|
|
// 4-byte alignment. -- ChrisJ 1999-02-20
|
2003-11-01 11:26:43 +01:00
|
|
|
|
|
|
|
node->nod_desc.dsc_dtype = dtype_int64;
|
|
|
|
node->nod_desc.dsc_length = sizeof(SINT64);
|
|
|
|
node->nod_desc.dsc_scale = 0;
|
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
2004-01-21 08:18:30 +01:00
|
|
|
node->nod_desc.dsc_address = (UCHAR*) node->nod_arg;
|
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;
|
2009-01-03 11:00:58 +01:00
|
|
|
const UCHAR* p = reinterpret_cast<const UCHAR*>(constant->str_data);
|
2003-12-22 11:00:59 +01:00
|
|
|
|
2008-02-27 17:00:31 +01:00
|
|
|
if (*p == 'X')
|
|
|
|
{
|
|
|
|
// oh no, a hex string!
|
|
|
|
*p++; // skip the 'X' part.
|
|
|
|
UCHAR byte = 0;
|
2009-01-03 20:04:32 +01:00
|
|
|
bool nibble = ((strlen(constant->str_data) - 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
|
|
|
}
|
|
|
|
|
|
|
|
*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)
|
|
|
|
// is going to want 2 nodes: nod_negate (to hold the minus)
|
|
|
|
// and nod_constant as a child to hold the value.
|
|
|
|
if (value < 0)
|
|
|
|
{
|
|
|
|
value = -value;
|
|
|
|
*(SINT64*) node->nod_desc.dsc_address = value;
|
|
|
|
dsql_nod* sub = node;
|
|
|
|
node = MAKE_node(nod_negate, 1);
|
|
|
|
node->nod_arg[0] = sub;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*(SINT64*) node->nod_desc.dsc_address = value;
|
|
|
|
} // hex constant
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// good old-fashioned base-10 number from SQLParse.cpp
|
|
|
|
|
|
|
|
// We convert the string to an int64. We treat the two adjacent
|
|
|
|
// 32-bit words node->nod_arg[0] and node->nod_arg[1] as a
|
|
|
|
// 64-bit integer: if we ever port to a platform which requires
|
|
|
|
// 8-byte alignment of int64 data, we will have to force 8-byte
|
|
|
|
// alignment of node->nod_arg, which is now only guaranteed
|
|
|
|
// 4-byte alignment. -- ChrisJ 1999-02-20
|
|
|
|
|
|
|
|
while (isdigit(*p))
|
|
|
|
value = 10 * value + (*(p++) - '0');
|
|
|
|
|
|
|
|
if (*p++ == '.')
|
|
|
|
{
|
|
|
|
while (isdigit(*p))
|
|
|
|
{
|
|
|
|
value = 10 * value + (*p++ - '0');
|
|
|
|
node->nod_desc.dsc_scale--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*(FB_UINT64*) (node->nod_desc.dsc_address) = value;
|
|
|
|
}
|
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:
|
|
|
|
node->nod_desc.dsc_dtype = dtype_sql_date;
|
|
|
|
break;
|
|
|
|
case CONSTANT_TIME:
|
|
|
|
node->nod_desc.dsc_dtype = dtype_sql_time;
|
|
|
|
break;
|
|
|
|
case CONSTANT_TIMESTAMP:
|
|
|
|
node->nod_desc.dsc_dtype = dtype_timestamp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
|
|
|
node->nod_desc.dsc_scale = 0;
|
|
|
|
node->nod_desc.dsc_length = type_lengths[node->nod_desc.dsc_dtype];
|
2004-01-21 08:18:30 +01:00
|
|
|
node->nod_desc.dsc_address = (UCHAR*) node->nod_arg;
|
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;
|
2003-11-01 11:26:43 +01:00
|
|
|
tmp.dsc_length = static_cast<USHORT>(constant->str_length);
|
2004-01-21 08:18:30 +01:00
|
|
|
tmp.dsc_address = (UCHAR*) constant->str_data;
|
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
|
|
|
|
2003-11-03 18:14:45 +01:00
|
|
|
CVT_move(&tmp, &node->nod_desc, ERRD_post);
|
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
|
|
|
default:
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(numeric_flag == CONSTANT_STRING);
|
2001-12-24 03:51:06 +01:00
|
|
|
DEV_BLKCHK(constant, dsql_type_str);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
node->nod_desc.dsc_dtype = dtype_text;
|
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
|
|
|
node->nod_desc.dsc_scale = 0;
|
2009-01-06 06:53:34 +01:00
|
|
|
node->nod_desc.dsc_length = static_cast<USHORT>(constant->str_length);
|
2004-01-21 08:18:30 +01:00
|
|
|
node->nod_desc.dsc_address = (UCHAR*) constant->str_data;
|
2004-05-21 08:16:17 +02:00
|
|
|
node->nod_desc.dsc_ttype() = ttype_dynamic;
|
2008-09-27 11:51:53 +02:00
|
|
|
// carry a pointer to the constant to resolve character set in pass1
|
2003-11-01 11:26:43 +01:00
|
|
|
node->nod_arg[0] = (dsql_nod*) constant;
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
**/
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_nod* MAKE_str_constant(dsql_str* 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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(), 1) dsql_nod;
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_type = nod_constant;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
DEV_BLKCHK(constant, dsql_type_str);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
node->nod_desc.dsc_dtype = dtype_text;
|
|
|
|
node->nod_desc.dsc_sub_type = 0;
|
|
|
|
node->nod_desc.dsc_scale = 0;
|
2001-12-24 03:51:06 +01:00
|
|
|
node->nod_desc.dsc_length = static_cast<USHORT>(constant->str_length);
|
2004-01-21 08:18:30 +01:00
|
|
|
node->nod_desc.dsc_address = (UCHAR*) constant->str_data;
|
2004-05-21 08:16:17 +02:00
|
|
|
node->nod_desc.dsc_ttype() = character_set;
|
2008-09-27 11:51:53 +02:00
|
|
|
// carry a pointer to the constant to resolve character set in pass1
|
2003-11-01 11:26:43 +01:00
|
|
|
node->nod_arg[0] = (dsql_nod*) constant;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_cstring
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a string node for a string whose
|
|
|
|
length is not known, but is null-terminated.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param str
|
|
|
|
|
|
|
|
**/
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_str* MAKE_cstring(const char* str)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
|
2003-02-12 20:28:13 +01:00
|
|
|
return MAKE_string(str, strlen(str));
|
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
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a descriptor from input node.
|
2003-10-05 08:27:16 +02:00
|
|
|
This function can modify node->nod_flags to add NOD_COMP_DIALECT
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param desc
|
|
|
|
@param node
|
2004-09-04 20:24:12 +02:00
|
|
|
@param null_replacement
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
**/
|
2008-05-24 05:19:52 +02:00
|
|
|
void MAKE_desc(CompiledStatement* statement, dsc* desc, dsql_nod* node, dsql_nod* null_replacement)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2006-08-16 02:09:27 +02:00
|
|
|
dsc desc1, desc2, desc3;
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT dtype, dtype1, dtype2;
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_map* map;
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_ctx* context;
|
|
|
|
dsql_rel* relation;
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_fld* field;
|
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.
|
|
|
|
//
|
|
|
|
// dimitr: But let's re-evaluate descriptors for expression arguments
|
|
|
|
// (when a NULL replacement node is provided) to always
|
|
|
|
// choose the correct resulting datatype. Example:
|
|
|
|
// NULLIF(NULL, 0) => CHAR(1), but
|
|
|
|
// 1 + NULLIF(NULL, 0) => INT
|
|
|
|
// This is required because of MAKE_desc() being called
|
|
|
|
// from custom pass1 handlers for some node types and thus
|
|
|
|
// causing an incorrect datatype (determined without
|
|
|
|
// context) to be cached in nod_desc.
|
|
|
|
|
|
|
|
if (node->nod_desc.dsc_dtype && !null_replacement)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
*desc = node->nod_desc;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (node->nod_type)
|
|
|
|
{
|
2004-09-05 09:23:42 +02:00
|
|
|
case nod_constant:
|
2004-09-13 21:36:30 +02:00
|
|
|
case nod_variable:
|
2004-09-05 09:23:42 +02:00
|
|
|
*desc = node->nod_desc;
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_agg_count:
|
|
|
|
/* count2
|
|
|
|
case nod_agg_distinct:
|
|
|
|
*/
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_map:
|
2003-11-01 11:26:43 +01:00
|
|
|
map = (dsql_map*) node->nod_arg[e_map_map];
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, map->map_node, null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_agg_min:
|
|
|
|
case nod_agg_max:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = DSC_nullable;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_agg_average:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = DSC_nullable;
|
2009-01-06 06:53:34 +01:00
|
|
|
if (!DTYPE_IS_NUMERIC(desc->dsc_dtype) && !DTYPE_IS_TEXT(desc->dsc_dtype))
|
2005-08-06 07:29:31 +02:00
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_agg_wrongarg) << Arg::Str("AVG"));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
|
|
|
else if (DTYPE_IS_TEXT(desc->dsc_dtype)) {
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_agg_average2:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = DSC_nullable;
|
|
|
|
dtype = desc->dsc_dtype;
|
2005-08-06 07:29:31 +02:00
|
|
|
if (!DTYPE_IS_NUMERIC(dtype)) {
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("AVG"));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
|
|
|
else if (DTYPE_IS_EXACT(dtype)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
|
|
|
node->nod_flags |= NOD_COMP_DIALECT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_agg_total:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2009-01-06 06:53:34 +01:00
|
|
|
if (!DTYPE_IS_NUMERIC(desc->dsc_dtype) && !DTYPE_IS_TEXT(desc->dsc_dtype))
|
2005-08-06 07:29:31 +02:00
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_agg_wrongarg) << Arg::Str("SUM"));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
|
|
|
else if (desc->dsc_dtype == dtype_short) {
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
}
|
|
|
|
else if (desc->dsc_dtype == dtype_int64) {
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
}
|
2005-08-06 07:29:31 +02:00
|
|
|
else if (DTYPE_IS_TEXT(desc->dsc_dtype)) {
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = DSC_nullable;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_agg_total2:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype = desc->dsc_dtype;
|
2005-08-06 07:29:31 +02:00
|
|
|
if (!DTYPE_IS_NUMERIC(dtype)) {
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("SUM"));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
|
|
|
else if (DTYPE_IS_EXACT(dtype)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
|
|
|
node->nod_flags |= NOD_COMP_DIALECT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
}
|
|
|
|
desc->dsc_flags = DSC_nullable;
|
|
|
|
return;
|
|
|
|
|
2006-04-24 19:24:26 +02:00
|
|
|
case nod_agg_list:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2007-05-05 21:28:46 +02:00
|
|
|
desc->makeBlob(desc->getBlobSubType(), desc->getTextType());
|
|
|
|
desc->setNullable(true);
|
2006-04-24 19:24:26 +02:00
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_concatenate:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
|
|
|
DSqlDataTypeUtil(statement).makeConcatenate(desc, &desc1, &desc2);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
2003-09-04 17:02:22 +02:00
|
|
|
case nod_derived_field:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[e_derived_field_value], null_replacement);
|
2003-09-04 17:02:22 +02:00
|
|
|
return;
|
|
|
|
|
2006-08-12 05:17:01 +02:00
|
|
|
case nod_upcase:
|
|
|
|
case nod_lowcase:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], null_replacement);
|
2006-08-12 05:17:01 +02:00
|
|
|
if (desc1.dsc_dtype <= dtype_any_text || desc1.dsc_dtype == dtype_blob)
|
|
|
|
{
|
|
|
|
*desc = desc1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc->dsc_dtype = dtype_varying;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_ttype() = ttype_ascii;
|
|
|
|
desc->dsc_length = sizeof(USHORT) + DSC_string_length(&desc1);
|
2003-10-05 08:27:16 +02:00
|
|
|
desc->dsc_flags = desc1.dsc_flags & DSC_nullable;
|
|
|
|
return;
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2006-08-12 05:17:01 +02:00
|
|
|
case nod_substr:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], null_replacement);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], null_replacement);
|
|
|
|
MAKE_desc(statement, &desc3, node->nod_arg[2], null_replacement);
|
|
|
|
DSqlDataTypeUtil(statement).makeSubstr(desc, &desc1, &desc2, &desc3);
|
2006-08-12 05:17:01 +02:00
|
|
|
return;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-28 00:45:31 +02:00
|
|
|
case nod_trim:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[e_trim_value], null_replacement);
|
2005-06-12 23:20:12 +02:00
|
|
|
if (node->nod_arg[e_trim_characters])
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[e_trim_characters], null_replacement);
|
2005-06-12 23:20:12 +02:00
|
|
|
else
|
|
|
|
desc2.dsc_flags = 0;
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2006-05-13 03:27:35 +02:00
|
|
|
if (desc1.dsc_dtype == dtype_blob)
|
2006-05-14 16:32:43 +02:00
|
|
|
{
|
2006-05-13 03:27:35 +02:00
|
|
|
*desc = desc1;
|
2006-05-14 16:32:43 +02:00
|
|
|
desc->dsc_flags |= (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
|
|
|
}
|
2006-05-13 03:27:35 +02:00
|
|
|
else if (desc1.dsc_dtype <= dtype_any_text)
|
|
|
|
{
|
2005-05-28 00:45:31 +02:00
|
|
|
*desc = desc1;
|
|
|
|
desc->dsc_dtype = dtype_varying;
|
|
|
|
desc->dsc_length = sizeof(USHORT) + DSC_string_length(&desc1);
|
2005-06-12 23:20:12 +02:00
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2006-05-13 03:27:35 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
desc->dsc_dtype = dtype_varying;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_ttype() = ttype_ascii;
|
|
|
|
desc->dsc_length = sizeof(USHORT) + DSC_string_length(&desc1);
|
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_cast:
|
2003-11-01 11:26:43 +01:00
|
|
|
field = (dsql_fld*) node->nod_arg[e_cast_target];
|
2001-05-23 15:26:42 +02:00
|
|
|
MAKE_desc_from_field(desc, field);
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[e_cast_source], NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = desc1.dsc_flags & DSC_nullable;
|
|
|
|
return;
|
|
|
|
|
2002-08-03 17:27:20 +02:00
|
|
|
case nod_simple_case:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc_from_list(statement, &desc1, node->nod_arg[e_simple_case_results],
|
2004-09-05 09:23:42 +02:00
|
|
|
null_replacement, "CASE");
|
2002-08-03 17:27:20 +02:00
|
|
|
*desc = desc1;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_searched_case:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc_from_list(statement, &desc1, node->nod_arg[e_searched_case_results],
|
2004-09-05 09:23:42 +02:00
|
|
|
null_replacement, "CASE");
|
2002-08-03 17:27:20 +02:00
|
|
|
*desc = desc1;
|
|
|
|
return;
|
|
|
|
|
2003-10-05 08:27:16 +02:00
|
|
|
case nod_coalesce:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc_from_list(statement, &desc1, node->nod_arg[0],
|
2004-09-05 09:23:42 +02:00
|
|
|
null_replacement, "COALESCE");
|
2002-08-03 17:27:20 +02:00
|
|
|
*desc = desc1;
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
case nod_collate:
|
|
|
|
ERRD_bugcheck("Not expecting nod_collate in dsql/MAKE_desc");
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case nod_add:
|
|
|
|
case nod_subtract:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
if (node->nod_arg[0]->nod_type == nod_null && node->nod_arg[1]->nod_type == nod_null)
|
2004-09-04 20:24:12 +02:00
|
|
|
{
|
|
|
|
// NULL + NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype1 = desc1.dsc_dtype;
|
2006-04-05 06:38:03 +02:00
|
|
|
if (dtype_int64 == dtype1 || DTYPE_IS_TEXT(dtype1))
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype1 = dtype_double;
|
2005-08-06 07:29:31 +02:00
|
|
|
|
|
|
|
dtype2 = desc2.dsc_dtype;
|
2006-04-05 06:38:03 +02:00
|
|
|
if (dtype_int64 == dtype2 || DTYPE_IS_TEXT(dtype2))
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype2 = dtype_double;
|
|
|
|
|
|
|
|
dtype = MAX(dtype1, dtype2);
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
if (DTYPE_IS_BLOB(dtype)) {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2005-08-06 07:29:31 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (dtype)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_sql_time:
|
|
|
|
case dtype_sql_date:
|
2008-09-27 11:51:53 +02:00
|
|
|
// CVC: I don't see how this case can happen since dialect 1 doesn't accept DATE or TIME
|
|
|
|
// Forbid <date/time> +- <string>
|
2009-01-06 06:53:34 +01:00
|
|
|
if (DTYPE_IS_TEXT(desc1.dsc_dtype) || DTYPE_IS_TEXT(desc2.dsc_dtype))
|
2003-10-21 00:41:11 +02:00
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_nodateortime_pm_string));
|
2003-10-21 00:41:11 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case dtype_timestamp:
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// Allow <timestamp> +- <string> (historical)
|
|
|
|
if (could_be_date(desc1) && could_be_date(desc2))
|
|
|
|
{
|
|
|
|
if (node->nod_type == nod_subtract)
|
|
|
|
{
|
|
|
|
// <any date> - <any date>
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Legal permutations are:
|
|
|
|
<timestamp> - <timestamp>
|
|
|
|
<timestamp> - <date>
|
|
|
|
<date> - <date>
|
|
|
|
<date> - <timestamp>
|
|
|
|
<time> - <time>
|
|
|
|
<timestamp> - <string>
|
2008-09-27 11:51:53 +02:00
|
|
|
<string> - <timestamp>
|
2001-05-23 15:26:42 +02:00
|
|
|
<string> - <string> */
|
|
|
|
|
2005-09-16 12:50:57 +02:00
|
|
|
if (DTYPE_IS_TEXT(desc1.dsc_dtype))
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype = dtype_timestamp;
|
2005-09-16 12:50:57 +02:00
|
|
|
else if (DTYPE_IS_TEXT(desc2.dsc_dtype))
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype = dtype_timestamp;
|
2005-09-16 12:50:57 +02:00
|
|
|
else if (desc1.dsc_dtype == desc2.dsc_dtype)
|
|
|
|
dtype = desc1.dsc_dtype;
|
2009-01-06 06:53:34 +01:00
|
|
|
else if ((desc1.dsc_dtype == dtype_timestamp) && (desc2.dsc_dtype == dtype_sql_date))
|
2003-12-22 11:00:59 +01:00
|
|
|
{
|
2004-09-04 20:24:12 +02:00
|
|
|
dtype = dtype_timestamp;
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2009-01-06 06:53:34 +01:00
|
|
|
else if ((desc2.dsc_dtype == dtype_timestamp) && (desc1.dsc_dtype == dtype_sql_date))
|
2003-12-22 11:00:59 +01:00
|
|
|
{
|
2004-09-04 20:24:12 +02:00
|
|
|
dtype = dtype_timestamp;
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
|
|
|
else {
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_datetime_subtract));
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (dtype == dtype_sql_date) {
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
|
|
|
else if (dtype == dtype_sql_time) {
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE;
|
2006-05-28 09:46:35 +02:00
|
|
|
desc->dsc_sub_type = dsc_num_type_numeric;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(dtype == dtype_timestamp);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
|
|
|
}
|
2003-09-28 02:36:28 +02:00
|
|
|
else if (is_date_and_time(desc1, desc2)) {
|
2008-09-27 11:51:53 +02:00
|
|
|
// <date> + <time>
|
|
|
|
// <time> + <date>
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_timestamp;
|
|
|
|
desc->dsc_length = type_lengths[dtype_timestamp];
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
2003-12-22 11:00:59 +01:00
|
|
|
else {
|
2008-09-27 11:51:53 +02:00
|
|
|
// <date> + <date>
|
|
|
|
// <time> + <time>
|
|
|
|
// CVC: Hard to see it, since we are in dialect 1.
|
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_dateortime_add));
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2006-05-28 09:46:35 +02:00
|
|
|
else if (DTYPE_IS_DATE(desc1.dsc_dtype) || (node->nod_type == nod_add))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2006-05-28 09:46:35 +02:00
|
|
|
// <date> +/- <non-date>
|
|
|
|
// <non-date> + <date>
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = desc1.dsc_dtype;
|
|
|
|
if (!DTYPE_IS_DATE(desc->dsc_dtype))
|
|
|
|
desc->dsc_dtype = desc2.dsc_dtype;
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(DTYPE_IS_DATE(desc->dsc_dtype));
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_length = type_lengths[desc->dsc_dtype];
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
|
|
|
else {
|
2008-09-27 11:51:53 +02:00
|
|
|
// <non-date> - <date>
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(node->nod_type == nod_subtract);
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_minus_date));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_varying:
|
|
|
|
case dtype_cstring:
|
|
|
|
case dtype_text:
|
|
|
|
case dtype_double:
|
|
|
|
case dtype_real:
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = MIN(NUMERIC_SCALE(desc1), NUMERIC_SCALE(desc2));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_add2:
|
|
|
|
case nod_subtract2:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
if (node->nod_arg[0]->nod_type == nod_null && node->nod_arg[1]->nod_type == nod_null)
|
2004-09-04 20:24:12 +02:00
|
|
|
{
|
|
|
|
// NULL + NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype1 = desc1.dsc_dtype;
|
|
|
|
dtype2 = desc2.dsc_dtype;
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// Arrays and blobs can never partipate in addition/subtraction
|
2005-12-12 18:36:19 +01:00
|
|
|
if (DTYPE_IS_BLOB(dtype1) || DTYPE_IS_BLOB(dtype2)) {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-08-06 07:29:31 +02:00
|
|
|
// In Dialect 2 or 3, strings can never partipate in addition / sub
|
|
|
|
// (use a specific cast instead)
|
2005-12-12 18:36:19 +01:00
|
|
|
if (DTYPE_IS_TEXT(dtype1) || DTYPE_IS_TEXT(dtype2))
|
2003-10-21 00:41:11 +02:00
|
|
|
{
|
2008-10-03 02:45:13 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_nostring_addsub_dial3));
|
2003-10-21 00:41:11 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Determine the TYPE of arithmetic to perform, store it
|
|
|
|
in dtype. Note: this is different from the result of
|
|
|
|
the operation, as <timestamp>-<timestamp> uses
|
|
|
|
<timestamp> arithmetic, but returns a <double> */
|
2008-09-15 17:25:18 +02:00
|
|
|
if (DTYPE_IS_EXACT(dtype1) && DTYPE_IS_EXACT(dtype2))
|
2005-08-06 07:29:31 +02:00
|
|
|
{
|
|
|
|
dtype = dtype_int64;
|
|
|
|
}
|
2008-09-15 17:25:18 +02:00
|
|
|
else if (DTYPE_IS_NUMERIC(dtype1) && DTYPE_IS_NUMERIC(dtype2))
|
2003-12-22 11:00:59 +01:00
|
|
|
{
|
2008-09-15 17:25:18 +02:00
|
|
|
fb_assert(DTYPE_IS_APPROX(dtype1) || DTYPE_IS_APPROX(dtype2));
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype = dtype_double;
|
|
|
|
}
|
|
|
|
else {
|
2008-09-27 11:51:53 +02:00
|
|
|
// mixed numeric and non-numeric:
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// The MAX(dtype) rule doesn't apply with dtype_int64
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (dtype_int64 == dtype1)
|
|
|
|
dtype1 = dtype_double;
|
|
|
|
if (dtype_int64 == dtype2)
|
|
|
|
dtype2 = dtype_double;
|
|
|
|
|
|
|
|
dtype = MAX(dtype1, dtype2);
|
|
|
|
}
|
|
|
|
|
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2005-08-06 07:29:31 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (dtype)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_sql_time:
|
|
|
|
case dtype_sql_date:
|
|
|
|
case dtype_timestamp:
|
|
|
|
|
2003-12-22 11:00:59 +01:00
|
|
|
if ((DTYPE_IS_DATE(dtype1) || (dtype1 == dtype_unknown)) &&
|
|
|
|
(DTYPE_IS_DATE(dtype2) || (dtype2 == dtype_unknown)))
|
|
|
|
{
|
2008-09-15 17:25:18 +02:00
|
|
|
if (node->nod_type == nod_subtract2)
|
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
// <any date> - <any date>
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Legal permutations are:
|
|
|
|
<timestamp> - <timestamp>
|
|
|
|
<timestamp> - <date>
|
|
|
|
<date> - <date>
|
|
|
|
<date> - <timestamp>
|
|
|
|
<time> - <time> */
|
|
|
|
|
|
|
|
if (dtype1 == dtype2)
|
|
|
|
dtype = dtype1;
|
2008-09-15 17:25:18 +02:00
|
|
|
else if (dtype1 == dtype_timestamp && dtype2 == dtype_sql_date)
|
|
|
|
dtype = dtype_timestamp;
|
|
|
|
else if (dtype2 == dtype_timestamp && dtype1 == dtype_sql_date)
|
|
|
|
dtype = dtype_timestamp;
|
|
|
|
else
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_datetime_subtract));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-15 17:25:18 +02:00
|
|
|
if (dtype == dtype_sql_date)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
2008-09-15 17:25:18 +02:00
|
|
|
else if (dtype == dtype_sql_time)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE;
|
2006-05-28 09:46:35 +02:00
|
|
|
desc->dsc_sub_type = dsc_num_type_numeric;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-09-15 17:25:18 +02:00
|
|
|
else
|
|
|
|
{
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(dtype == dtype_timestamp);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
|
|
|
desc->dsc_scale = -9;
|
2006-05-28 09:46:35 +02:00
|
|
|
desc->dsc_sub_type = dsc_num_type_numeric;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2008-09-15 17:25:18 +02:00
|
|
|
else if (is_date_and_time(desc1, desc2))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
/* <date> + <time> */
|
|
|
|
/* <time> + <date> */
|
|
|
|
desc->dsc_dtype = dtype_timestamp;
|
|
|
|
desc->dsc_length = type_lengths[dtype_timestamp];
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
2008-09-15 17:25:18 +02:00
|
|
|
else
|
2008-09-27 11:51:53 +02:00
|
|
|
{
|
|
|
|
// <date> + <date>
|
|
|
|
// <time> + <time>
|
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_dateortime_add));
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2006-05-28 09:46:35 +02:00
|
|
|
else if (DTYPE_IS_DATE(desc1.dsc_dtype) || (node->nod_type == nod_add2))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2006-05-28 09:46:35 +02:00
|
|
|
// <date> +/- <non-date>
|
|
|
|
// <non-date> + <date>
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = desc1.dsc_dtype;
|
|
|
|
if (!DTYPE_IS_DATE(desc->dsc_dtype))
|
|
|
|
desc->dsc_dtype = desc2.dsc_dtype;
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(DTYPE_IS_DATE(desc->dsc_dtype));
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_length = type_lengths[desc->dsc_dtype];
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
}
|
2008-09-15 17:25:18 +02:00
|
|
|
else
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
/* <non-date> - <date> */
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(node->nod_type == nod_subtract2);
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_minus_date));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_varying:
|
|
|
|
case dtype_cstring:
|
|
|
|
case dtype_text:
|
|
|
|
case dtype_double:
|
|
|
|
case dtype_real:
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_short:
|
|
|
|
case dtype_long:
|
|
|
|
case dtype_int64:
|
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
|
|
|
|
|
|
|
/* The result type is int64 because both operands are
|
|
|
|
exact numeric: hence we don't need the NUMERIC_SCALE
|
|
|
|
macro here. */
|
2008-09-15 17:34:14 +02:00
|
|
|
fb_assert(desc1.dsc_dtype == dtype_unknown || DTYPE_IS_EXACT(desc1.dsc_dtype));
|
|
|
|
fb_assert(desc2.dsc_dtype == dtype_unknown || DTYPE_IS_EXACT(desc2.dsc_dtype));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
desc->dsc_scale = MIN(desc1.dsc_scale, desc2.dsc_scale);
|
|
|
|
node->nod_flags |= NOD_COMP_DIALECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-09-27 11:51:53 +02:00
|
|
|
// a type which cannot participate in an add or subtract
|
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_addsub_dial3));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_multiply:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
if (node->nod_arg[0]->nod_type == nod_null && node->nod_arg[1]->nod_type == nod_null)
|
2004-09-04 20:24:12 +02:00
|
|
|
{
|
|
|
|
// NULL * NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-12-12 18:36:19 +01:00
|
|
|
// Arrays and blobs can never partipate in multiplication
|
|
|
|
if (DTYPE_IS_BLOB(desc1.dsc_dtype) || DTYPE_IS_BLOB(desc2.dsc_dtype)) {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2005-12-12 18:36:19 +01:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype = DSC_multiply_blr4_result[desc1.dsc_dtype][desc2.dsc_dtype];
|
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2005-08-06 07:29:31 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (dtype)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_double:
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_long:
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = NUMERIC_SCALE(desc1) + NUMERIC_SCALE(desc2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_multip_dial1));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_multiply2:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
if (node->nod_arg[0]->nod_type == nod_null && node->nod_arg[1]->nod_type == nod_null)
|
2004-09-04 20:24:12 +02:00
|
|
|
{
|
|
|
|
// NULL * NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// In Dialect 2 or 3, strings can never partipate in multiplication
|
2005-08-06 07:29:31 +02:00
|
|
|
// (use a specific cast instead)
|
|
|
|
if (DTYPE_IS_TEXT(desc1.dsc_dtype) || DTYPE_IS_TEXT(desc2.dsc_dtype))
|
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_nostring_multip_dial3));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// Arrays and blobs can never partipate in multiplication
|
2005-12-12 18:36:19 +01:00
|
|
|
if (DTYPE_IS_BLOB(desc1.dsc_dtype) || DTYPE_IS_BLOB(desc2.dsc_dtype)) {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2005-12-12 18:36:19 +01:00
|
|
|
}
|
|
|
|
|
2005-08-06 07:29:31 +02:00
|
|
|
dtype = DSC_multiply_result[desc1.dsc_dtype][desc2.dsc_dtype];
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2005-08-06 07:29:31 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (dtype)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_double:
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_int64:
|
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
|
|
|
desc->dsc_scale = NUMERIC_SCALE(desc1) + NUMERIC_SCALE(desc2);
|
|
|
|
node->nod_flags |= NOD_COMP_DIALECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_multip_dial3));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
2006-07-30 07:09:41 +02:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_count:
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_flags = 0;
|
|
|
|
return;
|
2006-07-30 07:09:41 +02:00
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case nod_divide:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
if (node->nod_arg[0]->nod_type == nod_null && node->nod_arg[1]->nod_type == nod_null)
|
2004-09-04 20:24:12 +02:00
|
|
|
{
|
|
|
|
// NULL / NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// Arrays and blobs can never partipate in division
|
2005-12-12 18:36:19 +01:00
|
|
|
if (DTYPE_IS_BLOB(desc1.dsc_dtype) || DTYPE_IS_BLOB(desc2.dsc_dtype)) {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2005-12-12 18:36:19 +01:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype1 = desc1.dsc_dtype;
|
2006-04-05 06:38:03 +02:00
|
|
|
if (dtype_int64 == dtype1 || DTYPE_IS_TEXT(dtype1))
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype1 = dtype_double;
|
|
|
|
|
|
|
|
dtype2 = desc2.dsc_dtype;
|
2006-04-05 06:38:03 +02:00
|
|
|
if (dtype_int64 == dtype2 || DTYPE_IS_TEXT(dtype2))
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype2 = dtype_double;
|
|
|
|
|
|
|
|
dtype = MAX(dtype1, dtype2);
|
|
|
|
|
2005-08-06 07:29:31 +02:00
|
|
|
if (!DTYPE_IS_NUMERIC(dtype)) {
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_mustuse_numeric_div_dial1));
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2005-08-06 07:29:31 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_divide2:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[0], node->nod_arg[1]);
|
|
|
|
MAKE_desc(statement, &desc2, node->nod_arg[1], node->nod_arg[0]);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
if (node->nod_arg[0]->nod_type == nod_null && node->nod_arg[1]->nod_type == nod_null)
|
2004-09-04 20:24:12 +02:00
|
|
|
{
|
|
|
|
// NULL / NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-08-06 07:29:31 +02:00
|
|
|
// In Dialect 2 or 3, strings can never partipate in division
|
|
|
|
// (use a specific cast instead)
|
|
|
|
if (DTYPE_IS_TEXT(desc1.dsc_dtype) || DTYPE_IS_TEXT(desc2.dsc_dtype))
|
|
|
|
{
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_nostring_div_dial3));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// Arrays and blobs can never partipate in division
|
2005-12-12 18:36:19 +01:00
|
|
|
if (DTYPE_IS_BLOB(desc1.dsc_dtype) || DTYPE_IS_BLOB(desc2.dsc_dtype)) {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2005-12-12 18:36:19 +01:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
dtype = DSC_multiply_result[desc1.dsc_dtype][desc2.dsc_dtype];
|
2001-12-24 03:51:06 +01:00
|
|
|
desc->dsc_dtype = static_cast<UCHAR>(dtype);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
2005-08-06 07:29:31 +02:00
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (dtype)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_int64:
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
|
|
|
desc->dsc_scale = NUMERIC_SCALE(desc1) + NUMERIC_SCALE(desc2);
|
|
|
|
node->nod_flags |= NOD_COMP_DIALECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case dtype_double:
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_div_dial3));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_negate:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[0], null_replacement);
|
2004-09-04 20:24:12 +02:00
|
|
|
|
|
|
|
if (node->nod_arg[0]->nod_type == nod_null)
|
|
|
|
{
|
|
|
|
// -NULL = NULL of INT
|
2005-02-14 06:51:25 +01:00
|
|
|
make_null(desc);
|
2004-09-04 20:24:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-08-06 07:29:31 +02:00
|
|
|
// In Dialect 2 or 3, a string can never partipate in negation
|
|
|
|
// (use a specific cast instead)
|
|
|
|
if (DTYPE_IS_TEXT(desc->dsc_dtype)) {
|
2008-05-24 05:19:52 +02:00
|
|
|
if (statement->req_client_dialect >= SQL_DIALECT_V6_TRANSITION) {
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_nostring_neg_dial3));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
|
|
|
desc->dsc_dtype = dtype_double;
|
|
|
|
desc->dsc_length = sizeof(double);
|
|
|
|
}
|
|
|
|
// Forbid blobs and arrays
|
|
|
|
else if (DTYPE_IS_BLOB(desc->dsc_dtype))
|
|
|
|
{
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_no_blob_array));
|
2003-12-22 11:00:59 +01:00
|
|
|
}
|
2005-08-06 07:29:31 +02:00
|
|
|
// Forbid other not numeric datatypes
|
|
|
|
else if (!DTYPE_IS_NUMERIC(desc->dsc_dtype)) {
|
2008-09-27 11:51:53 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
|
|
|
|
Arg::Gds(isc_dsql_invalid_type_neg));
|
2005-08-06 07:29:31 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_alias:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[e_alias_value], null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_dbkey:
|
2008-09-27 11:51:53 +02:00
|
|
|
// Fix for bug 10072 check that the target is a relation
|
2003-11-10 10:16:38 +01:00
|
|
|
context = (dsql_ctx*) node->nod_arg[0]->nod_arg[0];
|
2003-10-05 08:27:16 +02:00
|
|
|
relation = context->ctx_relation;
|
2009-01-08 10:26:06 +01:00
|
|
|
if (relation != 0)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_text;
|
2005-10-08 08:52:57 +02:00
|
|
|
if (relation->rel_flags & REL_creating)
|
|
|
|
desc->dsc_length = 8;
|
|
|
|
else
|
|
|
|
desc->dsc_length = relation->rel_dbkey_length;
|
2006-09-07 03:55:49 +02:00
|
|
|
desc->dsc_flags = DSC_nullable;
|
2004-05-21 08:16:17 +02:00
|
|
|
desc->dsc_ttype() = ttype_binary;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
|
|
|
|
Arg::Gds(isc_dsql_dbkey_from_non_table));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_udf:
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2003-11-10 10:16:38 +01:00
|
|
|
const dsql_udf* userFunc = (dsql_udf*) node->nod_arg[0];
|
2003-11-01 11:26:43 +01:00
|
|
|
desc->dsc_dtype = static_cast<UCHAR>(userFunc->udf_dtype);
|
|
|
|
desc->dsc_length = userFunc->udf_length;
|
|
|
|
desc->dsc_scale = static_cast<SCHAR>(userFunc->udf_scale);
|
|
|
|
/* CVC: Setting flags to zero obviously impeded DSQL to acknowledge
|
|
|
|
the fact that any UDF can return NULL simply returning a NULL
|
|
|
|
pointer. */
|
|
|
|
desc->dsc_flags = DSC_nullable;
|
2008-09-27 11:51:53 +02:00
|
|
|
|
|
|
|
if (desc->dsc_dtype <= dtype_any_text) {
|
2004-05-21 08:16:17 +02:00
|
|
|
desc->dsc_ttype() = userFunc->udf_character_set_id;
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
|
|
|
else {
|
2004-05-21 08:16:17 +02:00
|
|
|
desc->dsc_ttype() = userFunc->udf_sub_type;
|
2003-11-01 11:26:43 +01:00
|
|
|
}
|
|
|
|
return;
|
2002-11-21 00:48:34 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-04-12 17:56:34 +02:00
|
|
|
case nod_sys_function:
|
|
|
|
{
|
|
|
|
dsql_nod* nodeArgs = node->nod_arg[e_sysfunc_args];
|
|
|
|
Firebird::Array<const dsc*> args;
|
|
|
|
|
|
|
|
if (nodeArgs)
|
|
|
|
{
|
|
|
|
fb_assert(nodeArgs->nod_type == nod_list);
|
|
|
|
|
|
|
|
for (dsql_nod** p = nodeArgs->nod_arg;
|
2009-01-06 06:53:34 +01:00
|
|
|
p < nodeArgs->nod_arg + nodeArgs->nod_count; ++p)
|
2007-04-12 17:56:34 +02:00
|
|
|
{
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &(*p)->nod_desc, *p, NULL);
|
2007-04-12 17:56:34 +02:00
|
|
|
args.add(&(*p)->nod_desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const dsql_str* name = (dsql_str*) node->nod_arg[e_sysfunc_name];
|
2008-05-24 05:19:52 +02:00
|
|
|
DSqlDataTypeUtil(statement).makeSysFunction(desc, name->str_data, args.getCount(), args.begin());
|
2007-10-12 02:52:47 +02:00
|
|
|
|
2007-04-12 17:56:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_gen_id:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[e_gen_id_value], NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
2005-07-27 09:36:03 +02:00
|
|
|
desc->dsc_flags = (desc1.dsc_flags & DSC_nullable);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_gen_id2:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[e_gen_id_value], NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_length = sizeof(SINT64);
|
2005-07-27 09:36:03 +02:00
|
|
|
desc->dsc_flags = (desc1.dsc_flags & DSC_nullable);
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_flags |= NOD_COMP_DIALECT;
|
|
|
|
return;
|
|
|
|
|
2003-10-05 08:27:16 +02:00
|
|
|
case nod_limit:
|
2003-11-07 15:10:16 +01:00
|
|
|
case nod_rows:
|
2008-05-24 05:19:52 +02:00
|
|
|
if (statement->req_client_dialect <= SQL_DIALECT_V5) {
|
2003-10-05 08:27:16 +02:00
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof (SLONG);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
desc->dsc_dtype = dtype_int64;
|
|
|
|
desc->dsc_length = sizeof (SINT64);
|
|
|
|
}
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0; /* Can first/skip accept NULL in the future? */
|
|
|
|
return;
|
2002-06-29 08:56:51 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_field:
|
2004-09-05 23:50:54 +02:00
|
|
|
if (node->nod_desc.dsc_dtype)
|
|
|
|
{
|
|
|
|
*desc = node->nod_desc;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-15 13:21:47 +02:00
|
|
|
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-203) <<
|
|
|
|
Arg::Gds(isc_dsql_field_ref));
|
2004-09-05 23:50:54 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_user_name:
|
2003-10-05 08:27:16 +02:00
|
|
|
case nod_current_role:
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_dtype = dtype_varying;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0;
|
2006-07-12 20:44:08 +02:00
|
|
|
desc->dsc_ttype() = ttype_metadata;
|
|
|
|
desc->dsc_length =
|
2009-01-06 06:53:34 +01:00
|
|
|
USERNAME_LENGTH * METD_get_charset_bpc(statement, ttype_metadata) + sizeof(USHORT);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
2002-06-14 14:07:20 +02:00
|
|
|
case nod_internal_info:
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_current_time:
|
|
|
|
desc->dsc_dtype = dtype_sql_time;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0;
|
|
|
|
desc->dsc_length = type_lengths[desc->dsc_dtype];
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_current_date:
|
|
|
|
desc->dsc_dtype = dtype_sql_date;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0;
|
|
|
|
desc->dsc_length = type_lengths[desc->dsc_dtype];
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_current_timestamp:
|
|
|
|
desc->dsc_dtype = dtype_timestamp;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = 0;
|
|
|
|
desc->dsc_length = type_lengths[desc->dsc_dtype];
|
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_extract:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[e_extract_value], NULL);
|
2007-07-31 03:22:59 +02:00
|
|
|
|
2009-04-05 15:04:10 +02:00
|
|
|
switch (node->nod_arg[e_extract_part]->getSlong())
|
2003-12-22 11:00:59 +01:00
|
|
|
{
|
2007-07-31 03:22:59 +02:00
|
|
|
case blr_extract_second:
|
2008-09-27 11:51:53 +02:00
|
|
|
// QUADDATE - maybe this should be DECIMAL(6,4)
|
2007-07-31 03:22:59 +02:00
|
|
|
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_extract_millisecond:
|
2008-06-25 17:58:03 +02:00
|
|
|
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE + 3);
|
2007-07-31 03:22:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
desc->makeShort(0);
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-07-31 03:22:59 +02:00
|
|
|
|
|
|
|
desc->setNullable(desc1.isNullable());
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
2005-06-06 20:14:10 +02:00
|
|
|
case nod_strlen:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &desc1, node->nod_arg[e_strlen_value], NULL);
|
2005-05-28 00:45:31 +02:00
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags = (desc1.dsc_flags & DSC_nullable);
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_length = sizeof(ULONG);
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case nod_parameter:
|
|
|
|
/* We don't actually know the datatype of a parameter -
|
2008-09-27 11:51:53 +02:00
|
|
|
we have to guess it based on the context that the
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter appears in. (This is done is pass1.c::set_parameter_type())
|
|
|
|
However, a parameter can appear as part of an expression.
|
|
|
|
As MAKE_desc is used for both determination of parameter
|
|
|
|
types and for expression type checking, we just continue. */
|
2004-09-22 08:54:17 +02:00
|
|
|
if (node->nod_desc.dsc_dtype)
|
|
|
|
{
|
|
|
|
*desc = node->nod_desc;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_null:
|
|
|
|
/* This occurs when SQL statement specifies a literal NULL, eg:
|
|
|
|
* SELECT NULL FROM TABLE1;
|
|
|
|
* As we don't have a <dtype_null, SQL_NULL> datatype pairing,
|
|
|
|
* we don't know how to map this NULL to a host-language
|
2008-09-27 11:51:53 +02:00
|
|
|
* datatype. Therefore we now describe it as a
|
2001-05-23 15:26:42 +02:00
|
|
|
* CHAR(1) CHARACTER SET NONE type.
|
|
|
|
* No value will ever be sent back, as the value of the select
|
|
|
|
* will be NULL - this is only for purposes of DESCRIBING
|
2003-12-22 11:00:59 +01:00
|
|
|
* the statement. Note that this mapping could be done in dsql.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* as part of the DESCRIBE statement - but I suspect other areas
|
2003-12-22 11:00:59 +01:00
|
|
|
* of the code would break if this is declared dtype_unknown.
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
2004-09-04 20:24:12 +02:00
|
|
|
if (null_replacement)
|
|
|
|
{
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, null_replacement, NULL);
|
2005-04-20 15:06:42 +02:00
|
|
|
desc->dsc_flags |= (DSC_nullable | DSC_null);
|
2004-09-04 20:24:12 +02:00
|
|
|
}
|
|
|
|
else
|
2009-02-05 15:29:28 +01:00
|
|
|
desc->makeNullString();
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case nod_via:
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, node->nod_arg[e_via_value_1], null_replacement);
|
2001-05-23 15:26:42 +02:00
|
|
|
/**
|
|
|
|
Set the descriptor flag as nullable. The
|
2008-09-27 11:51:53 +02:00
|
|
|
select expression may or may not return
|
2001-05-23 15:26:42 +02:00
|
|
|
this row based on the WHERE clause. Setting this
|
|
|
|
flag warns the client to expect null values.
|
|
|
|
(bug 10379)
|
|
|
|
**/
|
|
|
|
desc->dsc_flags |= DSC_nullable;
|
|
|
|
return;
|
|
|
|
|
2008-09-01 15:18:02 +02:00
|
|
|
case nod_hidden_var:
|
|
|
|
MAKE_desc(statement, desc, node->nod_arg[e_hidden_var_expr], null_replacement);
|
2008-08-20 03:54:45 +02:00
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
default:
|
2008-09-27 11:51:53 +02:00
|
|
|
fb_assert(false); // unexpected dsql_nod type
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
case nod_dom_value: // computed value not used
|
2001-05-23 15:26:42 +02:00
|
|
|
/* By the time we get here, any nod_dom_value node should have had
|
|
|
|
* its descriptor set to the type of the domain being created, or
|
|
|
|
* to the type of the existing domain to which a CHECK constraint
|
|
|
|
* is being added.
|
|
|
|
*/
|
2003-12-22 11:00:59 +01:00
|
|
|
fb_assert(node->nod_desc.dsc_dtype != dtype_unknown);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (desc != &node->nod_desc)
|
|
|
|
*desc = node->nod_desc;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
desc->dsc_dtype = static_cast<UCHAR>(field->fld_dtype);
|
|
|
|
desc->dsc_scale = static_cast<SCHAR>(field->fld_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_sub_type = field->fld_sub_type;
|
|
|
|
desc->dsc_length = field->fld_length;
|
|
|
|
desc->dsc_flags = (field->fld_flags & FLD_nullable) ? DSC_nullable : 0;
|
|
|
|
if (desc->dsc_dtype <= dtype_any_text) {
|
2009-01-06 06:53:34 +01:00
|
|
|
INTL_ASSIGN_DSC(desc, field->fld_character_set_id, field->fld_collation_id);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (desc->dsc_dtype == dtype_blob)
|
2005-05-28 00:45:31 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
desc->dsc_scale = static_cast<SCHAR>(field->fld_character_set_id);
|
2005-05-28 00:45:31 +02:00
|
|
|
desc->dsc_flags |= field->fld_collation_id << 8;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
**/
|
2008-05-24 05:19:52 +02:00
|
|
|
void MAKE_desc_from_list(CompiledStatement* statement, dsc* desc, dsql_nod* node,
|
2004-09-05 09:23:42 +02:00
|
|
|
dsql_nod* null_replacement,
|
|
|
|
const TEXT* expression_name)
|
2002-08-03 17:27:20 +02:00
|
|
|
{
|
2007-04-12 17:56:34 +02:00
|
|
|
Firebird::Array<const dsc*> args;
|
2002-08-03 17:27:20 +02:00
|
|
|
|
2007-04-12 17:56:34 +02:00
|
|
|
fb_assert(node->nod_type == nod_list);
|
2003-08-25 00:15:23 +02:00
|
|
|
|
2007-04-12 17:56:34 +02:00
|
|
|
for (dsql_nod** p = node->nod_arg; p < node->nod_arg + node->nod_count; ++p)
|
|
|
|
{
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, &(*p)->nod_desc, *p, NULL);
|
2007-04-12 17:56:34 +02:00
|
|
|
args.add(&(*p)->nod_desc);
|
2002-08-03 17:27:20 +02:00
|
|
|
}
|
|
|
|
|
2008-05-24 05:19:52 +02:00
|
|
|
DSqlDataTypeUtil(statement).makeFromList(desc, expression_name, args.getCount(), args.begin());
|
2005-07-28 15:35:08 +02:00
|
|
|
|
2004-09-05 09:23:42 +02:00
|
|
|
// If we have literal NULLs only, let the result be either
|
|
|
|
// CHAR(1) CHARACTER SET NONE or the context-provided datatype
|
2007-04-12 17:56:34 +02:00
|
|
|
if (desc->isNull() && null_replacement)
|
2004-09-05 09:23:42 +02:00
|
|
|
{
|
2008-05-24 05:19:52 +02:00
|
|
|
MAKE_desc(statement, desc, null_replacement, NULL);
|
2007-10-12 02:52:47 +02:00
|
|
|
desc->dsc_flags |= DSC_null | DSC_nullable;
|
2004-09-05 09:23:42 +02:00
|
|
|
return;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
**/
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_nod* MAKE_field(dsql_ctx* context, dsql_fld* field, dsql_nod* 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);
|
|
|
|
DEV_BLKCHK(indices, dsql_type_nod);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_nod* node = MAKE_node(nod_field, e_fld_count);
|
|
|
|
node->nod_arg[e_fld_context] = (dsql_nod*) context;
|
|
|
|
node->nod_arg[e_fld_field] = (dsql_nod*) field;
|
2009-01-06 06:53:34 +01:00
|
|
|
if (field->fld_dimensions)
|
|
|
|
{
|
2009-01-08 10:26:06 +01:00
|
|
|
if (indices)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_arg[e_fld_indices] = indices;
|
|
|
|
MAKE_desc_from_field(&node->nod_desc, field);
|
2009-01-06 06:53:34 +01:00
|
|
|
node->nod_desc.dsc_dtype = static_cast<UCHAR>(field->fld_element_dtype);
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_desc.dsc_length = field->fld_element_length;
|
|
|
|
/*
|
|
|
|
node->nod_desc.dsc_scale = field->fld_scale;
|
|
|
|
node->nod_desc.dsc_sub_type = field->fld_sub_type;
|
|
|
|
*/
|
|
|
|
}
|
2009-01-08 10:26:06 +01:00
|
|
|
else
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_desc.dsc_dtype = dtype_array;
|
2003-11-11 13:19:20 +01:00
|
|
|
node->nod_desc.dsc_length = sizeof(ISC_QUAD);
|
2009-01-06 06:53:34 +01:00
|
|
|
node->nod_desc.dsc_scale = static_cast<SCHAR>(field->fld_scale);
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_desc.dsc_sub_type = field->fld_sub_type;
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
MAKE_desc_from_field(&node->nod_desc, field);
|
|
|
|
}
|
|
|
|
|
2008-06-05 13:02:42 +02:00
|
|
|
if ((field->fld_flags & FLD_nullable) || (context->ctx_flags & CTX_outer_join))
|
2003-11-10 10:16:38 +01:00
|
|
|
{
|
2007-10-04 17:33:34 +02:00
|
|
|
node->nod_desc.dsc_flags |= DSC_nullable;
|
2003-04-06 12:09:38 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
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
|
2009-01-06 06:53:34 +01:00
|
|
|
if ((field->fld_flags & FLD_system) && node->nod_desc.dsc_dtype <= dtype_varying &&
|
2006-01-21 15:55:16 +01:00
|
|
|
INTL_GET_CHARSET(&node->nod_desc) == 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
|
|
|
|
2005-09-14 20:09:40 +02:00
|
|
|
if (node->nod_desc.dsc_dtype == dtype_varying)
|
|
|
|
adjust = sizeof(USHORT);
|
|
|
|
else if (node->nod_desc.dsc_dtype == dtype_cstring)
|
|
|
|
adjust = 1;
|
2005-05-28 00:45:31 +02:00
|
|
|
|
2005-09-14 20:09:40 +02:00
|
|
|
node->nod_desc.dsc_length -= adjust;
|
|
|
|
node->nod_desc.dsc_length *= 3;
|
|
|
|
node->nod_desc.dsc_length += adjust;
|
2005-05-28 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
**/
|
|
|
|
dsql_nod* MAKE_field_name(const char* field_name)
|
|
|
|
{
|
|
|
|
dsql_nod* const field_node = MAKE_node(nod_field_name, (int) e_fln_count);
|
|
|
|
field_node->nod_arg[e_fln_name] = (dsql_nod*) MAKE_cstring(field_name);
|
|
|
|
return field_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_list
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a list node from a linked list stack of things.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param stack
|
|
|
|
|
|
|
|
**/
|
2004-04-18 16:22:27 +02:00
|
|
|
dsql_nod* MAKE_list(DsqlNodStack& stack)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-04-18 16:22:27 +02:00
|
|
|
USHORT count = stack.getCount();
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_nod* node = MAKE_node(nod_list, count);
|
|
|
|
dsql_nod** ptr = node->nod_arg + count;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-27 18:26:52 +02:00
|
|
|
while (stack.hasData())
|
2004-04-18 16:22:27 +02:00
|
|
|
{
|
|
|
|
*--ptr = stack.pop();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_node
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a node of given type.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param type
|
|
|
|
@param count
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_nod* MAKE_node(NOD_TYPE type, int count)
|
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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(), count) dsql_nod;
|
2001-05-23 15:26:42 +02:00
|
|
|
node->nod_type = type;
|
|
|
|
node->nod_count = count;
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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,
|
2005-09-02 07:30:16 +02:00
|
|
|
USHORT sqlda_index, const dsql_nod* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2005-05-12 19:46:31 +02: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
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
DEV_BLKCHK(message, dsql_type_msg);
|
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
|
|
|
{
|
2002-11-24 16:22:03 +01:00
|
|
|
// This parameter possibly already here. Look for it
|
2004-02-02 12:02:12 +01:00
|
|
|
for (dsql_par* temp = message->msg_parameters; temp; temp = temp->par_next) {
|
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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_par* parameter = FB_NEW(*tdbb->getDefaultPool()) dsql_par;
|
2001-05-23 15:26:42 +02:00
|
|
|
parameter->par_message = message;
|
2003-10-05 08:27:16 +02:00
|
|
|
parameter->par_next = message->msg_parameters;
|
2001-05-23 15:26:42 +02:00
|
|
|
message->msg_parameters = parameter;
|
|
|
|
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
|
|
|
|
2005-09-02 07:30:16 +02:00
|
|
|
if (node) {
|
|
|
|
make_parameter_names(parameter, node);
|
|
|
|
}
|
|
|
|
|
2008-09-27 11:51:53 +02:00
|
|
|
// If the parameter is used declared, set SQLDA index
|
2009-01-08 10:26:06 +01:00
|
|
|
if (sqlda_flag)
|
|
|
|
{
|
2008-03-25 17:42:10 +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
|
|
|
|
|
|
|
// If a null handing has been requested, set up a null flag
|
2001-05-23 15:26:42 +02: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;
|
|
|
|
}
|
|
|
|
|
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_string
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generalized routine for making a string block.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param str
|
|
|
|
@param length
|
|
|
|
|
|
|
|
**/
|
2003-11-10 10:16:38 +01:00
|
|
|
dsql_str* MAKE_string(const char* str, int length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-04-04 18:59:01 +02:00
|
|
|
fb_assert(length >= 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
return MAKE_tagged_string(str, length, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_symbol
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a symbol for an object and insert symbol into hash table.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param database
|
|
|
|
@param name
|
|
|
|
@param length
|
|
|
|
@param type
|
|
|
|
@param object
|
|
|
|
|
|
|
|
**/
|
2004-02-02 12:02:12 +01:00
|
|
|
dsql_sym* MAKE_symbol(dsql_dbb* database,
|
2003-11-01 11:26:43 +01:00
|
|
|
const TEXT* name, USHORT length, SYM_TYPE type, dsql_req* object)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
DEV_BLKCHK(database, dsql_type_dbb);
|
|
|
|
DEV_BLKCHK(object, dsql_type_req);
|
2003-11-04 00:59:24 +01:00
|
|
|
fb_assert(name);
|
|
|
|
fb_assert(length > 0);
|
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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_sym* symbol = FB_NEW_RPT(*tdbb->getDefaultPool(), length) dsql_sym;
|
2001-05-23 15:26:42 +02:00
|
|
|
symbol->sym_type = type;
|
2008-03-19 17:09:00 +01:00
|
|
|
symbol->sym_object = object;
|
2001-05-23 15:26:42 +02:00
|
|
|
symbol->sym_dbb = database;
|
|
|
|
symbol->sym_length = length;
|
2003-10-05 08:27:16 +02:00
|
|
|
TEXT* p = symbol->sym_name;
|
|
|
|
symbol->sym_string = p;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (length)
|
2008-02-03 12:20:48 +01:00
|
|
|
memcpy(p, name, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
HSHD_insert(symbol);
|
|
|
|
|
|
|
|
return symbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_tagged_string
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Generalized routine for making a string block.
|
|
|
|
Which is tagged with a character set descriptor.
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param str_
|
|
|
|
@param length
|
|
|
|
@param charset
|
|
|
|
|
|
|
|
**/
|
2004-05-31 04:34:35 +02:00
|
|
|
dsql_str* MAKE_tagged_string(const char* strvar, size_t length, const char* charset)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-02-28 14:48:16 +01:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
2003-02-12 20:28:13 +01:00
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_str* string = FB_NEW_RPT(*tdbb->getDefaultPool(), length) dsql_str;
|
2003-02-12 20:28:13 +01:00
|
|
|
string->str_charset = charset;
|
|
|
|
string->str_length = length;
|
2004-05-31 04:34:35 +02:00
|
|
|
memcpy(string->str_data, strvar, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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_trigger_type
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
@brief Make a trigger type
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
|
|
|
|
@param prefix_node
|
|
|
|
@param suffix_node
|
|
|
|
|
|
|
|
**/
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_nod* MAKE_trigger_type(dsql_nod* prefix_node, dsql_nod* suffix_node)
|
2002-06-14 14:07:20 +02:00
|
|
|
{
|
2007-10-19 13:51:58 +02:00
|
|
|
const SLONG prefix = prefix_node->getSlong();
|
|
|
|
const SLONG suffix = suffix_node->getSlong();
|
2002-06-14 14:07:20 +02:00
|
|
|
delete prefix_node;
|
|
|
|
delete suffix_node;
|
2007-10-17 16:35:31 +02:00
|
|
|
return MAKE_const_slong(prefix + suffix - 1);
|
2002-06-14 14:07: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_variable
|
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 field
|
|
|
|
@param name
|
|
|
|
@param type
|
|
|
|
@param msg_number
|
|
|
|
@param item_number
|
|
|
|
@param local_number
|
|
|
|
|
|
|
|
**/
|
2008-04-18 03:37:44 +02:00
|
|
|
dsql_nod* MAKE_variable(dsql_fld* field, const TEXT* name, const dsql_var_type type,
|
|
|
|
USHORT msg_number, USHORT item_number, USHORT local_number)
|
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
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
2003-10-05 08:27:16 +02:00
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
dsql_var* variable = FB_NEW_RPT(*tdbb->getDefaultPool(), strlen(name)) dsql_var;
|
2003-11-01 11:26:43 +01:00
|
|
|
dsql_nod* node = MAKE_node(nod_variable, e_var_count);
|
|
|
|
node->nod_arg[e_var_variable] = (dsql_nod*) variable;
|
2003-10-05 08:27:16 +02:00
|
|
|
variable->var_msg_number = msg_number;
|
|
|
|
variable->var_msg_item = item_number;
|
|
|
|
variable->var_variable_number = local_number;
|
|
|
|
variable->var_field = field;
|
|
|
|
strcpy(variable->var_name, name);
|
2008-05-10 05:44:57 +02:00
|
|
|
//variable->var_flags = 0;
|
2008-04-16 12:38:08 +02:00
|
|
|
variable->var_type = type;
|
2008-08-15 18:32:42 +02:00
|
|
|
if (field)
|
|
|
|
MAKE_desc_from_field(&node->nod_desc, field);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2008-02-28 14:48:16 +01:00
|
|
|
|
2005-02-14 06:51:25 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
make_null
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2005-02-14 06:51:25 +01:00
|
|
|
@brief Prepare a descriptor to signal SQL NULL
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2005-02-14 06:51:25 +01:00
|
|
|
@param desc
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2005-02-14 06:51:25 +01:00
|
|
|
**/
|
|
|
|
static void make_null(dsc* const desc)
|
|
|
|
{
|
|
|
|
desc->dsc_dtype = dtype_long;
|
|
|
|
desc->dsc_sub_type = 0;
|
|
|
|
desc->dsc_length = sizeof(SLONG);
|
|
|
|
desc->dsc_scale = 0;
|
|
|
|
desc->dsc_flags |= DSC_nullable;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 07:30:16 +02:00
|
|
|
/**
|
|
|
|
|
|
|
|
make_parameter_names
|
|
|
|
|
|
|
|
@brief Determine relation/column/alias names (if appropriate)
|
|
|
|
and store them in the given parameter.
|
|
|
|
|
|
|
|
@param parameter
|
|
|
|
@param item
|
|
|
|
|
|
|
|
**/
|
|
|
|
static void make_parameter_names(dsql_par* parameter, const dsql_nod* item)
|
|
|
|
{
|
|
|
|
const dsql_fld* field;
|
2006-12-01 14:49:11 +01:00
|
|
|
const dsql_ctx* context = NULL;
|
2005-09-02 07:30:16 +02:00
|
|
|
const dsql_str* string;
|
|
|
|
const dsql_nod* alias;
|
|
|
|
|
|
|
|
fb_assert(parameter && item);
|
|
|
|
|
|
|
|
const char* name_alias = NULL;
|
|
|
|
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (item->nod_type)
|
|
|
|
{
|
2005-09-02 07:30:16 +02:00
|
|
|
case nod_field:
|
|
|
|
field = (dsql_fld*) item->nod_arg[e_fld_field];
|
2008-01-16 07:52:43 +01:00
|
|
|
name_alias = field->fld_name.c_str();
|
2005-09-02 07:30:16 +02:00
|
|
|
context = (dsql_ctx*) item->nod_arg[e_fld_context];
|
|
|
|
break;
|
|
|
|
case nod_dbkey:
|
2008-09-07 23:50:00 +02:00
|
|
|
parameter->par_name = parameter->par_alias = DB_KEY_NAME;
|
2005-09-02 07:30:16 +02:00
|
|
|
context = (dsql_ctx*) item->nod_arg[0]->nod_arg[0];
|
|
|
|
break;
|
|
|
|
case nod_alias:
|
|
|
|
string = (dsql_str*) item->nod_arg[e_alias_alias];
|
2009-01-07 10:30:57 +01:00
|
|
|
parameter->par_alias = string->str_data;
|
2005-09-02 07:30:16 +02:00
|
|
|
alias = item->nod_arg[e_alias_value];
|
|
|
|
if (alias->nod_type == nod_field) {
|
|
|
|
field = (dsql_fld*) alias->nod_arg[e_fld_field];
|
2008-01-16 07:52:43 +01:00
|
|
|
parameter->par_name = field->fld_name.c_str();
|
2005-09-02 07:30:16 +02:00
|
|
|
context = (dsql_ctx*) alias->nod_arg[e_fld_context];
|
|
|
|
}
|
|
|
|
else if (alias->nod_type == nod_dbkey) {
|
2008-09-07 23:50:00 +02:00
|
|
|
parameter->par_name = DB_KEY_NAME;
|
2005-09-02 07:30:16 +02:00
|
|
|
context = (dsql_ctx*) alias->nod_arg[0]->nod_arg[0];
|
|
|
|
}
|
|
|
|
break;
|
2006-07-30 07:09:41 +02:00
|
|
|
case nod_via:
|
|
|
|
// subquery, aka sub-select
|
|
|
|
make_parameter_names(parameter, item->nod_arg[e_via_value_1]);
|
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
case nod_derived_field:
|
|
|
|
string = (dsql_str*) item->nod_arg[e_derived_field_name];
|
2009-01-07 10:30:57 +01:00
|
|
|
parameter->par_alias = string->str_data;
|
2005-09-02 07:30:16 +02:00
|
|
|
alias = item->nod_arg[e_derived_field_value];
|
|
|
|
if (alias->nod_type == nod_field) {
|
|
|
|
field = (dsql_fld*) alias->nod_arg[e_fld_field];
|
2008-01-16 07:52:43 +01:00
|
|
|
parameter->par_name = field->fld_name.c_str();
|
2005-09-02 07:30:16 +02:00
|
|
|
context = (dsql_ctx*) alias->nod_arg[e_fld_context];
|
|
|
|
}
|
|
|
|
else if (alias->nod_type == nod_dbkey) {
|
2008-09-07 23:50:00 +02:00
|
|
|
parameter->par_name = DB_KEY_NAME;
|
2005-09-02 07:30:16 +02:00
|
|
|
context = (dsql_ctx*) alias->nod_arg[0]->nod_arg[0];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case nod_map:
|
|
|
|
{
|
2006-07-30 07:09:41 +02:00
|
|
|
const dsql_map* map = (dsql_map*) item->nod_arg[e_map_map];
|
|
|
|
const dsql_nod* map_node = map->map_node;
|
|
|
|
while (map_node->nod_type == nod_map) {
|
|
|
|
// skip all the nod_map nodes
|
|
|
|
map = (dsql_map*) map_node->nod_arg[e_map_map];
|
|
|
|
map_node = map->map_node;
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|
2009-01-06 06:53:34 +01:00
|
|
|
switch (map_node->nod_type)
|
|
|
|
{
|
2006-07-30 07:09:41 +02:00
|
|
|
case nod_field:
|
|
|
|
field = (dsql_fld*) map_node->nod_arg[e_fld_field];
|
2008-01-16 07:52:43 +01:00
|
|
|
name_alias = field->fld_name.c_str();
|
2006-12-01 14:49:11 +01:00
|
|
|
context = (dsql_ctx*) map_node->nod_arg[e_fld_context];
|
2006-07-30 07:09:41 +02:00
|
|
|
break;
|
|
|
|
case nod_alias:
|
|
|
|
string = (dsql_str*) map_node->nod_arg[e_alias_alias];
|
2009-01-07 10:30:57 +01:00
|
|
|
parameter->par_alias = string->str_data;
|
2006-07-30 07:09:41 +02:00
|
|
|
alias = map_node->nod_arg[e_alias_value];
|
|
|
|
if (alias->nod_type == nod_field) {
|
|
|
|
field = (dsql_fld*) alias->nod_arg[e_fld_field];
|
2008-01-16 07:52:43 +01:00
|
|
|
parameter->par_name = field->fld_name.c_str();
|
2006-12-01 14:49:11 +01:00
|
|
|
context = (dsql_ctx*) alias->nod_arg[e_fld_context];
|
2006-07-30 07:09:41 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case nod_derived_field:
|
|
|
|
string = (dsql_str*) map_node->nod_arg[e_derived_field_name];
|
2009-01-07 10:30:57 +01:00
|
|
|
parameter->par_alias = string->str_data;
|
2006-07-30 07:09:41 +02:00
|
|
|
alias = map_node->nod_arg[e_derived_field_value];
|
|
|
|
if (alias->nod_type == nod_field) {
|
|
|
|
field = (dsql_fld*) alias->nod_arg[e_fld_field];
|
2008-01-16 07:52:43 +01:00
|
|
|
parameter->par_name = field->fld_name.c_str();
|
2006-12-01 14:49:11 +01:00
|
|
|
context = (dsql_ctx*) alias->nod_arg[e_fld_context];
|
2006-07-30 07:09:41 +02:00
|
|
|
}
|
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
|
2006-07-30 07:09:41 +02:00
|
|
|
case nod_agg_count:
|
|
|
|
name_alias = "COUNT";
|
|
|
|
break;
|
|
|
|
case nod_agg_total:
|
|
|
|
case nod_agg_total2:
|
|
|
|
name_alias = "SUM";
|
|
|
|
break;
|
|
|
|
case nod_agg_average:
|
|
|
|
case nod_agg_average2:
|
|
|
|
name_alias = "AVG";
|
|
|
|
break;
|
|
|
|
case nod_agg_min:
|
|
|
|
name_alias = "MIN";
|
|
|
|
break;
|
|
|
|
case nod_agg_max:
|
|
|
|
name_alias = "MAX";
|
|
|
|
break;
|
|
|
|
case nod_agg_list:
|
|
|
|
name_alias = "LIST";
|
|
|
|
break;
|
2008-09-07 21:44:48 +02:00
|
|
|
case nod_constant:
|
|
|
|
name_alias = "CONSTANT";
|
|
|
|
break;
|
2008-09-07 23:50:00 +02:00
|
|
|
case nod_dbkey:
|
|
|
|
name_alias = DB_KEY_NAME;
|
|
|
|
break;
|
2006-07-30 07:09:41 +02:00
|
|
|
} // switch(map_node->nod_type)
|
2006-04-24 19:24:26 +02:00
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
} // case nod_map
|
|
|
|
case nod_variable:
|
|
|
|
{
|
2006-07-30 07:09:41 +02:00
|
|
|
dsql_var* variable = (dsql_var*) item->nod_arg[e_var_variable];
|
2008-08-15 18:32:42 +02:00
|
|
|
if (variable->var_field)
|
|
|
|
name_alias = variable->var_field->fld_name.c_str();
|
2006-07-30 07:09:41 +02:00
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|
2008-09-27 11:51:53 +02:00
|
|
|
case nod_udf:
|
2005-09-02 07:30:16 +02:00
|
|
|
{
|
2006-07-30 07:09:41 +02:00
|
|
|
dsql_udf* userFunc = (dsql_udf*) item->nod_arg[0];
|
2008-01-16 07:52:43 +01:00
|
|
|
name_alias = userFunc->udf_name.c_str();
|
2006-07-30 07:09:41 +02:00
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|
2007-04-12 17:56:34 +02:00
|
|
|
case nod_sys_function:
|
|
|
|
name_alias = ((dsql_str*) item->nod_arg[e_sysfunc_name])->str_data;
|
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
case nod_gen_id:
|
|
|
|
case nod_gen_id2:
|
|
|
|
name_alias = "GEN_ID";
|
|
|
|
break;
|
|
|
|
case nod_user_name:
|
|
|
|
name_alias = "USER";
|
|
|
|
break;
|
|
|
|
case nod_current_role:
|
|
|
|
name_alias = "ROLE";
|
|
|
|
break;
|
|
|
|
case nod_internal_info:
|
|
|
|
{
|
2006-07-30 07:09:41 +02:00
|
|
|
internal_info_id id =
|
|
|
|
*reinterpret_cast<internal_info_id*>(item->nod_arg[0]->nod_desc.dsc_address);
|
|
|
|
name_alias = InternalInfo::getAlias(id);
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|
2006-07-30 07:09:41 +02:00
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
case nod_concatenate:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "CONCATENATION";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
2006-07-30 07:09:41 +02:00
|
|
|
case nod_constant:
|
|
|
|
case nod_null:
|
2006-07-31 03:46:52 +02:00
|
|
|
name_alias = "CONSTANT";
|
2006-07-30 07:09:41 +02:00
|
|
|
break;
|
2007-10-24 08:23:53 +02:00
|
|
|
case nod_negate:
|
|
|
|
{
|
|
|
|
// CVC: For this to be a thorough check, we need to recurse over all nodes.
|
|
|
|
// This means we should separate the code that sets aliases from
|
|
|
|
// the rest of the functionality here in make_parameter_names().
|
2007-10-27 20:09:32 +02:00
|
|
|
// Otherwise, we need to test here for most of the other node types.
|
2007-10-24 08:23:53 +02:00
|
|
|
// However, we need to be recursive only if we agree things like -gen_id()
|
|
|
|
// should be given the GEN_ID alias, too.
|
2008-04-14 09:05:49 +02:00
|
|
|
int level = 0;
|
2007-10-24 08:23:53 +02:00
|
|
|
const dsql_nod* node = item->nod_arg[0];
|
|
|
|
while (node->nod_type == nod_negate)
|
2008-04-14 09:05:49 +02:00
|
|
|
{
|
2007-10-24 08:23:53 +02:00
|
|
|
node = node->nod_arg[0];
|
2008-04-14 09:05:49 +02:00
|
|
|
++level;
|
|
|
|
}
|
2008-09-27 11:51:53 +02:00
|
|
|
|
2008-04-11 05:45:42 +02:00
|
|
|
switch (node->nod_type)
|
|
|
|
{
|
|
|
|
case nod_constant:
|
|
|
|
case nod_null:
|
2007-10-24 08:23:53 +02:00
|
|
|
name_alias = "CONSTANT";
|
2008-04-11 05:45:42 +02:00
|
|
|
break;
|
2008-04-14 09:05:49 +02:00
|
|
|
/*
|
2008-04-11 05:45:42 +02:00
|
|
|
case nod_add:
|
|
|
|
case nod_add2:
|
|
|
|
name_alias = "ADD";
|
|
|
|
break;
|
|
|
|
case nod_subtract:
|
|
|
|
case nod_subtract2:
|
|
|
|
name_alias = "SUBTRACT";
|
|
|
|
break;
|
2008-04-14 09:05:49 +02:00
|
|
|
*/
|
2008-04-11 05:45:42 +02:00
|
|
|
case nod_multiply:
|
|
|
|
case nod_multiply2:
|
2008-04-14 09:05:49 +02:00
|
|
|
if (!level)
|
|
|
|
name_alias = "MULTIPLY";
|
2008-04-11 05:45:42 +02:00
|
|
|
break;
|
|
|
|
case nod_divide:
|
|
|
|
case nod_divide2:
|
2008-04-14 09:05:49 +02:00
|
|
|
if (!level)
|
|
|
|
name_alias = "DIVIDE";
|
2008-04-11 05:45:42 +02:00
|
|
|
break;
|
|
|
|
}
|
2007-10-24 08:23:53 +02:00
|
|
|
}
|
|
|
|
break;
|
2006-07-30 07:09:41 +02:00
|
|
|
case nod_add:
|
|
|
|
case nod_add2:
|
|
|
|
name_alias = "ADD";
|
|
|
|
break;
|
|
|
|
case nod_subtract:
|
|
|
|
case nod_subtract2:
|
|
|
|
name_alias = "SUBTRACT";
|
|
|
|
break;
|
|
|
|
case nod_multiply:
|
|
|
|
case nod_multiply2:
|
|
|
|
name_alias = "MULTIPLY";
|
|
|
|
break;
|
|
|
|
case nod_divide:
|
|
|
|
case nod_divide2:
|
|
|
|
name_alias = "DIVIDE";
|
|
|
|
break;
|
2005-09-02 07:30:16 +02:00
|
|
|
case nod_substr:
|
|
|
|
name_alias = "SUBSTRING";
|
|
|
|
break;
|
|
|
|
case nod_trim:
|
|
|
|
name_alias = "TRIM";
|
|
|
|
break;
|
|
|
|
case nod_cast:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "CAST";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
|
|
|
case nod_upcase:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "UPPER";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
|
|
|
case nod_lowcase:
|
|
|
|
name_alias = "LOWER";
|
|
|
|
break;
|
|
|
|
case nod_current_date:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "CURRENT_DATE";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
|
|
|
case nod_current_time:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "CURRENT_TIME";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
|
|
|
case nod_current_timestamp:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "CURRENT_TIMESTAMP";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
|
|
|
case nod_extract:
|
2006-01-17 05:40:31 +01:00
|
|
|
if ( !Config::getOldColumnNaming() )
|
|
|
|
name_alias = "EXTRACT";
|
2005-09-02 07:30:16 +02:00
|
|
|
break;
|
|
|
|
case nod_strlen:
|
|
|
|
{
|
2007-10-19 13:51:58 +02:00
|
|
|
const ULONG length_type = item->nod_arg[e_strlen_type]->getSlong();
|
2005-09-02 07:30:16 +02:00
|
|
|
|
2006-07-30 07:09:41 +02:00
|
|
|
switch (length_type)
|
|
|
|
{
|
|
|
|
case blr_strlen_bit:
|
|
|
|
name_alias = "BIT_LENGTH";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_strlen_char:
|
|
|
|
name_alias = "CHAR_LENGTH";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case blr_strlen_octet:
|
|
|
|
name_alias = "OCTET_LENGTH";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
name_alias = "LENGTH";
|
|
|
|
fb_assert(false);
|
|
|
|
break;
|
|
|
|
}
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case nod_searched_case:
|
|
|
|
case nod_simple_case:
|
|
|
|
name_alias = "CASE";
|
|
|
|
break;
|
|
|
|
case nod_coalesce:
|
|
|
|
name_alias = "COALESCE";
|
|
|
|
break;
|
2008-09-27 11:51:53 +02:00
|
|
|
}
|
2005-09-02 07:30:16 +02:00
|
|
|
|
|
|
|
if (name_alias) {
|
|
|
|
parameter->par_name = parameter->par_alias = name_alias;
|
|
|
|
}
|
2006-12-01 14:49:11 +01:00
|
|
|
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
if (context->ctx_relation)
|
|
|
|
{
|
2008-01-16 07:52:43 +01:00
|
|
|
parameter->par_rel_name = context->ctx_relation->rel_name.c_str();
|
|
|
|
parameter->par_owner_name = context->ctx_relation->rel_owner.c_str();
|
2006-12-01 14:49:11 +01:00
|
|
|
}
|
|
|
|
else if (context->ctx_procedure)
|
|
|
|
{
|
2008-01-16 07:52:43 +01:00
|
|
|
parameter->par_rel_name = context->ctx_procedure->prc_name.c_str();
|
|
|
|
parameter->par_owner_name = context->ctx_procedure->prc_owner.c_str();
|
2006-12-01 14:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
parameter->par_rel_alias = context->ctx_alias;
|
|
|
|
}
|
2005-09-02 07:30:16 +02:00
|
|
|
}
|