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

Fixed regression with numeric literal having value equal to MIN_SINT64

This commit is contained in:
Alex Peshkoff 2017-07-02 23:06:20 +03:00
parent a0d26e7684
commit 933bd49536
4 changed files with 78 additions and 16 deletions

View File

@ -932,13 +932,14 @@ int Parser::yylexAux()
{ {
// The following variables are used to recognize kinds of numbers. // The following variables are used to recognize kinds of numbers.
bool have_error = false; // syntax error or value too large bool have_error = false; // syntax error or value too large
bool have_digit = false; // we've seen a digit bool have_digit = false; // we've seen a digit
bool have_decimal = false; // we've seen a '.' bool have_decimal = false; // we've seen a '.'
bool have_exp = false; // digit ... [eE] bool have_exp = false; // digit ... [eE]
bool have_exp_sign = false; // digit ... [eE] {+-] bool have_exp_sign = false; // digit ... [eE] {+-]
bool have_exp_digit = false; // digit ... [eE] ... digit bool have_exp_digit = false; // digit ... [eE] ... digit
bool have_overflow = false; // value of digits > MAX_SINT64 bool have_overflow = false; // value of digits > MAX_SINT64
bool positive_overflow = false; // number is exactly (MAX_SINT64 + 1)
FB_UINT64 number = 0; FB_UINT64 number = 0;
int expVal = 0; int expVal = 0;
FB_UINT64 limit_by_10 = MAX_SINT64 / 10; FB_UINT64 limit_by_10 = MAX_SINT64 / 10;
@ -1010,17 +1011,19 @@ int Parser::yylexAux()
if ((number > limit_by_10) || (c >= '8')) if ((number > limit_by_10) || (c >= '8'))
{ {
have_overflow = true; have_overflow = true;
if ((number == limit_by_10) && (c == '8'))
positive_overflow = true;
} }
} }
} }
else
positive_overflow = false;
if (!have_overflow) if (!have_overflow)
{
number = number * 10 + (c - '0'); number = number * 10 + (c - '0');
if (have_decimal) if (have_decimal)
--scale; --scale;
}
} }
else if ( (('E' == c) || ('e' == c)) && have_digit ) else if ( (('E' == c) || ('e' == c)) && have_digit )
have_exp = true; have_exp = true;
@ -1036,8 +1039,14 @@ int Parser::yylexAux()
{ {
fb_assert(have_digit); fb_assert(have_digit);
if (positive_overflow)
have_overflow = false;
if (scale < MIN_SCHAR || scale > MAX_SCHAR) if (scale < MIN_SCHAR || scale > MAX_SCHAR)
{
have_overflow = true; have_overflow = true;
positive_overflow = false;
}
// check for a more complex overflow case // check for a more complex overflow case
if ((!have_overflow) && (expSign > 0) && (expVal > -scale)) if ((!have_overflow) && (expSign > 0) && (expVal > -scale))
@ -1045,19 +1054,33 @@ int Parser::yylexAux()
expVal += scale; expVal += scale;
double maxNum = DBL_MAX / pow(10.0, expVal); double maxNum = DBL_MAX / pow(10.0, expVal);
if (double(number) > maxNum) if (double(number) > maxNum)
{
have_overflow = true; have_overflow = true;
positive_overflow = false;
}
} }
// Should we use floating point type? // Should we use floating point type?
if (have_exp_digit || have_overflow) if (have_exp_digit || have_overflow || positive_overflow)
{ {
if (positive_overflow && scale)
{
yylval.lim64ptr = newLim64String(
Firebird::string(lex.last_token, lex.ptr - lex.last_token), scale);
lex.last_token_bk = lex.last_token;
lex.line_start_bk = lex.line_start;
lex.lines_bk = lex.lines;
return TOK_LIMIT64_NUMBER;
}
yylval.stringPtr = newString( yylval.stringPtr = newString(
Firebird::string(lex.last_token, lex.ptr - lex.last_token)); Firebird::string(lex.last_token, lex.ptr - lex.last_token));
lex.last_token_bk = lex.last_token; lex.last_token_bk = lex.last_token;
lex.line_start_bk = lex.line_start; lex.line_start_bk = lex.line_start;
lex.lines_bk = lex.lines; lex.lines_bk = lex.lines;
return have_overflow ? TOK_DECIMAL_NUMBER : TOK_FLOAT_NUMBER; return positive_overflow ? TOK_LIMIT64_INT : have_overflow ? TOK_DECIMAL_NUMBER : TOK_FLOAT_NUMBER;
} }
if (!have_exp) if (!have_exp)

