8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 06:03:02 +01:00

Refactor EXTRACT

This commit is contained in:
asfernandes 2010-10-16 18:53:25 +00:00
parent 2dcef5c7ce
commit 2e0da292df
17 changed files with 400 additions and 356 deletions

View File

@ -3194,6 +3194,350 @@ ValueExprNode* CurrentUserNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/)
//--------------------
static RegisterNode<ExtractNode> regExtractNode(blr_extract);
ExtractNode::ExtractNode(MemoryPool& pool, UCHAR aBlrSubOp, dsql_nod* aArg)
: TypedNode<ValueExprNode, ExprNode::TYPE_EXTRACT>(pool),
blrSubOp(aBlrSubOp),
dsqlArg(aArg),
arg(NULL)
{
addChildNode(dsqlArg, arg);
}
DmlNode* ExtractNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
{
UCHAR blrSubOp = csb->csb_blr_reader.getByte();
ExtractNode* node = FB_NEW(pool) ExtractNode(pool, blrSubOp);
node->arg = PAR_parse_node(tdbb, csb, VALUE);
return node;
}
void ExtractNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text.printf("ExtractNode (%d)", blrSubOp);
ExprNode::print(text, nodes);
}
ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
// Figure out the data type of the sub parameter, and make
// sure the requested type of information can be extracted
dsql_nod* sub1 = PASS1_node(dsqlScratch, dsqlArg);
MAKE_desc(dsqlScratch, &sub1->nod_desc, sub1, NULL);
switch (blrSubOp)
{
case blr_extract_year:
case blr_extract_month:
case blr_extract_day:
case blr_extract_weekday:
case blr_extract_yearday:
case blr_extract_week:
if (sub1->nod_type != Dsql::nod_null &&
sub1->nod_desc.dsc_dtype != dtype_sql_date &&
sub1->nod_desc.dsc_dtype != dtype_timestamp)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
}
break;
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
if (sub1->nod_type != Dsql::nod_null &&
sub1->nod_desc.dsc_dtype != dtype_sql_time &&
sub1->nod_desc.dsc_dtype != dtype_timestamp)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
}
break;
default:
fb_assert(false);
break;
}
return FB_NEW(getPool()) ExtractNode(getPool(), blrSubOp, sub1);
}
void ExtractNode::setParameterName(dsql_par* parameter) const
{
parameter->par_name = parameter->par_alias = "EXTRACT";
}
bool ExtractNode::setParameterType(DsqlCompilerScratch* dsqlScratch, dsql_nod* thisNode,
dsql_nod* node, bool forceVarChar)
{
return PASS1_set_parameter_type(dsqlScratch, dsqlArg, node, forceVarChar);
}
void ExtractNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->appendUChar(blr_extract);
dsqlScratch->appendUChar(blrSubOp);
GEN_expr(dsqlScratch, dsqlArg);
}
void ExtractNode::make(DsqlCompilerScratch* dsqlScratch, dsql_nod* /*thisNode*/, dsc* desc,
dsql_nod* nullReplacement)
{
dsc desc1;
MAKE_desc(dsqlScratch, &desc1, dsqlArg, NULL);
switch (blrSubOp)
{
case blr_extract_second:
// QUADDATE - maybe this should be DECIMAL(6,4)
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE);
break;
case blr_extract_millisecond:
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE + 3);
break;
default:
desc->makeShort(0);
break;
}
desc->setNullable(desc1.isNullable());
}
void ExtractNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
{
switch (blrSubOp)
{
case blr_extract_second:
// QUADDATE - SECOND returns a float, or scaled!
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE);
break;
case blr_extract_millisecond:
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE + 3);
break;
default:
desc->makeShort(0);
break;
}
}
ValueExprNode* ExtractNode::copy(thread_db* tdbb, NodeCopier& copier)
{
ExtractNode* node = FB_NEW(*tdbb->getDefaultPool()) ExtractNode(*tdbb->getDefaultPool(), blrSubOp);
node->arg = copier.copy(tdbb, arg);
return node;
}
bool ExtractNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
{
if (!ExprNode::dsqlMatch(other, ignoreMapCast))
return false;
const ExtractNode* o = other->as<ExtractNode>();
fb_assert(o)
return blrSubOp == o->blrSubOp;
}
bool ExtractNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream)
{
if (!ExprNode::expressionEqual(tdbb, csb, other, stream))
return false;
ExtractNode* o = other->as<ExtractNode>();
fb_assert(o);
return blrSubOp == o->blrSubOp;
}
ExprNode* ExtractNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::pass2(tdbb, csb);
dsc desc;
getDesc(tdbb, csb, &desc);
node->nod_impure = CMP_impure(csb, sizeof(impure_value));
return this;
}
// Handles EXTRACT(part FROM date/time/timestamp)
dsc* ExtractNode::execute(thread_db* tdbb, jrd_req* request) const
{
impure_value* const impure = request->getImpure<impure_value>(node->nod_impure);
request->req_flags &= ~req_null;
const dsc* value = EVL_expr(tdbb, arg);
if (!value || (request->req_flags & req_null))
return NULL;
impure->vlu_desc.makeShort(0, &impure->vlu_misc.vlu_short);
tm times = {0};
int fractions;
switch (value->dsc_dtype)
{
case dtype_sql_time:
switch (blrSubOp)
{
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
TimeStamp::decode_time(*(GDS_TIME*) value->dsc_address,
&times.tm_hour, &times.tm_min, &times.tm_sec, &fractions);
break;
default:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalid_extractpart_time));
}
break;
case dtype_sql_date:
switch (blrSubOp)
{
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalid_extractpart_date));
break;
default:
TimeStamp::decode_date(*(GDS_DATE*) value->dsc_address, &times);
}
break;
case dtype_timestamp:
TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) value->dsc_address, &times, &fractions);
break;
default:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalidarg_extract));
break;
}
USHORT part;
switch (blrSubOp)
{
case blr_extract_year:
part = times.tm_year + 1900;
break;
case blr_extract_month:
part = times.tm_mon + 1;
break;
case blr_extract_day:
part = times.tm_mday;
break;
case blr_extract_hour:
part = times.tm_hour;
break;
case blr_extract_minute:
part = times.tm_min;
break;
case blr_extract_second:
impure->vlu_desc.dsc_dtype = dtype_long;
impure->vlu_desc.dsc_length = sizeof(ULONG);
impure->vlu_desc.dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE;
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&impure->vlu_misc.vlu_long);
*(ULONG*) impure->vlu_desc.dsc_address = times.tm_sec * ISC_TIME_SECONDS_PRECISION + fractions;
return &impure->vlu_desc;
case blr_extract_millisecond:
impure->vlu_desc.dsc_dtype = dtype_long;
impure->vlu_desc.dsc_length = sizeof(ULONG);
impure->vlu_desc.dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE + 3;
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&impure->vlu_misc.vlu_long);
(*(ULONG*) impure->vlu_desc.dsc_address) = fractions;
return &impure->vlu_desc;
case blr_extract_week:
{
// Algorithm for Converting Gregorian Dates to ISO 8601 Week Date by Rick McCarty, 1999
// http://personal.ecu.edu/mccartyr/ISOwdALG.txt
const int y = times.tm_year + 1900;
const int dayOfYearNumber = times.tm_yday + 1;
// Find the jan1Weekday for y (Monday=1, Sunday=7)
const int yy = (y - 1) % 100;
const int c = (y - 1) - yy;
const int g = yy + yy / 4;
const int jan1Weekday = 1 + (((((c / 100) % 4) * 5) + g) % 7);
// Find the weekday for y m d
const int h = dayOfYearNumber + (jan1Weekday - 1);
const int weekday = 1 + ((h - 1) % 7);
// Find if y m d falls in yearNumber y-1, weekNumber 52 or 53
int yearNumber, weekNumber;
if ((dayOfYearNumber <= (8 - jan1Weekday)) && (jan1Weekday > 4))
{
yearNumber = y - 1;
weekNumber = ((jan1Weekday == 5) || ((jan1Weekday == 6) &&
TimeStamp::isLeapYear(yearNumber))) ? 53 : 52;
}
else
{
yearNumber = y;
// Find if y m d falls in yearNumber y+1, weekNumber 1
int i = TimeStamp::isLeapYear(y) ? 366 : 365;
if ((i - dayOfYearNumber) < (4 - weekday))
{
yearNumber = y + 1;
weekNumber = 1;
}
}
// Find if y m d falls in yearNumber y, weekNumber 1 through 53
if (yearNumber == y)
{
int j = dayOfYearNumber + (7 - weekday) + (jan1Weekday - 1);
weekNumber = j / 7;
if (jan1Weekday > 4)
weekNumber--;
}
part = weekNumber;
break;
}
case blr_extract_yearday:
part = times.tm_yday;
break;
case blr_extract_weekday:
part = times.tm_wday;
break;
default:
fb_assert(false);
part = 0;
}
*(USHORT*) impure->vlu_desc.dsc_address = part;
return &impure->vlu_desc;
}
//--------------------
static RegisterNode<GenIdNode> regGenIdNode(blr_gen_id);
GenIdNode::GenIdNode(MemoryPool& pool, bool aDialect1, const MetaName& aName, dsql_nod* aArg)

