aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parse.y6
-rw-r--r--src/sqliteInt.h3
-rw-r--r--src/tokenize.c27
-rw-r--r--src/util.c21
4 files changed, 50 insertions, 7 deletions
diff --git a/src/parse.y b/src/parse.y
index 19491192e..b0d03a04e 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -1923,6 +1923,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(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
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 79a36e060..c4aaf9d20 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -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()
@@ -4792,6 +4794,7 @@ int sqlite3ErrorToParser(sqlite3*,int);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
void sqlite3DequoteToken(Token*);
+void sqlite3DequoteNumber(Expr*);
void sqlite3TokenInit(Token*,char*);
int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*);
diff --git a/src/tokenize.c b/src/tokenize.c
index f4d013dee..ae1f6da3f 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -441,21 +441,34 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
return i;
}
#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( *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]))
)
){
- i += 2;
- while( sqlite3Isdigit(z[i]) ){ i++; }
- *tokenType = TK_FLOAT;
+ 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]) ){
diff --git a/src/util.c b/src/util.c
index 207b901ba..24eff14e9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -312,6 +312,27 @@ void sqlite3DequoteExpr(Expr *p){
}
/*
+** Expression p is a QINTEGER or QFLOAT (quoted integer or float). 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(Expr *p){
+ if( p ){
+ const char *pIn = p->u.zToken;
+ char *pOut = p->u.zToken;
+ 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;
+ }
+ }while( *pIn++ );
+ }
+}
+
+/*
** If the input token p is quoted, try to adjust the token to remove
** the quotes. This is not always possible:
**