mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Allow "_" characters to appear between any two digits in an integer, real or hexadecimal SQL literal.
FossilOrigin-Name: 0e6700f43f133510c8049b2c5a2610cb3be29da7ed4d39b1fa65dc22c4cf529b
This commit is contained in:
@@ -1935,6 +1935,12 @@ filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
SPAN /* The span operator */
|
||||
ERROR /* An expression containing an error */
|
||||
.
|
||||
|
||||
term(A) ::= QNUMBER(X). {
|
||||
A=tokenExpr(pParse,@X,X);
|
||||
sqlite3DequoteNumber(pParse, A);
|
||||
}
|
||||
|
||||
/* There must be no more than 255 tokens defined above. If this grammar
|
||||
** is extended with new rules and tokens, they must either be so few in
|
||||
** number that TK_SPAN is no more than 255, or else the new tokens must
|
||||
|
@@ -609,6 +609,8 @@
|
||||
# define SQLITE_OMIT_ALTERTABLE
|
||||
#endif
|
||||
|
||||
#define SQLITE_DIGIT_SEPARATOR '_'
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if the input is an integer that is too large
|
||||
** to fit in 32-bits. This macro is used inside of various testcase()
|
||||
@@ -4795,6 +4797,7 @@ int sqlite3ErrorToParser(sqlite3*,int);
|
||||
void sqlite3Dequote(char*);
|
||||
void sqlite3DequoteExpr(Expr*);
|
||||
void sqlite3DequoteToken(Token*);
|
||||
void sqlite3DequoteNumber(Parse*, Expr*);
|
||||
void sqlite3TokenInit(Token*,char*);
|
||||
int sqlite3KeywordCode(const unsigned char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*);
|
||||
|
@@ -437,27 +437,58 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
*tokenType = TK_INTEGER;
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
|
||||
for(i=3; sqlite3Isxdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
for(i=3; 1; i++){
|
||||
if( sqlite3Isxdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
for(i=0; sqlite3Isdigit(z[i]); i++){}
|
||||
{
|
||||
for(i=0; 1; i++){
|
||||
if( sqlite3Isdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( z[i]=='.' ){
|
||||
i++;
|
||||
while( sqlite3Isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
if( (z[i]=='e' || z[i]=='E') &&
|
||||
( sqlite3Isdigit(z[i+1])
|
||||
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
|
||||
)
|
||||
){
|
||||
i += 2;
|
||||
while( sqlite3Isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
if( z[i]=='.' ){
|
||||
if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
|
||||
for(i++; 1; i++){
|
||||
if( sqlite3Isdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (z[i]=='e' || z[i]=='E') &&
|
||||
( sqlite3Isdigit(z[i+1])
|
||||
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
|
||||
)
|
||||
){
|
||||
if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT;
|
||||
for(i+=2; 1; i++){
|
||||
if( sqlite3Isdigit(z[i])==0 ){
|
||||
if( z[i]==SQLITE_DIGIT_SEPARATOR ){
|
||||
*tokenType = TK_QNUMBER;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while( IdChar(z[i]) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
i++;
|
||||
@@ -622,10 +653,13 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
if( tokenType>=TK_WINDOW ){
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|
||||
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
|
||||
|| tokenType==TK_QNUMBER
|
||||
);
|
||||
#else
|
||||
if( tokenType>=TK_SPACE ){
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
|
||||
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
|
||||
|| tokenType==TK_QNUMBER
|
||||
);
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
if( AtomicLoad(&db->u1.isInterrupted) ){
|
||||
pParse->rc = SQLITE_INTERRUPT;
|
||||
@@ -658,7 +692,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
assert( n==6 );
|
||||
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
}else{
|
||||
}else if( tokenType!=TK_QNUMBER ){
|
||||
Token x;
|
||||
x.z = zSql;
|
||||
x.n = n;
|
||||
|
28
src/util.c
28
src/util.c
@@ -311,6 +311,34 @@ void sqlite3DequoteExpr(Expr *p){
|
||||
sqlite3Dequote(p->u.zToken);
|
||||
}
|
||||
|
||||
/*
|
||||
** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken
|
||||
** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those
|
||||
** that contain '_' characters that must be removed before further processing.
|
||||
*/
|
||||
void sqlite3DequoteNumber(Parse *pParse, Expr *p){
|
||||
if( p ){
|
||||
const char *pIn = p->u.zToken;
|
||||
char *pOut = p->u.zToken;
|
||||
int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X'));
|
||||
assert( p->op==TK_QNUMBER );
|
||||
p->op = TK_INTEGER;
|
||||
do {
|
||||
if( *pIn!=SQLITE_DIGIT_SEPARATOR ){
|
||||
*pOut++ = *pIn;
|
||||
if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT;
|
||||
}else{
|
||||
if( (bHex==0 && (!sqlite3Isdigit(pIn[-1]) || !sqlite3Isdigit(pIn[1])))
|
||||
|| (bHex==1 && (!sqlite3Isxdigit(pIn[-1]) || !sqlite3Isxdigit(pIn[1])))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken);
|
||||
}
|
||||
}
|
||||
}while( *pIn++ );
|
||||
if( bHex ) p->op = TK_INTEGER;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If the input token p is quoted, try to adjust the token to remove
|
||||
** the quotes. This is not always possible:
|
||||
|
Reference in New Issue
Block a user