View File

@ -246,6 +246,37 @@ public:
};
class ExtractNode : public TypedNode<ValueExprNode, ExprNode::TYPE_EXTRACT>
{
public:
ExtractNode(MemoryPool& pool, UCHAR aBlrSubOp, dsql_nod* aArg = NULL);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void setParameterName(dsql_par* parameter) const;
virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, dsql_nod* thisNode,
dsql_nod* node, bool forceVarChar);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsql_nod* thisNode, dsc* desc,
dsql_nod* nullReplacement);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
public:
UCHAR blrSubOp;
dsql_nod* dsqlArg;
NestConst<jrd_nod> arg;
};
class GenIdNode : public TypedNode<ValueExprNode, ExprNode::TYPE_GEN_ID>
{
public:

View File

@ -264,6 +264,7 @@ public:
TYPE_CURRENT_TIMESTAMP,
TYPE_CURRENT_ROLE,
TYPE_CURRENT_USER,
TYPE_EXTRACT,
TYPE_GEN_ID,
TYPE_INTERNAL_INFO,
TYPE_MISSING_BOOL,

View File

@ -519,7 +519,6 @@ inline bool DsqlNodeVisitor<T, T2>::visitChildren(T node)
ret |= visit(&node->nod_arg[1]);
break;
case nod_extract:
case nod_simple_case:
case nod_searched_case:
case nod_list:

View File

@ -216,12 +216,6 @@ void GEN_expr(DsqlCompilerScratch* dsqlScratch, dsql_nod* node)
GEN_expr(dsqlScratch, node->nod_arg[e_derived_field_value]);
return;
case nod_extract:
dsqlScratch->appendUChar(blr_extract);
dsqlScratch->appendUChar(node->nod_arg[e_extract_part]->getSlong());
GEN_expr(dsqlScratch, node->nod_arg[e_extract_value]);
return;
case nod_dbkey:
node = node->nod_arg[0];
context = (dsql_ctx*) node->nod_arg[e_rel_context];

View File

@ -521,28 +521,6 @@ void MAKE_desc(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* node, dsql
}
return;
case nod_extract:
MAKE_desc(dsqlScratch, &desc1, node->nod_arg[e_extract_value], NULL);
switch (node->nod_arg[e_extract_part]->getSlong())
{
case blr_extract_second:
// QUADDATE - maybe this should be DECIMAL(6,4)
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE);
break;
case blr_extract_millisecond:
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE + 3);
break;
default:
desc->makeShort(0);
break;
}
desc->setNullable(desc1.isNullable());
return;
case nod_null:
// This occurs when SQL statement specifies a literal NULL, eg:
// SELECT NULL FROM TABLE1;
@ -1164,9 +1142,6 @@ void MAKE_parameter_names(dsql_par* parameter, const dsql_nod* item)
case nod_cast:
name_alias = "CAST";
break;
case nod_extract:
name_alias = "EXTRACT";
break;
case nod_searched_case:
case nod_simple_case:
name_alias = "CASE";

