8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 07:23: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:
dimitr 2002-08-03 15:27:20 +00:00
parent 4b39ede23b
commit 15a9015236
12 changed files with 3291 additions and 2417 deletions

View File

@ -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. V4 Multi-threading changes.
@ -2185,6 +2185,18 @@ void DSQL_pretty(NOD node, int column)
verb = "via"; verb = "via";
break; 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: case nod_add2:
verb = "add2"; verb = "add2";
break; break;

View File

@ -241,3 +241,6 @@
#define TRANSACTION_ID 497 #define TRANSACTION_ID 497
#define LARGEINT 498 #define LARGEINT 498
#define KW_INT64 499 #define KW_INT64 499
#define CASE 500
#define NULLIF 501
#define COALESCE 502

View File

@ -21,10 +21,11 @@
* Contributor(s): ______________________________________ * Contributor(s): ______________________________________
* 2001.6.21 Claudio Valderrama: BREAK and SUBSTRING. * 2001.6.21 Claudio Valderrama: BREAK and SUBSTRING.
* 2001.07.28: John Bellardo: Added code to generate blr_skip. * 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" #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); ASSERT_FILENAME static void gen_aggregate(REQ, NOD);
static void gen_cast(REQ, NOD); static void gen_cast(REQ, NOD);
static void gen_coalesce(REQ, NOD);
static void gen_constant(REQ, DSC *, BOOLEAN); static void gen_constant(REQ, DSC *, BOOLEAN);
static void gen_descriptor(REQ, DSC *, USHORT); static void gen_descriptor(REQ, DSC *, USHORT);
static void gen_error_condition(REQ, NOD); 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_plan(REQ, NOD);
static void gen_relation(REQ, CTX); static void gen_relation(REQ, CTX);
static void gen_rse(REQ, NOD); static void gen_rse(REQ, NOD);
static void gen_searched_case(REQ, NOD);
static void gen_select(REQ, NOD); static void gen_select(REQ, NOD);
static void gen_simple_case(REQ, NOD);
static void gen_sort(REQ, NOD); static void gen_sort(REQ, NOD);
static void gen_table_lock(REQ, NOD, USHORT); static void gen_table_lock(REQ, NOD, USHORT);
static void gen_udf(REQ, NOD); static void gen_udf(REQ, NOD);
@ -451,6 +455,15 @@ void GEN_expr( REQ request, NOD node)
case nod_gen_id2: case nod_gen_id2:
gen_gen_id(request, node); gen_gen_id(request, node);
return; 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_average:
case nod_count: case nod_count:
case nod_from: 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) 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) 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) static void gen_sort( REQ request, NOD list)
{ {
/************************************** /**************************************

View File

@ -28,7 +28,7 @@
* Contributor(s): * 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}, {BY, "BY", 1},
{CACHE, "CACHE", 1}, {CACHE, "CACHE", 1},
{CASCADE, "CASCADE", 1}, {CASCADE, "CASCADE", 1},
{CASE, "CASE", 2},
{CAST, "CAST", 1}, {CAST, "CAST", 1},
{KW_CHAR, "CHAR", 1}, {KW_CHAR, "CHAR", 1},
{CHARACTER, "CHARACTER", 1}, {CHARACTER, "CHARACTER", 1},
{CHECK, "CHECK", 1}, {CHECK, "CHECK", 1},
{CHECK_POINT_LEN, "CHECK_POINT_LENGTH", 1}, {CHECK_POINT_LEN, "CHECK_POINT_LENGTH", 1},
{COALESCE, "COALESCE", 2},
{COLLATE, "COLLATE", 1}, {COLLATE, "COLLATE", 1},
{COLUMN, "COLUMN", 2}, {COLUMN, "COLUMN", 2},
{COMMIT, "COMMIT", 1}, {COMMIT, "COMMIT", 1},
@ -186,6 +188,7 @@ static CONST TOK tokens [] = {
{NCHAR, "NCHAR", 1}, {NCHAR, "NCHAR", 1},
{NO, "NO", 1}, {NO, "NO", 1},
{NOT, "NOT", 1}, {NOT, "NOT", 1},
{NULLIF, "NULLIF", 2},
{KW_NULL, "NULL", 1}, {KW_NULL, "NULL", 1},
{KW_NUMERIC, "NUMERIC", 1}, {KW_NUMERIC, "NUMERIC", 1},
{NUM_LOG_BUFS, "NUM_LOG_BUFFERS", 1}, {NUM_LOG_BUFS, "NUM_LOG_BUFFERS", 1},

View File

@ -42,4 +42,4 @@ extern "C" {
extern bool KEYWORD_stringIsAToken(const char*); extern bool KEYWORD_stringIsAToken(const char*);
extern CONST TOK* KEYWORD_getTokens(); extern CONST TOK* KEYWORD_getTokens();
} }

View File

@ -24,6 +24,9 @@
* See case nod_udf in MAKE_desc(). * See case nod_udf in MAKE_desc().
* 2001.02.23 Claudio Valderrama: Fix SF bug #518350 with substring() * 2001.02.23 Claudio Valderrama: Fix SF bug #518350 with substring()
* and text blobs containing charsets other than ASCII/NONE/BINARY. * 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 //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; desc->dsc_flags = desc1.dsc_flags & DSC_nullable;
return; 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 #ifdef DEV_BUILD
case nod_collate: case nod_collate:
ERRD_bugcheck("Not expecting nod_collate in dsql/MAKE_desc"); 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) NOD MAKE_field(CTX context, FLD field, NOD indices)
{ {
/************************************** /**************************************

View File

@ -19,6 +19,8 @@
* *
* All Rights Reserved. * All Rights Reserved.
* Contributor(s): ______________________________________. * Contributor(s): ______________________________________.
*
* 2002-07-20 Arno Brinkman: Added MAKE_desc_from_list
*/ */
#ifndef _DSQL_MAKE_PROTO_H_ #ifndef _DSQL_MAKE_PROTO_H_
@ -31,6 +33,7 @@ struct nod* MAKE_str_constant(class str* , SSHORT);
class str* MAKE_cstring(CONST SCHAR*); class str* MAKE_cstring(CONST SCHAR*);
void MAKE_desc(struct dsc* , struct nod*); void MAKE_desc(struct dsc* , struct nod*);
void MAKE_desc_from_field(struct dsc* , class fld*); 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_field(class ctx* , class fld* , struct nod*);
struct nod* MAKE_list(class dsql_lls*); struct nod* MAKE_list(class dsql_lls*);
struct nod* MAKE_node(ENUM nod_t, int); struct nod* MAKE_node(ENUM nod_t, int);

View File

@ -24,6 +24,9 @@
* about source line in each node that's created. * 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.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 * 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_ #ifndef _DSQL_NODE_H_
@ -310,7 +313,10 @@ typedef ENUM nod_t
nod_limit, /* limit support */ nod_limit, /* limit support */
nod_redef_procedure, /* allows silent creation/overwriting of a procedure. */ nod_redef_procedure, /* allows silent creation/overwriting of a procedure. */
nod_exec_sql, /* EXECUTE VARCHAR */ 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; } 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_type 1 /* Basically, by_reference or by_descriptor */
#define e_udf_param_count 2 #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_ */ #endif /* _DSQL_NODE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,13 @@
* 2001.10.06 Claudio Valderrama: Honor explicit USER keyword in GRANTs and REVOKEs. * 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 * 2002.07.05 Mark O'Donohue: change keyword DEBUG to KW_DEBUG to avoid
* clashes with normal DEBUG macro. * 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 TRANSACTION_ID
%token LARGEINT %token LARGEINT
%token KW_INT64 %token KW_INT64
%token CASE
%token NULLIF
%token COALESCE
/* precedence declarations for expression evaluation */ /* precedence declarations for expression evaluation */
@ -2728,10 +2737,16 @@ grp_column_list : grp_column_elem
grp_column_elem : column_name grp_column_elem : column_name
| udf | udf
| group_by_function
| column_name COLLATE symbol_collation_name | column_name COLLATE symbol_collation_name
{ $$ = make_node (nod_collate, e_coll_count, (NOD) $3, $1); } { $$ = 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 having_clause : HAVING search_condition
{ $$ = $2; } { $$ = $2; }
| |
@ -3072,9 +3087,9 @@ like_predicate : value LIKE value
3, $1, $4, $6)); } 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); } { $$ = 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)); } { $$ = 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 */ /* set values */
scalar_set : '(' constant_list ')' in_predicate_value : table_subquery
| '(' value_list ')'
{ $$ = make_list ($2); } { $$ = make_list ($2); }
| '(' column_select ')' ;
{ $$ = $2; }
table_subquery : '(' column_select ')'
{ $$ = $2; }
; ;
column_select : SELECT limit_clause column_select : SELECT limit_clause
@ -3151,6 +3169,8 @@ value : column_name
| u_constant | u_constant
| parameter | parameter
| variable | variable
| cast_specification
| case_expression
| udf | udf
| '-' value | '-' value
{ $$ = make_node (nod_negate, 1, $2); } { $$ = make_node (nod_negate, 1, $2); }
@ -3403,7 +3423,15 @@ long_integer : NUMBER
{ $$ = $1;} { $$ = $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); } { $$ = make_node (nod_agg_count, 0, NULL); }
| COUNT '(' all_noise value ')' | COUNT '(' all_noise value ')'
{ $$ = make_node (nod_agg_count, 1, $4); } { $$ = make_node (nod_agg_count, 1, $4); }
@ -3450,32 +3478,37 @@ function : COUNT '(' '*' ')'
{ $$ = make_node (nod_agg_max, 1, $4); } { $$ = make_node (nod_agg_max, 1, $4); }
| MAXIMUM '(' DISTINCT value ')' | MAXIMUM '(' DISTINCT value ')'
{ $$ = make_node (nod_agg_max, 1, $4); } { $$ = 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 ')' udf : symbol_UDF_name '(' value_list ')'
{ $$ = make_node (nod_udf, 2, $1, $3); } { $$ = make_node (nod_udf, 2, $1, $3); }
@ -3483,6 +3516,61 @@ udf : symbol_UDF_name '(' value_list ')'
{ $$ = make_node (nod_udf, 1, $1); } { $$ = 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 timestamp_part : YEAR
{ $$ = MAKE_constant ((STR)blr_extract_year, CONSTANT_SLONG); } { $$ = MAKE_constant ((STR)blr_extract_year, CONSTANT_SLONG); }
| MONTH | MONTH

View File

@ -83,6 +83,9 @@
* *
* 2001.12.21 Claudio Valderrama: Fix SF Bug #494832 - pass1_variable() should work * 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. * 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" #include "firebird.h"
@ -133,6 +136,7 @@ static CTX pass1_alias(REQ, STR);
static NOD pass1_any(REQ, NOD, NOD_TYPE); static NOD pass1_any(REQ, NOD, NOD_TYPE);
static DSQL_REL pass1_base_table(REQ, DSQL_REL, STR); static DSQL_REL pass1_base_table(REQ, DSQL_REL, STR);
static void pass1_blob(REQ, NOD); static void pass1_blob(REQ, NOD);
static NOD pass1_coalesce(REQ, NOD, USHORT);
static NOD pass1_collate(REQ, NOD, STR); static NOD pass1_collate(REQ, NOD, STR);
static NOD pass1_constant(REQ, NOD); static NOD pass1_constant(REQ, NOD);
static NOD pass1_cursor(REQ, NOD, 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_delete(REQ, NOD);
static NOD pass1_field(REQ, NOD, USHORT); static NOD pass1_field(REQ, NOD, USHORT);
static NOD pass1_insert(REQ, NOD); 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_relation(REQ, NOD);
static NOD pass1_rse(REQ, NOD, 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_sel_list(REQ, NOD);
static NOD pass1_simple_case(REQ, NOD, USHORT);
static NOD pass1_sort(REQ, NOD, NOD); static NOD pass1_sort(REQ, NOD, NOD);
static NOD pass1_udf(REQ, NOD, USHORT); static NOD pass1_udf(REQ, NOD, USHORT);
static void pass1_udf_args(REQ, NOD, UDF, USHORT, DLLS *, 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; node->nod_desc.dsc_flags |= DSC_nullable;
return node; 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_id:
case nod_gen_id2: case nod_gen_id2:
node = MAKE_node(input->nod_type, e_gen_id_count); node = MAKE_node(input->nod_type, e_gen_id_count);
@ -1436,6 +1452,9 @@ static BOOLEAN aggregate_found2(
case nod_subtract2: case nod_subtract2:
case nod_upcase: case nod_upcase:
case nod_extract: case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_list: case nod_list:
aggregate = FALSE; aggregate = FALSE;
for (ptr = sub->nod_arg, end = ptr + sub->nod_count; ptr < end; ptr++) { 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_subtract2:
case nod_upcase: case nod_upcase:
case nod_extract: case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_list: case nod_list:
aggregate = FALSE; aggregate = FALSE;
for (ptr = sub->nod_arg, end = ptr + sub->nod_count; ptr < end; ptr++) 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_upcase:
case nod_internal_info: case nod_internal_info:
case nod_extract: case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_list: case nod_list:
temp = MAKE_node(field->nod_type, field->nod_count); temp = MAKE_node(field->nod_type, field->nod_count);
ptr2 = temp->nod_arg; ptr2 = temp->nod_arg;
@ -2238,6 +2263,9 @@ static BOOLEAN invalid_reference( NOD node, NOD list)
case nod_subtract: case nod_subtract:
case nod_upcase: case nod_upcase:
case nod_extract: case nod_extract:
case nod_coalesce:
case nod_simple_case:
case nod_searched_case:
case nod_add2: case nod_add2:
case nod_divide2: case nod_divide2:
case nod_multiply2: 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) 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) 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) 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) static NOD pass1_sort( REQ request, NOD input, NOD s_list)
{ {
/************************************** /**************************************

View File

@ -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 */ /* -- in BLR_version4 DD-Mon-YYYY HH:MM:SS.MMMM */
9, /* dtype_blob FFFF:FFFF */ 9, /* dtype_blob FFFF:FFFF */
9, /* dtype_array FFFF:FFFF */ 9, /* dtype_array FFFF:FFFF */
20 /* dtype_int64 -9223372036854775808 + decimal point */ 21 /* dtype_int64 -9223372036854775808 + decimal point */
}; };
/* blr to dsc type conversions */ /* blr to dsc type conversions */