View File

@ -144,6 +144,11 @@ public:
return FB_NEW_POOL(getPool()) Firebird::string(getPool(), s); return FB_NEW_POOL(getPool()) Firebird::string(getPool(), s);
} }
Lim64String* newLim64String(const Firebird::string& s, int scale)
{
return FB_NEW_POOL(getPool()) Lim64String(getPool(), s, scale);
}
IntlString* newIntlString(const Firebird::string& s, const char* charSet = NULL) IntlString* newIntlString(const Firebird::string& s, const char* charSet = NULL)
{ {
return FB_NEW_POOL(getPool()) IntlString(getPool(), s, charSet); return FB_NEW_POOL(getPool()) IntlString(getPool(), s, charSet);

View File

@ -983,6 +983,23 @@ private:
Firebird::string s; Firebird::string s;
}; };
class Lim64String : public Firebird::string
{
public:
Lim64String(Firebird::MemoryPool& p, const Firebird::string& str, int sc)
: Firebird::string(p, str),
scale(sc)
{ }
int getScale()
{
return scale;
}
private:
int scale;
};
} // namespace } // namespace
/*! \var unsigned DSQL_debug /*! \var unsigned DSQL_debug

View File

@ -332,8 +332,8 @@ using namespace Firebird;
%token <metaNamePtr> WORK %token <metaNamePtr> WORK
%token <metaNamePtr> WRITE %token <metaNamePtr> WRITE
%token <stringPtr> FLOAT_NUMBER %token <stringPtr> FLOAT_NUMBER DECIMAL_NUMBER LIMIT64_INT
%token <stringPtr> DECIMAL_NUMBER %token <lim64ptr> LIMIT64_NUMBER
%token <metaNamePtr> SYMBOL %token <metaNamePtr> SYMBOL
%token <int32Val> NUMBER %token <int32Val> NUMBER
@ -681,6 +681,7 @@ using namespace Firebird;
Firebird::QualifiedName* qualifiedNamePtr; Firebird::QualifiedName* qualifiedNamePtr;
Firebird::string* stringPtr; Firebird::string* stringPtr;
Jrd::IntlString* intlStringPtr; Jrd::IntlString* intlStringPtr;
Jrd::Lim64String* lim64ptr;
Jrd::DbFileClause* dbFileClause; Jrd::DbFileClause* dbFileClause;
Firebird::Array<NestConst<Jrd::DbFileClause> >* dbFilesClause; Firebird::Array<NestConst<Jrd::DbFileClause> >* dbFilesClause;
Jrd::ExternalClause* externalClause; Jrd::ExternalClause* externalClause;
@ -1846,6 +1847,10 @@ sequence_value
$$ = -signedNumber; $$ = -signedNumber;
} }
| '-' LIMIT64_INT
{
$$ = MIN_SINT64;
}
; ;
@ -7118,12 +7123,24 @@ value_list
%type <valueExprNode> constant %type <valueExprNode> constant
constant constant
: u_constant : u_constant
| '-' u_numeric_constant { $$ = newNode<NegateNode>($2); } | '-' ul_numeric_constant { $$ = newNode<NegateNode>($2); }
| '-' LIMIT64_INT { $$ = MAKE_const_sint64(MIN_SINT64, 0); }
| '-' LIMIT64_NUMBER { $$ = MAKE_const_sint64(MIN_SINT64, $2->getScale()); }
| boolean_literal | boolean_literal
; ;
%type <valueExprNode> u_numeric_constant %type <valueExprNode> u_numeric_constant
u_numeric_constant u_numeric_constant
: ul_numeric_constant
{ $$ = $1; }
| LIMIT64_NUMBER
{ $$ = MAKE_constant($1->c_str(), CONSTANT_DECIMAL); }
| LIMIT64_INT
{ $$ = MAKE_constant($1->c_str(), CONSTANT_DECIMAL); }
;
%type <valueExprNode> ul_numeric_constant
ul_numeric_constant
: NUMBER : NUMBER
{ $$ = MAKE_const_slong($1); } { $$ = MAKE_const_slong($1); }
| FLOAT_NUMBER | FLOAT_NUMBER