mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 04:03:03 +01:00
1) Implemented CASE, NULLIF, COALESCE
2) Allowed grouping by internal functions (some work in pass1.cpp still required) Thanks to Arno Brinkman.
This commit is contained in:
parent
4b39ede23b
commit
15a9015236
@ -29,7 +29,7 @@
|
||||
*
|
||||
*/
|
||||
/*
|
||||
$Id: dsql.cpp,v 1.18 2002-07-06 05:31:55 skywalker Exp $
|
||||
$Id: dsql.cpp,v 1.19 2002-08-03 15:27:20 dimitr Exp $
|
||||
*/
|
||||
/**************************************************************
|
||||
V4 Multi-threading changes.
|
||||
@ -2185,6 +2185,18 @@ void DSQL_pretty(NOD node, int column)
|
||||
verb = "via";
|
||||
break;
|
||||
|
||||
case nod_coalesce:
|
||||
verb = "coalesce";
|
||||
break;
|
||||
|
||||
case nod_simple_case:
|
||||
verb = "simple_case";
|
||||
break;
|
||||
|
||||
case nod_searched_case:
|
||||
verb = "searched_case";
|
||||
break;
|
||||
|
||||
case nod_add2:
|
||||
verb = "add2";
|
||||
break;
|
||||
|
@ -241,3 +241,6 @@
|
||||
#define TRANSACTION_ID 497
|
||||
#define LARGEINT 498
|
||||
#define KW_INT64 499
|
||||
#define CASE 500
|
||||
#define NULLIF 501
|
||||
#define COALESCE 502
|
||||
|
116
src/dsql/gen.cpp
116
src/dsql/gen.cpp
@ -21,10 +21,11 @@
|
||||
* Contributor(s): ______________________________________
|
||||
* 2001.6.21 Claudio Valderrama: BREAK and SUBSTRING.
|
||||
* 2001.07.28: John Bellardo: Added code to generate blr_skip.
|
||||
* 2002.07.30: Arno Brinkman: Added code, procedures to generate COALESCE, CASE
|
||||
*
|
||||
*/
|
||||
/*
|
||||
$Id: gen.cpp,v 1.8 2002-07-10 14:52:42 dimitr Exp $
|
||||
$Id: gen.cpp,v 1.9 2002-08-03 15:27:20 dimitr Exp $
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
@ -48,6 +49,7 @@ $Id: gen.cpp,v 1.8 2002-07-10 14:52:42 dimitr Exp $
|
||||
|
||||
ASSERT_FILENAME static void gen_aggregate(REQ, NOD);
|
||||
static void gen_cast(REQ, NOD);
|
||||
static void gen_coalesce(REQ, NOD);
|
||||
static void gen_constant(REQ, DSC *, BOOLEAN);
|
||||
static void gen_descriptor(REQ, DSC *, USHORT);
|
||||
static void gen_error_condition(REQ, NOD);
|
||||
@ -60,7 +62,9 @@ static void gen_parameter(REQ, PAR);
|
||||
static void gen_plan(REQ, NOD);
|
||||
static void gen_relation(REQ, CTX);
|
||||
static void gen_rse(REQ, NOD);
|
||||
static void gen_searched_case(REQ, NOD);
|
||||
static void gen_select(REQ, NOD);
|
||||
static void gen_simple_case(REQ, NOD);
|
||||
static void gen_sort(REQ, NOD);
|
||||
static void gen_table_lock(REQ, NOD, USHORT);
|
||||
static void gen_udf(REQ, NOD);
|
||||
@ -451,6 +455,15 @@ void GEN_expr( REQ request, NOD node)
|
||||
case nod_gen_id2:
|
||||
gen_gen_id(request, node);
|
||||
return;
|
||||
case nod_coalesce:
|
||||
gen_coalesce(request, node);
|
||||
return;
|
||||
case nod_simple_case:
|
||||
gen_simple_case(request, node);
|
||||
return;
|
||||
case nod_searched_case:
|
||||
gen_searched_case(request, node);
|
||||
return;
|
||||
case nod_average:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
@ -1164,6 +1177,39 @@ static void gen_cast( REQ request, NOD node)
|
||||
}
|
||||
|
||||
|
||||
static void gen_coalesce( REQ request, NOD node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g e n _ c o a l e s c e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Generate BLR for coalesce function
|
||||
*
|
||||
**************************************/
|
||||
NOD list, *ptr, *end;
|
||||
|
||||
/* blr_value_if is used for building the coalesce function */
|
||||
|
||||
list = node->nod_arg[0];
|
||||
STUFF(blr_cast);
|
||||
gen_descriptor(request, &node->nod_desc, TRUE);
|
||||
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++)
|
||||
{
|
||||
STUFF(blr_value_if);
|
||||
STUFF(blr_missing);
|
||||
GEN_expr(request, *ptr);
|
||||
}
|
||||
STUFF(blr_null);
|
||||
for (end = list->nod_arg, ptr = end + list->nod_count, ptr--; ptr >= end; ptr--)
|
||||
{
|
||||
GEN_expr(request, *ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gen_constant( REQ request, DSC * desc, BOOLEAN negate_value)
|
||||
{
|
||||
/**************************************
|
||||
@ -1985,6 +2031,39 @@ static void gen_rse( REQ request, NOD rse)
|
||||
}
|
||||
|
||||
|
||||
static void gen_searched_case( REQ request, NOD node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g e n _ s e a r c h e d _ c a s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Generate BLR for CASE function (searched)
|
||||
*
|
||||
**************************************/
|
||||
NOD boolean_list, results_list, *bptr, *rptr, *end;
|
||||
|
||||
/* blr_value_if is used for building the case expression */
|
||||
|
||||
STUFF(blr_cast);
|
||||
gen_descriptor(request, &node->nod_desc, TRUE);
|
||||
SSHORT count = node->nod_arg[e_searched_case_search_conditions]->nod_count;
|
||||
boolean_list = node->nod_arg[e_searched_case_search_conditions];
|
||||
results_list = node->nod_arg[e_searched_case_results];
|
||||
for (bptr = boolean_list->nod_arg, end = bptr + count, rptr = results_list->nod_arg;
|
||||
bptr < end; bptr++, rptr++)
|
||||
{
|
||||
STUFF(blr_value_if);
|
||||
GEN_expr(request, *bptr);
|
||||
GEN_expr(request, *rptr);
|
||||
}
|
||||
/* else_result */
|
||||
GEN_expr(request, node->nod_arg[e_searched_case_results]->nod_arg[count]);
|
||||
}
|
||||
|
||||
|
||||
static void gen_select( REQ request, NOD rse)
|
||||
{
|
||||
/**************************************
|
||||
@ -2283,6 +2362,41 @@ static void gen_select( REQ request, NOD rse)
|
||||
}
|
||||
|
||||
|
||||
static void gen_simple_case( REQ request, NOD node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g e n _ s i m p l e _ c a s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Generate BLR for CASE function (simple)
|
||||
*
|
||||
**************************************/
|
||||
NOD when_list, results_list, *wptr, *rptr, *end;
|
||||
|
||||
/* blr_value_if is used for building the case expression */
|
||||
|
||||
STUFF(blr_cast);
|
||||
gen_descriptor(request, &node->nod_desc, TRUE);
|
||||
SSHORT count = node->nod_arg[e_simple_case_when_operands]->nod_count;
|
||||
when_list = node->nod_arg[e_simple_case_when_operands];
|
||||
results_list = node->nod_arg[e_simple_case_results];
|
||||
for (wptr = when_list->nod_arg, end = wptr + count, rptr = results_list->nod_arg;
|
||||
wptr < end; wptr++, rptr++)
|
||||
{
|
||||
STUFF(blr_value_if);
|
||||
STUFF(blr_eql);
|
||||
GEN_expr(request, node->nod_arg[e_simple_case_case_operand]);
|
||||
GEN_expr(request, *wptr);
|
||||
GEN_expr(request, *rptr);
|
||||
}
|
||||
/* else_result */
|
||||
GEN_expr(request, node->nod_arg[e_simple_case_results]->nod_arg[count]);
|
||||
}
|
||||
|
||||
|
||||
static void gen_sort( REQ request, NOD list)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -28,7 +28,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
* $Id: keywords.cpp,v 1.3 2002-07-30 09:49:16 dimitr Exp $
|
||||
* $Id: keywords.cpp,v 1.4 2002-08-03 15:27:20 dimitr Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -79,11 +79,13 @@ static CONST TOK tokens [] = {
|
||||
{BY, "BY", 1},
|
||||
{CACHE, "CACHE", 1},
|
||||
{CASCADE, "CASCADE", 1},
|
||||
{CASE, "CASE", 2},
|
||||
{CAST, "CAST", 1},
|
||||
{KW_CHAR, "CHAR", 1},
|
||||
{CHARACTER, "CHARACTER", 1},
|
||||
{CHECK, "CHECK", 1},
|
||||
{CHECK_POINT_LEN, "CHECK_POINT_LENGTH", 1},
|
||||
{COALESCE, "COALESCE", 2},
|
||||
{COLLATE, "COLLATE", 1},
|
||||
{COLUMN, "COLUMN", 2},
|
||||
{COMMIT, "COMMIT", 1},
|
||||
@ -186,6 +188,7 @@ static CONST TOK tokens [] = {
|
||||
{NCHAR, "NCHAR", 1},
|
||||
{NO, "NO", 1},
|
||||
{NOT, "NOT", 1},
|
||||
{NULLIF, "NULLIF", 2},
|
||||
{KW_NULL, "NULL", 1},
|
||||
{KW_NUMERIC, "NUMERIC", 1},
|
||||
{NUM_LOG_BUFS, "NUM_LOG_BUFFERS", 1},
|
||||
|
@ -42,4 +42,4 @@ extern "C" {
|
||||
extern bool KEYWORD_stringIsAToken(const char*);
|
||||
extern CONST TOK* KEYWORD_getTokens();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,9 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
//This MUST be before any other includes
|
||||
@ -422,6 +425,21 @@ void MAKE_desc( DSC * desc, NOD node)
|
||||
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;
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
case nod_collate:
|
||||
ERRD_bugcheck("Not expecting nod_collate in dsql/MAKE_desc");
|
||||
@ -1045,6 +1063,232 @@ void MAKE_desc_from_field( DSC * desc, FLD field)
|
||||
}
|
||||
|
||||
|
||||
void MAKE_desc_from_list( DSC * desc, 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.
|
||||
*
|
||||
**************************************/
|
||||
{
|
||||
NOD *arg, *end, tnod;
|
||||
DSC desc1, desc2;
|
||||
UCHAR max_exact_dtype = 0;
|
||||
SCHAR maxscale;
|
||||
USHORT cnvlength, maxlength, maxtextlength = 0;
|
||||
USHORT firstarg = 1, all_exact = 1, any_approx = 0, text_in_list = 0, varying_in_list = 0;
|
||||
USHORT all_datetime = 1, max_datetime_dtype = 0;
|
||||
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;
|
||||
for (end = arg + node->nod_count; arg < end; arg++)
|
||||
{
|
||||
/* ignore NULL value from walking */
|
||||
tnod = *arg;
|
||||
if (tnod->nod_type == nod_null)
|
||||
continue;
|
||||
MAKE_desc(&desc1, *arg);
|
||||
if (firstarg)
|
||||
{
|
||||
desc2 = desc1;
|
||||
maxscale = desc1.dsc_scale;
|
||||
maxlength = desc1.dsc_length;
|
||||
firstarg = 0;
|
||||
}
|
||||
if (!any_approx)
|
||||
{
|
||||
any_approx = DTYPE_IS_APPROX(desc1.dsc_dtype);
|
||||
}
|
||||
if (DTYPE_IS_EXACT(desc1.dsc_dtype))
|
||||
{
|
||||
if (desc1.dsc_dtype > max_exact_dtype)
|
||||
{
|
||||
max_exact_dtype = desc1.dsc_dtype;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
all_exact = 0;
|
||||
}
|
||||
/* scale is negative so check less than < ! */
|
||||
if (desc1.dsc_scale < maxscale)
|
||||
{
|
||||
maxscale = desc1.dsc_scale;
|
||||
}
|
||||
if (desc1.dsc_length > maxlength)
|
||||
{
|
||||
maxlength = desc1.dsc_length;
|
||||
}
|
||||
if (desc1.dsc_dtype <= dtype_any_text)
|
||||
{
|
||||
if (desc1.dsc_dtype == dtype_text)
|
||||
{
|
||||
cnvlength = desc1.dsc_length;
|
||||
}
|
||||
if (desc1.dsc_dtype == dtype_cstring)
|
||||
{
|
||||
cnvlength = desc1.dsc_length - 1;
|
||||
}
|
||||
if (desc1.dsc_dtype == dtype_varying)
|
||||
{
|
||||
cnvlength = desc1.dsc_length - sizeof (USHORT);
|
||||
varying_in_list = 1;
|
||||
}
|
||||
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
|
||||
*/
|
||||
if (!text_in_list)
|
||||
{
|
||||
ttype = desc1.dsc_ttype;
|
||||
}
|
||||
text_in_list = 1;
|
||||
if (desc1.dsc_dtype == dtype_varying)
|
||||
{
|
||||
varying_in_list = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get max needed-length for not text types suchs as int64,timestamp etc.. */
|
||||
cnvlength = DSC_convert_to_text_length(desc1.dsc_dtype);
|
||||
if (cnvlength > maxtextlength)
|
||||
{
|
||||
maxtextlength = cnvlength;
|
||||
}
|
||||
}
|
||||
if (DTYPE_IS_DATE(desc1.dsc_dtype))
|
||||
{
|
||||
if (desc1.dsc_dtype == dtype_timestamp &&
|
||||
max_datetime_dtype != dtype_timestamp)
|
||||
{
|
||||
max_datetime_dtype = dtype_timestamp;
|
||||
}
|
||||
if (desc1.dsc_dtype == dtype_sql_date)
|
||||
{
|
||||
if (max_datetime_dtype != dtype_timestamp &&
|
||||
max_datetime_dtype != dtype_sql_time)
|
||||
{
|
||||
max_datetime_dtype = dtype_sql_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (max_datetime_dtype == dtype_sql_time)
|
||||
{
|
||||
/* Well raise exception or just cast everything to varchar ? */
|
||||
text_in_list = 1;
|
||||
varying_in_list = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (desc1.dsc_dtype == dtype_sql_time)
|
||||
{
|
||||
if (max_datetime_dtype != dtype_timestamp &&
|
||||
max_datetime_dtype != dtype_sql_date)
|
||||
{
|
||||
max_datetime_dtype = dtype_sql_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (max_datetime_dtype == dtype_sql_date)
|
||||
{
|
||||
/* Well raise exception or just cast everything to varchar ? */
|
||||
text_in_list = 1;
|
||||
varying_in_list = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
all_datetime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we haven't had a type at all then all values are NULL nodes */
|
||||
if (firstarg)
|
||||
{
|
||||
maxtextlength = desc1.dsc_length;
|
||||
text_in_list = 1;
|
||||
firstarg = 0;
|
||||
}
|
||||
|
||||
desc->dsc_flags = DSC_nullable;
|
||||
/* If any of the arguments are from type text use a text type */
|
||||
if (text_in_list)
|
||||
{
|
||||
if (varying_in_list)
|
||||
{
|
||||
desc->dsc_dtype = dtype_varying;
|
||||
maxtextlength += sizeof(USHORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
desc->dsc_dtype = dtype_text;
|
||||
}
|
||||
desc->dsc_ttype = ttype; /* same as dsc_subtype */
|
||||
desc->dsc_length = maxtextlength;
|
||||
desc->dsc_scale = 0;
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
/* Any other handeling use 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;
|
||||
}
|
||||
|
||||
|
||||
NOD MAKE_field(CTX context, FLD field, NOD indices)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -19,6 +19,8 @@
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
* 2002-07-20 Arno Brinkman: Added MAKE_desc_from_list
|
||||
*/
|
||||
|
||||
#ifndef _DSQL_MAKE_PROTO_H_
|
||||
@ -31,6 +33,7 @@ struct nod* MAKE_str_constant(class str* , SSHORT);
|
||||
class str* MAKE_cstring(CONST SCHAR*);
|
||||
void MAKE_desc(struct dsc* , struct nod*);
|
||||
void MAKE_desc_from_field(struct dsc* , class fld*);
|
||||
void MAKE_desc_from_list(struct dsc* , struct nod*);
|
||||
struct nod* MAKE_field(class ctx* , class fld* , struct nod*);
|
||||
struct nod* MAKE_list(class dsql_lls*);
|
||||
struct nod* MAKE_node(ENUM nod_t, int);
|
||||
|
@ -24,6 +24,9 @@
|
||||
* about source line in each node that's created.
|
||||
* 2001.07.28 John Bellardo: Added e_rse_limit to nod_rse and nod_limit.
|
||||
* 2001.08.03 John Bellardo: Reordered args to no_sel for new LIMIT syntax
|
||||
* 2002.07.30 Arno Brinkman:
|
||||
* 2002.07.30 Added nod_searched_case, nod_simple_case, nod_coalesce
|
||||
* 2002.07.30 and constants for arguments
|
||||
*/
|
||||
|
||||
#ifndef _DSQL_NODE_H_
|
||||
@ -310,7 +313,10 @@ typedef ENUM nod_t
|
||||
nod_limit, /* limit support */
|
||||
nod_redef_procedure, /* allows silent creation/overwriting of a procedure. */
|
||||
nod_exec_sql, /* EXECUTE VARCHAR */
|
||||
nod_internal_info /* Internal engine info */
|
||||
nod_internal_info, /* internal engine info */
|
||||
nod_searched_case, /* searched CASE function */
|
||||
nod_simple_case, /* simple CASE function */
|
||||
nod_coalesce /* COALESCE function */
|
||||
} NOD_TYPE;
|
||||
|
||||
|
||||
@ -800,4 +806,17 @@ typedef nod *NOD;
|
||||
#define e_udf_param_type 1 /* Basically, by_reference or by_descriptor */
|
||||
#define e_udf_param_count 2
|
||||
|
||||
/* CASE <case_operand> {WHEN <when_operand> THEN <when_result>}.. [ELSE <else_result>] END
|
||||
Node-constants for after pass1 */
|
||||
|
||||
#define e_simple_case_case_operand 0 /* 1 value */
|
||||
#define e_simple_case_when_operands 1 /* list */
|
||||
#define e_simple_case_results 2 /* list including else_result */
|
||||
|
||||
/* CASE {WHEN <search_condition> THEN <when_result>}.. [ELSE <else_result>] END
|
||||
Node-constants for after pass1 */
|
||||
|
||||
#define e_searched_case_search_conditions 0 /* list boolean expressions */
|
||||
#define e_searched_case_results 1 /* list including else_result */
|
||||
|
||||
#endif /* _DSQL_NODE_H_ */
|
||||
|
4956
src/dsql/parse.cpp
4956
src/dsql/parse.cpp
File diff suppressed because it is too large
Load Diff
150
src/dsql/parse.y
150
src/dsql/parse.y
@ -38,7 +38,13 @@
|
||||
* 2001.10.06 Claudio Valderrama: Honor explicit USER keyword in GRANTs and REVOKEs.
|
||||
* 2002.07.05 Mark O'Donohue: change keyword DEBUG to KW_DEBUG to avoid
|
||||
* clashes with normal DEBUG macro.
|
||||
*
|
||||
* 2002.07.30 Arno Brinkman:
|
||||
* 2002.07.30 Let IN predicate handle value_expressions
|
||||
* 2002.07.30 tokens CASE, NULLIF, COALESCE added
|
||||
* 2002.07.30 See block < CASE expression > what is added to value as case_expression
|
||||
* 2002.07.30 function is split up into aggregate_function, numeric_value_function, string_value_function, generate_value_function
|
||||
* 2002.07.30 new group_by_function and added to grp_column_elem. (TODO: allow these functions in select_group_by_list inside the engine)
|
||||
* 2002.07.30 cast removed from function and added as cast_specification to value
|
||||
*/
|
||||
|
||||
|
||||
@ -391,6 +397,9 @@ static void yyerror (TEXT *);
|
||||
%token TRANSACTION_ID
|
||||
%token LARGEINT
|
||||
%token KW_INT64
|
||||
%token CASE
|
||||
%token NULLIF
|
||||
%token COALESCE
|
||||
|
||||
/* precedence declarations for expression evaluation */
|
||||
|
||||
@ -2728,10 +2737,16 @@ grp_column_list : grp_column_elem
|
||||
|
||||
grp_column_elem : column_name
|
||||
| udf
|
||||
| group_by_function
|
||||
| column_name COLLATE symbol_collation_name
|
||||
{ $$ = make_node (nod_collate, e_coll_count, (NOD) $3, $1); }
|
||||
;
|
||||
|
||||
group_by_function : numeric_value_function
|
||||
| string_value_function
|
||||
| case_expression
|
||||
;
|
||||
|
||||
having_clause : HAVING search_condition
|
||||
{ $$ = $2; }
|
||||
|
|
||||
@ -3072,9 +3087,9 @@ like_predicate : value LIKE value
|
||||
3, $1, $4, $6)); }
|
||||
;
|
||||
|
||||
in_predicate : value IN scalar_set
|
||||
in_predicate : value IN in_predicate_value
|
||||
{ $$ = make_node (nod_eql_any, 2, $1, $3); }
|
||||
| value NOT IN scalar_set
|
||||
| value NOT IN in_predicate_value
|
||||
{ $$ = make_node (nod_not, 1, make_node (nod_eql_any, 2, $1, $4)); }
|
||||
;
|
||||
|
||||
@ -3111,10 +3126,13 @@ null_predicate : value IS KW_NULL
|
||||
|
||||
/* set values */
|
||||
|
||||
scalar_set : '(' constant_list ')'
|
||||
in_predicate_value : table_subquery
|
||||
| '(' value_list ')'
|
||||
{ $$ = make_list ($2); }
|
||||
| '(' column_select ')'
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
table_subquery : '(' column_select ')'
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
column_select : SELECT limit_clause
|
||||
@ -3151,6 +3169,8 @@ value : column_name
|
||||
| u_constant
|
||||
| parameter
|
||||
| variable
|
||||
| cast_specification
|
||||
| case_expression
|
||||
| udf
|
||||
| '-' value
|
||||
{ $$ = make_node (nod_negate, 1, $2); }
|
||||
@ -3403,7 +3423,15 @@ long_integer : NUMBER
|
||||
{ $$ = $1;}
|
||||
;
|
||||
|
||||
function : COUNT '(' '*' ')'
|
||||
/* functions */
|
||||
|
||||
function : aggregate_function
|
||||
| generate_value_function
|
||||
| numeric_value_function
|
||||
| string_value_function
|
||||
;
|
||||
|
||||
aggregate_function : COUNT '(' '*' ')'
|
||||
{ $$ = make_node (nod_agg_count, 0, NULL); }
|
||||
| COUNT '(' all_noise value ')'
|
||||
{ $$ = make_node (nod_agg_count, 1, $4); }
|
||||
@ -3450,32 +3478,37 @@ function : COUNT '(' '*' ')'
|
||||
{ $$ = make_node (nod_agg_max, 1, $4); }
|
||||
| MAXIMUM '(' DISTINCT value ')'
|
||||
{ $$ = make_node (nod_agg_max, 1, $4); }
|
||||
| CAST '(' rhs AS data_type_descriptor ')'
|
||||
{ $$ = make_node (nod_cast, e_cast_count, $5, $3); }
|
||||
| KW_UPPER '(' value ')'
|
||||
{ $$ = make_node (nod_upcase, 1, $3); }
|
||||
| GEN_ID '(' symbol_generator_name ',' value ')'
|
||||
{
|
||||
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
|
||||
$$ = make_node (nod_gen_id2, 2, $3, $5);
|
||||
else
|
||||
$$ = make_node (nod_gen_id, 2, $3, $5);
|
||||
}
|
||||
| EXTRACT '(' timestamp_part FROM value ')'
|
||||
{ $$ = make_node (nod_extract, e_extract_count, $3, $5); }
|
||||
/* CVC: It was easier to provide a constant with maximum value if the
|
||||
third parameter -length- is ommitted than to chase and fix the functions
|
||||
that treat nod_substr as an aggregate and do not expect NULL arguments. */
|
||||
| SUBSTRING '(' value FROM pos_short_integer ')'
|
||||
{ $$ = make_node (nod_substr, e_substr_count, $3,
|
||||
MAKE_constant ((STR) ((SLONG)($5) - 1), CONSTANT_SLONG),
|
||||
MAKE_constant ((STR) SHRT_POS_MAX, CONSTANT_SLONG)); }
|
||||
| SUBSTRING '(' value FROM pos_short_integer FOR nonneg_short_integer ')'
|
||||
{ $$ = make_node (nod_substr, e_substr_count, $3,
|
||||
MAKE_constant ((STR) ((SLONG)($5) - 1), CONSTANT_SLONG),
|
||||
MAKE_constant ((STR) ($7), CONSTANT_SLONG)); }
|
||||
;
|
||||
|
||||
/* Firebird specific functions into 'generate_value_function' */
|
||||
|
||||
generate_value_function : GEN_ID '(' symbol_generator_name ',' value ')'
|
||||
{
|
||||
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
|
||||
$$ = make_node (nod_gen_id2, 2, $3, $5);
|
||||
else
|
||||
$$ = make_node (nod_gen_id, 2, $3, $5);
|
||||
}
|
||||
;
|
||||
|
||||
numeric_value_function : EXTRACT '(' timestamp_part FROM value ')'
|
||||
{ $$ = make_node (nod_extract, e_extract_count, $3, $5); }
|
||||
/* CVC: It was easier to provide a constant with maximum value if the
|
||||
third parameter -length- is ommitted than to chase and fix the functions
|
||||
that treat nod_substr as an aggregate and do not expect NULL arguments. */
|
||||
;
|
||||
|
||||
string_value_function : SUBSTRING '(' value FROM pos_short_integer ')'
|
||||
{ $$ = make_node (nod_substr, e_substr_count, $3,
|
||||
MAKE_constant ((STR) ((SLONG)($5) - 1), CONSTANT_SLONG),
|
||||
MAKE_constant ((STR) SHRT_POS_MAX, CONSTANT_SLONG)); }
|
||||
| SUBSTRING '(' value FROM pos_short_integer FOR nonneg_short_integer ')'
|
||||
{ $$ = make_node (nod_substr, e_substr_count, $3,
|
||||
MAKE_constant ((STR) ((SLONG)($5) - 1), CONSTANT_SLONG),
|
||||
MAKE_constant ((STR) ($7), CONSTANT_SLONG)); }
|
||||
| KW_UPPER '(' value ')'
|
||||
{ $$ = make_node (nod_upcase, 1, $3); }
|
||||
;
|
||||
|
||||
udf : symbol_UDF_name '(' value_list ')'
|
||||
{ $$ = make_node (nod_udf, 2, $1, $3); }
|
||||
@ -3483,6 +3516,61 @@ udf : symbol_UDF_name '(' value_list ')'
|
||||
{ $$ = make_node (nod_udf, 1, $1); }
|
||||
;
|
||||
|
||||
cast_specification : CAST '(' rhs AS data_type_descriptor ')'
|
||||
{ $$ = make_node (nod_cast, e_cast_count, $5, $3); }
|
||||
;
|
||||
|
||||
/* case expressions */
|
||||
|
||||
case_expression : case_abbreviation
|
||||
| case_specification
|
||||
;
|
||||
|
||||
case_abbreviation : NULLIF '(' value ',' value ')'
|
||||
{ $$ = make_node (nod_searched_case, 2,
|
||||
make_node (nod_list, 2, make_node (nod_eql, 2, $3, $5),
|
||||
make_node (nod_null, 0, NULL)), $3); }
|
||||
| COALESCE '(' null_or_value ',' null_or_value_list ')'
|
||||
{ $$ = make_node (nod_coalesce, 2, $3, $5); }
|
||||
;
|
||||
|
||||
case_specification : simple_case
|
||||
| searched_case
|
||||
;
|
||||
|
||||
simple_case : CASE case_operand simple_when_clause END
|
||||
{ $$ = make_node (nod_simple_case, 3, $2, make_list($3), make_node (nod_null, 0, NULL)); }
|
||||
| CASE case_operand simple_when_clause ELSE case_result END
|
||||
{ $$ = make_node (nod_simple_case, 3, $2, make_list($3), $5); }
|
||||
;
|
||||
|
||||
simple_when_clause : WHEN when_operand THEN case_result
|
||||
{ $$ = make_node (nod_list, 2, $2, $4); }
|
||||
| simple_when_clause WHEN when_operand THEN case_result
|
||||
{ $$ = make_node (nod_list, 2, $1, make_node (nod_list, 2, $3, $5)); }
|
||||
;
|
||||
|
||||
searched_case : CASE searched_when_clause END
|
||||
{ $$ = make_node (nod_searched_case, 2, make_list($2), make_node (nod_null, 0, NULL)); }
|
||||
| CASE searched_when_clause ELSE case_result END
|
||||
{ $$ = make_node (nod_searched_case, 2, make_list($2), $4); }
|
||||
;
|
||||
|
||||
searched_when_clause : WHEN search_condition THEN case_result
|
||||
{ $$ = make_node (nod_list, 2, $2, $4); }
|
||||
| searched_when_clause WHEN search_condition THEN case_result
|
||||
{ $$ = make_node (nod_list, 2, $1, make_node (nod_list, 2, $3, $5)); }
|
||||
;
|
||||
|
||||
when_operand : value
|
||||
;
|
||||
|
||||
case_operand : value
|
||||
;
|
||||
|
||||
case_result : null_or_value
|
||||
;
|
||||
|
||||
timestamp_part : YEAR
|
||||
{ $$ = MAKE_constant ((STR)blr_extract_year, CONSTANT_SLONG); }
|
||||
| MONTH
|
||||
|
@ -83,6 +83,9 @@
|
||||
*
|
||||
* 2001.12.21 Claudio Valderrama: Fix SF Bug #494832 - pass1_variable() should work
|
||||
* with def_proc, mod_proc, redef_proc, def_trig and mod_trig node types.
|
||||
*
|
||||
* 2002.07.30 Arno Brinkman: Added pass1_coalesce, pass1_simple_case, pass1_searched_case
|
||||
* and pass1_put_args_on_stack
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
@ -133,6 +136,7 @@ static CTX pass1_alias(REQ, STR);
|
||||
static NOD pass1_any(REQ, NOD, NOD_TYPE);
|
||||
static DSQL_REL pass1_base_table(REQ, DSQL_REL, STR);
|
||||
static void pass1_blob(REQ, NOD);
|
||||
static NOD pass1_coalesce(REQ, NOD, USHORT);
|
||||
static NOD pass1_collate(REQ, NOD, STR);
|
||||
static NOD pass1_constant(REQ, NOD);
|
||||
static NOD pass1_cursor(REQ, NOD, NOD);
|
||||
@ -141,9 +145,12 @@ static NOD pass1_dbkey(REQ, NOD);
|
||||
static NOD pass1_delete(REQ, NOD);
|
||||
static NOD pass1_field(REQ, NOD, USHORT);
|
||||
static NOD pass1_insert(REQ, NOD);
|
||||
static void pass1_put_args_on_stack(REQ, NOD, DLLS *, USHORT);
|
||||
static NOD pass1_relation(REQ, NOD);
|
||||
static NOD pass1_rse(REQ, NOD, NOD);
|
||||
static NOD pass1_searched_case(REQ, NOD, USHORT);
|
||||
static NOD pass1_sel_list(REQ, NOD);
|
||||
static NOD pass1_simple_case(REQ, NOD, USHORT);
|
||||
static NOD pass1_sort(REQ, NOD, NOD);
|
||||
static NOD pass1_udf(REQ, NOD, USHORT);
|
||||
static void pass1_udf_args(REQ, NOD, UDF, USHORT, DLLS *, USHORT);
|
||||
@ -438,6 +445,15 @@ NOD PASS1_node(REQ request, NOD input, USHORT proc_flag)
|
||||
node->nod_desc.dsc_flags |= DSC_nullable;
|
||||
return node;
|
||||
|
||||
case nod_coalesce:
|
||||
return pass1_coalesce(request, input, proc_flag);
|
||||
|
||||
case nod_simple_case:
|
||||
return pass1_simple_case(request, input, proc_flag);
|
||||
|
||||
case nod_searched_case:
|
||||
return pass1_searched_case(request, input, proc_flag);
|
||||
|
||||
case nod_gen_id:
|
||||
case nod_gen_id2:
|
||||
node = MAKE_node(input->nod_type, e_gen_id_count);
|
||||
@ -1436,6 +1452,9 @@ static BOOLEAN aggregate_found2(
|
||||
case nod_subtract2:
|
||||
case nod_upcase:
|
||||
case nod_extract:
|
||||
case nod_coalesce:
|
||||
case nod_simple_case:
|
||||
case nod_searched_case:
|
||||
case nod_list:
|
||||
aggregate = FALSE;
|
||||
for (ptr = sub->nod_arg, end = ptr + sub->nod_count; ptr < end; ptr++) {
|
||||
@ -1515,6 +1534,9 @@ static BOOLEAN aggregate_in_list (NOD sub, BOOLEAN *field, NOD list)
|
||||
case nod_subtract2:
|
||||
case nod_upcase:
|
||||
case nod_extract:
|
||||
case nod_coalesce:
|
||||
case nod_simple_case:
|
||||
case nod_searched_case:
|
||||
case nod_list:
|
||||
aggregate = FALSE;
|
||||
for (ptr = sub->nod_arg, end = ptr + sub->nod_count; ptr < end; ptr++)
|
||||
@ -1748,6 +1770,9 @@ static NOD copy_field( NOD field, CTX context)
|
||||
case nod_upcase:
|
||||
case nod_internal_info:
|
||||
case nod_extract:
|
||||
case nod_coalesce:
|
||||
case nod_simple_case:
|
||||
case nod_searched_case:
|
||||
case nod_list:
|
||||
temp = MAKE_node(field->nod_type, field->nod_count);
|
||||
ptr2 = temp->nod_arg;
|
||||
@ -2238,6 +2263,9 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
|
||||
case nod_subtract:
|
||||
case nod_upcase:
|
||||
case nod_extract:
|
||||
case nod_coalesce:
|
||||
case nod_simple_case:
|
||||
case nod_searched_case:
|
||||
case nod_add2:
|
||||
case nod_divide2:
|
||||
case nod_multiply2:
|
||||
@ -2657,6 +2685,40 @@ static void pass1_blob( REQ request, NOD input)
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_coalesce( REQ request, NOD input, USHORT proc_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a s s 1 _ c o a l e s c e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Handle a reference to a coalesce function.
|
||||
*
|
||||
**************************************/
|
||||
NOD node;
|
||||
DLLS stack;
|
||||
|
||||
DEV_BLKCHK(request, dsql_type_req);
|
||||
DEV_BLKCHK(input, dsql_type_nod);
|
||||
DEV_BLKCHK(input->nod_arg[0], dsql_type_nod);
|
||||
|
||||
node = MAKE_node(nod_coalesce, 1);
|
||||
|
||||
/* Pass list of arguments 2..n on stack and make a list from it */
|
||||
stack = NULL;
|
||||
pass1_put_args_on_stack(request, input->nod_arg [0], &stack, proc_flag);
|
||||
pass1_put_args_on_stack(request, input->nod_arg [1], &stack, proc_flag);
|
||||
node->nod_arg[0] = MAKE_list(stack);
|
||||
|
||||
/* Set describer for output node */
|
||||
MAKE_desc(&node->nod_desc, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_collate( REQ request, NOD sub1, STR collation)
|
||||
{
|
||||
/**************************************
|
||||
@ -3370,6 +3432,36 @@ static NOD pass1_insert( REQ request, NOD input)
|
||||
}
|
||||
|
||||
|
||||
static void pass1_put_args_on_stack( REQ request, NOD input, DLLS *stack, USHORT proc_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a s s 1 _ p u t _ a r g s _ o n _ s t a c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Put recursivly non list nodes on stack
|
||||
*
|
||||
**************************************/
|
||||
NOD *ptr, *end;
|
||||
|
||||
DEV_BLKCHK(request, dsql_type_req);
|
||||
DEV_BLKCHK(input, dsql_type_nod);
|
||||
|
||||
if (input->nod_type != nod_list)
|
||||
{
|
||||
LLS_PUSH(PASS1_node(request, input, proc_flag), stack);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ptr = input->nod_arg, end = ptr + input->nod_count; ptr < end; ptr++)
|
||||
{
|
||||
pass1_put_args_on_stack(request, *ptr, stack, proc_flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_relation( REQ request, NOD input)
|
||||
{
|
||||
/**************************************
|
||||
@ -3811,6 +3903,54 @@ static NOD pass1_rse( REQ request, NOD input, NOD order)
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_searched_case( REQ request, NOD input, USHORT proc_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a s s 1 _ s e a r c h e d _ c a s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Handle a reference to a searched case expression.
|
||||
*
|
||||
**************************************/
|
||||
NOD node, list, *ptr, *end;
|
||||
DLLS stack;
|
||||
|
||||
DEV_BLKCHK(request, dsql_type_req);
|
||||
DEV_BLKCHK(input, dsql_type_nod);
|
||||
DEV_BLKCHK(input->nod_arg[0], dsql_type_nod);
|
||||
|
||||
node = MAKE_node(nod_searched_case, 3);
|
||||
|
||||
list = input->nod_arg[0];
|
||||
|
||||
/* build boolean-expression list */
|
||||
stack = NULL;
|
||||
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++,ptr++)
|
||||
{
|
||||
pass1_put_args_on_stack(request, *ptr, &stack, proc_flag);
|
||||
}
|
||||
node->nod_arg[e_searched_case_search_conditions] = MAKE_list(stack);
|
||||
|
||||
/* build when_result list including else_result at the end */
|
||||
/* else_result is included for easy handling in MAKE_desc() */
|
||||
stack = NULL;
|
||||
for (ptr = list->nod_arg, end = ptr + list->nod_count, ptr++; ptr < end; ptr++,ptr++)
|
||||
{
|
||||
pass1_put_args_on_stack(request, *ptr, &stack, proc_flag);
|
||||
}
|
||||
pass1_put_args_on_stack(request, input->nod_arg[1], &stack, proc_flag);
|
||||
node->nod_arg[e_searched_case_results] = MAKE_list(stack);
|
||||
|
||||
/* Set describer for output node */
|
||||
MAKE_desc(&node->nod_desc, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_sel_list( REQ request, NOD input)
|
||||
{
|
||||
/**************************************
|
||||
@ -3858,6 +3998,58 @@ static NOD pass1_sel_list( REQ request, NOD input)
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_simple_case( REQ request, NOD input, USHORT proc_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a s s 1 _ s i m p l e _ c a s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Handle a reference to a simple case expression.
|
||||
*
|
||||
**************************************/
|
||||
NOD node, list, *ptr, *end;
|
||||
DLLS stack;
|
||||
|
||||
DEV_BLKCHK(request, dsql_type_req);
|
||||
DEV_BLKCHK(input, dsql_type_nod);
|
||||
DEV_BLKCHK(input->nod_arg [0], dsql_type_nod);
|
||||
|
||||
node = MAKE_node(nod_simple_case, 3);
|
||||
|
||||
/* build case_operand node */
|
||||
node->nod_arg[e_simple_case_case_operand] =
|
||||
PASS1_node(request, input->nod_arg[0], proc_flag);
|
||||
|
||||
list = input->nod_arg[1];
|
||||
|
||||
/* build when_operand list */
|
||||
stack = NULL;
|
||||
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++,ptr++)
|
||||
{
|
||||
pass1_put_args_on_stack(request, *ptr, &stack, proc_flag);
|
||||
}
|
||||
node->nod_arg[e_simple_case_when_operands] = MAKE_list(stack);
|
||||
|
||||
/* build when_result list including else_result at the end */
|
||||
/* else_result is included for easy handling in MAKE_desc() */
|
||||
stack = NULL;
|
||||
for (ptr = list->nod_arg, end = ptr + list->nod_count, ptr++; ptr < end; ptr++,ptr++)
|
||||
{
|
||||
pass1_put_args_on_stack(request, *ptr, &stack, proc_flag);
|
||||
}
|
||||
pass1_put_args_on_stack(request, input->nod_arg [2], &stack, proc_flag);
|
||||
node->nod_arg[e_simple_case_results] = MAKE_list(stack);
|
||||
|
||||
/* Set describer for output node */
|
||||
MAKE_desc(&node->nod_desc, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
static NOD pass1_sort( REQ request, NOD input, NOD s_list)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -64,7 +64,7 @@ static USHORT CONST _DSC_convert_to_text_length[DTYPE_TYPE_MAX] =
|
||||
/* -- in BLR_version4 DD-Mon-YYYY HH:MM:SS.MMMM */
|
||||
9, /* dtype_blob FFFF:FFFF */
|
||||
9, /* dtype_array FFFF:FFFF */
|
||||
20 /* dtype_int64 -9223372036854775808 + decimal point */
|
||||
21 /* dtype_int64 -9223372036854775808 + decimal point */
|
||||
};
|
||||
|
||||
/* blr to dsc type conversions */
|
||||
|
Loading…
Reference in New Issue
Block a user