Fossil SCM
Bring the built-in SQLite and the regexp implementation into alignment with upstream.
Commit
9642cde38468682b797d1138102c23bd3d25d259303f322e7502c9cd53956a94
Parent
b666bbc54d746e3…
5 files changed
+74
-50
+55
-71
+2
-2
+47
-19
+5
+74
-50
| --- extsrc/shell.c | ||
| +++ extsrc/shell.c | ||
| @@ -1512,31 +1512,31 @@ | ||
| 1512 | 1512 | } |
| 1513 | 1513 | } |
| 1514 | 1514 | if( isNeg && v>0x7fffffffffffffffULL ) goto integer_overflow; |
| 1515 | 1515 | return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v; |
| 1516 | 1516 | integer_overflow: |
| 1517 | - return isNeg ? 0x8000000000000000LL : 0x7fffffffffffffffLL; | |
| 1517 | + return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL; | |
| 1518 | 1518 | } |
| 1519 | 1519 | |
| 1520 | 1520 | /* |
| 1521 | 1521 | ** A variable length string to which one can append text. |
| 1522 | 1522 | */ |
| 1523 | 1523 | typedef struct ShellText ShellText; |
| 1524 | 1524 | struct ShellText { |
| 1525 | - char *z; | |
| 1526 | - int n; | |
| 1527 | - int nAlloc; | |
| 1525 | + char *zTxt; /* The text */ | |
| 1526 | + i64 n; /* Number of bytes of zTxt[] actually used */ | |
| 1527 | + i64 nAlloc; /* Number of bytes allocated for zTxt[] */ | |
| 1528 | 1528 | }; |
| 1529 | 1529 | |
| 1530 | 1530 | /* |
| 1531 | 1531 | ** Initialize and destroy a ShellText object |
| 1532 | 1532 | */ |
| 1533 | 1533 | static void initText(ShellText *p){ |
| 1534 | 1534 | memset(p, 0, sizeof(*p)); |
| 1535 | 1535 | } |
| 1536 | 1536 | static void freeText(ShellText *p){ |
| 1537 | - free(p->z); | |
| 1537 | + sqlite3_free(p->zTxt); | |
| 1538 | 1538 | initText(p); |
| 1539 | 1539 | } |
| 1540 | 1540 | |
| 1541 | 1541 | /* zIn is either a pointer to a NULL-terminated string in memory obtained |
| 1542 | 1542 | ** from malloc(), or a NULL pointer. The string pointed to by zAppend is |
| @@ -1557,30 +1557,30 @@ | ||
| 1557 | 1557 | for(i=0; i<nAppend; i++){ |
| 1558 | 1558 | if( zAppend[i]==quote ) len++; |
| 1559 | 1559 | } |
| 1560 | 1560 | } |
| 1561 | 1561 | |
| 1562 | - if( p->z==0 || p->n+len>=p->nAlloc ){ | |
| 1562 | + if( p->zTxt==0 || p->n+len>=p->nAlloc ){ | |
| 1563 | 1563 | p->nAlloc = p->nAlloc*2 + len + 20; |
| 1564 | - p->z = realloc(p->z, p->nAlloc); | |
| 1565 | - shell_check_oom(p->z); | |
| 1564 | + p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc); | |
| 1565 | + shell_check_oom(p->zTxt); | |
| 1566 | 1566 | } |
| 1567 | 1567 | |
| 1568 | 1568 | if( quote ){ |
| 1569 | - char *zCsr = p->z+p->n; | |
| 1569 | + char *zCsr = p->zTxt+p->n; | |
| 1570 | 1570 | *zCsr++ = quote; |
| 1571 | 1571 | for(i=0; i<nAppend; i++){ |
| 1572 | 1572 | *zCsr++ = zAppend[i]; |
| 1573 | 1573 | if( zAppend[i]==quote ) *zCsr++ = quote; |
| 1574 | 1574 | } |
| 1575 | 1575 | *zCsr++ = quote; |
| 1576 | - p->n = (int)(zCsr - p->z); | |
| 1576 | + p->n = (i64)(zCsr - p->zTxt); | |
| 1577 | 1577 | *zCsr = '\0'; |
| 1578 | 1578 | }else{ |
| 1579 | - memcpy(p->z+p->n, zAppend, nAppend); | |
| 1579 | + memcpy(p->zTxt+p->n, zAppend, nAppend); | |
| 1580 | 1580 | p->n += nAppend; |
| 1581 | - p->z[p->n] = '\0'; | |
| 1581 | + p->zTxt[p->n] = '\0'; | |
| 1582 | 1582 | } |
| 1583 | 1583 | } |
| 1584 | 1584 | |
| 1585 | 1585 | /* |
| 1586 | 1586 | ** Attempt to determine if identifier zName needs to be quoted, either |
| @@ -1601,10 +1601,13 @@ | ||
| 1601 | 1601 | } |
| 1602 | 1602 | |
| 1603 | 1603 | /* |
| 1604 | 1604 | ** Construct a fake object name and column list to describe the structure |
| 1605 | 1605 | ** of the view, virtual table, or table valued function zSchema.zName. |
| 1606 | +** | |
| 1607 | +** The returned string comes from sqlite3_mprintf() and should be freed | |
| 1608 | +** by the caller using sqlite3_free(). | |
| 1606 | 1609 | */ |
| 1607 | 1610 | static char *shellFakeSchema( |
| 1608 | 1611 | sqlite3 *db, /* The database connection containing the vtab */ |
| 1609 | 1612 | const char *zSchema, /* Schema of the database holding the vtab */ |
| 1610 | 1613 | const char *zName /* The name of the virtual table */ |
| @@ -1641,13 +1644,13 @@ | ||
| 1641 | 1644 | } |
| 1642 | 1645 | appendText(&s, ")", 0); |
| 1643 | 1646 | sqlite3_finalize(pStmt); |
| 1644 | 1647 | if( nRow==0 ){ |
| 1645 | 1648 | freeText(&s); |
| 1646 | - s.z = 0; | |
| 1649 | + s.zTxt = 0; | |
| 1647 | 1650 | } |
| 1648 | - return s.z; | |
| 1651 | + return s.zTxt; | |
| 1649 | 1652 | } |
| 1650 | 1653 | |
| 1651 | 1654 | /* |
| 1652 | 1655 | ** SQL function: strtod(X) |
| 1653 | 1656 | ** |
| @@ -1746,11 +1749,11 @@ | ||
| 1746 | 1749 | if( z==0 ){ |
| 1747 | 1750 | z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake); |
| 1748 | 1751 | }else{ |
| 1749 | 1752 | z = sqlite3_mprintf("%z\n/* %s */", z, zFake); |
| 1750 | 1753 | } |
| 1751 | - free(zFake); | |
| 1754 | + sqlite3_free(zFake); | |
| 1752 | 1755 | } |
| 1753 | 1756 | if( z ){ |
| 1754 | 1757 | sqlite3_result_text(pCtx, z, -1, sqlite3_free); |
| 1755 | 1758 | return; |
| 1756 | 1759 | } |
| @@ -6993,11 +6996,11 @@ | ||
| 6993 | 6996 | ** The following regular expression syntax is supported: |
| 6994 | 6997 | ** |
| 6995 | 6998 | ** X* zero or more occurrences of X |
| 6996 | 6999 | ** X+ one or more occurrences of X |
| 6997 | 7000 | ** X? zero or one occurrences of X |
| 6998 | -** X{p,q} between p and q occurrences of X | |
| 7001 | +** X{p,q} between p and q occurrences of X, 0 <= p,q <= 999 | |
| 6999 | 7002 | ** (X) match X |
| 7000 | 7003 | ** X|Y X or Y |
| 7001 | 7004 | ** ^X X occurring at the beginning of the string |
| 7002 | 7005 | ** X$ X occurring at the end of the string |
| 7003 | 7006 | ** . Match any single character |
| @@ -7022,15 +7025,22 @@ | ||
| 7022 | 7025 | ** expression and M is the size of the input string. The matcher never |
| 7023 | 7026 | ** exhibits exponential behavior. Note that the X{p,q} operator expands |
| 7024 | 7027 | ** to p copies of X following by q-p copies of X? and that the size of the |
| 7025 | 7028 | ** regular expression in the O(N*M) performance bound is computed after |
| 7026 | 7029 | ** this expansion. |
| 7030 | +** | |
| 7031 | +** To help prevent DoS attacks, the values of p and q in the "{p,q}" syntax | |
| 7032 | +** are limited to SQLITE_MAX_REGEXP_REPEAT, default 999. | |
| 7027 | 7033 | */ |
| 7028 | 7034 | #include <string.h> |
| 7029 | 7035 | #include <stdlib.h> |
| 7030 | 7036 | /* #include "sqlite3ext.h" */ |
| 7031 | 7037 | SQLITE_EXTENSION_INIT1 |
| 7038 | + | |
| 7039 | +#ifndef SQLITE_MAX_REGEXP_REPEAT | |
| 7040 | +# define SQLITE_MAX_REGEXP_REPEAT 999 | |
| 7041 | +#endif | |
| 7032 | 7042 | |
| 7033 | 7043 | /* |
| 7034 | 7044 | ** The following #defines change the names of some functions implemented in |
| 7035 | 7045 | ** this file to prevent name collisions with C-library functions of the |
| 7036 | 7046 | ** same name. |
| @@ -7530,22 +7540,30 @@ | ||
| 7530 | 7540 | case '^': { |
| 7531 | 7541 | re_append(p, RE_OP_ATSTART, 0); |
| 7532 | 7542 | break; |
| 7533 | 7543 | } |
| 7534 | 7544 | case '{': { |
| 7535 | - int m = 0, n = 0; | |
| 7536 | - int sz, j; | |
| 7545 | + unsigned int m = 0, n = 0; | |
| 7546 | + unsigned int sz, j; | |
| 7537 | 7547 | if( iPrev<0 ) return "'{m,n}' without operand"; |
| 7538 | - while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } | |
| 7548 | + while( (c=rePeek(p))>='0' && c<='9' ){ | |
| 7549 | + m = m*10 + c - '0'; | |
| 7550 | + if( m>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; | |
| 7551 | + p->sIn.i++; | |
| 7552 | + } | |
| 7539 | 7553 | n = m; |
| 7540 | 7554 | if( c==',' ){ |
| 7541 | 7555 | p->sIn.i++; |
| 7542 | 7556 | n = 0; |
| 7543 | - while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } | |
| 7557 | + while( (c=rePeek(p))>='0' && c<='9' ){ | |
| 7558 | + n = n*10 + c-'0'; | |
| 7559 | + if( n>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; | |
| 7560 | + p->sIn.i++; | |
| 7561 | + } | |
| 7544 | 7562 | } |
| 7545 | 7563 | if( c!='}' ) return "unmatched '{'"; |
| 7546 | - if( n>0 && n<m ) return "n less than m in '{m,n}'"; | |
| 7564 | + if( n<m ) return "n less than m in '{m,n}'"; | |
| 7547 | 7565 | p->sIn.i++; |
| 7548 | 7566 | sz = p->nState - iPrev; |
| 7549 | 7567 | if( m==0 ){ |
| 7550 | 7568 | if( n==0 ) return "both m and n are zero in '{m,n}'"; |
| 7551 | 7569 | re_insert(p, iPrev, RE_OP_FORK, sz+1); |
| @@ -22098,11 +22116,11 @@ | ||
| 22098 | 22116 | */ |
| 22099 | 22117 | static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ |
| 22100 | 22118 | int i; |
| 22101 | 22119 | unsigned char *aBlob = (unsigned char*)pBlob; |
| 22102 | 22120 | |
| 22103 | - char *zStr = sqlite3_malloc(nBlob*2 + 1); | |
| 22121 | + char *zStr = sqlite3_malloc64((i64)nBlob*2 + 1); | |
| 22104 | 22122 | shell_check_oom(zStr); |
| 22105 | 22123 | |
| 22106 | 22124 | for(i=0; i<nBlob; i++){ |
| 22107 | 22125 | static const char aHex[] = { |
| 22108 | 22126 | '0', '1', '2', '3', '4', '5', '6', '7', |
| @@ -23375,11 +23393,16 @@ | ||
| 23375 | 23393 | if( p->zDestTable ){ |
| 23376 | 23394 | sqlite3_free(p->zDestTable); |
| 23377 | 23395 | p->zDestTable = 0; |
| 23378 | 23396 | } |
| 23379 | 23397 | if( zName==0 ) return; |
| 23380 | - p->zDestTable = sqlite3_mprintf("\"%w\"", zName); | |
| 23398 | + if( quoteChar(zName) ){ | |
| 23399 | + p->zDestTable = sqlite3_mprintf("\"%w\"", zName); | |
| 23400 | + }else{ | |
| 23401 | + p->zDestTable = sqlite3_mprintf("%s", zName); | |
| 23402 | + } | |
| 23403 | + shell_check_oom(p->zDestTable); | |
| 23381 | 23404 | } |
| 23382 | 23405 | |
| 23383 | 23406 | /* |
| 23384 | 23407 | ** Maybe construct two lines of text that point out the position of a |
| 23385 | 23408 | ** syntax error. Return a pointer to the text, in memory obtained from |
| @@ -25182,17 +25205,17 @@ | ||
| 25182 | 25205 | appendText(&sSelect, " FROM ", 0); |
| 25183 | 25206 | appendText(&sSelect, zTable, quoteChar(zTable)); |
| 25184 | 25207 | |
| 25185 | 25208 | savedDestTable = p->zDestTable; |
| 25186 | 25209 | savedMode = p->mode; |
| 25187 | - p->zDestTable = sTable.z; | |
| 25210 | + p->zDestTable = sTable.zTxt; | |
| 25188 | 25211 | p->mode = p->cMode = MODE_Insert; |
| 25189 | - rc = shell_exec(p, sSelect.z, 0); | |
| 25212 | + rc = shell_exec(p, sSelect.zTxt, 0); | |
| 25190 | 25213 | if( (rc&0xff)==SQLITE_CORRUPT ){ |
| 25191 | 25214 | sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out); |
| 25192 | 25215 | toggleSelectOrder(p->db); |
| 25193 | - shell_exec(p, sSelect.z, 0); | |
| 25216 | + shell_exec(p, sSelect.zTxt, 0); | |
| 25194 | 25217 | toggleSelectOrder(p->db); |
| 25195 | 25218 | } |
| 25196 | 25219 | p->zDestTable = savedDestTable; |
| 25197 | 25220 | p->mode = savedMode; |
| 25198 | 25221 | freeText(&sTable); |
| @@ -25802,14 +25825,14 @@ | ||
| 25802 | 25825 | ** If p->aAuxDb[].zDbFilename is 0, then read from standard input. |
| 25803 | 25826 | */ |
| 25804 | 25827 | static unsigned char *readHexDb(ShellState *p, int *pnData){ |
| 25805 | 25828 | unsigned char *a = 0; |
| 25806 | 25829 | int nLine; |
| 25807 | - int n = 0; | |
| 25830 | + int n = 0; /* Size of db per first line of hex dump */ | |
| 25831 | + i64 sz = 0; /* n rounded up to nearest page boundary */ | |
| 25808 | 25832 | int pgsz = 0; |
| 25809 | - int iOffset = 0; | |
| 25810 | - int j, k; | |
| 25833 | + i64 iOffset = 0; | |
| 25811 | 25834 | int rc; |
| 25812 | 25835 | FILE *in; |
| 25813 | 25836 | const char *zDbFilename = p->pAuxDb->zDbFilename; |
| 25814 | 25837 | unsigned int x[16]; |
| 25815 | 25838 | char zLine[1000]; |
| @@ -25829,20 +25852,21 @@ | ||
| 25829 | 25852 | nLine++; |
| 25830 | 25853 | if( sqlite3_fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; |
| 25831 | 25854 | rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); |
| 25832 | 25855 | if( rc!=2 ) goto readHexDb_error; |
| 25833 | 25856 | if( n<0 ) goto readHexDb_error; |
| 25834 | - if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error; | |
| 25835 | - n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ | |
| 25836 | - a = sqlite3_malloc( n ? n : 1 ); | |
| 25837 | - shell_check_oom(a); | |
| 25838 | - memset(a, 0, n); | |
| 25839 | 25857 | if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ |
| 25840 | 25858 | sqlite3_fputs("invalid pagesize\n", stderr); |
| 25841 | 25859 | goto readHexDb_error; |
| 25842 | 25860 | } |
| 25861 | + sz = ((i64)n+pgsz-1)&~(pgsz-1); /* Round up to nearest multiple of pgsz */ | |
| 25862 | + a = sqlite3_malloc( sz ? sz : 1 ); | |
| 25863 | + shell_check_oom(a); | |
| 25864 | + memset(a, 0, sz); | |
| 25843 | 25865 | for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){ |
| 25866 | + int j = 0; /* Page number from "| page" line */ | |
| 25867 | + int k = 0; /* Offset from "| page" line */ | |
| 25844 | 25868 | rc = sscanf(zLine, "| page %d offset %d", &j, &k); |
| 25845 | 25869 | if( rc==2 ){ |
| 25846 | 25870 | iOffset = k; |
| 25847 | 25871 | continue; |
| 25848 | 25872 | } |
| @@ -25851,18 +25875,18 @@ | ||
| 25851 | 25875 | } |
| 25852 | 25876 | rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", |
| 25853 | 25877 | &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], |
| 25854 | 25878 | &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); |
| 25855 | 25879 | if( rc==17 ){ |
| 25856 | - k = iOffset+j; | |
| 25857 | - if( k+16<=n && k>=0 ){ | |
| 25880 | + i64 iOff = iOffset+j; | |
| 25881 | + if( iOff+16<=sz && iOff>=0 ){ | |
| 25858 | 25882 | int ii; |
| 25859 | - for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; | |
| 25883 | + for(ii=0; ii<16; ii++) a[iOff+ii] = x[ii]&0xff; | |
| 25860 | 25884 | } |
| 25861 | 25885 | } |
| 25862 | 25886 | } |
| 25863 | - *pnData = n; | |
| 25887 | + *pnData = sz; | |
| 25864 | 25888 | if( in!=p->in ){ |
| 25865 | 25889 | fclose(in); |
| 25866 | 25890 | }else{ |
| 25867 | 25891 | p->lineno = nLine; |
| 25868 | 25892 | } |
| @@ -25925,11 +25949,11 @@ | ||
| 25925 | 25949 | p->pLog = pSavedLog; |
| 25926 | 25950 | |
| 25927 | 25951 | if( zFake ){ |
| 25928 | 25952 | sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), |
| 25929 | 25953 | -1, sqlite3_free); |
| 25930 | - free(zFake); | |
| 25954 | + sqlite3_free(zFake); | |
| 25931 | 25955 | } |
| 25932 | 25956 | } |
| 25933 | 25957 | |
| 25934 | 25958 | /* Flags for open_db(). |
| 25935 | 25959 | ** |
| @@ -31009,13 +31033,13 @@ | ||
| 31009 | 31033 | appendText(&sSelect, "name NOT LIKE 'sqlite__%%' ESCAPE '_' AND ", 0); |
| 31010 | 31034 | } |
| 31011 | 31035 | appendText(&sSelect, "sql IS NOT NULL" |
| 31012 | 31036 | " ORDER BY snum, rowid", 0); |
| 31013 | 31037 | if( bDebug ){ |
| 31014 | - sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.z); | |
| 31038 | + sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.zTxt); | |
| 31015 | 31039 | }else{ |
| 31016 | - rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg); | |
| 31040 | + rc = sqlite3_exec(p->db, sSelect.zTxt, callback, &data, &zErrMsg); | |
| 31017 | 31041 | } |
| 31018 | 31042 | freeText(&sSelect); |
| 31019 | 31043 | } |
| 31020 | 31044 | if( zErrMsg ){ |
| 31021 | 31045 | shellEmitError(zErrMsg); |
| @@ -31335,26 +31359,26 @@ | ||
| 31335 | 31359 | sqlite3_fprintf(p->out, "%s\n", zSql); |
| 31336 | 31360 | }else |
| 31337 | 31361 | if( cli_strcmp(zOp,"run")==0 ){ |
| 31338 | 31362 | char *zErrMsg = 0; |
| 31339 | 31363 | str.n = 0; |
| 31340 | - str.z[0] = 0; | |
| 31364 | + str.zTxt[0] = 0; | |
| 31341 | 31365 | rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); |
| 31342 | 31366 | nTest++; |
| 31343 | 31367 | if( bVerbose ){ |
| 31344 | - sqlite3_fprintf(p->out, "Result: %s\n", str.z); | |
| 31368 | + sqlite3_fprintf(p->out, "Result: %s\n", str.zTxt); | |
| 31345 | 31369 | } |
| 31346 | 31370 | if( rc || zErrMsg ){ |
| 31347 | 31371 | nErr++; |
| 31348 | 31372 | rc = 1; |
| 31349 | 31373 | sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg); |
| 31350 | 31374 | sqlite3_free(zErrMsg); |
| 31351 | - }else if( cli_strcmp(zAns,str.z)!=0 ){ | |
| 31375 | + }else if( cli_strcmp(zAns,str.zTxt)!=0 ){ | |
| 31352 | 31376 | nErr++; |
| 31353 | 31377 | rc = 1; |
| 31354 | 31378 | sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns); |
| 31355 | - sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.z); | |
| 31379 | + sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.zTxt); | |
| 31356 | 31380 | } |
| 31357 | 31381 | } |
| 31358 | 31382 | else{ |
| 31359 | 31383 | sqlite3_fprintf(stderr, |
| 31360 | 31384 | "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); |
| @@ -31466,11 +31490,11 @@ | ||
| 31466 | 31490 | appendText(&sQuery, "SELECT * FROM ", 0); |
| 31467 | 31491 | appendText(&sQuery, zTab, 0); |
| 31468 | 31492 | appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0); |
| 31469 | 31493 | } |
| 31470 | 31494 | appendText(&sSql, zSep, 0); |
| 31471 | - appendText(&sSql, sQuery.z, '\''); | |
| 31495 | + appendText(&sSql, sQuery.zTxt, '\''); | |
| 31472 | 31496 | sQuery.n = 0; |
| 31473 | 31497 | appendText(&sSql, ",", 0); |
| 31474 | 31498 | appendText(&sSql, zTab, '\''); |
| 31475 | 31499 | zSep = "),("; |
| 31476 | 31500 | } |
| @@ -31478,17 +31502,17 @@ | ||
| 31478 | 31502 | if( bSeparate ){ |
| 31479 | 31503 | zSql = sqlite3_mprintf( |
| 31480 | 31504 | "%s))" |
| 31481 | 31505 | " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label" |
| 31482 | 31506 | " FROM [sha3sum$query]", |
| 31483 | - sSql.z, iSize); | |
| 31507 | + sSql.zTxt, iSize); | |
| 31484 | 31508 | }else{ |
| 31485 | 31509 | zSql = sqlite3_mprintf( |
| 31486 | 31510 | "%s))" |
| 31487 | 31511 | " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" |
| 31488 | 31512 | " FROM [sha3sum$query]", |
| 31489 | - sSql.z, iSize); | |
| 31513 | + sSql.zTxt, iSize); | |
| 31490 | 31514 | } |
| 31491 | 31515 | shell_check_oom(zSql); |
| 31492 | 31516 | freeText(&sQuery); |
| 31493 | 31517 | freeText(&sSql); |
| 31494 | 31518 | if( bDebug ){ |
| @@ -31684,11 +31708,11 @@ | ||
| 31684 | 31708 | goto meta_command_exit; |
| 31685 | 31709 | } |
| 31686 | 31710 | for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ |
| 31687 | 31711 | const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); |
| 31688 | 31712 | if( zDbName==0 ) continue; |
| 31689 | - if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0); | |
| 31713 | + if( s.zTxt && s.zTxt[0] ) appendText(&s, " UNION ALL ", 0); | |
| 31690 | 31714 | if( sqlite3_stricmp(zDbName, "main")==0 ){ |
| 31691 | 31715 | appendText(&s, "SELECT name FROM ", 0); |
| 31692 | 31716 | }else{ |
| 31693 | 31717 | appendText(&s, "SELECT ", 0); |
| 31694 | 31718 | appendText(&s, zDbName, '\''); |
| @@ -31706,11 +31730,11 @@ | ||
| 31706 | 31730 | } |
| 31707 | 31731 | } |
| 31708 | 31732 | rc = sqlite3_finalize(pStmt); |
| 31709 | 31733 | if( rc==SQLITE_OK ){ |
| 31710 | 31734 | appendText(&s, " ORDER BY 1", 0); |
| 31711 | - rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); | |
| 31735 | + rc = sqlite3_prepare_v2(p->db, s.zTxt, -1, &pStmt, 0); | |
| 31712 | 31736 | } |
| 31713 | 31737 | freeText(&s); |
| 31714 | 31738 | if( rc ) return shellDatabaseError(p->db); |
| 31715 | 31739 | |
| 31716 | 31740 | /* Run the SQL statement prepared by the above block. Store the results |
| 31717 | 31741 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -1512,31 +1512,31 @@ | |
| 1512 | } |
| 1513 | } |
| 1514 | if( isNeg && v>0x7fffffffffffffffULL ) goto integer_overflow; |
| 1515 | return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v; |
| 1516 | integer_overflow: |
| 1517 | return isNeg ? 0x8000000000000000LL : 0x7fffffffffffffffLL; |
| 1518 | } |
| 1519 | |
| 1520 | /* |
| 1521 | ** A variable length string to which one can append text. |
| 1522 | */ |
| 1523 | typedef struct ShellText ShellText; |
| 1524 | struct ShellText { |
| 1525 | char *z; |
| 1526 | int n; |
| 1527 | int nAlloc; |
| 1528 | }; |
| 1529 | |
| 1530 | /* |
| 1531 | ** Initialize and destroy a ShellText object |
| 1532 | */ |
| 1533 | static void initText(ShellText *p){ |
| 1534 | memset(p, 0, sizeof(*p)); |
| 1535 | } |
| 1536 | static void freeText(ShellText *p){ |
| 1537 | free(p->z); |
| 1538 | initText(p); |
| 1539 | } |
| 1540 | |
| 1541 | /* zIn is either a pointer to a NULL-terminated string in memory obtained |
| 1542 | ** from malloc(), or a NULL pointer. The string pointed to by zAppend is |
| @@ -1557,30 +1557,30 @@ | |
| 1557 | for(i=0; i<nAppend; i++){ |
| 1558 | if( zAppend[i]==quote ) len++; |
| 1559 | } |
| 1560 | } |
| 1561 | |
| 1562 | if( p->z==0 || p->n+len>=p->nAlloc ){ |
| 1563 | p->nAlloc = p->nAlloc*2 + len + 20; |
| 1564 | p->z = realloc(p->z, p->nAlloc); |
| 1565 | shell_check_oom(p->z); |
| 1566 | } |
| 1567 | |
| 1568 | if( quote ){ |
| 1569 | char *zCsr = p->z+p->n; |
| 1570 | *zCsr++ = quote; |
| 1571 | for(i=0; i<nAppend; i++){ |
| 1572 | *zCsr++ = zAppend[i]; |
| 1573 | if( zAppend[i]==quote ) *zCsr++ = quote; |
| 1574 | } |
| 1575 | *zCsr++ = quote; |
| 1576 | p->n = (int)(zCsr - p->z); |
| 1577 | *zCsr = '\0'; |
| 1578 | }else{ |
| 1579 | memcpy(p->z+p->n, zAppend, nAppend); |
| 1580 | p->n += nAppend; |
| 1581 | p->z[p->n] = '\0'; |
| 1582 | } |
| 1583 | } |
| 1584 | |
| 1585 | /* |
| 1586 | ** Attempt to determine if identifier zName needs to be quoted, either |
| @@ -1601,10 +1601,13 @@ | |
| 1601 | } |
| 1602 | |
| 1603 | /* |
| 1604 | ** Construct a fake object name and column list to describe the structure |
| 1605 | ** of the view, virtual table, or table valued function zSchema.zName. |
| 1606 | */ |
| 1607 | static char *shellFakeSchema( |
| 1608 | sqlite3 *db, /* The database connection containing the vtab */ |
| 1609 | const char *zSchema, /* Schema of the database holding the vtab */ |
| 1610 | const char *zName /* The name of the virtual table */ |
| @@ -1641,13 +1644,13 @@ | |
| 1641 | } |
| 1642 | appendText(&s, ")", 0); |
| 1643 | sqlite3_finalize(pStmt); |
| 1644 | if( nRow==0 ){ |
| 1645 | freeText(&s); |
| 1646 | s.z = 0; |
| 1647 | } |
| 1648 | return s.z; |
| 1649 | } |
| 1650 | |
| 1651 | /* |
| 1652 | ** SQL function: strtod(X) |
| 1653 | ** |
| @@ -1746,11 +1749,11 @@ | |
| 1746 | if( z==0 ){ |
| 1747 | z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake); |
| 1748 | }else{ |
| 1749 | z = sqlite3_mprintf("%z\n/* %s */", z, zFake); |
| 1750 | } |
| 1751 | free(zFake); |
| 1752 | } |
| 1753 | if( z ){ |
| 1754 | sqlite3_result_text(pCtx, z, -1, sqlite3_free); |
| 1755 | return; |
| 1756 | } |
| @@ -6993,11 +6996,11 @@ | |
| 6993 | ** The following regular expression syntax is supported: |
| 6994 | ** |
| 6995 | ** X* zero or more occurrences of X |
| 6996 | ** X+ one or more occurrences of X |
| 6997 | ** X? zero or one occurrences of X |
| 6998 | ** X{p,q} between p and q occurrences of X |
| 6999 | ** (X) match X |
| 7000 | ** X|Y X or Y |
| 7001 | ** ^X X occurring at the beginning of the string |
| 7002 | ** X$ X occurring at the end of the string |
| 7003 | ** . Match any single character |
| @@ -7022,15 +7025,22 @@ | |
| 7022 | ** expression and M is the size of the input string. The matcher never |
| 7023 | ** exhibits exponential behavior. Note that the X{p,q} operator expands |
| 7024 | ** to p copies of X following by q-p copies of X? and that the size of the |
| 7025 | ** regular expression in the O(N*M) performance bound is computed after |
| 7026 | ** this expansion. |
| 7027 | */ |
| 7028 | #include <string.h> |
| 7029 | #include <stdlib.h> |
| 7030 | /* #include "sqlite3ext.h" */ |
| 7031 | SQLITE_EXTENSION_INIT1 |
| 7032 | |
| 7033 | /* |
| 7034 | ** The following #defines change the names of some functions implemented in |
| 7035 | ** this file to prevent name collisions with C-library functions of the |
| 7036 | ** same name. |
| @@ -7530,22 +7540,30 @@ | |
| 7530 | case '^': { |
| 7531 | re_append(p, RE_OP_ATSTART, 0); |
| 7532 | break; |
| 7533 | } |
| 7534 | case '{': { |
| 7535 | int m = 0, n = 0; |
| 7536 | int sz, j; |
| 7537 | if( iPrev<0 ) return "'{m,n}' without operand"; |
| 7538 | while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } |
| 7539 | n = m; |
| 7540 | if( c==',' ){ |
| 7541 | p->sIn.i++; |
| 7542 | n = 0; |
| 7543 | while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } |
| 7544 | } |
| 7545 | if( c!='}' ) return "unmatched '{'"; |
| 7546 | if( n>0 && n<m ) return "n less than m in '{m,n}'"; |
| 7547 | p->sIn.i++; |
| 7548 | sz = p->nState - iPrev; |
| 7549 | if( m==0 ){ |
| 7550 | if( n==0 ) return "both m and n are zero in '{m,n}'"; |
| 7551 | re_insert(p, iPrev, RE_OP_FORK, sz+1); |
| @@ -22098,11 +22116,11 @@ | |
| 22098 | */ |
| 22099 | static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ |
| 22100 | int i; |
| 22101 | unsigned char *aBlob = (unsigned char*)pBlob; |
| 22102 | |
| 22103 | char *zStr = sqlite3_malloc(nBlob*2 + 1); |
| 22104 | shell_check_oom(zStr); |
| 22105 | |
| 22106 | for(i=0; i<nBlob; i++){ |
| 22107 | static const char aHex[] = { |
| 22108 | '0', '1', '2', '3', '4', '5', '6', '7', |
| @@ -23375,11 +23393,16 @@ | |
| 23375 | if( p->zDestTable ){ |
| 23376 | sqlite3_free(p->zDestTable); |
| 23377 | p->zDestTable = 0; |
| 23378 | } |
| 23379 | if( zName==0 ) return; |
| 23380 | p->zDestTable = sqlite3_mprintf("\"%w\"", zName); |
| 23381 | } |
| 23382 | |
| 23383 | /* |
| 23384 | ** Maybe construct two lines of text that point out the position of a |
| 23385 | ** syntax error. Return a pointer to the text, in memory obtained from |
| @@ -25182,17 +25205,17 @@ | |
| 25182 | appendText(&sSelect, " FROM ", 0); |
| 25183 | appendText(&sSelect, zTable, quoteChar(zTable)); |
| 25184 | |
| 25185 | savedDestTable = p->zDestTable; |
| 25186 | savedMode = p->mode; |
| 25187 | p->zDestTable = sTable.z; |
| 25188 | p->mode = p->cMode = MODE_Insert; |
| 25189 | rc = shell_exec(p, sSelect.z, 0); |
| 25190 | if( (rc&0xff)==SQLITE_CORRUPT ){ |
| 25191 | sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out); |
| 25192 | toggleSelectOrder(p->db); |
| 25193 | shell_exec(p, sSelect.z, 0); |
| 25194 | toggleSelectOrder(p->db); |
| 25195 | } |
| 25196 | p->zDestTable = savedDestTable; |
| 25197 | p->mode = savedMode; |
| 25198 | freeText(&sTable); |
| @@ -25802,14 +25825,14 @@ | |
| 25802 | ** If p->aAuxDb[].zDbFilename is 0, then read from standard input. |
| 25803 | */ |
| 25804 | static unsigned char *readHexDb(ShellState *p, int *pnData){ |
| 25805 | unsigned char *a = 0; |
| 25806 | int nLine; |
| 25807 | int n = 0; |
| 25808 | int pgsz = 0; |
| 25809 | int iOffset = 0; |
| 25810 | int j, k; |
| 25811 | int rc; |
| 25812 | FILE *in; |
| 25813 | const char *zDbFilename = p->pAuxDb->zDbFilename; |
| 25814 | unsigned int x[16]; |
| 25815 | char zLine[1000]; |
| @@ -25829,20 +25852,21 @@ | |
| 25829 | nLine++; |
| 25830 | if( sqlite3_fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; |
| 25831 | rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); |
| 25832 | if( rc!=2 ) goto readHexDb_error; |
| 25833 | if( n<0 ) goto readHexDb_error; |
| 25834 | if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error; |
| 25835 | n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ |
| 25836 | a = sqlite3_malloc( n ? n : 1 ); |
| 25837 | shell_check_oom(a); |
| 25838 | memset(a, 0, n); |
| 25839 | if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ |
| 25840 | sqlite3_fputs("invalid pagesize\n", stderr); |
| 25841 | goto readHexDb_error; |
| 25842 | } |
| 25843 | for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){ |
| 25844 | rc = sscanf(zLine, "| page %d offset %d", &j, &k); |
| 25845 | if( rc==2 ){ |
| 25846 | iOffset = k; |
| 25847 | continue; |
| 25848 | } |
| @@ -25851,18 +25875,18 @@ | |
| 25851 | } |
| 25852 | rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", |
| 25853 | &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], |
| 25854 | &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); |
| 25855 | if( rc==17 ){ |
| 25856 | k = iOffset+j; |
| 25857 | if( k+16<=n && k>=0 ){ |
| 25858 | int ii; |
| 25859 | for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; |
| 25860 | } |
| 25861 | } |
| 25862 | } |
| 25863 | *pnData = n; |
| 25864 | if( in!=p->in ){ |
| 25865 | fclose(in); |
| 25866 | }else{ |
| 25867 | p->lineno = nLine; |
| 25868 | } |
| @@ -25925,11 +25949,11 @@ | |
| 25925 | p->pLog = pSavedLog; |
| 25926 | |
| 25927 | if( zFake ){ |
| 25928 | sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), |
| 25929 | -1, sqlite3_free); |
| 25930 | free(zFake); |
| 25931 | } |
| 25932 | } |
| 25933 | |
| 25934 | /* Flags for open_db(). |
| 25935 | ** |
| @@ -31009,13 +31033,13 @@ | |
| 31009 | appendText(&sSelect, "name NOT LIKE 'sqlite__%%' ESCAPE '_' AND ", 0); |
| 31010 | } |
| 31011 | appendText(&sSelect, "sql IS NOT NULL" |
| 31012 | " ORDER BY snum, rowid", 0); |
| 31013 | if( bDebug ){ |
| 31014 | sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.z); |
| 31015 | }else{ |
| 31016 | rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg); |
| 31017 | } |
| 31018 | freeText(&sSelect); |
| 31019 | } |
| 31020 | if( zErrMsg ){ |
| 31021 | shellEmitError(zErrMsg); |
| @@ -31335,26 +31359,26 @@ | |
| 31335 | sqlite3_fprintf(p->out, "%s\n", zSql); |
| 31336 | }else |
| 31337 | if( cli_strcmp(zOp,"run")==0 ){ |
| 31338 | char *zErrMsg = 0; |
| 31339 | str.n = 0; |
| 31340 | str.z[0] = 0; |
| 31341 | rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); |
| 31342 | nTest++; |
| 31343 | if( bVerbose ){ |
| 31344 | sqlite3_fprintf(p->out, "Result: %s\n", str.z); |
| 31345 | } |
| 31346 | if( rc || zErrMsg ){ |
| 31347 | nErr++; |
| 31348 | rc = 1; |
| 31349 | sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg); |
| 31350 | sqlite3_free(zErrMsg); |
| 31351 | }else if( cli_strcmp(zAns,str.z)!=0 ){ |
| 31352 | nErr++; |
| 31353 | rc = 1; |
| 31354 | sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns); |
| 31355 | sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.z); |
| 31356 | } |
| 31357 | } |
| 31358 | else{ |
| 31359 | sqlite3_fprintf(stderr, |
| 31360 | "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); |
| @@ -31466,11 +31490,11 @@ | |
| 31466 | appendText(&sQuery, "SELECT * FROM ", 0); |
| 31467 | appendText(&sQuery, zTab, 0); |
| 31468 | appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0); |
| 31469 | } |
| 31470 | appendText(&sSql, zSep, 0); |
| 31471 | appendText(&sSql, sQuery.z, '\''); |
| 31472 | sQuery.n = 0; |
| 31473 | appendText(&sSql, ",", 0); |
| 31474 | appendText(&sSql, zTab, '\''); |
| 31475 | zSep = "),("; |
| 31476 | } |
| @@ -31478,17 +31502,17 @@ | |
| 31478 | if( bSeparate ){ |
| 31479 | zSql = sqlite3_mprintf( |
| 31480 | "%s))" |
| 31481 | " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label" |
| 31482 | " FROM [sha3sum$query]", |
| 31483 | sSql.z, iSize); |
| 31484 | }else{ |
| 31485 | zSql = sqlite3_mprintf( |
| 31486 | "%s))" |
| 31487 | " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" |
| 31488 | " FROM [sha3sum$query]", |
| 31489 | sSql.z, iSize); |
| 31490 | } |
| 31491 | shell_check_oom(zSql); |
| 31492 | freeText(&sQuery); |
| 31493 | freeText(&sSql); |
| 31494 | if( bDebug ){ |
| @@ -31684,11 +31708,11 @@ | |
| 31684 | goto meta_command_exit; |
| 31685 | } |
| 31686 | for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ |
| 31687 | const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); |
| 31688 | if( zDbName==0 ) continue; |
| 31689 | if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0); |
| 31690 | if( sqlite3_stricmp(zDbName, "main")==0 ){ |
| 31691 | appendText(&s, "SELECT name FROM ", 0); |
| 31692 | }else{ |
| 31693 | appendText(&s, "SELECT ", 0); |
| 31694 | appendText(&s, zDbName, '\''); |
| @@ -31706,11 +31730,11 @@ | |
| 31706 | } |
| 31707 | } |
| 31708 | rc = sqlite3_finalize(pStmt); |
| 31709 | if( rc==SQLITE_OK ){ |
| 31710 | appendText(&s, " ORDER BY 1", 0); |
| 31711 | rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); |
| 31712 | } |
| 31713 | freeText(&s); |
| 31714 | if( rc ) return shellDatabaseError(p->db); |
| 31715 | |
| 31716 | /* Run the SQL statement prepared by the above block. Store the results |
| 31717 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -1512,31 +1512,31 @@ | |
| 1512 | } |
| 1513 | } |
| 1514 | if( isNeg && v>0x7fffffffffffffffULL ) goto integer_overflow; |
| 1515 | return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v; |
| 1516 | integer_overflow: |
| 1517 | return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL; |
| 1518 | } |
| 1519 | |
| 1520 | /* |
| 1521 | ** A variable length string to which one can append text. |
| 1522 | */ |
| 1523 | typedef struct ShellText ShellText; |
| 1524 | struct ShellText { |
| 1525 | char *zTxt; /* The text */ |
| 1526 | i64 n; /* Number of bytes of zTxt[] actually used */ |
| 1527 | i64 nAlloc; /* Number of bytes allocated for zTxt[] */ |
| 1528 | }; |
| 1529 | |
| 1530 | /* |
| 1531 | ** Initialize and destroy a ShellText object |
| 1532 | */ |
| 1533 | static void initText(ShellText *p){ |
| 1534 | memset(p, 0, sizeof(*p)); |
| 1535 | } |
| 1536 | static void freeText(ShellText *p){ |
| 1537 | sqlite3_free(p->zTxt); |
| 1538 | initText(p); |
| 1539 | } |
| 1540 | |
| 1541 | /* zIn is either a pointer to a NULL-terminated string in memory obtained |
| 1542 | ** from malloc(), or a NULL pointer. The string pointed to by zAppend is |
| @@ -1557,30 +1557,30 @@ | |
| 1557 | for(i=0; i<nAppend; i++){ |
| 1558 | if( zAppend[i]==quote ) len++; |
| 1559 | } |
| 1560 | } |
| 1561 | |
| 1562 | if( p->zTxt==0 || p->n+len>=p->nAlloc ){ |
| 1563 | p->nAlloc = p->nAlloc*2 + len + 20; |
| 1564 | p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc); |
| 1565 | shell_check_oom(p->zTxt); |
| 1566 | } |
| 1567 | |
| 1568 | if( quote ){ |
| 1569 | char *zCsr = p->zTxt+p->n; |
| 1570 | *zCsr++ = quote; |
| 1571 | for(i=0; i<nAppend; i++){ |
| 1572 | *zCsr++ = zAppend[i]; |
| 1573 | if( zAppend[i]==quote ) *zCsr++ = quote; |
| 1574 | } |
| 1575 | *zCsr++ = quote; |
| 1576 | p->n = (i64)(zCsr - p->zTxt); |
| 1577 | *zCsr = '\0'; |
| 1578 | }else{ |
| 1579 | memcpy(p->zTxt+p->n, zAppend, nAppend); |
| 1580 | p->n += nAppend; |
| 1581 | p->zTxt[p->n] = '\0'; |
| 1582 | } |
| 1583 | } |
| 1584 | |
| 1585 | /* |
| 1586 | ** Attempt to determine if identifier zName needs to be quoted, either |
| @@ -1601,10 +1601,13 @@ | |
| 1601 | } |
| 1602 | |
| 1603 | /* |
| 1604 | ** Construct a fake object name and column list to describe the structure |
| 1605 | ** of the view, virtual table, or table valued function zSchema.zName. |
| 1606 | ** |
| 1607 | ** The returned string comes from sqlite3_mprintf() and should be freed |
| 1608 | ** by the caller using sqlite3_free(). |
| 1609 | */ |
| 1610 | static char *shellFakeSchema( |
| 1611 | sqlite3 *db, /* The database connection containing the vtab */ |
| 1612 | const char *zSchema, /* Schema of the database holding the vtab */ |
| 1613 | const char *zName /* The name of the virtual table */ |
| @@ -1641,13 +1644,13 @@ | |
| 1644 | } |
| 1645 | appendText(&s, ")", 0); |
| 1646 | sqlite3_finalize(pStmt); |
| 1647 | if( nRow==0 ){ |
| 1648 | freeText(&s); |
| 1649 | s.zTxt = 0; |
| 1650 | } |
| 1651 | return s.zTxt; |
| 1652 | } |
| 1653 | |
| 1654 | /* |
| 1655 | ** SQL function: strtod(X) |
| 1656 | ** |
| @@ -1746,11 +1749,11 @@ | |
| 1749 | if( z==0 ){ |
| 1750 | z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake); |
| 1751 | }else{ |
| 1752 | z = sqlite3_mprintf("%z\n/* %s */", z, zFake); |
| 1753 | } |
| 1754 | sqlite3_free(zFake); |
| 1755 | } |
| 1756 | if( z ){ |
| 1757 | sqlite3_result_text(pCtx, z, -1, sqlite3_free); |
| 1758 | return; |
| 1759 | } |
| @@ -6993,11 +6996,11 @@ | |
| 6996 | ** The following regular expression syntax is supported: |
| 6997 | ** |
| 6998 | ** X* zero or more occurrences of X |
| 6999 | ** X+ one or more occurrences of X |
| 7000 | ** X? zero or one occurrences of X |
| 7001 | ** X{p,q} between p and q occurrences of X, 0 <= p,q <= 999 |
| 7002 | ** (X) match X |
| 7003 | ** X|Y X or Y |
| 7004 | ** ^X X occurring at the beginning of the string |
| 7005 | ** X$ X occurring at the end of the string |
| 7006 | ** . Match any single character |
| @@ -7022,15 +7025,22 @@ | |
| 7025 | ** expression and M is the size of the input string. The matcher never |
| 7026 | ** exhibits exponential behavior. Note that the X{p,q} operator expands |
| 7027 | ** to p copies of X following by q-p copies of X? and that the size of the |
| 7028 | ** regular expression in the O(N*M) performance bound is computed after |
| 7029 | ** this expansion. |
| 7030 | ** |
| 7031 | ** To help prevent DoS attacks, the values of p and q in the "{p,q}" syntax |
| 7032 | ** are limited to SQLITE_MAX_REGEXP_REPEAT, default 999. |
| 7033 | */ |
| 7034 | #include <string.h> |
| 7035 | #include <stdlib.h> |
| 7036 | /* #include "sqlite3ext.h" */ |
| 7037 | SQLITE_EXTENSION_INIT1 |
| 7038 | |
| 7039 | #ifndef SQLITE_MAX_REGEXP_REPEAT |
| 7040 | # define SQLITE_MAX_REGEXP_REPEAT 999 |
| 7041 | #endif |
| 7042 | |
| 7043 | /* |
| 7044 | ** The following #defines change the names of some functions implemented in |
| 7045 | ** this file to prevent name collisions with C-library functions of the |
| 7046 | ** same name. |
| @@ -7530,22 +7540,30 @@ | |
| 7540 | case '^': { |
| 7541 | re_append(p, RE_OP_ATSTART, 0); |
| 7542 | break; |
| 7543 | } |
| 7544 | case '{': { |
| 7545 | unsigned int m = 0, n = 0; |
| 7546 | unsigned int sz, j; |
| 7547 | if( iPrev<0 ) return "'{m,n}' without operand"; |
| 7548 | while( (c=rePeek(p))>='0' && c<='9' ){ |
| 7549 | m = m*10 + c - '0'; |
| 7550 | if( m>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; |
| 7551 | p->sIn.i++; |
| 7552 | } |
| 7553 | n = m; |
| 7554 | if( c==',' ){ |
| 7555 | p->sIn.i++; |
| 7556 | n = 0; |
| 7557 | while( (c=rePeek(p))>='0' && c<='9' ){ |
| 7558 | n = n*10 + c-'0'; |
| 7559 | if( n>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; |
| 7560 | p->sIn.i++; |
| 7561 | } |
| 7562 | } |
| 7563 | if( c!='}' ) return "unmatched '{'"; |
| 7564 | if( n<m ) return "n less than m in '{m,n}'"; |
| 7565 | p->sIn.i++; |
| 7566 | sz = p->nState - iPrev; |
| 7567 | if( m==0 ){ |
| 7568 | if( n==0 ) return "both m and n are zero in '{m,n}'"; |
| 7569 | re_insert(p, iPrev, RE_OP_FORK, sz+1); |
| @@ -22098,11 +22116,11 @@ | |
| 22116 | */ |
| 22117 | static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ |
| 22118 | int i; |
| 22119 | unsigned char *aBlob = (unsigned char*)pBlob; |
| 22120 | |
| 22121 | char *zStr = sqlite3_malloc64((i64)nBlob*2 + 1); |
| 22122 | shell_check_oom(zStr); |
| 22123 | |
| 22124 | for(i=0; i<nBlob; i++){ |
| 22125 | static const char aHex[] = { |
| 22126 | '0', '1', '2', '3', '4', '5', '6', '7', |
| @@ -23375,11 +23393,16 @@ | |
| 23393 | if( p->zDestTable ){ |
| 23394 | sqlite3_free(p->zDestTable); |
| 23395 | p->zDestTable = 0; |
| 23396 | } |
| 23397 | if( zName==0 ) return; |
| 23398 | if( quoteChar(zName) ){ |
| 23399 | p->zDestTable = sqlite3_mprintf("\"%w\"", zName); |
| 23400 | }else{ |
| 23401 | p->zDestTable = sqlite3_mprintf("%s", zName); |
| 23402 | } |
| 23403 | shell_check_oom(p->zDestTable); |
| 23404 | } |
| 23405 | |
| 23406 | /* |
| 23407 | ** Maybe construct two lines of text that point out the position of a |
| 23408 | ** syntax error. Return a pointer to the text, in memory obtained from |
| @@ -25182,17 +25205,17 @@ | |
| 25205 | appendText(&sSelect, " FROM ", 0); |
| 25206 | appendText(&sSelect, zTable, quoteChar(zTable)); |
| 25207 | |
| 25208 | savedDestTable = p->zDestTable; |
| 25209 | savedMode = p->mode; |
| 25210 | p->zDestTable = sTable.zTxt; |
| 25211 | p->mode = p->cMode = MODE_Insert; |
| 25212 | rc = shell_exec(p, sSelect.zTxt, 0); |
| 25213 | if( (rc&0xff)==SQLITE_CORRUPT ){ |
| 25214 | sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out); |
| 25215 | toggleSelectOrder(p->db); |
| 25216 | shell_exec(p, sSelect.zTxt, 0); |
| 25217 | toggleSelectOrder(p->db); |
| 25218 | } |
| 25219 | p->zDestTable = savedDestTable; |
| 25220 | p->mode = savedMode; |
| 25221 | freeText(&sTable); |
| @@ -25802,14 +25825,14 @@ | |
| 25825 | ** If p->aAuxDb[].zDbFilename is 0, then read from standard input. |
| 25826 | */ |
| 25827 | static unsigned char *readHexDb(ShellState *p, int *pnData){ |
| 25828 | unsigned char *a = 0; |
| 25829 | int nLine; |
| 25830 | int n = 0; /* Size of db per first line of hex dump */ |
| 25831 | i64 sz = 0; /* n rounded up to nearest page boundary */ |
| 25832 | int pgsz = 0; |
| 25833 | i64 iOffset = 0; |
| 25834 | int rc; |
| 25835 | FILE *in; |
| 25836 | const char *zDbFilename = p->pAuxDb->zDbFilename; |
| 25837 | unsigned int x[16]; |
| 25838 | char zLine[1000]; |
| @@ -25829,20 +25852,21 @@ | |
| 25852 | nLine++; |
| 25853 | if( sqlite3_fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; |
| 25854 | rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); |
| 25855 | if( rc!=2 ) goto readHexDb_error; |
| 25856 | if( n<0 ) goto readHexDb_error; |
| 25857 | if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ |
| 25858 | sqlite3_fputs("invalid pagesize\n", stderr); |
| 25859 | goto readHexDb_error; |
| 25860 | } |
| 25861 | sz = ((i64)n+pgsz-1)&~(pgsz-1); /* Round up to nearest multiple of pgsz */ |
| 25862 | a = sqlite3_malloc( sz ? sz : 1 ); |
| 25863 | shell_check_oom(a); |
| 25864 | memset(a, 0, sz); |
| 25865 | for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){ |
| 25866 | int j = 0; /* Page number from "| page" line */ |
| 25867 | int k = 0; /* Offset from "| page" line */ |
| 25868 | rc = sscanf(zLine, "| page %d offset %d", &j, &k); |
| 25869 | if( rc==2 ){ |
| 25870 | iOffset = k; |
| 25871 | continue; |
| 25872 | } |
| @@ -25851,18 +25875,18 @@ | |
| 25875 | } |
| 25876 | rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", |
| 25877 | &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], |
| 25878 | &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); |
| 25879 | if( rc==17 ){ |
| 25880 | i64 iOff = iOffset+j; |
| 25881 | if( iOff+16<=sz && iOff>=0 ){ |
| 25882 | int ii; |
| 25883 | for(ii=0; ii<16; ii++) a[iOff+ii] = x[ii]&0xff; |
| 25884 | } |
| 25885 | } |
| 25886 | } |
| 25887 | *pnData = sz; |
| 25888 | if( in!=p->in ){ |
| 25889 | fclose(in); |
| 25890 | }else{ |
| 25891 | p->lineno = nLine; |
| 25892 | } |
| @@ -25925,11 +25949,11 @@ | |
| 25949 | p->pLog = pSavedLog; |
| 25950 | |
| 25951 | if( zFake ){ |
| 25952 | sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), |
| 25953 | -1, sqlite3_free); |
| 25954 | sqlite3_free(zFake); |
| 25955 | } |
| 25956 | } |
| 25957 | |
| 25958 | /* Flags for open_db(). |
| 25959 | ** |
| @@ -31009,13 +31033,13 @@ | |
| 31033 | appendText(&sSelect, "name NOT LIKE 'sqlite__%%' ESCAPE '_' AND ", 0); |
| 31034 | } |
| 31035 | appendText(&sSelect, "sql IS NOT NULL" |
| 31036 | " ORDER BY snum, rowid", 0); |
| 31037 | if( bDebug ){ |
| 31038 | sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.zTxt); |
| 31039 | }else{ |
| 31040 | rc = sqlite3_exec(p->db, sSelect.zTxt, callback, &data, &zErrMsg); |
| 31041 | } |
| 31042 | freeText(&sSelect); |
| 31043 | } |
| 31044 | if( zErrMsg ){ |
| 31045 | shellEmitError(zErrMsg); |
| @@ -31335,26 +31359,26 @@ | |
| 31359 | sqlite3_fprintf(p->out, "%s\n", zSql); |
| 31360 | }else |
| 31361 | if( cli_strcmp(zOp,"run")==0 ){ |
| 31362 | char *zErrMsg = 0; |
| 31363 | str.n = 0; |
| 31364 | str.zTxt[0] = 0; |
| 31365 | rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); |
| 31366 | nTest++; |
| 31367 | if( bVerbose ){ |
| 31368 | sqlite3_fprintf(p->out, "Result: %s\n", str.zTxt); |
| 31369 | } |
| 31370 | if( rc || zErrMsg ){ |
| 31371 | nErr++; |
| 31372 | rc = 1; |
| 31373 | sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg); |
| 31374 | sqlite3_free(zErrMsg); |
| 31375 | }else if( cli_strcmp(zAns,str.zTxt)!=0 ){ |
| 31376 | nErr++; |
| 31377 | rc = 1; |
| 31378 | sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns); |
| 31379 | sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.zTxt); |
| 31380 | } |
| 31381 | } |
| 31382 | else{ |
| 31383 | sqlite3_fprintf(stderr, |
| 31384 | "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); |
| @@ -31466,11 +31490,11 @@ | |
| 31490 | appendText(&sQuery, "SELECT * FROM ", 0); |
| 31491 | appendText(&sQuery, zTab, 0); |
| 31492 | appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0); |
| 31493 | } |
| 31494 | appendText(&sSql, zSep, 0); |
| 31495 | appendText(&sSql, sQuery.zTxt, '\''); |
| 31496 | sQuery.n = 0; |
| 31497 | appendText(&sSql, ",", 0); |
| 31498 | appendText(&sSql, zTab, '\''); |
| 31499 | zSep = "),("; |
| 31500 | } |
| @@ -31478,17 +31502,17 @@ | |
| 31502 | if( bSeparate ){ |
| 31503 | zSql = sqlite3_mprintf( |
| 31504 | "%s))" |
| 31505 | " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label" |
| 31506 | " FROM [sha3sum$query]", |
| 31507 | sSql.zTxt, iSize); |
| 31508 | }else{ |
| 31509 | zSql = sqlite3_mprintf( |
| 31510 | "%s))" |
| 31511 | " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" |
| 31512 | " FROM [sha3sum$query]", |
| 31513 | sSql.zTxt, iSize); |
| 31514 | } |
| 31515 | shell_check_oom(zSql); |
| 31516 | freeText(&sQuery); |
| 31517 | freeText(&sSql); |
| 31518 | if( bDebug ){ |
| @@ -31684,11 +31708,11 @@ | |
| 31708 | goto meta_command_exit; |
| 31709 | } |
| 31710 | for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ |
| 31711 | const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); |
| 31712 | if( zDbName==0 ) continue; |
| 31713 | if( s.zTxt && s.zTxt[0] ) appendText(&s, " UNION ALL ", 0); |
| 31714 | if( sqlite3_stricmp(zDbName, "main")==0 ){ |
| 31715 | appendText(&s, "SELECT name FROM ", 0); |
| 31716 | }else{ |
| 31717 | appendText(&s, "SELECT ", 0); |
| 31718 | appendText(&s, zDbName, '\''); |
| @@ -31706,11 +31730,11 @@ | |
| 31730 | } |
| 31731 | } |
| 31732 | rc = sqlite3_finalize(pStmt); |
| 31733 | if( rc==SQLITE_OK ){ |
| 31734 | appendText(&s, " ORDER BY 1", 0); |
| 31735 | rc = sqlite3_prepare_v2(p->db, s.zTxt, -1, &pStmt, 0); |
| 31736 | } |
| 31737 | freeText(&s); |
| 31738 | if( rc ) return shellDatabaseError(p->db); |
| 31739 | |
| 31740 | /* Run the SQL statement prepared by the above block. Store the results |
| 31741 |
+55
-71
| --- extsrc/sqlite3.c | ||
| +++ extsrc/sqlite3.c | ||
| @@ -16,11 +16,11 @@ | ||
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | -** 821cc0e421bc14a68ebaee507e38a900e0c8 with changes in files: | |
| 21 | +** 911c745f88c0ee8569e67bbcbbab034264f8 with changes in files: | |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| @@ -467,14 +467,14 @@ | ||
| 467 | 467 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 468 | 468 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 469 | 469 | */ |
| 470 | 470 | #define SQLITE_VERSION "3.51.0" |
| 471 | 471 | #define SQLITE_VERSION_NUMBER 3051000 |
| 472 | -#define SQLITE_SOURCE_ID "2025-09-24 19:10:58 821cc0e421bc14a68ebaee507e38a900e0c84ff6ba7ee95bf796cad387755232" | |
| 472 | +#define SQLITE_SOURCE_ID "2025-09-26 13:14:20 911c745f88c0ee8569e67bbcbbab034264f8c981b505aadac3ce7289486a1a68" | |
| 473 | 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | 474 | #define SQLITE_SCM_TAGS "" |
| 475 | -#define SQLITE_SCM_DATETIME "2025-09-24T19:10:58.215Z" | |
| 475 | +#define SQLITE_SCM_DATETIME "2025-09-26T13:14:20.156Z" | |
| 476 | 476 | |
| 477 | 477 | /* |
| 478 | 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | 480 | ** |
| @@ -21707,11 +21707,11 @@ | ||
| 21707 | 21707 | SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); |
| 21708 | 21708 | SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); |
| 21709 | 21709 | SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); |
| 21710 | 21710 | SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); |
| 21711 | 21711 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 21712 | -SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); | |
| 21712 | +SQLITE_PRIVATE Module *sqlite3JsonVtabRegister(sqlite3*,const char*); | |
| 21713 | 21713 | #endif |
| 21714 | 21714 | SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); |
| 21715 | 21715 | SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); |
| 21716 | 21716 | SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); |
| 21717 | 21717 | SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p); |
| @@ -124262,10 +124262,15 @@ | ||
| 124262 | 124262 | if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ |
| 124263 | 124263 | Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); |
| 124264 | 124264 | if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ |
| 124265 | 124265 | pMod = sqlite3PragmaVtabRegister(db, zName); |
| 124266 | 124266 | } |
| 124267 | +#ifndef SQLITE_OMIT_JSON | |
| 124268 | + if( pMod==0 && sqlite3_strnicmp(zName, "json", 4)==0 ){ | |
| 124269 | + pMod = sqlite3JsonVtabRegister(db, zName); | |
| 124270 | + } | |
| 124271 | +#endif | |
| 124267 | 124272 | if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ |
| 124268 | 124273 | testcase( pMod->pEpoTab==0 ); |
| 124269 | 124274 | return pMod->pEpoTab; |
| 124270 | 124275 | } |
| 124271 | 124276 | } |
| @@ -183862,13 +183867,10 @@ | ||
| 183862 | 183867 | #endif |
| 183863 | 183868 | #ifdef SQLITE_ENABLE_DBSTAT_VTAB |
| 183864 | 183869 | sqlite3DbstatRegister, |
| 183865 | 183870 | #endif |
| 183866 | 183871 | sqlite3TestExtInit, |
| 183867 | -#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) | |
| 183868 | - sqlite3JsonTableFunctions, | |
| 183869 | -#endif | |
| 183870 | 183872 | #ifdef SQLITE_ENABLE_STMTVTAB |
| 183871 | 183873 | sqlite3StmtVtabInit, |
| 183872 | 183874 | #endif |
| 183873 | 183875 | #ifdef SQLITE_ENABLE_BYTECODE_VTAB |
| 183874 | 183876 | sqlite3VdbeBytecodeVtabInit, |
| @@ -211323,11 +211325,11 @@ | ||
| 211323 | 211325 | switch( (u8)zIn[1] ){ |
| 211324 | 211326 | case '\'': |
| 211325 | 211327 | jsonAppendChar(pOut, '\''); |
| 211326 | 211328 | break; |
| 211327 | 211329 | case 'v': |
| 211328 | - jsonAppendRawNZ(pOut, "\\u0009", 6); | |
| 211330 | + jsonAppendRawNZ(pOut, "\\u000b", 6); | |
| 211329 | 211331 | break; |
| 211330 | 211332 | case 'x': |
| 211331 | 211333 | if( sz2<4 ){ |
| 211332 | 211334 | pOut->eErr |= JSTRING_MALFORMED; |
| 211333 | 211335 | sz2 = 2; |
| @@ -212173,23 +212175,31 @@ | ||
| 212173 | 212175 | /* |
| 212174 | 212176 | ** Return the value of the BLOB node at index i. |
| 212175 | 212177 | ** |
| 212176 | 212178 | ** If the value is a primitive, return it as an SQL value. |
| 212177 | 212179 | ** If the value is an array or object, return it as either |
| 212178 | -** JSON text or the BLOB encoding, depending on the JSON_B flag | |
| 212179 | -** on the userdata. | |
| 212180 | +** JSON text or the BLOB encoding, depending on the eMode flag | |
| 212181 | +** as follows: | |
| 212182 | +** | |
| 212183 | +** eMode==0 JSONB if the JSON_B flag is set in userdata or | |
| 212184 | +** text if the JSON_B flag is omitted from userdata. | |
| 212185 | +** | |
| 212186 | +** eMode==1 Text | |
| 212187 | +** | |
| 212188 | +** eMode==2 JSONB | |
| 212180 | 212189 | */ |
| 212181 | 212190 | static void jsonReturnFromBlob( |
| 212182 | 212191 | JsonParse *pParse, /* Complete JSON parse tree */ |
| 212183 | 212192 | u32 i, /* Index of the node */ |
| 212184 | 212193 | sqlite3_context *pCtx, /* Return value for this function */ |
| 212185 | - int textOnly /* return text JSON. Disregard user-data */ | |
| 212194 | + int eMode /* Format of return: text of JSONB */ | |
| 212186 | 212195 | ){ |
| 212187 | 212196 | u32 n, sz; |
| 212188 | 212197 | int rc; |
| 212189 | 212198 | sqlite3 *db = sqlite3_context_db_handle(pCtx); |
| 212190 | 212199 | |
| 212200 | + assert( eMode>=0 && eMode<=2 ); | |
| 212191 | 212201 | n = jsonbPayloadSize(pParse, i, &sz); |
| 212192 | 212202 | if( n==0 ){ |
| 212193 | 212203 | sqlite3_result_error(pCtx, "malformed JSON", -1); |
| 212194 | 212204 | return; |
| 212195 | 212205 | } |
| @@ -212304,12 +212314,18 @@ | ||
| 212304 | 212314 | sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC); |
| 212305 | 212315 | break; |
| 212306 | 212316 | } |
| 212307 | 212317 | case JSONB_ARRAY: |
| 212308 | 212318 | case JSONB_OBJECT: { |
| 212309 | - int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)); | |
| 212310 | - if( flags & JSON_BLOB ){ | |
| 212319 | + if( eMode==0 ){ | |
| 212320 | + if( (SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)) & JSON_BLOB)!=0 ){ | |
| 212321 | + eMode = 2; | |
| 212322 | + }else{ | |
| 212323 | + eMode = 1; | |
| 212324 | + } | |
| 212325 | + } | |
| 212326 | + if( eMode==2 ){ | |
| 212311 | 212327 | sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); |
| 212312 | 212328 | }else{ |
| 212313 | 212329 | jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); |
| 212314 | 212330 | } |
| 212315 | 212331 | break; |
| @@ -213952,10 +213968,11 @@ | ||
| 213952 | 213968 | u32 i; /* Index in sParse.aBlob[] of current row */ |
| 213953 | 213969 | u32 iEnd; /* EOF when i equals or exceeds this value */ |
| 213954 | 213970 | u32 nRoot; /* Size of the root path in bytes */ |
| 213955 | 213971 | u8 eType; /* Type of the container for element i */ |
| 213956 | 213972 | u8 bRecursive; /* True for json_tree(). False for json_each() */ |
| 213973 | + u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */ | |
| 213957 | 213974 | u32 nParent; /* Current nesting depth */ |
| 213958 | 213975 | u32 nParentAlloc; /* Space allocated for aParent[] */ |
| 213959 | 213976 | JsonParent *aParent; /* Parent elements of i */ |
| 213960 | 213977 | sqlite3 *db; /* Database connection */ |
| 213961 | 213978 | JsonString path; /* Current path */ |
| @@ -213963,10 +213980,12 @@ | ||
| 213963 | 213980 | }; |
| 213964 | 213981 | typedef struct JsonEachConnection JsonEachConnection; |
| 213965 | 213982 | struct JsonEachConnection { |
| 213966 | 213983 | sqlite3_vtab base; /* Base class - must be first */ |
| 213967 | 213984 | sqlite3 *db; /* Database connection */ |
| 213985 | + u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */ | |
| 213986 | + u8 bRecursive; /* True for json_tree(). False for json_each() */ | |
| 213968 | 213987 | }; |
| 213969 | 213988 | |
| 213970 | 213989 | |
| 213971 | 213990 | /* Constructor for the json_each virtual table */ |
| 213972 | 213991 | static int jsonEachConnect( |
| @@ -214005,10 +214024,12 @@ | ||
| 214005 | 214024 | pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew)); |
| 214006 | 214025 | *ppVtab = (sqlite3_vtab*)pNew; |
| 214007 | 214026 | if( pNew==0 ) return SQLITE_NOMEM; |
| 214008 | 214027 | sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); |
| 214009 | 214028 | pNew->db = db; |
| 214029 | + pNew->eMode = argv[0][4]=='b' ? 2 : 1; | |
| 214030 | + pNew->bRecursive = argv[0][4+pNew->eMode]=='t'; | |
| 214010 | 214031 | } |
| 214011 | 214032 | return rc; |
| 214012 | 214033 | } |
| 214013 | 214034 | |
| 214014 | 214035 | /* destructor for json_each virtual table */ |
| @@ -214016,34 +214037,26 @@ | ||
| 214016 | 214037 | JsonEachConnection *p = (JsonEachConnection*)pVtab; |
| 214017 | 214038 | sqlite3DbFree(p->db, pVtab); |
| 214018 | 214039 | return SQLITE_OK; |
| 214019 | 214040 | } |
| 214020 | 214041 | |
| 214021 | -/* constructor for a JsonEachCursor object for json_each(). */ | |
| 214022 | -static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ | |
| 214042 | +/* constructor for a JsonEachCursor object for json_each()/json_tree(). */ | |
| 214043 | +static int jsonEachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ | |
| 214023 | 214044 | JsonEachConnection *pVtab = (JsonEachConnection*)p; |
| 214024 | 214045 | JsonEachCursor *pCur; |
| 214025 | 214046 | |
| 214026 | 214047 | UNUSED_PARAMETER(p); |
| 214027 | 214048 | pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); |
| 214028 | 214049 | if( pCur==0 ) return SQLITE_NOMEM; |
| 214029 | 214050 | pCur->db = pVtab->db; |
| 214051 | + pCur->eMode = pVtab->eMode; | |
| 214052 | + pCur->bRecursive = pVtab->bRecursive; | |
| 214030 | 214053 | jsonStringZero(&pCur->path); |
| 214031 | 214054 | *ppCursor = &pCur->base; |
| 214032 | 214055 | return SQLITE_OK; |
| 214033 | 214056 | } |
| 214034 | 214057 | |
| 214035 | -/* constructor for a JsonEachCursor object for json_tree(). */ | |
| 214036 | -static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ | |
| 214037 | - int rc = jsonEachOpenEach(p, ppCursor); | |
| 214038 | - if( rc==SQLITE_OK ){ | |
| 214039 | - JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; | |
| 214040 | - pCur->bRecursive = 1; | |
| 214041 | - } | |
| 214042 | - return rc; | |
| 214043 | -} | |
| 214044 | - | |
| 214045 | 214058 | /* Reset a JsonEachCursor back to its original state. Free any memory |
| 214046 | 214059 | ** held. */ |
| 214047 | 214060 | static void jsonEachCursorReset(JsonEachCursor *p){ |
| 214048 | 214061 | jsonParseReset(&p->sParse); |
| 214049 | 214062 | jsonStringReset(&p->path); |
| @@ -214244,11 +214257,11 @@ | ||
| 214244 | 214257 | } |
| 214245 | 214258 | break; |
| 214246 | 214259 | } |
| 214247 | 214260 | case JEACH_VALUE: { |
| 214248 | 214261 | u32 i = jsonSkipLabel(p); |
| 214249 | - jsonReturnFromBlob(&p->sParse, i, ctx, 1); | |
| 214262 | + jsonReturnFromBlob(&p->sParse, i, ctx, p->eMode); | |
| 214250 | 214263 | if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ |
| 214251 | 214264 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 214252 | 214265 | } |
| 214253 | 214266 | break; |
| 214254 | 214267 | } |
| @@ -214488,40 +214501,11 @@ | ||
| 214488 | 214501 | 0, /* xCreate */ |
| 214489 | 214502 | jsonEachConnect, /* xConnect */ |
| 214490 | 214503 | jsonEachBestIndex, /* xBestIndex */ |
| 214491 | 214504 | jsonEachDisconnect, /* xDisconnect */ |
| 214492 | 214505 | 0, /* xDestroy */ |
| 214493 | - jsonEachOpenEach, /* xOpen - open a cursor */ | |
| 214494 | - jsonEachClose, /* xClose - close a cursor */ | |
| 214495 | - jsonEachFilter, /* xFilter - configure scan constraints */ | |
| 214496 | - jsonEachNext, /* xNext - advance a cursor */ | |
| 214497 | - jsonEachEof, /* xEof - check for end of scan */ | |
| 214498 | - jsonEachColumn, /* xColumn - read data */ | |
| 214499 | - jsonEachRowid, /* xRowid - read data */ | |
| 214500 | - 0, /* xUpdate */ | |
| 214501 | - 0, /* xBegin */ | |
| 214502 | - 0, /* xSync */ | |
| 214503 | - 0, /* xCommit */ | |
| 214504 | - 0, /* xRollback */ | |
| 214505 | - 0, /* xFindMethod */ | |
| 214506 | - 0, /* xRename */ | |
| 214507 | - 0, /* xSavepoint */ | |
| 214508 | - 0, /* xRelease */ | |
| 214509 | - 0, /* xRollbackTo */ | |
| 214510 | - 0, /* xShadowName */ | |
| 214511 | - 0 /* xIntegrity */ | |
| 214512 | -}; | |
| 214513 | - | |
| 214514 | -/* The methods of the json_tree virtual table. */ | |
| 214515 | -static sqlite3_module jsonTreeModule = { | |
| 214516 | - 0, /* iVersion */ | |
| 214517 | - 0, /* xCreate */ | |
| 214518 | - jsonEachConnect, /* xConnect */ | |
| 214519 | - jsonEachBestIndex, /* xBestIndex */ | |
| 214520 | - jsonEachDisconnect, /* xDisconnect */ | |
| 214521 | - 0, /* xDestroy */ | |
| 214522 | - jsonEachOpenTree, /* xOpen - open a cursor */ | |
| 214506 | + jsonEachOpen, /* xOpen - open a cursor */ | |
| 214523 | 214507 | jsonEachClose, /* xClose - close a cursor */ |
| 214524 | 214508 | jsonEachFilter, /* xFilter - configure scan constraints */ |
| 214525 | 214509 | jsonEachNext, /* xNext - advance a cursor */ |
| 214526 | 214510 | jsonEachEof, /* xEof - check for end of scan */ |
| 214527 | 214511 | jsonEachColumn, /* xColumn - read data */ |
| @@ -214606,26 +214590,25 @@ | ||
| 214606 | 214590 | #endif |
| 214607 | 214591 | } |
| 214608 | 214592 | |
| 214609 | 214593 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 214610 | 214594 | /* |
| 214611 | -** Register the JSON table-valued functions | |
| 214595 | +** Register the JSON table-valued function named zName and return a | |
| 214596 | +** pointer to its Module object. Return NULL if something goes wrong. | |
| 214612 | 214597 | */ |
| 214613 | -SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){ | |
| 214614 | - int rc = SQLITE_OK; | |
| 214615 | - static const struct { | |
| 214616 | - const char *zName; | |
| 214617 | - sqlite3_module *pModule; | |
| 214618 | - } aMod[] = { | |
| 214619 | - { "json_each", &jsonEachModule }, | |
| 214620 | - { "json_tree", &jsonTreeModule }, | |
| 214621 | - }; | |
| 214598 | +SQLITE_PRIVATE Module *sqlite3JsonVtabRegister(sqlite3 *db, const char *zName){ | |
| 214622 | 214599 | unsigned int i; |
| 214623 | - for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ | |
| 214624 | - rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); | |
| 214600 | + static const char *azModule[] = { | |
| 214601 | + "json_each", "json_tree", "jsonb_each", "jsonb_tree" | |
| 214602 | + }; | |
| 214603 | + assert( sqlite3HashFind(&db->aModule, zName)==0 ); | |
| 214604 | + for(i=0; i<sizeof(azModule)/sizeof(azModule[0]); i++){ | |
| 214605 | + if( sqlite3StrICmp(azModule[i],zName)==0 ){ | |
| 214606 | + return sqlite3VtabCreateModule(db, azModule[i], &jsonEachModule, 0, 0); | |
| 214607 | + } | |
| 214625 | 214608 | } |
| 214626 | - return rc; | |
| 214609 | + return 0; | |
| 214627 | 214610 | } |
| 214628 | 214611 | #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) */ |
| 214629 | 214612 | |
| 214630 | 214613 | /************** End of json.c ************************************************/ |
| 214631 | 214614 | /************** Begin file rtree.c *******************************************/ |
| @@ -234701,10 +234684,11 @@ | ||
| 234701 | 234684 | } |
| 234702 | 234685 | } |
| 234703 | 234686 | |
| 234704 | 234687 | assert( sApply.bRebase || sApply.rebase.nBuf==0 ); |
| 234705 | 234688 | if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ |
| 234689 | + assert( ppRebase!=0 && pnRebase!=0 ); | |
| 234706 | 234690 | *ppRebase = (void*)sApply.rebase.aBuf; |
| 234707 | 234691 | *pnRebase = sApply.rebase.nBuf; |
| 234708 | 234692 | sApply.rebase.aBuf = 0; |
| 234709 | 234693 | } |
| 234710 | 234694 | sessionUpdateFree(&sApply); |
| @@ -252414,11 +252398,11 @@ | ||
| 252414 | 252398 | u8 tmpSpace[SZ_FTS5STRUCTURE(1)]; |
| 252415 | 252399 | } uFts; |
| 252416 | 252400 | fts5StructureInvalidate(p); |
| 252417 | 252401 | fts5IndexDiscardData(p); |
| 252418 | 252402 | pTmp = &uFts.sFts; |
| 252419 | - memset(pTmp, 0, SZ_FTS5STRUCTURE(1)); | |
| 252403 | + memset(uFts.tmpSpace, 0, sizeof(uFts.tmpSpace)); | |
| 252420 | 252404 | if( p->pConfig->bContentlessDelete ){ |
| 252421 | 252405 | pTmp->nOriginCntr = 1; |
| 252422 | 252406 | } |
| 252423 | 252407 | fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); |
| 252424 | 252408 | fts5StructureWrite(p, pTmp); |
| @@ -258722,11 +258706,11 @@ | ||
| 258722 | 258706 | int nArg, /* Number of args */ |
| 258723 | 258707 | sqlite3_value **apUnused /* Function arguments */ |
| 258724 | 258708 | ){ |
| 258725 | 258709 | assert( nArg==0 ); |
| 258726 | 258710 | UNUSED_PARAM2(nArg, apUnused); |
| 258727 | - sqlite3_result_text(pCtx, "fts5: 2025-09-24 19:10:58 821cc0e421bc14a68ebaee507e38a900e0c84ff6ba7ee95bf796cad387755232", -1, SQLITE_TRANSIENT); | |
| 258711 | + sqlite3_result_text(pCtx, "fts5: 2025-09-26 11:47:13 d022ee167b90a7c32049a93d476e869270018017f60551185024409730d77640", -1, SQLITE_TRANSIENT); | |
| 258728 | 258712 | } |
| 258729 | 258713 | |
| 258730 | 258714 | /* |
| 258731 | 258715 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 258732 | 258716 | ** |
| 258733 | 258717 |
| --- extsrc/sqlite3.c | |
| +++ extsrc/sqlite3.c | |
| @@ -16,11 +16,11 @@ | |
| 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | ** |
| 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | ** 821cc0e421bc14a68ebaee507e38a900e0c8 with changes in files: |
| 22 | ** |
| 23 | ** |
| 24 | */ |
| 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | #define SQLITE_CORE 1 |
| @@ -467,14 +467,14 @@ | |
| 467 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 468 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 469 | */ |
| 470 | #define SQLITE_VERSION "3.51.0" |
| 471 | #define SQLITE_VERSION_NUMBER 3051000 |
| 472 | #define SQLITE_SOURCE_ID "2025-09-24 19:10:58 821cc0e421bc14a68ebaee507e38a900e0c84ff6ba7ee95bf796cad387755232" |
| 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | #define SQLITE_SCM_TAGS "" |
| 475 | #define SQLITE_SCM_DATETIME "2025-09-24T19:10:58.215Z" |
| 476 | |
| 477 | /* |
| 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | ** |
| @@ -21707,11 +21707,11 @@ | |
| 21707 | SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); |
| 21708 | SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); |
| 21709 | SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); |
| 21710 | SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); |
| 21711 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 21712 | SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); |
| 21713 | #endif |
| 21714 | SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); |
| 21715 | SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); |
| 21716 | SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); |
| 21717 | SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p); |
| @@ -124262,10 +124262,15 @@ | |
| 124262 | if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ |
| 124263 | Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); |
| 124264 | if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ |
| 124265 | pMod = sqlite3PragmaVtabRegister(db, zName); |
| 124266 | } |
| 124267 | if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ |
| 124268 | testcase( pMod->pEpoTab==0 ); |
| 124269 | return pMod->pEpoTab; |
| 124270 | } |
| 124271 | } |
| @@ -183862,13 +183867,10 @@ | |
| 183862 | #endif |
| 183863 | #ifdef SQLITE_ENABLE_DBSTAT_VTAB |
| 183864 | sqlite3DbstatRegister, |
| 183865 | #endif |
| 183866 | sqlite3TestExtInit, |
| 183867 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 183868 | sqlite3JsonTableFunctions, |
| 183869 | #endif |
| 183870 | #ifdef SQLITE_ENABLE_STMTVTAB |
| 183871 | sqlite3StmtVtabInit, |
| 183872 | #endif |
| 183873 | #ifdef SQLITE_ENABLE_BYTECODE_VTAB |
| 183874 | sqlite3VdbeBytecodeVtabInit, |
| @@ -211323,11 +211325,11 @@ | |
| 211323 | switch( (u8)zIn[1] ){ |
| 211324 | case '\'': |
| 211325 | jsonAppendChar(pOut, '\''); |
| 211326 | break; |
| 211327 | case 'v': |
| 211328 | jsonAppendRawNZ(pOut, "\\u0009", 6); |
| 211329 | break; |
| 211330 | case 'x': |
| 211331 | if( sz2<4 ){ |
| 211332 | pOut->eErr |= JSTRING_MALFORMED; |
| 211333 | sz2 = 2; |
| @@ -212173,23 +212175,31 @@ | |
| 212173 | /* |
| 212174 | ** Return the value of the BLOB node at index i. |
| 212175 | ** |
| 212176 | ** If the value is a primitive, return it as an SQL value. |
| 212177 | ** If the value is an array or object, return it as either |
| 212178 | ** JSON text or the BLOB encoding, depending on the JSON_B flag |
| 212179 | ** on the userdata. |
| 212180 | */ |
| 212181 | static void jsonReturnFromBlob( |
| 212182 | JsonParse *pParse, /* Complete JSON parse tree */ |
| 212183 | u32 i, /* Index of the node */ |
| 212184 | sqlite3_context *pCtx, /* Return value for this function */ |
| 212185 | int textOnly /* return text JSON. Disregard user-data */ |
| 212186 | ){ |
| 212187 | u32 n, sz; |
| 212188 | int rc; |
| 212189 | sqlite3 *db = sqlite3_context_db_handle(pCtx); |
| 212190 | |
| 212191 | n = jsonbPayloadSize(pParse, i, &sz); |
| 212192 | if( n==0 ){ |
| 212193 | sqlite3_result_error(pCtx, "malformed JSON", -1); |
| 212194 | return; |
| 212195 | } |
| @@ -212304,12 +212314,18 @@ | |
| 212304 | sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC); |
| 212305 | break; |
| 212306 | } |
| 212307 | case JSONB_ARRAY: |
| 212308 | case JSONB_OBJECT: { |
| 212309 | int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)); |
| 212310 | if( flags & JSON_BLOB ){ |
| 212311 | sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); |
| 212312 | }else{ |
| 212313 | jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); |
| 212314 | } |
| 212315 | break; |
| @@ -213952,10 +213968,11 @@ | |
| 213952 | u32 i; /* Index in sParse.aBlob[] of current row */ |
| 213953 | u32 iEnd; /* EOF when i equals or exceeds this value */ |
| 213954 | u32 nRoot; /* Size of the root path in bytes */ |
| 213955 | u8 eType; /* Type of the container for element i */ |
| 213956 | u8 bRecursive; /* True for json_tree(). False for json_each() */ |
| 213957 | u32 nParent; /* Current nesting depth */ |
| 213958 | u32 nParentAlloc; /* Space allocated for aParent[] */ |
| 213959 | JsonParent *aParent; /* Parent elements of i */ |
| 213960 | sqlite3 *db; /* Database connection */ |
| 213961 | JsonString path; /* Current path */ |
| @@ -213963,10 +213980,12 @@ | |
| 213963 | }; |
| 213964 | typedef struct JsonEachConnection JsonEachConnection; |
| 213965 | struct JsonEachConnection { |
| 213966 | sqlite3_vtab base; /* Base class - must be first */ |
| 213967 | sqlite3 *db; /* Database connection */ |
| 213968 | }; |
| 213969 | |
| 213970 | |
| 213971 | /* Constructor for the json_each virtual table */ |
| 213972 | static int jsonEachConnect( |
| @@ -214005,10 +214024,12 @@ | |
| 214005 | pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew)); |
| 214006 | *ppVtab = (sqlite3_vtab*)pNew; |
| 214007 | if( pNew==0 ) return SQLITE_NOMEM; |
| 214008 | sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); |
| 214009 | pNew->db = db; |
| 214010 | } |
| 214011 | return rc; |
| 214012 | } |
| 214013 | |
| 214014 | /* destructor for json_each virtual table */ |
| @@ -214016,34 +214037,26 @@ | |
| 214016 | JsonEachConnection *p = (JsonEachConnection*)pVtab; |
| 214017 | sqlite3DbFree(p->db, pVtab); |
| 214018 | return SQLITE_OK; |
| 214019 | } |
| 214020 | |
| 214021 | /* constructor for a JsonEachCursor object for json_each(). */ |
| 214022 | static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ |
| 214023 | JsonEachConnection *pVtab = (JsonEachConnection*)p; |
| 214024 | JsonEachCursor *pCur; |
| 214025 | |
| 214026 | UNUSED_PARAMETER(p); |
| 214027 | pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); |
| 214028 | if( pCur==0 ) return SQLITE_NOMEM; |
| 214029 | pCur->db = pVtab->db; |
| 214030 | jsonStringZero(&pCur->path); |
| 214031 | *ppCursor = &pCur->base; |
| 214032 | return SQLITE_OK; |
| 214033 | } |
| 214034 | |
| 214035 | /* constructor for a JsonEachCursor object for json_tree(). */ |
| 214036 | static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ |
| 214037 | int rc = jsonEachOpenEach(p, ppCursor); |
| 214038 | if( rc==SQLITE_OK ){ |
| 214039 | JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; |
| 214040 | pCur->bRecursive = 1; |
| 214041 | } |
| 214042 | return rc; |
| 214043 | } |
| 214044 | |
| 214045 | /* Reset a JsonEachCursor back to its original state. Free any memory |
| 214046 | ** held. */ |
| 214047 | static void jsonEachCursorReset(JsonEachCursor *p){ |
| 214048 | jsonParseReset(&p->sParse); |
| 214049 | jsonStringReset(&p->path); |
| @@ -214244,11 +214257,11 @@ | |
| 214244 | } |
| 214245 | break; |
| 214246 | } |
| 214247 | case JEACH_VALUE: { |
| 214248 | u32 i = jsonSkipLabel(p); |
| 214249 | jsonReturnFromBlob(&p->sParse, i, ctx, 1); |
| 214250 | if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ |
| 214251 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 214252 | } |
| 214253 | break; |
| 214254 | } |
| @@ -214488,40 +214501,11 @@ | |
| 214488 | 0, /* xCreate */ |
| 214489 | jsonEachConnect, /* xConnect */ |
| 214490 | jsonEachBestIndex, /* xBestIndex */ |
| 214491 | jsonEachDisconnect, /* xDisconnect */ |
| 214492 | 0, /* xDestroy */ |
| 214493 | jsonEachOpenEach, /* xOpen - open a cursor */ |
| 214494 | jsonEachClose, /* xClose - close a cursor */ |
| 214495 | jsonEachFilter, /* xFilter - configure scan constraints */ |
| 214496 | jsonEachNext, /* xNext - advance a cursor */ |
| 214497 | jsonEachEof, /* xEof - check for end of scan */ |
| 214498 | jsonEachColumn, /* xColumn - read data */ |
| 214499 | jsonEachRowid, /* xRowid - read data */ |
| 214500 | 0, /* xUpdate */ |
| 214501 | 0, /* xBegin */ |
| 214502 | 0, /* xSync */ |
| 214503 | 0, /* xCommit */ |
| 214504 | 0, /* xRollback */ |
| 214505 | 0, /* xFindMethod */ |
| 214506 | 0, /* xRename */ |
| 214507 | 0, /* xSavepoint */ |
| 214508 | 0, /* xRelease */ |
| 214509 | 0, /* xRollbackTo */ |
| 214510 | 0, /* xShadowName */ |
| 214511 | 0 /* xIntegrity */ |
| 214512 | }; |
| 214513 | |
| 214514 | /* The methods of the json_tree virtual table. */ |
| 214515 | static sqlite3_module jsonTreeModule = { |
| 214516 | 0, /* iVersion */ |
| 214517 | 0, /* xCreate */ |
| 214518 | jsonEachConnect, /* xConnect */ |
| 214519 | jsonEachBestIndex, /* xBestIndex */ |
| 214520 | jsonEachDisconnect, /* xDisconnect */ |
| 214521 | 0, /* xDestroy */ |
| 214522 | jsonEachOpenTree, /* xOpen - open a cursor */ |
| 214523 | jsonEachClose, /* xClose - close a cursor */ |
| 214524 | jsonEachFilter, /* xFilter - configure scan constraints */ |
| 214525 | jsonEachNext, /* xNext - advance a cursor */ |
| 214526 | jsonEachEof, /* xEof - check for end of scan */ |
| 214527 | jsonEachColumn, /* xColumn - read data */ |
| @@ -214606,26 +214590,25 @@ | |
| 214606 | #endif |
| 214607 | } |
| 214608 | |
| 214609 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 214610 | /* |
| 214611 | ** Register the JSON table-valued functions |
| 214612 | */ |
| 214613 | SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){ |
| 214614 | int rc = SQLITE_OK; |
| 214615 | static const struct { |
| 214616 | const char *zName; |
| 214617 | sqlite3_module *pModule; |
| 214618 | } aMod[] = { |
| 214619 | { "json_each", &jsonEachModule }, |
| 214620 | { "json_tree", &jsonTreeModule }, |
| 214621 | }; |
| 214622 | unsigned int i; |
| 214623 | for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ |
| 214624 | rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); |
| 214625 | } |
| 214626 | return rc; |
| 214627 | } |
| 214628 | #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) */ |
| 214629 | |
| 214630 | /************** End of json.c ************************************************/ |
| 214631 | /************** Begin file rtree.c *******************************************/ |
| @@ -234701,10 +234684,11 @@ | |
| 234701 | } |
| 234702 | } |
| 234703 | |
| 234704 | assert( sApply.bRebase || sApply.rebase.nBuf==0 ); |
| 234705 | if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ |
| 234706 | *ppRebase = (void*)sApply.rebase.aBuf; |
| 234707 | *pnRebase = sApply.rebase.nBuf; |
| 234708 | sApply.rebase.aBuf = 0; |
| 234709 | } |
| 234710 | sessionUpdateFree(&sApply); |
| @@ -252414,11 +252398,11 @@ | |
| 252414 | u8 tmpSpace[SZ_FTS5STRUCTURE(1)]; |
| 252415 | } uFts; |
| 252416 | fts5StructureInvalidate(p); |
| 252417 | fts5IndexDiscardData(p); |
| 252418 | pTmp = &uFts.sFts; |
| 252419 | memset(pTmp, 0, SZ_FTS5STRUCTURE(1)); |
| 252420 | if( p->pConfig->bContentlessDelete ){ |
| 252421 | pTmp->nOriginCntr = 1; |
| 252422 | } |
| 252423 | fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); |
| 252424 | fts5StructureWrite(p, pTmp); |
| @@ -258722,11 +258706,11 @@ | |
| 258722 | int nArg, /* Number of args */ |
| 258723 | sqlite3_value **apUnused /* Function arguments */ |
| 258724 | ){ |
| 258725 | assert( nArg==0 ); |
| 258726 | UNUSED_PARAM2(nArg, apUnused); |
| 258727 | sqlite3_result_text(pCtx, "fts5: 2025-09-24 19:10:58 821cc0e421bc14a68ebaee507e38a900e0c84ff6ba7ee95bf796cad387755232", -1, SQLITE_TRANSIENT); |
| 258728 | } |
| 258729 | |
| 258730 | /* |
| 258731 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 258732 | ** |
| 258733 |
| --- extsrc/sqlite3.c | |
| +++ extsrc/sqlite3.c | |
| @@ -16,11 +16,11 @@ | |
| 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | ** |
| 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | ** 911c745f88c0ee8569e67bbcbbab034264f8 with changes in files: |
| 22 | ** |
| 23 | ** |
| 24 | */ |
| 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | #define SQLITE_CORE 1 |
| @@ -467,14 +467,14 @@ | |
| 467 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 468 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 469 | */ |
| 470 | #define SQLITE_VERSION "3.51.0" |
| 471 | #define SQLITE_VERSION_NUMBER 3051000 |
| 472 | #define SQLITE_SOURCE_ID "2025-09-26 13:14:20 911c745f88c0ee8569e67bbcbbab034264f8c981b505aadac3ce7289486a1a68" |
| 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | #define SQLITE_SCM_TAGS "" |
| 475 | #define SQLITE_SCM_DATETIME "2025-09-26T13:14:20.156Z" |
| 476 | |
| 477 | /* |
| 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | ** |
| @@ -21707,11 +21707,11 @@ | |
| 21707 | SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); |
| 21708 | SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); |
| 21709 | SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); |
| 21710 | SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); |
| 21711 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 21712 | SQLITE_PRIVATE Module *sqlite3JsonVtabRegister(sqlite3*,const char*); |
| 21713 | #endif |
| 21714 | SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); |
| 21715 | SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); |
| 21716 | SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); |
| 21717 | SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p); |
| @@ -124262,10 +124262,15 @@ | |
| 124262 | if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ |
| 124263 | Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); |
| 124264 | if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ |
| 124265 | pMod = sqlite3PragmaVtabRegister(db, zName); |
| 124266 | } |
| 124267 | #ifndef SQLITE_OMIT_JSON |
| 124268 | if( pMod==0 && sqlite3_strnicmp(zName, "json", 4)==0 ){ |
| 124269 | pMod = sqlite3JsonVtabRegister(db, zName); |
| 124270 | } |
| 124271 | #endif |
| 124272 | if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ |
| 124273 | testcase( pMod->pEpoTab==0 ); |
| 124274 | return pMod->pEpoTab; |
| 124275 | } |
| 124276 | } |
| @@ -183862,13 +183867,10 @@ | |
| 183867 | #endif |
| 183868 | #ifdef SQLITE_ENABLE_DBSTAT_VTAB |
| 183869 | sqlite3DbstatRegister, |
| 183870 | #endif |
| 183871 | sqlite3TestExtInit, |
| 183872 | #ifdef SQLITE_ENABLE_STMTVTAB |
| 183873 | sqlite3StmtVtabInit, |
| 183874 | #endif |
| 183875 | #ifdef SQLITE_ENABLE_BYTECODE_VTAB |
| 183876 | sqlite3VdbeBytecodeVtabInit, |
| @@ -211323,11 +211325,11 @@ | |
| 211325 | switch( (u8)zIn[1] ){ |
| 211326 | case '\'': |
| 211327 | jsonAppendChar(pOut, '\''); |
| 211328 | break; |
| 211329 | case 'v': |
| 211330 | jsonAppendRawNZ(pOut, "\\u000b", 6); |
| 211331 | break; |
| 211332 | case 'x': |
| 211333 | if( sz2<4 ){ |
| 211334 | pOut->eErr |= JSTRING_MALFORMED; |
| 211335 | sz2 = 2; |
| @@ -212173,23 +212175,31 @@ | |
| 212175 | /* |
| 212176 | ** Return the value of the BLOB node at index i. |
| 212177 | ** |
| 212178 | ** If the value is a primitive, return it as an SQL value. |
| 212179 | ** If the value is an array or object, return it as either |
| 212180 | ** JSON text or the BLOB encoding, depending on the eMode flag |
| 212181 | ** as follows: |
| 212182 | ** |
| 212183 | ** eMode==0 JSONB if the JSON_B flag is set in userdata or |
| 212184 | ** text if the JSON_B flag is omitted from userdata. |
| 212185 | ** |
| 212186 | ** eMode==1 Text |
| 212187 | ** |
| 212188 | ** eMode==2 JSONB |
| 212189 | */ |
| 212190 | static void jsonReturnFromBlob( |
| 212191 | JsonParse *pParse, /* Complete JSON parse tree */ |
| 212192 | u32 i, /* Index of the node */ |
| 212193 | sqlite3_context *pCtx, /* Return value for this function */ |
| 212194 | int eMode /* Format of return: text of JSONB */ |
| 212195 | ){ |
| 212196 | u32 n, sz; |
| 212197 | int rc; |
| 212198 | sqlite3 *db = sqlite3_context_db_handle(pCtx); |
| 212199 | |
| 212200 | assert( eMode>=0 && eMode<=2 ); |
| 212201 | n = jsonbPayloadSize(pParse, i, &sz); |
| 212202 | if( n==0 ){ |
| 212203 | sqlite3_result_error(pCtx, "malformed JSON", -1); |
| 212204 | return; |
| 212205 | } |
| @@ -212304,12 +212314,18 @@ | |
| 212314 | sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC); |
| 212315 | break; |
| 212316 | } |
| 212317 | case JSONB_ARRAY: |
| 212318 | case JSONB_OBJECT: { |
| 212319 | if( eMode==0 ){ |
| 212320 | if( (SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)) & JSON_BLOB)!=0 ){ |
| 212321 | eMode = 2; |
| 212322 | }else{ |
| 212323 | eMode = 1; |
| 212324 | } |
| 212325 | } |
| 212326 | if( eMode==2 ){ |
| 212327 | sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); |
| 212328 | }else{ |
| 212329 | jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); |
| 212330 | } |
| 212331 | break; |
| @@ -213952,10 +213968,11 @@ | |
| 213968 | u32 i; /* Index in sParse.aBlob[] of current row */ |
| 213969 | u32 iEnd; /* EOF when i equals or exceeds this value */ |
| 213970 | u32 nRoot; /* Size of the root path in bytes */ |
| 213971 | u8 eType; /* Type of the container for element i */ |
| 213972 | u8 bRecursive; /* True for json_tree(). False for json_each() */ |
| 213973 | u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */ |
| 213974 | u32 nParent; /* Current nesting depth */ |
| 213975 | u32 nParentAlloc; /* Space allocated for aParent[] */ |
| 213976 | JsonParent *aParent; /* Parent elements of i */ |
| 213977 | sqlite3 *db; /* Database connection */ |
| 213978 | JsonString path; /* Current path */ |
| @@ -213963,10 +213980,12 @@ | |
| 213980 | }; |
| 213981 | typedef struct JsonEachConnection JsonEachConnection; |
| 213982 | struct JsonEachConnection { |
| 213983 | sqlite3_vtab base; /* Base class - must be first */ |
| 213984 | sqlite3 *db; /* Database connection */ |
| 213985 | u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */ |
| 213986 | u8 bRecursive; /* True for json_tree(). False for json_each() */ |
| 213987 | }; |
| 213988 | |
| 213989 | |
| 213990 | /* Constructor for the json_each virtual table */ |
| 213991 | static int jsonEachConnect( |
| @@ -214005,10 +214024,12 @@ | |
| 214024 | pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew)); |
| 214025 | *ppVtab = (sqlite3_vtab*)pNew; |
| 214026 | if( pNew==0 ) return SQLITE_NOMEM; |
| 214027 | sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); |
| 214028 | pNew->db = db; |
| 214029 | pNew->eMode = argv[0][4]=='b' ? 2 : 1; |
| 214030 | pNew->bRecursive = argv[0][4+pNew->eMode]=='t'; |
| 214031 | } |
| 214032 | return rc; |
| 214033 | } |
| 214034 | |
| 214035 | /* destructor for json_each virtual table */ |
| @@ -214016,34 +214037,26 @@ | |
| 214037 | JsonEachConnection *p = (JsonEachConnection*)pVtab; |
| 214038 | sqlite3DbFree(p->db, pVtab); |
| 214039 | return SQLITE_OK; |
| 214040 | } |
| 214041 | |
| 214042 | /* constructor for a JsonEachCursor object for json_each()/json_tree(). */ |
| 214043 | static int jsonEachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ |
| 214044 | JsonEachConnection *pVtab = (JsonEachConnection*)p; |
| 214045 | JsonEachCursor *pCur; |
| 214046 | |
| 214047 | UNUSED_PARAMETER(p); |
| 214048 | pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); |
| 214049 | if( pCur==0 ) return SQLITE_NOMEM; |
| 214050 | pCur->db = pVtab->db; |
| 214051 | pCur->eMode = pVtab->eMode; |
| 214052 | pCur->bRecursive = pVtab->bRecursive; |
| 214053 | jsonStringZero(&pCur->path); |
| 214054 | *ppCursor = &pCur->base; |
| 214055 | return SQLITE_OK; |
| 214056 | } |
| 214057 | |
| 214058 | /* Reset a JsonEachCursor back to its original state. Free any memory |
| 214059 | ** held. */ |
| 214060 | static void jsonEachCursorReset(JsonEachCursor *p){ |
| 214061 | jsonParseReset(&p->sParse); |
| 214062 | jsonStringReset(&p->path); |
| @@ -214244,11 +214257,11 @@ | |
| 214257 | } |
| 214258 | break; |
| 214259 | } |
| 214260 | case JEACH_VALUE: { |
| 214261 | u32 i = jsonSkipLabel(p); |
| 214262 | jsonReturnFromBlob(&p->sParse, i, ctx, p->eMode); |
| 214263 | if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ |
| 214264 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 214265 | } |
| 214266 | break; |
| 214267 | } |
| @@ -214488,40 +214501,11 @@ | |
| 214501 | 0, /* xCreate */ |
| 214502 | jsonEachConnect, /* xConnect */ |
| 214503 | jsonEachBestIndex, /* xBestIndex */ |
| 214504 | jsonEachDisconnect, /* xDisconnect */ |
| 214505 | 0, /* xDestroy */ |
| 214506 | jsonEachOpen, /* xOpen - open a cursor */ |
| 214507 | jsonEachClose, /* xClose - close a cursor */ |
| 214508 | jsonEachFilter, /* xFilter - configure scan constraints */ |
| 214509 | jsonEachNext, /* xNext - advance a cursor */ |
| 214510 | jsonEachEof, /* xEof - check for end of scan */ |
| 214511 | jsonEachColumn, /* xColumn - read data */ |
| @@ -214606,26 +214590,25 @@ | |
| 214590 | #endif |
| 214591 | } |
| 214592 | |
| 214593 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) |
| 214594 | /* |
| 214595 | ** Register the JSON table-valued function named zName and return a |
| 214596 | ** pointer to its Module object. Return NULL if something goes wrong. |
| 214597 | */ |
| 214598 | SQLITE_PRIVATE Module *sqlite3JsonVtabRegister(sqlite3 *db, const char *zName){ |
| 214599 | unsigned int i; |
| 214600 | static const char *azModule[] = { |
| 214601 | "json_each", "json_tree", "jsonb_each", "jsonb_tree" |
| 214602 | }; |
| 214603 | assert( sqlite3HashFind(&db->aModule, zName)==0 ); |
| 214604 | for(i=0; i<sizeof(azModule)/sizeof(azModule[0]); i++){ |
| 214605 | if( sqlite3StrICmp(azModule[i],zName)==0 ){ |
| 214606 | return sqlite3VtabCreateModule(db, azModule[i], &jsonEachModule, 0, 0); |
| 214607 | } |
| 214608 | } |
| 214609 | return 0; |
| 214610 | } |
| 214611 | #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) */ |
| 214612 | |
| 214613 | /************** End of json.c ************************************************/ |
| 214614 | /************** Begin file rtree.c *******************************************/ |
| @@ -234701,10 +234684,11 @@ | |
| 234684 | } |
| 234685 | } |
| 234686 | |
| 234687 | assert( sApply.bRebase || sApply.rebase.nBuf==0 ); |
| 234688 | if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ |
| 234689 | assert( ppRebase!=0 && pnRebase!=0 ); |
| 234690 | *ppRebase = (void*)sApply.rebase.aBuf; |
| 234691 | *pnRebase = sApply.rebase.nBuf; |
| 234692 | sApply.rebase.aBuf = 0; |
| 234693 | } |
| 234694 | sessionUpdateFree(&sApply); |
| @@ -252414,11 +252398,11 @@ | |
| 252398 | u8 tmpSpace[SZ_FTS5STRUCTURE(1)]; |
| 252399 | } uFts; |
| 252400 | fts5StructureInvalidate(p); |
| 252401 | fts5IndexDiscardData(p); |
| 252402 | pTmp = &uFts.sFts; |
| 252403 | memset(uFts.tmpSpace, 0, sizeof(uFts.tmpSpace)); |
| 252404 | if( p->pConfig->bContentlessDelete ){ |
| 252405 | pTmp->nOriginCntr = 1; |
| 252406 | } |
| 252407 | fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); |
| 252408 | fts5StructureWrite(p, pTmp); |
| @@ -258722,11 +258706,11 @@ | |
| 258706 | int nArg, /* Number of args */ |
| 258707 | sqlite3_value **apUnused /* Function arguments */ |
| 258708 | ){ |
| 258709 | assert( nArg==0 ); |
| 258710 | UNUSED_PARAM2(nArg, apUnused); |
| 258711 | sqlite3_result_text(pCtx, "fts5: 2025-09-26 11:47:13 d022ee167b90a7c32049a93d476e869270018017f60551185024409730d77640", -1, SQLITE_TRANSIENT); |
| 258712 | } |
| 258713 | |
| 258714 | /* |
| 258715 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 258716 | ** |
| 258717 |
+2
-2
| --- extsrc/sqlite3.h | ||
| +++ extsrc/sqlite3.h | ||
| @@ -146,14 +146,14 @@ | ||
| 146 | 146 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 147 | 147 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 148 | 148 | */ |
| 149 | 149 | #define SQLITE_VERSION "3.51.0" |
| 150 | 150 | #define SQLITE_VERSION_NUMBER 3051000 |
| 151 | -#define SQLITE_SOURCE_ID "2025-09-24 19:10:58 821cc0e421bc14a68ebaee507e38a900e0c84ff6ba7ee95bf796cad387755232" | |
| 151 | +#define SQLITE_SOURCE_ID "2025-09-26 13:14:20 911c745f88c0ee8569e67bbcbbab034264f8c981b505aadac3ce7289486a1a68" | |
| 152 | 152 | #define SQLITE_SCM_BRANCH "trunk" |
| 153 | 153 | #define SQLITE_SCM_TAGS "" |
| 154 | -#define SQLITE_SCM_DATETIME "2025-09-24T19:10:58.215Z" | |
| 154 | +#define SQLITE_SCM_DATETIME "2025-09-26T13:14:20.156Z" | |
| 155 | 155 | |
| 156 | 156 | /* |
| 157 | 157 | ** CAPI3REF: Run-Time Library Version Numbers |
| 158 | 158 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 159 | 159 | ** |
| 160 | 160 |
| --- extsrc/sqlite3.h | |
| +++ extsrc/sqlite3.h | |
| @@ -146,14 +146,14 @@ | |
| 146 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 147 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 148 | */ |
| 149 | #define SQLITE_VERSION "3.51.0" |
| 150 | #define SQLITE_VERSION_NUMBER 3051000 |
| 151 | #define SQLITE_SOURCE_ID "2025-09-24 19:10:58 821cc0e421bc14a68ebaee507e38a900e0c84ff6ba7ee95bf796cad387755232" |
| 152 | #define SQLITE_SCM_BRANCH "trunk" |
| 153 | #define SQLITE_SCM_TAGS "" |
| 154 | #define SQLITE_SCM_DATETIME "2025-09-24T19:10:58.215Z" |
| 155 | |
| 156 | /* |
| 157 | ** CAPI3REF: Run-Time Library Version Numbers |
| 158 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 159 | ** |
| 160 |
| --- extsrc/sqlite3.h | |
| +++ extsrc/sqlite3.h | |
| @@ -146,14 +146,14 @@ | |
| 146 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 147 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 148 | */ |
| 149 | #define SQLITE_VERSION "3.51.0" |
| 150 | #define SQLITE_VERSION_NUMBER 3051000 |
| 151 | #define SQLITE_SOURCE_ID "2025-09-26 13:14:20 911c745f88c0ee8569e67bbcbbab034264f8c981b505aadac3ce7289486a1a68" |
| 152 | #define SQLITE_SCM_BRANCH "trunk" |
| 153 | #define SQLITE_SCM_TAGS "" |
| 154 | #define SQLITE_SCM_DATETIME "2025-09-26T13:14:20.156Z" |
| 155 | |
| 156 | /* |
| 157 | ** CAPI3REF: Run-Time Library Version Numbers |
| 158 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 159 | ** |
| 160 |
+47
-19
| --- src/regexp.c | ||
| +++ src/regexp.c | ||
| @@ -24,11 +24,11 @@ | ||
| 24 | 24 | ** The following regular expression syntax is supported: |
| 25 | 25 | ** |
| 26 | 26 | ** X* zero or more occurrences of X |
| 27 | 27 | ** X+ one or more occurrences of X |
| 28 | 28 | ** X? zero or one occurrences of X |
| 29 | -** X{p,q} between p and q occurrences of X | |
| 29 | +** X{p,q} between p and q occurrences of X, 0 <= p,q <= 999 | |
| 30 | 30 | ** (X) match X |
| 31 | 31 | ** X|Y X or Y |
| 32 | 32 | ** ^X X occurring at the beginning of the string |
| 33 | 33 | ** X$ X occurring at the end of the string |
| 34 | 34 | ** . Match any single character |
| @@ -53,16 +53,24 @@ | ||
| 53 | 53 | ** expression and M is the size of the input string. The matcher never |
| 54 | 54 | ** exhibits exponential behavior. Note that the X{p,q} operator expands |
| 55 | 55 | ** to p copies of X following by q-p copies of X? and that the size of the |
| 56 | 56 | ** regular expression in the O(N*M) performance bound is computed after |
| 57 | 57 | ** this expansion. |
| 58 | +** | |
| 59 | +** To help prevent DoS attacks, the values of p and q in the "{p,q}" syntax | |
| 60 | +** are limited to SQLITE_MAX_REGEXP_REPEAT, default 999. | |
| 58 | 61 | */ |
| 59 | 62 | #include "config.h" |
| 60 | 63 | #include "regexp.h" |
| 64 | + | |
| 65 | +#ifndef SQLITE_MAX_REGEXP_REPEAT | |
| 66 | +# define SQLITE_MAX_REGEXP_REPEAT 999 | |
| 67 | +#endif | |
| 61 | 68 | |
| 62 | 69 | /* The end-of-input character */ |
| 63 | 70 | #define RE_EOF 0 /* End of input */ |
| 71 | +#define RE_START 0xfffffff /* Start of input - larger than an UTF-8 */ | |
| 64 | 72 | |
| 65 | 73 | /* The NFA is implemented as sequence of opcodes taken from the following |
| 66 | 74 | ** set. Each opcode has a single integer argument. |
| 67 | 75 | */ |
| 68 | 76 | #define RE_OP_MATCH 1 /* Match the one character in the argument */ |
| @@ -80,10 +88,11 @@ | ||
| 80 | 88 | #define RE_OP_DIGIT 13 /* digit: [0-9] */ |
| 81 | 89 | #define RE_OP_NOTDIGIT 14 /* Not a digit */ |
| 82 | 90 | #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ |
| 83 | 91 | #define RE_OP_NOTSPACE 16 /* Not a digit */ |
| 84 | 92 | #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ |
| 93 | +#define RE_OP_ATSTART 18 /* Currently at the start of the string */ | |
| 85 | 94 | |
| 86 | 95 | /* Each opcode is a "state" in the NFA */ |
| 87 | 96 | typedef unsigned short ReStateNumber; |
| 88 | 97 | |
| 89 | 98 | /* Because this is an NFA and not a DFA, multiple states can be active at |
| @@ -185,11 +194,11 @@ | ||
| 185 | 194 | ReStateSet aStateSet[2], *pThis, *pNext; |
| 186 | 195 | ReStateNumber aSpace[100]; |
| 187 | 196 | ReStateNumber *pToFree; |
| 188 | 197 | unsigned int i = 0; |
| 189 | 198 | unsigned int iSwap = 0; |
| 190 | - int c = RE_EOF+1; | |
| 199 | + int c = RE_START; | |
| 191 | 200 | int cPrev = 0; |
| 192 | 201 | int rc = 0; |
| 193 | 202 | ReInput in; |
| 194 | 203 | |
| 195 | 204 | in.z = zIn; |
| @@ -204,10 +213,11 @@ | ||
| 204 | 213 | strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) |
| 205 | 214 | ){ |
| 206 | 215 | in.i++; |
| 207 | 216 | } |
| 208 | 217 | if( in.i+pRe->nInit>in.mx ) return 0; |
| 218 | + c = RE_START-1; | |
| 209 | 219 | } |
| 210 | 220 | |
| 211 | 221 | if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ |
| 212 | 222 | pToFree = 0; |
| 213 | 223 | aStateSet[0].aState = aSpace; |
| @@ -231,10 +241,14 @@ | ||
| 231 | 241 | int x = pThis->aState[i]; |
| 232 | 242 | switch( pRe->aOp[x] ){ |
| 233 | 243 | case RE_OP_MATCH: { |
| 234 | 244 | if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); |
| 235 | 245 | break; |
| 246 | + } | |
| 247 | + case RE_OP_ATSTART: { | |
| 248 | + if( cPrev==RE_START ) re_add_state(pThis, x+1); | |
| 249 | + break; | |
| 236 | 250 | } |
| 237 | 251 | case RE_OP_ANY: { |
| 238 | 252 | if( c!=0 ) re_add_state(pNext, x+1); |
| 239 | 253 | break; |
| 240 | 254 | } |
| @@ -313,11 +327,13 @@ | ||
| 313 | 327 | } |
| 314 | 328 | } |
| 315 | 329 | } |
| 316 | 330 | } |
| 317 | 331 | for(i=0; i<pNext->nState; i++){ |
| 318 | - if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } | |
| 332 | + int x = pNext->aState[i]; | |
| 333 | + while( pRe->aOp[x]==RE_OP_GOTO ) x += pRe->aArg[x]; | |
| 334 | + if( pRe->aOp[x]==RE_OP_ACCEPT ){ rc = 1; break; } | |
| 319 | 335 | } |
| 320 | 336 | re_match_end: |
| 321 | 337 | fossil_free(pToFree); |
| 322 | 338 | return rc; |
| 323 | 339 | } |
| @@ -468,11 +484,10 @@ | ||
| 468 | 484 | const char *zErr; |
| 469 | 485 | while( (c = p->xNextChar(&p->sIn))!=0 ){ |
| 470 | 486 | iStart = p->nState; |
| 471 | 487 | switch( c ){ |
| 472 | 488 | case '|': |
| 473 | - case '$': | |
| 474 | 489 | case ')': { |
| 475 | 490 | p->sIn.i--; |
| 476 | 491 | return 0; |
| 477 | 492 | } |
| 478 | 493 | case '(': { |
| @@ -504,29 +519,46 @@ | ||
| 504 | 519 | } |
| 505 | 520 | case '?': { |
| 506 | 521 | if( iPrev<0 ) return "'?' without operand"; |
| 507 | 522 | re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); |
| 508 | 523 | break; |
| 524 | + } | |
| 525 | + case '$': { | |
| 526 | + re_append(p, RE_OP_MATCH, RE_EOF); | |
| 527 | + break; | |
| 528 | + } | |
| 529 | + case '^': { | |
| 530 | + re_append(p, RE_OP_ATSTART, 0); | |
| 531 | + break; | |
| 509 | 532 | } |
| 510 | 533 | case '{': { |
| 511 | - int m = 0, n = 0; | |
| 512 | - int sz, j; | |
| 534 | + unsigned int m = 0, n = 0; | |
| 535 | + unsigned int sz, j; | |
| 513 | 536 | if( iPrev<0 ) return "'{m,n}' without operand"; |
| 514 | - while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } | |
| 537 | + while( (c=rePeek(p))>='0' && c<='9' ){ | |
| 538 | + m = m*10 + c - '0'; | |
| 539 | + if( m>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; | |
| 540 | + p->sIn.i++; | |
| 541 | + } | |
| 515 | 542 | n = m; |
| 516 | 543 | if( c==',' ){ |
| 517 | 544 | p->sIn.i++; |
| 518 | 545 | n = 0; |
| 519 | - while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } | |
| 546 | + while( (c=rePeek(p))>='0' && c<='9' ){ | |
| 547 | + n = n*10 + c-'0'; | |
| 548 | + if( n>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; | |
| 549 | + p->sIn.i++; | |
| 550 | + } | |
| 520 | 551 | } |
| 521 | 552 | if( c!='}' ) return "unmatched '{'"; |
| 522 | 553 | if( n>0 && n<m ) return "n less than m in '{m,n}'"; |
| 523 | 554 | p->sIn.i++; |
| 524 | 555 | sz = p->nState - iPrev; |
| 525 | 556 | if( m==0 ){ |
| 526 | 557 | if( n==0 ) return "both m and n are zero in '{m,n}'"; |
| 527 | 558 | re_insert(p, iPrev, RE_OP_FORK, sz+1); |
| 559 | + iPrev++; | |
| 528 | 560 | n--; |
| 529 | 561 | }else{ |
| 530 | 562 | for(j=1; j<m; j++) re_copy(p, iPrev, sz); |
| 531 | 563 | } |
| 532 | 564 | for(j=m; j<n; j++){ |
| @@ -537,11 +569,11 @@ | ||
| 537 | 569 | re_append(p, RE_OP_FORK, -sz); |
| 538 | 570 | } |
| 539 | 571 | break; |
| 540 | 572 | } |
| 541 | 573 | case '[': { |
| 542 | - int iFirst = p->nState; | |
| 574 | + unsigned int iFirst = p->nState; | |
| 543 | 575 | if( rePeek(p)=='^' ){ |
| 544 | 576 | re_append(p, RE_OP_CC_EXC, 0); |
| 545 | 577 | p->sIn.i++; |
| 546 | 578 | }else{ |
| 547 | 579 | re_append(p, RE_OP_CC_INC, 0); |
| @@ -561,11 +593,11 @@ | ||
| 561 | 593 | re_append(p, RE_OP_CC_VALUE, c); |
| 562 | 594 | } |
| 563 | 595 | if( rePeek(p)==']' ){ p->sIn.i++; break; } |
| 564 | 596 | } |
| 565 | 597 | if( c==0 ) return "unclosed '['"; |
| 566 | - p->aArg[iFirst] = p->nState - iFirst; | |
| 598 | + if( p->nState>iFirst ) p->aArg[iFirst] = p->nState - iFirst; | |
| 567 | 599 | break; |
| 568 | 600 | } |
| 569 | 601 | case '\\': { |
| 570 | 602 | int specialOp = 0; |
| 571 | 603 | switch( rePeek(p) ){ |
| @@ -641,15 +673,11 @@ | ||
| 641 | 673 | zErr = re_subcompile_re(pRe); |
| 642 | 674 | if( zErr ){ |
| 643 | 675 | re_free(pRe); |
| 644 | 676 | return zErr; |
| 645 | 677 | } |
| 646 | - if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ | |
| 647 | - re_append(pRe, RE_OP_MATCH, RE_EOF); | |
| 648 | - re_append(pRe, RE_OP_ACCEPT, 0); | |
| 649 | - *ppRe = pRe; | |
| 650 | - }else if( pRe->sIn.i>=pRe->sIn.mx ){ | |
| 678 | + if( pRe->sIn.i>=pRe->sIn.mx ){ | |
| 651 | 679 | re_append(pRe, RE_OP_ACCEPT, 0); |
| 652 | 680 | *ppRe = pRe; |
| 653 | 681 | }else{ |
| 654 | 682 | re_free(pRe); |
| 655 | 683 | return "unrecognized character"; |
| @@ -658,23 +686,23 @@ | ||
| 658 | 686 | /* The following is a performance optimization. If the regex begins with |
| 659 | 687 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are |
| 660 | 688 | ** one or more matching characters, enter those matching characters into |
| 661 | 689 | ** zInit[]. The re_match() routine can then search ahead in the input |
| 662 | 690 | ** string looking for the initial match without having to run the whole |
| 663 | - ** regex engine over the string. Do not worry able trying to match | |
| 691 | + ** regex engine over the string. Do not worry about trying to match | |
| 664 | 692 | ** unicode characters beyond plane 0 - those are very rare and this is |
| 665 | 693 | ** just an optimization. */ |
| 666 | 694 | if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ |
| 667 | 695 | for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ |
| 668 | 696 | unsigned x = pRe->aArg[i]; |
| 669 | - if( x<=127 ){ | |
| 697 | + if( x<=0x7f ){ | |
| 670 | 698 | pRe->zInit[j++] = (unsigned char)x; |
| 671 | - }else if( x<=0xfff ){ | |
| 699 | + }else if( x<=0x7ff ){ | |
| 672 | 700 | pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); |
| 673 | 701 | pRe->zInit[j++] = 0x80 | (x&0x3f); |
| 674 | 702 | }else if( x<=0xffff ){ |
| 675 | - pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12)); | |
| 703 | + pRe->zInit[j++] = (unsigned char)(0xe0 | (x>>12)); | |
| 676 | 704 | pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); |
| 677 | 705 | pRe->zInit[j++] = 0x80 | (x&0x3f); |
| 678 | 706 | }else{ |
| 679 | 707 | break; |
| 680 | 708 | } |
| 681 | 709 |
| --- src/regexp.c | |
| +++ src/regexp.c | |
| @@ -24,11 +24,11 @@ | |
| 24 | ** The following regular expression syntax is supported: |
| 25 | ** |
| 26 | ** X* zero or more occurrences of X |
| 27 | ** X+ one or more occurrences of X |
| 28 | ** X? zero or one occurrences of X |
| 29 | ** X{p,q} between p and q occurrences of X |
| 30 | ** (X) match X |
| 31 | ** X|Y X or Y |
| 32 | ** ^X X occurring at the beginning of the string |
| 33 | ** X$ X occurring at the end of the string |
| 34 | ** . Match any single character |
| @@ -53,16 +53,24 @@ | |
| 53 | ** expression and M is the size of the input string. The matcher never |
| 54 | ** exhibits exponential behavior. Note that the X{p,q} operator expands |
| 55 | ** to p copies of X following by q-p copies of X? and that the size of the |
| 56 | ** regular expression in the O(N*M) performance bound is computed after |
| 57 | ** this expansion. |
| 58 | */ |
| 59 | #include "config.h" |
| 60 | #include "regexp.h" |
| 61 | |
| 62 | /* The end-of-input character */ |
| 63 | #define RE_EOF 0 /* End of input */ |
| 64 | |
| 65 | /* The NFA is implemented as sequence of opcodes taken from the following |
| 66 | ** set. Each opcode has a single integer argument. |
| 67 | */ |
| 68 | #define RE_OP_MATCH 1 /* Match the one character in the argument */ |
| @@ -80,10 +88,11 @@ | |
| 80 | #define RE_OP_DIGIT 13 /* digit: [0-9] */ |
| 81 | #define RE_OP_NOTDIGIT 14 /* Not a digit */ |
| 82 | #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ |
| 83 | #define RE_OP_NOTSPACE 16 /* Not a digit */ |
| 84 | #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ |
| 85 | |
| 86 | /* Each opcode is a "state" in the NFA */ |
| 87 | typedef unsigned short ReStateNumber; |
| 88 | |
| 89 | /* Because this is an NFA and not a DFA, multiple states can be active at |
| @@ -185,11 +194,11 @@ | |
| 185 | ReStateSet aStateSet[2], *pThis, *pNext; |
| 186 | ReStateNumber aSpace[100]; |
| 187 | ReStateNumber *pToFree; |
| 188 | unsigned int i = 0; |
| 189 | unsigned int iSwap = 0; |
| 190 | int c = RE_EOF+1; |
| 191 | int cPrev = 0; |
| 192 | int rc = 0; |
| 193 | ReInput in; |
| 194 | |
| 195 | in.z = zIn; |
| @@ -204,10 +213,11 @@ | |
| 204 | strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) |
| 205 | ){ |
| 206 | in.i++; |
| 207 | } |
| 208 | if( in.i+pRe->nInit>in.mx ) return 0; |
| 209 | } |
| 210 | |
| 211 | if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ |
| 212 | pToFree = 0; |
| 213 | aStateSet[0].aState = aSpace; |
| @@ -231,10 +241,14 @@ | |
| 231 | int x = pThis->aState[i]; |
| 232 | switch( pRe->aOp[x] ){ |
| 233 | case RE_OP_MATCH: { |
| 234 | if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); |
| 235 | break; |
| 236 | } |
| 237 | case RE_OP_ANY: { |
| 238 | if( c!=0 ) re_add_state(pNext, x+1); |
| 239 | break; |
| 240 | } |
| @@ -313,11 +327,13 @@ | |
| 313 | } |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | for(i=0; i<pNext->nState; i++){ |
| 318 | if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } |
| 319 | } |
| 320 | re_match_end: |
| 321 | fossil_free(pToFree); |
| 322 | return rc; |
| 323 | } |
| @@ -468,11 +484,10 @@ | |
| 468 | const char *zErr; |
| 469 | while( (c = p->xNextChar(&p->sIn))!=0 ){ |
| 470 | iStart = p->nState; |
| 471 | switch( c ){ |
| 472 | case '|': |
| 473 | case '$': |
| 474 | case ')': { |
| 475 | p->sIn.i--; |
| 476 | return 0; |
| 477 | } |
| 478 | case '(': { |
| @@ -504,29 +519,46 @@ | |
| 504 | } |
| 505 | case '?': { |
| 506 | if( iPrev<0 ) return "'?' without operand"; |
| 507 | re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); |
| 508 | break; |
| 509 | } |
| 510 | case '{': { |
| 511 | int m = 0, n = 0; |
| 512 | int sz, j; |
| 513 | if( iPrev<0 ) return "'{m,n}' without operand"; |
| 514 | while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } |
| 515 | n = m; |
| 516 | if( c==',' ){ |
| 517 | p->sIn.i++; |
| 518 | n = 0; |
| 519 | while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } |
| 520 | } |
| 521 | if( c!='}' ) return "unmatched '{'"; |
| 522 | if( n>0 && n<m ) return "n less than m in '{m,n}'"; |
| 523 | p->sIn.i++; |
| 524 | sz = p->nState - iPrev; |
| 525 | if( m==0 ){ |
| 526 | if( n==0 ) return "both m and n are zero in '{m,n}'"; |
| 527 | re_insert(p, iPrev, RE_OP_FORK, sz+1); |
| 528 | n--; |
| 529 | }else{ |
| 530 | for(j=1; j<m; j++) re_copy(p, iPrev, sz); |
| 531 | } |
| 532 | for(j=m; j<n; j++){ |
| @@ -537,11 +569,11 @@ | |
| 537 | re_append(p, RE_OP_FORK, -sz); |
| 538 | } |
| 539 | break; |
| 540 | } |
| 541 | case '[': { |
| 542 | int iFirst = p->nState; |
| 543 | if( rePeek(p)=='^' ){ |
| 544 | re_append(p, RE_OP_CC_EXC, 0); |
| 545 | p->sIn.i++; |
| 546 | }else{ |
| 547 | re_append(p, RE_OP_CC_INC, 0); |
| @@ -561,11 +593,11 @@ | |
| 561 | re_append(p, RE_OP_CC_VALUE, c); |
| 562 | } |
| 563 | if( rePeek(p)==']' ){ p->sIn.i++; break; } |
| 564 | } |
| 565 | if( c==0 ) return "unclosed '['"; |
| 566 | p->aArg[iFirst] = p->nState - iFirst; |
| 567 | break; |
| 568 | } |
| 569 | case '\\': { |
| 570 | int specialOp = 0; |
| 571 | switch( rePeek(p) ){ |
| @@ -641,15 +673,11 @@ | |
| 641 | zErr = re_subcompile_re(pRe); |
| 642 | if( zErr ){ |
| 643 | re_free(pRe); |
| 644 | return zErr; |
| 645 | } |
| 646 | if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ |
| 647 | re_append(pRe, RE_OP_MATCH, RE_EOF); |
| 648 | re_append(pRe, RE_OP_ACCEPT, 0); |
| 649 | *ppRe = pRe; |
| 650 | }else if( pRe->sIn.i>=pRe->sIn.mx ){ |
| 651 | re_append(pRe, RE_OP_ACCEPT, 0); |
| 652 | *ppRe = pRe; |
| 653 | }else{ |
| 654 | re_free(pRe); |
| 655 | return "unrecognized character"; |
| @@ -658,23 +686,23 @@ | |
| 658 | /* The following is a performance optimization. If the regex begins with |
| 659 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are |
| 660 | ** one or more matching characters, enter those matching characters into |
| 661 | ** zInit[]. The re_match() routine can then search ahead in the input |
| 662 | ** string looking for the initial match without having to run the whole |
| 663 | ** regex engine over the string. Do not worry able trying to match |
| 664 | ** unicode characters beyond plane 0 - those are very rare and this is |
| 665 | ** just an optimization. */ |
| 666 | if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ |
| 667 | for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ |
| 668 | unsigned x = pRe->aArg[i]; |
| 669 | if( x<=127 ){ |
| 670 | pRe->zInit[j++] = (unsigned char)x; |
| 671 | }else if( x<=0xfff ){ |
| 672 | pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); |
| 673 | pRe->zInit[j++] = 0x80 | (x&0x3f); |
| 674 | }else if( x<=0xffff ){ |
| 675 | pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12)); |
| 676 | pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); |
| 677 | pRe->zInit[j++] = 0x80 | (x&0x3f); |
| 678 | }else{ |
| 679 | break; |
| 680 | } |
| 681 |
| --- src/regexp.c | |
| +++ src/regexp.c | |
| @@ -24,11 +24,11 @@ | |
| 24 | ** The following regular expression syntax is supported: |
| 25 | ** |
| 26 | ** X* zero or more occurrences of X |
| 27 | ** X+ one or more occurrences of X |
| 28 | ** X? zero or one occurrences of X |
| 29 | ** X{p,q} between p and q occurrences of X, 0 <= p,q <= 999 |
| 30 | ** (X) match X |
| 31 | ** X|Y X or Y |
| 32 | ** ^X X occurring at the beginning of the string |
| 33 | ** X$ X occurring at the end of the string |
| 34 | ** . Match any single character |
| @@ -53,16 +53,24 @@ | |
| 53 | ** expression and M is the size of the input string. The matcher never |
| 54 | ** exhibits exponential behavior. Note that the X{p,q} operator expands |
| 55 | ** to p copies of X following by q-p copies of X? and that the size of the |
| 56 | ** regular expression in the O(N*M) performance bound is computed after |
| 57 | ** this expansion. |
| 58 | ** |
| 59 | ** To help prevent DoS attacks, the values of p and q in the "{p,q}" syntax |
| 60 | ** are limited to SQLITE_MAX_REGEXP_REPEAT, default 999. |
| 61 | */ |
| 62 | #include "config.h" |
| 63 | #include "regexp.h" |
| 64 | |
| 65 | #ifndef SQLITE_MAX_REGEXP_REPEAT |
| 66 | # define SQLITE_MAX_REGEXP_REPEAT 999 |
| 67 | #endif |
| 68 | |
| 69 | /* The end-of-input character */ |
| 70 | #define RE_EOF 0 /* End of input */ |
| 71 | #define RE_START 0xfffffff /* Start of input - larger than an UTF-8 */ |
| 72 | |
| 73 | /* The NFA is implemented as sequence of opcodes taken from the following |
| 74 | ** set. Each opcode has a single integer argument. |
| 75 | */ |
| 76 | #define RE_OP_MATCH 1 /* Match the one character in the argument */ |
| @@ -80,10 +88,11 @@ | |
| 88 | #define RE_OP_DIGIT 13 /* digit: [0-9] */ |
| 89 | #define RE_OP_NOTDIGIT 14 /* Not a digit */ |
| 90 | #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ |
| 91 | #define RE_OP_NOTSPACE 16 /* Not a digit */ |
| 92 | #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ |
| 93 | #define RE_OP_ATSTART 18 /* Currently at the start of the string */ |
| 94 | |
| 95 | /* Each opcode is a "state" in the NFA */ |
| 96 | typedef unsigned short ReStateNumber; |
| 97 | |
| 98 | /* Because this is an NFA and not a DFA, multiple states can be active at |
| @@ -185,11 +194,11 @@ | |
| 194 | ReStateSet aStateSet[2], *pThis, *pNext; |
| 195 | ReStateNumber aSpace[100]; |
| 196 | ReStateNumber *pToFree; |
| 197 | unsigned int i = 0; |
| 198 | unsigned int iSwap = 0; |
| 199 | int c = RE_START; |
| 200 | int cPrev = 0; |
| 201 | int rc = 0; |
| 202 | ReInput in; |
| 203 | |
| 204 | in.z = zIn; |
| @@ -204,10 +213,11 @@ | |
| 213 | strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) |
| 214 | ){ |
| 215 | in.i++; |
| 216 | } |
| 217 | if( in.i+pRe->nInit>in.mx ) return 0; |
| 218 | c = RE_START-1; |
| 219 | } |
| 220 | |
| 221 | if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ |
| 222 | pToFree = 0; |
| 223 | aStateSet[0].aState = aSpace; |
| @@ -231,10 +241,14 @@ | |
| 241 | int x = pThis->aState[i]; |
| 242 | switch( pRe->aOp[x] ){ |
| 243 | case RE_OP_MATCH: { |
| 244 | if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); |
| 245 | break; |
| 246 | } |
| 247 | case RE_OP_ATSTART: { |
| 248 | if( cPrev==RE_START ) re_add_state(pThis, x+1); |
| 249 | break; |
| 250 | } |
| 251 | case RE_OP_ANY: { |
| 252 | if( c!=0 ) re_add_state(pNext, x+1); |
| 253 | break; |
| 254 | } |
| @@ -313,11 +327,13 @@ | |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | for(i=0; i<pNext->nState; i++){ |
| 332 | int x = pNext->aState[i]; |
| 333 | while( pRe->aOp[x]==RE_OP_GOTO ) x += pRe->aArg[x]; |
| 334 | if( pRe->aOp[x]==RE_OP_ACCEPT ){ rc = 1; break; } |
| 335 | } |
| 336 | re_match_end: |
| 337 | fossil_free(pToFree); |
| 338 | return rc; |
| 339 | } |
| @@ -468,11 +484,10 @@ | |
| 484 | const char *zErr; |
| 485 | while( (c = p->xNextChar(&p->sIn))!=0 ){ |
| 486 | iStart = p->nState; |
| 487 | switch( c ){ |
| 488 | case '|': |
| 489 | case ')': { |
| 490 | p->sIn.i--; |
| 491 | return 0; |
| 492 | } |
| 493 | case '(': { |
| @@ -504,29 +519,46 @@ | |
| 519 | } |
| 520 | case '?': { |
| 521 | if( iPrev<0 ) return "'?' without operand"; |
| 522 | re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); |
| 523 | break; |
| 524 | } |
| 525 | case '$': { |
| 526 | re_append(p, RE_OP_MATCH, RE_EOF); |
| 527 | break; |
| 528 | } |
| 529 | case '^': { |
| 530 | re_append(p, RE_OP_ATSTART, 0); |
| 531 | break; |
| 532 | } |
| 533 | case '{': { |
| 534 | unsigned int m = 0, n = 0; |
| 535 | unsigned int sz, j; |
| 536 | if( iPrev<0 ) return "'{m,n}' without operand"; |
| 537 | while( (c=rePeek(p))>='0' && c<='9' ){ |
| 538 | m = m*10 + c - '0'; |
| 539 | if( m>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; |
| 540 | p->sIn.i++; |
| 541 | } |
| 542 | n = m; |
| 543 | if( c==',' ){ |
| 544 | p->sIn.i++; |
| 545 | n = 0; |
| 546 | while( (c=rePeek(p))>='0' && c<='9' ){ |
| 547 | n = n*10 + c-'0'; |
| 548 | if( n>SQLITE_MAX_REGEXP_REPEAT ) return "integer too large"; |
| 549 | p->sIn.i++; |
| 550 | } |
| 551 | } |
| 552 | if( c!='}' ) return "unmatched '{'"; |
| 553 | if( n>0 && n<m ) return "n less than m in '{m,n}'"; |
| 554 | p->sIn.i++; |
| 555 | sz = p->nState - iPrev; |
| 556 | if( m==0 ){ |
| 557 | if( n==0 ) return "both m and n are zero in '{m,n}'"; |
| 558 | re_insert(p, iPrev, RE_OP_FORK, sz+1); |
| 559 | iPrev++; |
| 560 | n--; |
| 561 | }else{ |
| 562 | for(j=1; j<m; j++) re_copy(p, iPrev, sz); |
| 563 | } |
| 564 | for(j=m; j<n; j++){ |
| @@ -537,11 +569,11 @@ | |
| 569 | re_append(p, RE_OP_FORK, -sz); |
| 570 | } |
| 571 | break; |
| 572 | } |
| 573 | case '[': { |
| 574 | unsigned int iFirst = p->nState; |
| 575 | if( rePeek(p)=='^' ){ |
| 576 | re_append(p, RE_OP_CC_EXC, 0); |
| 577 | p->sIn.i++; |
| 578 | }else{ |
| 579 | re_append(p, RE_OP_CC_INC, 0); |
| @@ -561,11 +593,11 @@ | |
| 593 | re_append(p, RE_OP_CC_VALUE, c); |
| 594 | } |
| 595 | if( rePeek(p)==']' ){ p->sIn.i++; break; } |
| 596 | } |
| 597 | if( c==0 ) return "unclosed '['"; |
| 598 | if( p->nState>iFirst ) p->aArg[iFirst] = p->nState - iFirst; |
| 599 | break; |
| 600 | } |
| 601 | case '\\': { |
| 602 | int specialOp = 0; |
| 603 | switch( rePeek(p) ){ |
| @@ -641,15 +673,11 @@ | |
| 673 | zErr = re_subcompile_re(pRe); |
| 674 | if( zErr ){ |
| 675 | re_free(pRe); |
| 676 | return zErr; |
| 677 | } |
| 678 | if( pRe->sIn.i>=pRe->sIn.mx ){ |
| 679 | re_append(pRe, RE_OP_ACCEPT, 0); |
| 680 | *ppRe = pRe; |
| 681 | }else{ |
| 682 | re_free(pRe); |
| 683 | return "unrecognized character"; |
| @@ -658,23 +686,23 @@ | |
| 686 | /* The following is a performance optimization. If the regex begins with |
| 687 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are |
| 688 | ** one or more matching characters, enter those matching characters into |
| 689 | ** zInit[]. The re_match() routine can then search ahead in the input |
| 690 | ** string looking for the initial match without having to run the whole |
| 691 | ** regex engine over the string. Do not worry about trying to match |
| 692 | ** unicode characters beyond plane 0 - those are very rare and this is |
| 693 | ** just an optimization. */ |
| 694 | if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ |
| 695 | for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ |
| 696 | unsigned x = pRe->aArg[i]; |
| 697 | if( x<=0x7f ){ |
| 698 | pRe->zInit[j++] = (unsigned char)x; |
| 699 | }else if( x<=0x7ff ){ |
| 700 | pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); |
| 701 | pRe->zInit[j++] = 0x80 | (x&0x3f); |
| 702 | }else if( x<=0xffff ){ |
| 703 | pRe->zInit[j++] = (unsigned char)(0xe0 | (x>>12)); |
| 704 | pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); |
| 705 | pRe->zInit[j++] = 0x80 | (x&0x3f); |
| 706 | }else{ |
| 707 | break; |
| 708 | } |
| 709 |
+5
| --- www/grep.md | ||
| +++ www/grep.md | ||
| @@ -99,10 +99,15 @@ | ||
| 99 | 99 | There are several restrictions in Fossil `grep` relative to a fully |
| 100 | 100 | POSIX compatible regular expression engine. Among them are: |
| 101 | 101 | |
| 102 | 102 | * There is currently no support for POSIX character classes such as |
| 103 | 103 | `[:lower:]`. |
| 104 | + | |
| 105 | +* The values of `p` and `q` in the "`{p,q}`" syntax can be no greater | |
| 106 | + than 999. This is because the NFA that is used for regular expression | |
| 107 | + matching is proportional in size to the largest p or q value, and hence | |
| 108 | + allowing arbitrarily large values could result in a DoS attack. | |
| 104 | 109 | |
| 105 | 110 | * Fossil `grep` does not currently attempt to take your operating |
| 106 | 111 | system's locale settings into account when doing this match. Since |
| 107 | 112 | Fossil has no way to mark a given file as having a particular |
| 108 | 113 | encoding, Fossil `grep` assumes the input files are in UTF-8 format. |
| 109 | 114 |
| --- www/grep.md | |
| +++ www/grep.md | |
| @@ -99,10 +99,15 @@ | |
| 99 | There are several restrictions in Fossil `grep` relative to a fully |
| 100 | POSIX compatible regular expression engine. Among them are: |
| 101 | |
| 102 | * There is currently no support for POSIX character classes such as |
| 103 | `[:lower:]`. |
| 104 | |
| 105 | * Fossil `grep` does not currently attempt to take your operating |
| 106 | system's locale settings into account when doing this match. Since |
| 107 | Fossil has no way to mark a given file as having a particular |
| 108 | encoding, Fossil `grep` assumes the input files are in UTF-8 format. |
| 109 |
| --- www/grep.md | |
| +++ www/grep.md | |
| @@ -99,10 +99,15 @@ | |
| 99 | There are several restrictions in Fossil `grep` relative to a fully |
| 100 | POSIX compatible regular expression engine. Among them are: |
| 101 | |
| 102 | * There is currently no support for POSIX character classes such as |
| 103 | `[:lower:]`. |
| 104 | |
| 105 | * The values of `p` and `q` in the "`{p,q}`" syntax can be no greater |
| 106 | than 999. This is because the NFA that is used for regular expression |
| 107 | matching is proportional in size to the largest p or q value, and hence |
| 108 | allowing arbitrarily large values could result in a DoS attack. |
| 109 | |
| 110 | * Fossil `grep` does not currently attempt to take your operating |
| 111 | system's locale settings into account when doing this match. Since |
| 112 | Fossil has no way to mark a given file as having a particular |
| 113 | encoding, Fossil `grep` assumes the input files are in UTF-8 format. |
| 114 |