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

1581 lines
43 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Dynamic SQL runtime support
* MODULE: make.c
* DESCRIPTION: Routines to make various blocks.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-06-29 08:56:51 +02:00
* 2001.11.21 Claudio Valderrama: Finally solved the mystery of DSQL
* not recognizing when a UDF returns NULL. This fixes SF bug #484399.
* See case nod_udf in MAKE_desc().
* 2001.02.23 Claudio Valderrama: Fix SF bug #518350 with substring()
* and text blobs containing charsets other than ASCII/NONE/BINARY.
* 2002.07.30 Arno Brinkman:
* COALESCE, CASE support added
* procedure MAKE_desc_from_list added
2001-05-23 15:26:42 +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
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <ctype.h>
#include <string.h>
#include "../dsql/dsql.h"
#include "../dsql/node.h"
#include "../dsql/sym.h"
#include "../jrd/gds.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/intl.h"
#include "../jrd/constants.h"
#include "../jrd/align.h"
#include "../dsql/alld_proto.h"
#include "../dsql/errd_proto.h"
#include "../dsql/hsh_proto.h"
#include "../dsql/make_proto.h"
#include "../jrd/thd_proto.h"
#include "../jrd/dsc_proto.h"
#include "../jrd/cvt_proto.h"
#include "../common/config/config.h"
2001-05-23 15:26:42 +02:00
ASSERT_FILENAME /* declare things assert() needs */
/* InterBase provides transparent conversion from string to date in
* contexts where it makes sense. This macro checks a descriptor to
* see if it is something that *could* represent a date value
*/
#define COULD_BE_DATE(d) (DTYPE_IS_DATE((d).dsc_dtype) || ((d).dsc_dtype <= dtype_any_text))
/* One of d1,d2 is time, the other is date */
#define IS_DATE_AND_TIME(d1,d2) \
((((d1).dsc_dtype==dtype_sql_time)&&((d2).dsc_dtype==dtype_sql_date)) || \
(((d2).dsc_dtype==dtype_sql_time)&&((d1).dsc_dtype==dtype_sql_date)))
2001-12-24 03:51:06 +01:00
2002-11-11 20:08:37 +01:00
DSQL_NOD MAKE_constant(STR constant, int numeric_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ c o n s t a n t
*
**************************************
*
* Functional description
* Make a constant node.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD node;
2001-05-23 15:26:42 +02:00
TSQL tdsql;
tdsql = GET_THREAD_DATA;
node = FB_NEW_RPT(*tdsql->tsql_default,
2001-12-24 03:51:06 +01:00
(numeric_flag == CONSTANT_TIMESTAMP ||
numeric_flag == CONSTANT_SINT64) ? 2 : 1) dsql_nod;
2001-05-23 15:26:42 +02:00
node->nod_type = nod_constant;
if (numeric_flag == CONSTANT_SLONG) {
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;
2002-11-11 20:08:37 +01:00
node->nod_arg[0] = (DSQL_NOD) constant;
2001-05-23 15:26:42 +02:00
}
else if (numeric_flag == 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
constants of less than 256 bytes.
*/
node->nod_desc.dsc_dtype = dtype_double;
node->nod_desc.dsc_scale = static_cast < char >(constant->str_length); /* Scale has no use for double */
node->nod_desc.dsc_sub_type = 0;
node->nod_desc.dsc_length = sizeof(double);
node->nod_desc.dsc_address = constant->str_data;
node->nod_desc.dsc_ttype = ttype_ascii;
2002-11-11 20:08:37 +01:00
node->nod_arg[0] = (DSQL_NOD) constant;
2001-05-23 15:26:42 +02:00
}
else if (numeric_flag == CONSTANT_SINT64) {
/* 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 */
UINT64 value = 0;
UCHAR *p = constant->str_data;
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;
node->nod_desc.dsc_address = (UCHAR *) node->nod_arg;
/* 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. */
while (isdigit(*p))
value = 10 * value + (*(p++) - '0');
2002-07-06 07:32:02 +02:00
if (*p++ == '.') {
2001-05-23 15:26:42 +02:00
while (isdigit(*p)) {
value = 10 * value + (*p++ - '0');
node->nod_desc.dsc_scale--;
}
}
*(UINT64 *) (node->nod_desc.dsc_address) = value;
}
else if (numeric_flag == CONSTANT_DATE ||
numeric_flag == CONSTANT_TIME ||
numeric_flag == CONSTANT_TIMESTAMP) {
DSC tmp;
/* Setup the constant's descriptor */
switch (numeric_flag) {
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];
node->nod_desc.dsc_address = (UCHAR *) node->nod_arg;
/* Set up a descriptor to point to the string */
tmp.dsc_dtype = dtype_text;
tmp.dsc_scale = 0;
tmp.dsc_flags = 0;
tmp.dsc_ttype = ttype_ascii;
2001-12-24 03:51:06 +01:00
tmp.dsc_length = static_cast<USHORT>(constant->str_length);
2001-05-23 15:26:42 +02:00
tmp.dsc_address = constant->str_data;
/* Now invoke the string_to_date/time/timestamp routines */
CVT_move(&tmp, &node->nod_desc,
2001-12-24 03:51:06 +01:00
reinterpret_cast<void (*)()> (ERRD_post));
2001-05-23 15:26:42 +02:00
}
else {
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;
node->nod_desc.dsc_length =
2001-12-24 03:51:06 +01:00
static_cast<USHORT>(constant->str_length);
2001-05-23 15:26:42 +02:00
node->nod_desc.dsc_address = constant->str_data;
node->nod_desc.dsc_ttype = ttype_dynamic;
/* carry a pointer to the constant to resolve character set in pass1 */
2002-11-11 20:08:37 +01:00
node->nod_arg[0] = (DSQL_NOD) constant;
2001-05-23 15:26:42 +02:00
}
return node;
}
2002-11-11 20:08:37 +01:00
DSQL_NOD MAKE_str_constant(STR constant, SSHORT character_set)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ s t r - c o n s t a n t
*
**************************************
*
* Functional description
* Make a constant node when the
* character set ID is already known.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD node;
2001-05-23 15:26:42 +02:00
TSQL tdsql;
tdsql = GET_THREAD_DATA;
node = FB_NEW_RPT(*tdsql->tsql_default, 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);
2001-05-23 15:26:42 +02:00
node->nod_desc.dsc_address = constant->str_data;
node->nod_desc.dsc_ttype = character_set;
/* carry a pointer to the constant to resolve character set in pass1 */
2002-11-11 20:08:37 +01:00
node->nod_arg[0] = (DSQL_NOD) constant;
2001-05-23 15:26:42 +02:00
return node;
}
STR MAKE_cstring(CONST SCHAR * str)
{
/**************************************
*
* M A K E _ c s t r i n g
*
**************************************
*
* Functional description
* Make a string node for a string whose
* length is not known, but is null-terminated.
*
**************************************/
return MAKE_string((UCHAR *) str, strlen(str));
}
2002-11-11 20:08:37 +01:00
void MAKE_desc( DSC * desc, DSQL_NOD node)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ d e s c
*
**************************************
*
* Functional description
* Make a descriptor from input node.
*
**************************************/
DSC desc1, desc2;
USHORT dtype, dtype1, dtype2;
MAP map;
DSQL_CTX context;
2001-05-23 15:26:42 +02:00
DSQL_REL relation;
UDF udf;
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
/* If we already know the datatype, don't worry about anything */
if (node->nod_desc.dsc_dtype) {
*desc = node->nod_desc;
return;
}
switch (node->nod_type) {
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:
map = (MAP) node->nod_arg[e_map_map];
MAKE_desc(desc, map->map_node);
return;
case nod_agg_min:
case nod_agg_max:
MAKE_desc(desc, node->nod_arg[0]);
desc->dsc_flags = DSC_nullable;
return;
case nod_agg_average:
MAKE_desc(desc, node->nod_arg[0]);
desc->dsc_flags = DSC_nullable;
dtype = desc->dsc_dtype;
if (!DTYPE_CAN_AVERAGE(dtype))
ERRD_post(gds_expression_eval_err, 0);
return;
case nod_agg_average2:
MAKE_desc(desc, node->nod_arg[0]);
desc->dsc_flags = DSC_nullable;
dtype = desc->dsc_dtype;
if (!DTYPE_CAN_AVERAGE(dtype))
ERRD_post(gds_expression_eval_err, 0);
if (DTYPE_IS_EXACT(dtype)) {
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:
MAKE_desc(desc, node->nod_arg[0]);
if (desc->dsc_dtype == dtype_short) {
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);
}
desc->dsc_flags = DSC_nullable;
return;
case nod_agg_total2:
MAKE_desc(desc, node->nod_arg[0]);
dtype = desc->dsc_dtype;
if (DTYPE_IS_EXACT(dtype)) {
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;
case nod_concatenate:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
desc->dsc_scale = 0;
desc->dsc_dtype = dtype_varying;
if (desc1.dsc_dtype <= dtype_any_text)
desc->dsc_ttype = desc1.dsc_ttype;
else
desc->dsc_ttype = ttype_ascii;
desc->dsc_length = sizeof(USHORT) +
DSC_string_length(&desc1) + DSC_string_length(&desc2);
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
return;
case nod_upcase:
2002-06-29 08:56:51 +02:00
case nod_substr:
2001-05-23 15:26:42 +02:00
MAKE_desc(&desc1, node->nod_arg[0]);
if (desc1.dsc_dtype <= dtype_any_text) {
*desc = desc1;
return;
}
desc->dsc_dtype = dtype_varying;
desc->dsc_scale = 0;
2002-06-29 08:56:51 +02:00
/* Beware that JRD treats substring() always as returning CHAR
instead of VARCHAR for historical reasons. */
if (node->nod_type == nod_substr && desc1.dsc_dtype == dtype_blob) {
SLONG len = 0;
2002-11-11 20:08:37 +01:00
DSQL_NOD for_node = node->nod_arg [e_substr_length];
2002-06-29 08:56:51 +02:00
assert (for_node->nod_desc.dsc_dtype == dtype_long);
/* Migrate the charset from the blob to the string. */
desc->dsc_ttype = desc1.dsc_scale;
len = *(SLONG *) for_node->nod_desc.dsc_address;
/* For now, our substring() doesn't handle MBCS blobs,
neither at the DSQL layer nor at the JRD layer. */
if (len <= (ULONG) MAX_COLUMN_SIZE - sizeof (USHORT) && len >= 0) {
desc->dsc_length = sizeof (USHORT) + len;
}
else {
ERRD_post (gds_sqlerr, gds_arg_number, (SLONG) -204,
gds_arg_gds, gds_dsql_datatype_err,
gds_arg_gds, gds_imp_exc,
gds_arg_gds, gds_field_name,
2002-06-29 08:56:51 +02:00
gds_arg_string, "substring()", /* field->fld_name,*/
0);
}
}
else {
desc->dsc_ttype = ttype_ascii;
desc->dsc_length = sizeof (USHORT) + DSC_string_length (&desc1);
}
desc->dsc_flags = desc1.dsc_flags & DSC_nullable;
return;
2001-05-23 15:26:42 +02:00
case nod_cast:
field = (DSQL_FLD) node->nod_arg[e_cast_target];
2001-05-23 15:26:42 +02:00
MAKE_desc_from_field(desc, field);
MAKE_desc(&desc1, node->nod_arg[e_cast_source]);
desc->dsc_flags = desc1.dsc_flags & DSC_nullable;
return;
case nod_simple_case:
MAKE_desc_from_list(&desc1, node->nod_arg[e_simple_case_results]);
*desc = desc1;
return;
case nod_searched_case:
MAKE_desc_from_list(&desc1, node->nod_arg[e_searched_case_results]);
*desc = desc1;
return;
case nod_coalesce:
MAKE_desc_from_list(&desc1, node->nod_arg[0]);
*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:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
dtype1 = desc1.dsc_dtype;
dtype2 = desc2.dsc_dtype;
if (dtype_int64 == dtype1)
dtype1 = dtype_double;
if (dtype_int64 == dtype2)
dtype2 = dtype_double;
dtype = MAX(dtype1, dtype2);
if (DTYPE_IS_BLOB(dtype))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
switch (dtype) {
case dtype_sql_time:
case dtype_sql_date:
/* Forbid <date/time> +- <string> */
if (IS_DTYPE_ANY_TEXT(desc1.dsc_dtype) ||
IS_DTYPE_ANY_TEXT(desc2.dsc_dtype))
ERRD_post(gds_expression_eval_err, 0);
case dtype_timestamp:
/* Allow <timestamp> +- <string> (historical) */
if (COULD_BE_DATE(desc1) && COULD_BE_DATE(desc2)) {
if (node->nod_type == nod_subtract) {
/* <any date> - <any date> */
/* Legal permutations are:
<timestamp> - <timestamp>
<timestamp> - <date>
<date> - <date>
<date> - <timestamp>
<time> - <time>
<timestamp> - <string>
<string> - <timestamp>
<string> - <string> */
if (IS_DTYPE_ANY_TEXT(dtype1))
dtype = dtype_timestamp;
else if (IS_DTYPE_ANY_TEXT(dtype2))
dtype = dtype_timestamp;
else if (dtype1 == dtype2)
dtype = dtype1;
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
ERRD_post(gds_expression_eval_err, 0);
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;
}
else {
assert(dtype == dtype_timestamp);
desc->dsc_dtype = dtype_double;
desc->dsc_length = sizeof(double);
desc->dsc_scale = 0;
}
}
else if (IS_DATE_AND_TIME(desc1, desc2)) {
/* <date> + <time> */
/* <time> + <date> */
desc->dsc_dtype = dtype_timestamp;
desc->dsc_length = type_lengths[dtype_timestamp];
desc->dsc_scale = 0;
}
else
/* <date> + <date> */
ERRD_post(gds_expression_eval_err, 0);
}
else if (DTYPE_IS_DATE(desc1.dsc_dtype) ||
/* <date> +/- <non-date> */
(node->nod_type == nod_add))
/* <non-date> + <date> */
{
desc->dsc_dtype = desc1.dsc_dtype;
if (!DTYPE_IS_DATE(desc->dsc_dtype))
desc->dsc_dtype = desc2.dsc_dtype;
assert(DTYPE_IS_DATE(desc->dsc_dtype));
desc->dsc_length = type_lengths[desc->dsc_dtype];
desc->dsc_scale = 0;
}
else {
/* <non-date> - <date> */
assert(node->nod_type == nod_subtract);
ERRD_post(gds_expression_eval_err, 0);
}
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:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
dtype1 = desc1.dsc_dtype;
dtype2 = desc2.dsc_dtype;
/* Arrays and blobs can never partipate in addition/subtraction */
if (DTYPE_IS_BLOB(desc1.dsc_dtype) || DTYPE_IS_BLOB(desc2.dsc_dtype))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
/* In Dialect 2 or 3, strings can never partipate in addition / sub
(Use a specific cast instead) */
if (IS_DTYPE_ANY_TEXT(desc1.dsc_dtype) ||
IS_DTYPE_ANY_TEXT(desc2.dsc_dtype))
ERRD_post(gds_expression_eval_err, 0);
/* 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> */
if (DTYPE_IS_EXACT(desc1.dsc_dtype)
&& DTYPE_IS_EXACT(desc2.dsc_dtype)) dtype = dtype_int64;
else if (DTYPE_IS_NUMERIC(desc1.dsc_dtype)
&& DTYPE_IS_NUMERIC(desc2.dsc_dtype)) {
assert(DTYPE_IS_APPROX(desc1.dsc_dtype) ||
DTYPE_IS_APPROX(desc2.dsc_dtype));
dtype = dtype_double;
}
else {
/* mixed numeric and non-numeric: */
assert(DTYPE_IS_DATE(dtype1) || DTYPE_IS_DATE(dtype2));
/* The MAX(dtype) rule doesn't apply with dtype_int64 */
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;
switch (dtype) {
case dtype_sql_time:
case dtype_sql_date:
case dtype_timestamp:
if ((DTYPE_IS_DATE(dtype1) || (dtype1 == dtype_null)) &&
(DTYPE_IS_DATE(dtype2) || (dtype2 == dtype_null))) {
if (node->nod_type == nod_subtract2) {
/* <any date> - <any date> */
/* Legal permutations are:
<timestamp> - <timestamp>
<timestamp> - <date>
<date> - <date>
<date> - <timestamp>
<time> - <time> */
if (dtype1 == dtype2)
dtype = dtype1;
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
ERRD_post(gds_expression_eval_err, 0);
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;
}
else {
assert(dtype == dtype_timestamp);
desc->dsc_dtype = dtype_int64;
desc->dsc_length = sizeof(SINT64);
desc->dsc_scale = -9;
}
}
else if (IS_DATE_AND_TIME(desc1, desc2)) {
/* <date> + <time> */
/* <time> + <date> */
desc->dsc_dtype = dtype_timestamp;
desc->dsc_length = type_lengths[dtype_timestamp];
desc->dsc_scale = 0;
}
else
/* <date> + <date> */
ERRD_post(gds_expression_eval_err, 0);
}
else if (DTYPE_IS_DATE(desc1.dsc_dtype) ||
/* <date> +/- <non-date> */
(node->nod_type == nod_add2))
/* <non-date> + <date> */
{
desc->dsc_dtype = desc1.dsc_dtype;
if (!DTYPE_IS_DATE(desc->dsc_dtype))
desc->dsc_dtype = desc2.dsc_dtype;
assert(DTYPE_IS_DATE(desc->dsc_dtype));
desc->dsc_length = type_lengths[desc->dsc_dtype];
desc->dsc_scale = 0;
}
else {
/* <non-date> - <date> */
assert(node->nod_type == nod_subtract2);
ERRD_post(gds_expression_eval_err, 0);
}
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. */
assert(DTYPE_IS_EXACT(desc1.dsc_dtype));
assert(DTYPE_IS_EXACT(desc2.dsc_dtype));
desc->dsc_scale = MIN(desc1.dsc_scale, desc2.dsc_scale);
node->nod_flags |= NOD_COMP_DIALECT;
break;
default:
/* a type which cannot participate in an add or subtract */
ERRD_post(gds_expression_eval_err, 0);
}
return;
case nod_multiply:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
dtype = DSC_multiply_blr4_result[desc1.dsc_dtype][desc2.dsc_dtype];
if (dtype_null == dtype)
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
switch (dtype) {
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:
ERRD_post(gds_expression_eval_err, 0);
}
return;
case nod_multiply2:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
dtype = DSC_multiply_result[desc1.dsc_dtype][desc2.dsc_dtype];
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
switch (dtype) {
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:
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
break;
}
return;
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;
case nod_divide:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
dtype1 = desc1.dsc_dtype;
if (dtype_int64 == dtype1)
dtype1 = dtype_double;
dtype2 = desc2.dsc_dtype;
if (dtype_int64 == dtype2)
dtype2 = dtype_double;
dtype = MAX(dtype1, dtype2);
if (!DTYPE_CAN_DIVIDE(dtype))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
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:
MAKE_desc(&desc1, node->nod_arg[0]);
MAKE_desc(&desc2, node->nod_arg[1]);
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;
switch (dtype) {
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:
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
break;
}
return;
case nod_negate:
MAKE_desc(desc, node->nod_arg[0]);
if (!DTYPE_CAN_NEGATE(desc->dsc_dtype))
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, gds_dsql_no_blob_array, 0);
return;
case nod_alias:
MAKE_desc(desc, node->nod_arg[e_alias_value]);
return;
case nod_dbkey:
/* Fix for bug 10072 check that the target is a relation */
context = (DSQL_CTX) node->nod_arg[0]->nod_arg[0];
2002-07-06 07:32:02 +02:00
relation = context->ctx_relation;
if (relation != 0) {
2001-05-23 15:26:42 +02:00
desc->dsc_dtype = dtype_text;
desc->dsc_length = relation->rel_dbkey_length;
desc->dsc_flags = 0;
desc->dsc_ttype = ttype_binary;
}
else {
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 607,
gds_arg_gds, isc_dsql_dbkey_from_non_table, 0);
}
return;
case nod_udf:
udf = (UDF) node->nod_arg[0];
2001-12-24 03:51:06 +01:00
desc->dsc_dtype = static_cast<UCHAR>(udf->udf_dtype);
2001-05-23 15:26:42 +02:00
desc->dsc_length = udf->udf_length;
2001-12-24 03:51:06 +01:00
desc->dsc_scale = static_cast<SCHAR>(udf->udf_scale);
2002-06-29 08:56:51 +02:00
/* 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;
if (desc->dsc_dtype <= dtype_any_text) {
desc->dsc_ttype = udf->udf_character_set_id;
}
else {
desc->dsc_ttype = udf->udf_sub_type;
}
2001-05-23 15:26:42 +02:00
return;
case nod_gen_id:
desc->dsc_dtype = dtype_long;
desc->dsc_sub_type = 0;
desc->dsc_scale = 0;
desc->dsc_length = sizeof(SLONG);
desc->dsc_flags = node->nod_arg[e_gen_id_value]->nod_desc.dsc_flags;
return;
case nod_gen_id2:
desc->dsc_dtype = dtype_int64;
desc->dsc_sub_type = 0;
desc->dsc_scale = 0;
desc->dsc_length = sizeof(SINT64);
desc->dsc_flags = node->nod_arg[e_gen_id_value]->nod_desc.dsc_flags;
node->nod_flags |= NOD_COMP_DIALECT;
return;
2002-06-29 08:56:51 +02:00
case nod_limit:
if (node->nod_desc.dsc_scale <= SQL_DIALECT_V5) {
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;
2001-05-23 15:26:42 +02:00
case nod_field:
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 203,
gds_arg_gds, gds_dsql_field_ref, 0);
return;
case nod_user_name:
2002-06-29 08:56:51 +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;
desc->dsc_ttype = ttype_dynamic;
desc->dsc_length = USERNAME_LENGTH + sizeof(USHORT);
return;
case nod_internal_info:
case nod_proc_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:
MAKE_desc(&desc1, node->nod_arg[e_extract_value]);
desc->dsc_sub_type = 0;
desc->dsc_scale = 0;
desc->dsc_flags = (desc1.dsc_flags & DSC_nullable);
if (*(ULONG *) node->nod_arg[e_extract_part]->nod_desc.dsc_address
== blr_extract_second) {
/* QUADDATE - maybe this should be DECIMAL(6,4) */
desc->dsc_dtype = dtype_long;
desc->dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE;
desc->dsc_length = sizeof(ULONG);
return;
}
desc->dsc_dtype = dtype_short;
desc->dsc_length = sizeof(SSHORT);
return;
case nod_parameter:
/* We don't actually know the datatype of a parameter -
we have to guess it based on the context that the
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. */
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
* datatype. Therefore we now describe it as a
* 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
* the statement. Note that this mapping could be done in dsql.c
* as part of the DESCRIBE statement - but I suspect other areas
* of the code would break if this is declared dtype_null.
*/
desc->dsc_dtype = dtype_text;
desc->dsc_length = 1;
desc->dsc_scale = 0;
desc->dsc_ttype = 0;
desc->dsc_flags = DSC_nullable;
return;
case nod_via:
MAKE_desc(desc, node->nod_arg[e_via_value_1]);
/**
Set the descriptor flag as nullable. The
select expression may or may not return
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;
default:
ASSERT_FAIL; /* unexpected dsql_nod type */
2001-05-23 15:26:42 +02:00
case nod_dom_value: /* computed value not used */
/* 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.
*/
assert(node->nod_desc.dsc_dtype != dtype_null);
if (desc != &node->nod_desc)
*desc = node->nod_desc;
return;
}
}
void MAKE_desc_from_field( DSC * desc, DSQL_FLD field)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ d e s c _ f r o m _ f i e l d
*
**************************************
*
* Functional description
* Compute a DSC from a field's description information.
*
**************************************/
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) {
INTL_ASSIGN_DSC(desc, field->fld_character_set_id,
field->fld_collation_id);
}
else if (desc->dsc_dtype == dtype_blob)
2001-12-24 03:51:06 +01:00
desc->dsc_scale = static_cast<SCHAR>(field->fld_character_set_id);
2001-05-23 15:26:42 +02:00
}
2002-11-11 20:08:37 +01:00
void MAKE_desc_from_list( DSC * desc, DSQL_NOD node)
/**************************************
*
* M A K E _ d e s c _ f r o m _ l i s t
*
**************************************
*
* Functional description
* Make a descriptor from a list of values
* according the sql-standard.
*
**************************************/
{
2002-11-11 20:08:37 +01:00
DSQL_NOD *arg, *end, tnod;
DSC desc1, desc2;
UCHAR max_exact_dtype = 0;
SCHAR maxscale;
USHORT cnvlength, maxlength, maxtextlength = 0;
2002-10-19 02:49:23 +02:00
BOOLEAN firstarg = TRUE, all_exact = TRUE, any_approx = FALSE, text_in_list = FALSE;
BOOLEAN varying_in_list = FALSE, all_datetime = TRUE, max_datetime_dtype = FALSE;
SSHORT ttype;
/*-------------------------------------------------------
TODO : BLOB with SubType Text
if an blob (with subtype text) is in the list then
the output should be always be an blob subtype text
-------------------------------------------------------*/
ttype = ttype_ascii; /* default type if all nodes are nod_null */
/* Walk through arguments list */
arg = node->nod_arg;
2002-10-19 02:49:23 +02:00
for (end = arg + node->nod_count; arg < end; arg++) {
/* ignore NULL value from walking */
tnod = *arg;
2002-10-19 02:49:23 +02:00
if (tnod->nod_type == nod_null || tnod->nod_type == nod_parameter) {
continue;
2002-10-19 02:49:23 +02:00
}
MAKE_desc(&desc1, *arg);
2002-10-19 02:49:23 +02:00
if (firstarg) {
desc2 = desc1;
maxscale = desc1.dsc_scale;
maxlength = desc1.dsc_length;
2002-10-19 02:49:23 +02:00
firstarg = FALSE;
}
2002-10-19 02:49:23 +02:00
if (!any_approx) {
any_approx = DTYPE_IS_APPROX(desc1.dsc_dtype);
}
2002-10-19 02:49:23 +02:00
if (DTYPE_IS_EXACT(desc1.dsc_dtype)) {
if (desc1.dsc_dtype > max_exact_dtype) {
max_exact_dtype = desc1.dsc_dtype;
}
}
2002-10-19 02:49:23 +02:00
else {
all_exact = FALSE;
}
/* scale is negative so check less than < ! */
2002-10-19 02:49:23 +02:00
if (desc1.dsc_scale < maxscale) {
maxscale = desc1.dsc_scale;
}
2002-10-19 02:49:23 +02:00
if (desc1.dsc_length > maxlength) {
maxlength = desc1.dsc_length;
}
2002-10-19 02:49:23 +02:00
if (desc1.dsc_dtype <= dtype_any_text) {
if (desc1.dsc_dtype == dtype_text) {
cnvlength = desc1.dsc_length;
}
2002-10-19 02:49:23 +02:00
if (desc1.dsc_dtype == dtype_cstring) {
cnvlength = desc1.dsc_length - 1;
}
2002-10-19 02:49:23 +02:00
if (desc1.dsc_dtype == dtype_varying) {
cnvlength = desc1.dsc_length - sizeof (USHORT);
2002-10-19 02:49:23 +02:00
varying_in_list = TRUE;
}
2002-10-19 02:49:23 +02:00
if (cnvlength > maxtextlength) {
maxtextlength = cnvlength;
}
/* Pick first characterset-collate from args-list
*
* Is there an better way to determine the
* characterset / collate from the list ?
* Maybe first according SQL-standard which has an order UTF32,UTF16,UTF8
* then by a Firebird specified order
*/
2002-10-19 02:49:23 +02:00
if (!text_in_list) {
ttype = desc1.dsc_ttype;
}
2002-10-19 02:49:23 +02:00
text_in_list = TRUE;
if (desc1.dsc_dtype == dtype_varying) {
varying_in_list = TRUE;
}
}
2002-10-19 02:49:23 +02:00
else {
/* Get max needed-length for not text types suchs as int64,timestamp etc.. */
cnvlength = DSC_convert_to_text_length(desc1.dsc_dtype);
2002-10-19 02:49:23 +02:00
if (cnvlength > maxtextlength) {
maxtextlength = cnvlength;
}
}
2002-10-19 02:49:23 +02:00
if (DTYPE_IS_DATE(desc1.dsc_dtype)) {
if (desc1.dsc_dtype == dtype_timestamp &&
2002-10-19 02:49:23 +02:00
max_datetime_dtype != dtype_timestamp) {
max_datetime_dtype = dtype_timestamp;
}
2002-10-19 02:49:23 +02:00
if (desc1.dsc_dtype == dtype_sql_date) {
if (max_datetime_dtype != dtype_timestamp &&
2002-10-19 02:49:23 +02:00
max_datetime_dtype != dtype_sql_time) {
max_datetime_dtype = dtype_sql_date;
}
2002-10-19 02:49:23 +02:00
else {
if (max_datetime_dtype == dtype_sql_time) {
/* Well raise exception or just cast everything to varchar ? */
2002-10-19 02:49:23 +02:00
text_in_list = TRUE;
varying_in_list = TRUE;
}
}
}
2002-10-19 02:49:23 +02:00
if (desc1.dsc_dtype == dtype_sql_time) {
if (max_datetime_dtype != dtype_timestamp &&
2002-10-19 02:49:23 +02:00
max_datetime_dtype != dtype_sql_date) {
max_datetime_dtype = dtype_sql_time;
}
2002-10-19 02:49:23 +02:00
else {
if (max_datetime_dtype == dtype_sql_date) {
/* Well raise exception or just cast everything to varchar ? */
2002-10-19 02:49:23 +02:00
text_in_list = TRUE;
varying_in_list = TRUE;
}
}
}
}
2002-10-19 02:49:23 +02:00
else {
all_datetime = FALSE;
}
}
/* If we haven't had a type at all then all values are NULL and/or parameter nodes */
2002-10-19 02:49:23 +02:00
if (firstarg) {
ERRD_post(gds_sqlerr, gds_arg_number, (SLONG) - 804,
gds_arg_gds, gds_dsql_datatype_err, 0);
}
desc->dsc_flags = DSC_nullable;
/* If any of the arguments are from type text use a text type */
2002-10-19 02:49:23 +02:00
if (text_in_list) {
if (varying_in_list) {
desc->dsc_dtype = dtype_varying;
maxtextlength += sizeof(USHORT);
}
2002-10-19 02:49:23 +02:00
else {
desc->dsc_dtype = dtype_text;
}
desc->dsc_ttype = ttype; /* same as dsc_subtype */
desc->dsc_length = maxtextlength;
desc->dsc_scale = 0;
return;
}
2002-10-19 02:49:23 +02:00
if (all_exact) {
desc->dsc_dtype = max_exact_dtype;
desc->dsc_sub_type = dsc_num_type_numeric;
desc->dsc_scale = maxscale;
desc->dsc_length = maxlength;
return;
}
2002-10-19 02:49:23 +02:00
if (any_approx) {
desc->dsc_dtype = dtype_double;
desc->dsc_length = sizeof(double);
desc->dsc_scale = 0;
desc->dsc_sub_type = 0;
/*desc->dsc_flags = 0;*/
return;
}
2002-10-19 02:49:23 +02:00
if (all_datetime) {
desc->dsc_dtype = max_datetime_dtype;
desc->dsc_length = type_lengths[desc->dsc_dtype];
desc->dsc_scale = 0;
desc->dsc_sub_type = 0;
return;
}
2002-10-19 02:49:23 +02:00
/* For any other handling, use the 1st argument as descriptor */
/* According SQL standard handled by db-engine */
desc->dsc_dtype = desc2.dsc_dtype;
desc->dsc_scale = desc2.dsc_scale;
desc->dsc_length = desc2.dsc_length;
desc->dsc_sub_type = desc2.dsc_sub_type;
/*desc->dsc_flags = desc2.dsc_flags;*/
return;
}
DSQL_NOD MAKE_field(DSQL_CTX context, DSQL_FLD field, DSQL_NOD indices)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ f i e l d
*
**************************************
*
* Functional description
* Make up a field node.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD node;
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
node = MAKE_node(nod_field, e_fld_count);
2002-11-11 20:08:37 +01:00
node->nod_arg[e_fld_context] = (DSQL_NOD) context;
node->nod_arg[e_fld_field] = (DSQL_NOD) field;
2001-05-23 15:26:42 +02:00
if (field->fld_dimensions) {
if (indices) {
node->nod_arg[e_fld_indices] = indices;
MAKE_desc_from_field(&node->nod_desc, field);
node->nod_desc.dsc_dtype =
2001-12-24 03:51:06 +01:00
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;
*/
}
else {
node->nod_desc.dsc_dtype = dtype_array;
node->nod_desc.dsc_length = sizeof(GDS__QUAD);
node->nod_desc.dsc_scale =
2001-12-24 03:51:06 +01:00
static_cast<SCHAR>(field->fld_scale);
2001-05-23 15:26:42 +02:00
node->nod_desc.dsc_sub_type = field->fld_sub_type;
}
}
else {
assert(!indices);
MAKE_desc_from_field(&node->nod_desc, field);
}
if ((field->fld_flags & FLD_nullable) ||
(context->ctx_flags & CTX_outer_join))
2001-05-23 15:26:42 +02:00
node->nod_desc.dsc_flags = DSC_nullable;
return node;
}
2002-11-11 20:08:37 +01:00
DSQL_NOD MAKE_list(DLLS stack)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ l i s t
*
**************************************
*
* Functional description
* Make a list node from a linked list stack of things.
*
**************************************/
2001-12-24 03:51:06 +01:00
DLLS temp;
2001-05-23 15:26:42 +02:00
USHORT count;
2002-11-11 20:08:37 +01:00
DSQL_NOD node, *ptr;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(stack, dsql_type_lls);
2001-05-23 15:26:42 +02:00
for (temp = stack, count = 0; temp; temp = temp->lls_next)
++count;
node = MAKE_node(nod_list, count);
ptr = node->nod_arg + count;
while (stack)
2002-11-11 20:08:37 +01:00
*--ptr = (DSQL_NOD) LLS_POP(&stack);
2001-05-23 15:26:42 +02:00
return node;
}
2002-11-11 20:08:37 +01:00
DSQL_NOD MAKE_node(NOD_TYPE type, int count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ n o d e
*
**************************************
*
* Functional description
* Make a node of given type.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD node;
2001-05-23 15:26:42 +02:00
TSQL tdsql;
tdsql = GET_THREAD_DATA;
node = FB_NEW_RPT(*tdsql->tsql_default, count) dsql_nod;
2001-05-23 15:26:42 +02:00
node->nod_type = type;
node->nod_count = count;
return node;
}
PAR MAKE_parameter(DSQL_MSG message, USHORT sqlda_flag, USHORT null_flag, USHORT sqlda_index)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ p a r a m e t e r
*
**************************************
*
* Functional description
* Generate a parameter block for a message. If requested,
* set up for a null flag as well.
*
**************************************/
PAR parameter, null;
TSQL tdsql;
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(message, dsql_type_msg);
if (sqlda_flag && sqlda_index && (sqlda_index < message->msg_index) &&
!Config::getOldParameterOrdering())
{
// This parameter possibly already here. Look for it
for (PAR temp = message->msg_parameters; temp; temp = temp->par_next) {
if (temp->par_index == sqlda_index)
return temp;
}
}
2001-05-23 15:26:42 +02:00
tdsql = GET_THREAD_DATA;
parameter = FB_NEW(*tdsql->tsql_default) par;
2001-05-23 15:26:42 +02:00
parameter->par_message = message;
2002-07-06 07:32:02 +02:00
parameter->par_next = message->msg_parameters;
if (parameter->par_next != 0)
2001-05-23 15:26:42 +02:00
parameter->par_next->par_ordered = parameter;
else
message->msg_par_ordered = parameter;
message->msg_parameters = parameter;
parameter->par_parameter = message->msg_parameter++;
parameter->par_rel_name = NULL;
parameter->par_owner_name = NULL;
/* If the parameter is used declared, set SQLDA index */
if (sqlda_flag) {
if (sqlda_index && !Config::getOldParameterOrdering()) {
parameter->par_index = sqlda_index;
if (message->msg_index < sqlda_index) message->msg_index = sqlda_index;
} else {
parameter->par_index = ++message->msg_index;
}
}
2001-05-23 15:26:42 +02:00
/* If a null handing has been requested, set up a null flag */
if (null_flag) {
parameter->par_null = null = MAKE_parameter(message, FALSE, FALSE, 0);
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;
}
STR MAKE_string(CONST UCHAR * str, int length)
{
/**************************************
*
* M A K E _ s t r i n g
*
**************************************
*
* Functional description
* Generalized routine for making a string block.
*
**************************************/
return MAKE_tagged_string(str, length, NULL);
}
SYM MAKE_symbol(DBB database,
CONST TEXT * name, USHORT length, SYM_TYPE type, DSQL_REQ object)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ s y m b o l
*
**************************************
*
* Functional description
* Make a symbol for an object and insert symbol into hash table.
*
**************************************/
SYM symbol;
TEXT *p;
TSQL tdsql;
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(database, dsql_type_dbb);
DEV_BLKCHK(object, dsql_type_req);
2001-05-23 15:26:42 +02:00
assert(name);
assert(length > 0);
tdsql = GET_THREAD_DATA;
symbol = FB_NEW_RPT(*tdsql->tsql_default, length) sym;
2001-05-23 15:26:42 +02:00
symbol->sym_type = type;
symbol->sym_object = (BLK) object;
symbol->sym_dbb = database;
symbol->sym_length = length;
symbol->sym_string = p = symbol->sym_name;
if (length)
MOVE_FAST(name, p, length);
HSHD_insert(symbol);
return symbol;
}
2001-12-24 03:51:06 +01:00
STR MAKE_tagged_string(CONST UCHAR * str_, int length, CONST TEXT * charset)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M A K E _ t a g g e d _ s t r i n g
*
**************************************
*
* Functional description
* Generalized routine for making a string block.
* Which is tagged with a character set descriptor.
*
**************************************/
UCHAR *p;
STR string;
TSQL tdsql;
tdsql = GET_THREAD_DATA;
string = FB_NEW_RPT(*tdsql->tsql_default, length) str;
2001-05-23 15:26:42 +02:00
string->str_charset = const_cast < char *>(charset);
string->str_length = length;
for (p = string->str_data; length; --length)
2001-12-24 03:51:06 +01:00
*p++ = *str_++;
2001-05-23 15:26:42 +02:00
return string;
}
2002-11-11 20:08:37 +01:00
DSQL_NOD MAKE_trigger_type(DSQL_NOD prefix_node, DSQL_NOD suffix_node)
{
/**************************************
*
* M A K E _ t r i g g e r _ t y p e
*
**************************************
*
* Functional description
* Make a trigger type
*
**************************************/
long prefix = (long) prefix_node->nod_arg[0], suffix = (long) suffix_node->nod_arg[0];
delete prefix_node;
delete suffix_node;
return MAKE_constant((STR) (prefix + suffix - 1), CONSTANT_SLONG);
}
DSQL_NOD MAKE_variable(DSQL_FLD field,
2001-05-23 15:26:42 +02:00
CONST TEXT * name,
USHORT type,
USHORT msg_number, USHORT item_number, USHORT local_number)
{
/**************************************
*
* M A K E _ v a r i a b l e
*
**************************************
*
* Functional description
* Make up a field node.
*
**************************************/
2002-11-11 20:08:37 +01:00
DSQL_NOD node;
2001-12-24 03:51:06 +01:00
VAR var_;
2001-05-23 15:26:42 +02:00
TSQL tdsql;
2001-12-24 03:51:06 +01:00
DEV_BLKCHK(field, dsql_type_fld);
2001-05-23 15:26:42 +02:00
tdsql = GET_THREAD_DATA;
var_ = FB_NEW_RPT(*tdsql->tsql_default, strlen(name)) var;
2001-05-23 15:26:42 +02:00
node = MAKE_node(nod_variable, e_var_count);
2002-11-11 20:08:37 +01:00
node->nod_arg[e_var_variable] = (DSQL_NOD) var_;
2001-12-24 03:51:06 +01:00
var_->var_msg_number = msg_number;
var_->var_msg_item = item_number;
var_->var_variable_number = local_number;
var_->var_field = field;
strcpy(var_->var_name, name);
var_->var_flags = type;
2001-05-23 15:26:42 +02:00
MAKE_desc_from_field(&node->nod_desc, field);
return node;
}