Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 103 additions & 16 deletions src/common/cvt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <cstddef>
#include <stdio.h>
#include <string.h>
#include <string_view>
#include <stdlib.h>
#include <ctype.h>
#include "iberror.h"
Expand Down Expand Up @@ -127,10 +128,44 @@ constexpr SLONG LONG_LIMIT = ((1L << 30) / 5);
//#define QUAD_LIMIT ((((SINT64) 1) << 62) / 5)
constexpr SINT64 INT64_LIMIT = ((((SINT64) 1) << 62) / 5);

#define TODAY "TODAY"
#define NOW "NOW"
#define TOMORROW "TOMORROW"
#define YESTERDAY "YESTERDAY"
namespace {

struct SpecialDateTimeName
{
std::string_view name;
SpecialDateTime value;
};

constexpr SpecialDateTimeName SPECIAL_DATETIME_NAMES[] =
{
{"NOW", SpecialDateTime::NOW},
{"TODAY", SpecialDateTime::TODAY},
{"TOMORROW", SpecialDateTime::TOMORROW},
{"YESTERDAY", SpecialDateTime::YESTERDAY}
};

constexpr FB_SIZE_T maxSpecialDateTimeLength()
{
FB_SIZE_T result = 0;
for (const auto& it : SPECIAL_DATETIME_NAMES)
{
if (it.name.length() > result)
result = it.name.length();
}

for (const TEXT* const* month = FB_LONG_MONTHS_UPPER; *month; ++month)
{
const FB_SIZE_T length = std::string_view(*month).length();
if (length > result)
result = length;
}

return result;
}

constexpr FB_SIZE_T MAX_DATETIME_WORD_LENGTH = maxSpecialDateTimeLength();

} // anonymous namespace

#define CVT_COPY_BUFF(from, to, len) \
{if (len) {memcpy(to, from, len); from += len; to += len;} }
Expand Down Expand Up @@ -673,6 +708,49 @@ static void integer_to_text(const dsc* from, dsc* to, Callbacks* cb)
*(USHORT*) (to->dsc_address) = static_cast<USHORT>(q - to->dsc_address - sizeof(SSHORT));
}

SpecialDateTime CVT_get_special_datetime(const char* str, FB_SIZE_T length)
{
/**************************************
*
* C V T _ g e t _ s p e c i a l _ d a t e t i m e
*
**************************************
*
* Functional description
* Recognize a special date/time expression such as 'NOW' or 'TODAY'.
* Leading and trailing blanks are ignored, the comparison is case
* insensitive. Return SpecialDateTime::NONE if the string is not one
* of the special expressions.
*
**************************************/
const char* p = str;
const char* end = str + length;

while (p < end && (*p == ' ' || *p == '\t'))
++p;

while (end > p && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\0'))
--end;

const FB_SIZE_T len = end - p;

for (const auto& item : SPECIAL_DATETIME_NAMES)
{
if (len != item.name.length())
continue;

FB_SIZE_T pos = 0;

while (pos < len && UPPER7(p[pos]) == item.name[pos])
++pos;

if (pos == len)
return item.value;
}

return SpecialDateTime::NONE;
}


void CVT_string_to_datetime(const dsc* desc,
ISC_TIMESTAMP_TZ* date, bool* timezone_present,
Expand Down Expand Up @@ -793,14 +871,21 @@ void CVT_string_to_datetime(const dsc* desc,
}
else if (LETTER7_UPPER(c) && !have_english_month && i - start_component < 2)
{
TEXT temp[sizeof(YESTERDAY) + 1];
TEXT temp[MAX_DATETIME_WORD_LENGTH + 1];

TEXT* t = temp;
while ((p < end) && (t < &temp[sizeof(temp) - 1]))
while (p < end)
{
c = UPPER7(*p);
if (!LETTER7_UPPER(c))
break;

if (t >= &temp[sizeof(temp) - 1])
{
CVT_conversion_error(desc, cb->err);
return;
}

*t++ = c;
p++;
}
Expand Down Expand Up @@ -868,7 +953,9 @@ void CVT_string_to_datetime(const dsc* desc,
break;
}

if (strcmp(temp, NOW) == 0)
const SpecialDateTime special = CVT_get_special_datetime(temp, strlen(temp));

if (special == SpecialDateTime::NOW)
return;

if (expect_type == expect_sql_time || expect_type == expect_sql_time_tz)
Expand All @@ -879,23 +966,23 @@ void CVT_string_to_datetime(const dsc* desc,

date->utc_timestamp.timestamp_time = 0;

if (strcmp(temp, TODAY) == 0)
switch (special)
{
case SpecialDateTime::TODAY:
return;

if (strcmp(temp, TOMORROW) == 0)
{
case SpecialDateTime::TOMORROW:
++date->utc_timestamp.timestamp_date;
return;
}

if (strcmp(temp, YESTERDAY) == 0)
{
case SpecialDateTime::YESTERDAY:
--date->utc_timestamp.timestamp_date;
return;
}

CVT_conversion_error(desc, cb->err);
return;
default:
CVT_conversion_error(desc, cb->err);
return;
}
}
}
n = month_ptr - FB_LONG_MONTHS_UPPER;
Expand Down
10 changes: 10 additions & 0 deletions src/common/cvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ enum EXPECT_DATETIME
expect_sql_time_tz
};

enum class SpecialDateTime
{
NONE,
NOW,
TODAY,
TOMORROW,
YESTERDAY
};

class Int128;

} // namespace Firebird
Expand All @@ -103,6 +112,7 @@ USHORT CVT_get_string_ptr(const dsc*, TTypeId*, UCHAR**, vary*, USHORT, Firebird
USHORT CVT_get_string_ptr_common(const dsc*, TTypeId*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, Firebird::Callbacks*);
SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
SQUAD CVT_get_quad(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
Firebird::SpecialDateTime CVT_get_special_datetime(const char*, FB_SIZE_T);
void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird::EXPECT_DATETIME,
bool, Firebird::Callbacks*);
const UCHAR* CVT_get_bytes(const dsc*, unsigned&);
Expand Down
32 changes: 30 additions & 2 deletions src/dsql/BoolNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "../dsql/make_proto.h"
#include "../dsql/pass1_proto.h"
#include "../dsql/DSqlDataTypeUtil.h"
#include "../jrd/cvt2_proto.h"

using namespace Firebird;
using namespace Jrd;
Expand Down Expand Up @@ -462,12 +463,39 @@ BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
fb_assert(false);
}