View File

@ -181,7 +181,6 @@ enum nod_t
nod_role_name,
nod_grant_admin,
nod_del_role,
nod_extract,
nod_mod_field_name,
nod_mod_field_type,
nod_mod_field_pos,
@ -649,12 +648,6 @@ enum node_args {
e_stat_name = 0,
e_stat_count,
// SQL extract() function
e_extract_part = 0, // constant representing part to extract
e_extract_value, // Must be a time or date value
e_extract_count,
e_mod_fld_name_orig_name = 0, // nod_mod_field_name
e_mod_fld_name_new_name,
e_mod_fld_name_count,

View File

@ -797,7 +797,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <legacyNode> table_constraint table_constraint_definition
%type <legacyNode> table_list table_lock table_name table_or_alias_list table_primary
%type <legacyNode> table_proc table_proc_inputs table_reference table_subquery tbl_reserve_options
%type <legacyNode> timestamp_part top tra_misc_options tra_timeout tran_opt tran_opt_list tran_opt_list_m
%type <legacyNode> top tra_misc_options tra_timeout tran_opt tran_opt_list tran_opt_list_m
%type <legacyNode> trim_function
%type <uintVal> time_precision_opt timestamp_precision_opt
@ -868,7 +868,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <sysFuncCallNode> system_function_special_syntax
%type <blrOp> trim_specification
%type <blrOp> timestamp_part trim_specification
// Predicates
%type <boolExprNode> between_predicate comparison_predicate distinct_predicate
@ -5553,9 +5553,10 @@ numeric_value_function
| length_expression
;
extract_expression : EXTRACT '(' timestamp_part FROM value ')'
{ $$ = make_node (nod_extract, (int) e_extract_count, $3, $5); }
;
extract_expression
: EXTRACT '(' timestamp_part FROM value ')'
{ $$ = makeClassNode(FB_NEW(getPool()) ExtractNode(getPool(), $3, $5)); }
;
length_expression
: bit_length_expression
@ -5645,25 +5646,25 @@ system_function_special_syntax
: DATEADD '(' value timestamp_part TO value ')'
{
$$ = FB_NEW(getPool()) SysFuncCallNode(getPool(), toName($1),
make_node(nod_list, 3, $3, $4, $6));
make_node(nod_list, 3, $3, MAKE_const_slong($4), $6));
$$->dsqlSpecialSyntax = true;
}
| DATEADD '(' timestamp_part ',' value ',' value ')'
{
$$ = FB_NEW(getPool()) SysFuncCallNode(getPool(), toName($1),
make_node(nod_list, 3, $5, $3, $7));
make_node(nod_list, 3, $5, MAKE_const_slong($3), $7));
$$->dsqlSpecialSyntax = true;
}
| DATEDIFF '(' timestamp_part FROM value TO value ')'
{
$$ = FB_NEW(getPool()) SysFuncCallNode(getPool(), toName($1),
make_node(nod_list, 3, $3, $5, $7));
make_node(nod_list, 3, MAKE_const_slong($3), $5, $7));
$$->dsqlSpecialSyntax = true;
}
| DATEDIFF '(' timestamp_part ',' value ',' value ')'
{
$$ = FB_NEW(getPool()) SysFuncCallNode(getPool(), toName($1),
make_node(nod_list, 3, $3, $5, $7));
make_node(nod_list, 3, MAKE_const_slong($3), $5, $7));
$$->dsqlSpecialSyntax = true;
}
| OVERLAY '(' value PLACING value FROM value FOR value ')'
@ -5846,27 +5847,18 @@ next_value_expression
;
timestamp_part : YEAR
{ $$ = MAKE_const_slong (blr_extract_year); }
| MONTH
{ $$ = MAKE_const_slong (blr_extract_month); }
| DAY
{ $$ = MAKE_const_slong (blr_extract_day); }
| HOUR
{ $$ = MAKE_const_slong (blr_extract_hour); }
| MINUTE
{ $$ = MAKE_const_slong (blr_extract_minute); }
| SECOND
{ $$ = MAKE_const_slong (blr_extract_second); }
| MILLISECOND
{ $$ = MAKE_const_slong (blr_extract_millisecond); }
| WEEK
{ $$ = MAKE_const_slong (blr_extract_week); }
| WEEKDAY
{ $$ = MAKE_const_slong (blr_extract_weekday); }
| YEARDAY
{ $$ = MAKE_const_slong (blr_extract_yearday); }
;
timestamp_part
: YEAR { $$ = blr_extract_year; }
| MONTH { $$ = blr_extract_month; }
| DAY { $$ = blr_extract_day; }
| HOUR { $$ = blr_extract_hour; }
| MINUTE { $$ = blr_extract_minute; }
| SECOND { $$ = blr_extract_second; }
| MILLISECOND { $$ = blr_extract_millisecond; }
| WEEK { $$ = blr_extract_week; }
| WEEKDAY { $$ = blr_extract_weekday; }
| YEARDAY { $$ = blr_extract_yearday; }
;
all_noise
:

View File

@ -1292,54 +1292,6 @@ dsql_nod* PASS1_node(DsqlCompilerScratch* dsqlScratch, dsql_nod* input)
node = pass1_collate(dsqlScratch, sub1, (dsql_str*) input->nod_arg[e_coll_target]);
return node;
case nod_extract:
// Figure out the data type of the sub parameter, and make
// sure the requested type of information can be extracted
sub1 = PASS1_node(dsqlScratch, input->nod_arg[e_extract_value]);
MAKE_desc(dsqlScratch, &sub1->nod_desc, sub1, NULL);
switch (input->nod_arg[e_extract_part]->getSlong())
{
case blr_extract_year:
case blr_extract_month:
case blr_extract_day:
case blr_extract_weekday:
case blr_extract_yearday:
case blr_extract_week:
if (sub1->nod_type != nod_null &&
sub1->nod_desc.dsc_dtype != dtype_sql_date &&
sub1->nod_desc.dsc_dtype != dtype_timestamp)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
}
break;
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
if (sub1->nod_type != nod_null &&
sub1->nod_desc.dsc_dtype != dtype_sql_time &&
sub1->nod_desc.dsc_dtype != dtype_timestamp)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
}
break;
default:
fb_assert(false);
break;
}
node = MAKE_node(input->nod_type, e_extract_count);
node->nod_arg[e_extract_part] = input->nod_arg[e_extract_part];
node->nod_arg[e_extract_value] = sub1;
if (sub1->nod_desc.dsc_flags & DSC_nullable) {
node->nod_desc.dsc_flags |= DSC_nullable;
}
return node;
case nod_delete:
case nod_insert:
case nod_merge:
@ -8515,7 +8467,6 @@ bool PASS1_set_parameter_type(DsqlCompilerScratch* dsqlScratch, dsql_nod* in_nod
return false;
}
case nod_extract:
case nod_limit:
case nod_rows:
{
@ -8615,6 +8566,7 @@ static void set_parameter_name( dsql_nod* par_node, const dsql_nod* fld_node, co
{
case ExprNode::TYPE_ARITHMETIC:
case ExprNode::TYPE_CONCATENATE:
case ExprNode::TYPE_EXTRACT:
case ExprNode::TYPE_NEGATE:
case ExprNode::TYPE_STR_CASE:
case ExprNode::TYPE_STR_LEN:
@ -8642,7 +8594,6 @@ static void set_parameter_name( dsql_nod* par_node, const dsql_nod* fld_node, co
}
return;
case nod_extract:
case nod_limit:
case nod_rows:
{
@ -8882,9 +8833,6 @@ void DSQL_pretty(const dsql_nod* node, int column)
case nod_exec_procedure:
verb = "execute procedure";
break;
case nod_extract:
verb = "extract";
break;
case nod_flag:
verb = "flag";
break;

View File

@ -338,11 +338,6 @@ bool OPT_expression_equal2(thread_db* tdbb, CompilerScratch* csb,
node2->nod_arg[e_cast_source], stream);
}
case nod_extract:
return node1->nod_arg[e_extract_part] == node2->nod_arg[e_extract_part] &&
OPT_expression_equal2(tdbb, csb, node1->nod_arg[e_extract_value],
node2->nod_arg[e_extract_value], stream);
case nod_list:
{
jrd_nod* const* ptr1 = node1->nod_arg;

View File

@ -583,24 +583,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC* des
desc->dsc_flags = 0;
return;
case nod_extract:
switch ((IPTR) node->nod_arg[e_extract_part])
{
case blr_extract_second:
// QUADDATE - SECOND returns a float, or scaled!
desc->makeLong(ISC_TIME_SECONDS_PRECISION_SCALE);
break;
case blr_extract_millisecond:
desc->makeLong(0);
break;
default:
desc->makeShort(0);
break;
}
return;
case nod_literal:
*desc = ((Literal*) node)->lit_desc;
@ -1226,14 +1208,6 @@ jrd_nod* NodeCopier::copy(thread_db* tdbb, jrd_nod* input)
node->nod_arg[e_cast_fmt] = input->nod_arg[e_cast_fmt];
return (node);
case nod_extract:
node = PAR_make_node(tdbb, e_extract_length);
node->nod_count = input->nod_count;
node->nod_type = input->nod_type;
node->nod_arg[e_extract_value] = copy(tdbb, input->nod_arg[e_extract_value]);
node->nod_arg[e_extract_part] = input->nod_arg[e_extract_part];
return (node);
case nod_count:
case nod_max:
case nod_min:
@ -3079,7 +3053,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
case nod_null:
case nod_scalar:
case nod_cast:
case nod_extract:
case nod_derived_expr:
{
dsc descriptor_a;

View File

@ -121,7 +121,6 @@ using namespace Firebird;
static dsc* cast(thread_db*, dsc*, const jrd_nod*, impure_value*);
static dsc* dbkey(thread_db*, const jrd_nod*, impure_value*);
static dsc* eval_statistical(thread_db*, const jrd_nod*, impure_value*);
static dsc* extract(thread_db*, const jrd_nod*, impure_value*);
static dsc* record_version(thread_db*, const jrd_nod*, impure_value*);
static dsc* scalar(thread_db*, const jrd_nod*, impure_value*);
@ -471,9 +470,6 @@ dsc* EVL_expr(thread_db* tdbb, const jrd_nod* node)
request->req_flags |= req_null;
return NULL;
case nod_extract:
return extract(tdbb, node, impure);
case nod_max:
case nod_min:
case nod_count:
@ -1224,185 +1220,6 @@ static dsc* eval_statistical(thread_db* tdbb, const jrd_nod* node, impure_value*
}
// *************
// e x t r a c t
// *************
// Handles EXTRACT(part FROM date/time/timestamp)
static dsc* extract(thread_db* tdbb, const jrd_nod* node, impure_value* impure)
{
SET_TDBB(tdbb);
DEV_BLKCHK(node, type_nod);
const ULONG extract_part = (IPTR) node->nod_arg[e_extract_part];
const dsc* value = EVL_expr(tdbb, node->nod_arg[e_extract_value]);
impure->vlu_desc.dsc_dtype = dtype_short;
impure->vlu_desc.dsc_scale = 0;
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&impure->vlu_misc.vlu_short);
impure->vlu_desc.dsc_length = sizeof(SSHORT);
jrd_req* request = tdbb->getRequest();
// CVC: Borland used special signaling for nulls in outer joins.
if (!value || (request->req_flags & req_null))
{
request->req_flags |= req_null;
impure->vlu_misc.vlu_short = 0;
return &impure->vlu_desc;
}
tm times = {0};
int fractions;
switch (value->dsc_dtype)
{
case dtype_sql_time:
switch (extract_part)
{
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
Firebird::TimeStamp::decode_time(*(GDS_TIME*) value->dsc_address,
&times.tm_hour, &times.tm_min, &times.tm_sec, &fractions);
break;
default:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalid_extractpart_time));
}
break;
case dtype_sql_date:
switch (extract_part)
{
case blr_extract_hour:
case blr_extract_minute:
case blr_extract_second:
case blr_extract_millisecond:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalid_extractpart_date));
break;
default:
Firebird::TimeStamp::decode_date(*(GDS_DATE*) value->dsc_address, &times);
}
break;
case dtype_timestamp:
Firebird::TimeStamp::decode_timestamp(*(GDS_TIMESTAMP*) value->dsc_address,
&times, &fractions);
break;
default:
ERR_post(Arg::Gds(isc_expression_eval_err) <<
Arg::Gds(isc_invalidarg_extract));
break;
}
USHORT part;
switch (extract_part)
{
case blr_extract_year:
part = times.tm_year + 1900;
break;
case blr_extract_month:
part = times.tm_mon + 1;
break;
case blr_extract_day:
part = times.tm_mday;
break;
case blr_extract_hour:
part = times.tm_hour;
break;
case blr_extract_minute:
part = times.tm_min;
break;
case blr_extract_second:
impure->vlu_desc.dsc_dtype = dtype_long;
impure->vlu_desc.dsc_length = sizeof(ULONG);
impure->vlu_desc.dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE;
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&impure->vlu_misc.vlu_long);
*(ULONG*) impure->vlu_desc.dsc_address = times.tm_sec * ISC_TIME_SECONDS_PRECISION + fractions;
return &impure->vlu_desc;
case blr_extract_millisecond:
impure->vlu_desc.dsc_dtype = dtype_long;
impure->vlu_desc.dsc_length = sizeof(ULONG);
impure->vlu_desc.dsc_scale = ISC_TIME_SECONDS_PRECISION_SCALE + 3;
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&impure->vlu_misc.vlu_long);
(*(ULONG*) impure->vlu_desc.dsc_address) = fractions;
return &impure->vlu_desc;
case blr_extract_week:
{
// Algorithm for Converting Gregorian Dates to ISO 8601 Week Date by Rick McCarty, 1999
// http://personal.ecu.edu/mccartyr/ISOwdALG.txt
const int y = times.tm_year + 1900;
const int dayOfYearNumber = times.tm_yday + 1;
// Find the jan1Weekday for y (Monday=1, Sunday=7)
const int yy = (y - 1) % 100;
const int c = (y - 1) - yy;
const int g = yy + yy / 4;
const int jan1Weekday = 1 + (((((c / 100) % 4) * 5) + g) % 7);
// Find the weekday for y m d
const int h = dayOfYearNumber + (jan1Weekday - 1);
const int weekday = 1 + ((h - 1) % 7);
// Find if y m d falls in yearNumber y-1, weekNumber 52 or 53
int yearNumber, weekNumber;
if ((dayOfYearNumber <= (8 - jan1Weekday)) && (jan1Weekday > 4))
{
yearNumber = y - 1;
weekNumber = ((jan1Weekday == 5) || ((jan1Weekday == 6) &&
Firebird::TimeStamp::isLeapYear(yearNumber))) ? 53 : 52;
}
else
{
yearNumber = y;
// Find if y m d falls in yearNumber y+1, weekNumber 1
int i = Firebird::TimeStamp::isLeapYear(y) ? 366 : 365;
if ((i - dayOfYearNumber) < (4 - weekday))
{
yearNumber = y + 1;
weekNumber = 1;
}
}
// Find if y m d falls in yearNumber y, weekNumber 1 through 53
if (yearNumber == y)
{
int j = dayOfYearNumber + (7 - weekday) + (jan1Weekday - 1);
weekNumber = j / 7;
if (jan1Weekday > 4)
weekNumber--;
}
part = weekNumber;
}
break;
case blr_extract_yearday:
part = times.tm_yday;
break;
case blr_extract_weekday:
part = times.tm_wday;
break;
default:
fb_assert(false);
part = 0;
}
*(USHORT*) impure->vlu_desc.dsc_address = part;
return &impure->vlu_desc;
}
static dsc* record_version(thread_db* tdbb, const jrd_nod* node, impure_value* impure)
{
/**************************************

View File

@ -302,12 +302,6 @@ const int e_cast_fmt = 1;
const int e_cast_iteminfo = 2;
const int e_cast_length = 3;
// SQL Date supporting nodes
const int e_extract_value = 0; // Node
const int e_extract_part = 1; // Integer
const int e_extract_count = 1; // Number of nodes
const int e_extract_length = 2; // Number of entries in nod_args
const int e_dcl_cur_rse = 0;
const int e_dcl_cur_refs = 1;
const int e_dcl_cur_number = 2;

View File

@ -66,7 +66,6 @@ NODE(nod_scalar, scalar, "")
NODE(nod_null, null, "NULL")
NODE(nod_cast, cast, "CAST")
NODE(nod_rec_version, record_version, "RECORD VERSION")
NODE(nod_extract, extract, "EXTRACT")
NODE(nod_domain_validation, domain_validation, "")
NODE(nod_derived_expr, derived_expr, "derived_expr")

View File

@ -126,10 +126,6 @@ bool JrdNodeVisitor::visitChildren(const JrdNode& node)
ret |= visit(jrdNode->nod_arg[e_cast_source]);
break;
case nod_extract:
ret |= visit(jrdNode->nod_arg[e_extract_value]);
break;
case nod_derived_expr:
{
jrd_nod* /*const*/* ptr = jrdNode->nod_arg;

View File

@ -2650,13 +2650,6 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
node = par_cast(tdbb, csb);
break;
case blr_extract:
// This forced conversion looks strange, but extract_part fits in a byte
node->nod_arg[e_extract_part] = (jrd_nod*)(U_IPTR) csb->csb_blr_reader.getByte();
node->nod_arg[e_extract_value] = PAR_parse_node(tdbb, csb, sub_type);
node->nod_count = e_extract_count;
break;
case blr_dcl_variable:
{
dsc* desc = (dsc*) (node->nod_arg + e_dcl_desc);

View File

@ -196,7 +196,7 @@ static const VERB verbs[] =
PAIR(nod_class_exprnode_jrd, blr_ansi_all, 1, 0, TYPE_BOOL, TYPE_RSE),
/* Improved Date Support */
PAIR(nod_extract, blr_extract, e_extract_length, e_extract_count, VALUE, VALUE),
PAIR(nod_class_exprnode_jrd, blr_extract, 1, 0, VALUE, VALUE),
PAIR(nod_class_exprnode_jrd, blr_current_date, 1, 0, VALUE, OTHER),
PAIR(nod_class_exprnode_jrd, blr_current_time, 1, 0, VALUE, OTHER),
PAIR(nod_class_exprnode_jrd, blr_current_time2, 1, 0, VALUE, OTHER),