procArg1 = doDsqlPass(dsqlScratch, procArg1);
procArg2 = doDsqlPass(dsqlScratch, procArg2);
procArg3 = doDsqlPass(dsqlScratch, procArg3);


const auto convertLiteralToOperand =
[&](NestConst<ValueExprNode>& literalArg, NestConst<ValueExprNode>& referenceArg)
{
LiteralNode* const literal = nodeAs<LiteralNode>(literalArg);

if (!literal || literal->litDesc.dsc_dtype != dtype_text)
return;

dsc referenceDesc;
DsqlDescMaker::fromNode(dsqlScratch, &referenceDesc, referenceArg);

if (referenceDesc.isUnknown())
return;

if (ValueExprNode* const value = MAKE_constant_from_literal(literal, &referenceDesc))
literalArg = value;
};

convertLiteralToOperand(procArg1, procArg2);
convertLiteralToOperand(procArg2, procArg1);

if (blrOp == blr_between)
convertLiteralToOperand(procArg3, procArg1);

ComparativeBoolNode* node = FB_NEW_POOL(dsqlScratch->getPool()) ComparativeBoolNode(dsqlScratch->getPool(), blrOp,
doDsqlPass(dsqlScratch, procArg1),
procArg1,
procArg2,
doDsqlPass(dsqlScratch, procArg3));
procArg3);

if (dsqlCheckBoolean)
{
Expand Down
59 changes: 59 additions & 0 deletions src/dsql/make.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "../jrd/ods.h"
#include "../jrd/ini.h"
#include "../jrd/cvt_proto.h"
#include "../jrd/cvt2_proto.h"
#include "../jrd/scl_proto.h"
#include "../common/dsc_proto.h"
#include "../yvalve/why_proto.h"
Expand Down Expand Up @@ -337,6 +338,64 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag, S
}


ValueExprNode* MAKE_constant_from_literal(LiteralNode* from, const dsc* reference)
{
if (from->litDesc.dsc_dtype != dtype_text)
return nullptr;

if (CVT2_compare_priority[from->litDesc.dsc_dtype] >=
CVT2_compare_priority[reference->dsc_dtype])
{
return nullptr;
}

dsql_constant_type to;

switch (reference->dsc_dtype)
{
case dtype_double:
to = CONSTANT_DOUBLE;
break;
case dtype_dec64:
case dtype_dec128:
to = CONSTANT_DECIMAL;
break;
case dtype_int128:
to = CONSTANT_NUM128;
break;
case dtype_sql_date:
to = CONSTANT_DATE;
break;
case dtype_sql_time:
case dtype_sql_time_tz:
to = CONSTANT_TIME;
break;
case dtype_timestamp:
to = CONSTANT_TIMESTAMP;
break;
default:
return nullptr;
}

switch (to)
{
case CONSTANT_DATE:
case CONSTANT_TIME:
case CONSTANT_TIMESTAMP:
if (CVT_get_special_datetime(reinterpret_cast<const char*>(from->litDesc.dsc_address),
from->litDesc.dsc_length) != SpecialDateTime::NONE)
{
return nullptr;
}
break;
default:
break;
}

return MAKE_constant(reinterpret_cast<const char*>(from->litDesc.dsc_address), to, 0);
}


/**

MAKE_str_constant
Expand Down
2 changes: 2 additions & 0 deletions src/dsql/make_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ Jrd::dsql_par* MAKE_parameter(Jrd::dsql_msg*, bool, bool, USHORT, const Jrd::Val
void MAKE_parameter_names(Jrd::dsql_par*, const Jrd::ValueExprNode*);
Jrd::LiteralNode* MAKE_system_privilege(const char*);

Jrd::ValueExprNode* MAKE_constant_from_literal(Jrd::LiteralNode*, const dsc*);

#endif // DSQL_MAKE_PROTO_H
Loading