Fossil SCM
Merge trunk into rss-content.
Commit
f118634c5caefd1fcae765b2298eb86e9a8378046e3e9db8e7c83c90d34c005b
Parent
d7d3fdab9e3b1a1…
74 files changed
+1
-2
+440
-282
+1551
-532
+32
-8
+17
-41
+43
-73
+30
-37
+72
-10
+1
-1
+1199
-181
+20
-1
+1
-1
+2
+3
-2
+4
+2
+1
+37
-8
+2
-1
+177
-1
+26
-14
+12
-11
+16
-4
+1
-1
+14
-7
+1
-1
+1301
-214
+1301
-214
+663
+8
-5
+4
+1295
-35
+5
-6
+10
-10
+62
-7
+3
-2
+101
-38
+3
-1
+2
-1
+6
-1
+98
-53
+39
-3
+61
-21
+128
-1
+251
-58
+2
-2
+1
-1
+4
+4
+13
-3
+34
+17
-2
+22
-3
+33
+107
-27
+18
+11
-6
+2
-2
+11
-39
+11
-39
+16
-15
+115
-43
+4
-1
+2
+4
+45
-36
+26
+2
-2
+28
-10
+193
-1
+142
-119
+6
-6
+3
-1
+3
-3
~
extsrc/qrf.h
~
extsrc/shell.c
~
extsrc/sqlite3.c
~
extsrc/sqlite3.h
~
skins/ardoise/css.txt
~
skins/blitz/css.txt
~
skins/darkmode/css.txt
~
src/ajax.c
~
src/alerts.c
~
src/attach.c
~
src/builtin.c
~
src/bundle.c
~
src/capabilities.c
~
src/cgi.c
~
src/checkin.c
~
src/comformat.c
~
src/configure.c
~
src/content.c
~
src/db.c
~
src/default.css
~
src/delta.c
~
src/deltafunc.c
~
src/diff.tcl
~
src/diffcmd.c
~
src/event.c
~
src/finfo.c
~
src/forum.c
~
src/forum.c
~
src/fossil.attach.js
~
src/fossil.bootstrap.js
~
src/fossil.dom.js
~
src/fossil.page.forumpost.js
~
src/fossil.page.wikiedit.js
~
src/fossil.popupwidget.js
~
src/fossil.storage.js
~
src/fossil.tabs.js
~
src/info.c
~
src/login.c
~
src/main.c
~
src/main.mk
~
src/manifest.c
~
src/markdown.md
~
src/merge.c
~
src/moderate.c
~
src/name.c
~
src/schema.c
~
src/setup.c
~
src/setupuser.c
~
src/sqlcmd.c
~
src/stash.c
~
src/stat.c
~
src/statrep.c
~
src/style.c
~
src/style.forum.css
~
src/tag.c
~
src/timeline.c
~
src/tkt.c
~
src/util.c
~
src/wiki.c
~
src/wiki.c
~
src/wiki.wiki
~
src/wikiformat.c
~
tools/makemake.tcl
~
win/Makefile.mingw
~
win/Makefile.msc
~
www/caps/ref.html
~
www/changes.wiki
~
www/customskin.md
~
www/fileformat.wiki
~
www/forum.wiki
~
www/fossil-v-git.wiki
~
www/javascript.md
~
www/server/any/cgi.md
~
www/sync.wiki
+1
-2
| --- extsrc/qrf.h | ||
| +++ extsrc/qrf.h | ||
| @@ -68,12 +68,11 @@ | ||
| 68 | 68 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 69 | 69 | char **pzErr /* OUT: Write error message here */ |
| 70 | 70 | ); |
| 71 | 71 | |
| 72 | 72 | /* |
| 73 | -** Range of values for sqlite3_qrf_spec.aWidth[] entries and for | |
| 74 | -** sqlite3_qrf_spec.mxColWidth and .nScreenWidth | |
| 73 | +** Range of values for sqlite3_qrf_spec.aWidth[] entries. | |
| 75 | 74 | */ |
| 76 | 75 | #define QRF_MAX_WIDTH 10000 |
| 77 | 76 | #define QRF_MIN_WIDTH 0 |
| 78 | 77 | |
| 79 | 78 | /* |
| 80 | 79 |
| --- extsrc/qrf.h | |
| +++ extsrc/qrf.h | |
| @@ -68,12 +68,11 @@ | |
| 68 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 69 | char **pzErr /* OUT: Write error message here */ |
| 70 | ); |
| 71 | |
| 72 | /* |
| 73 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries and for |
| 74 | ** sqlite3_qrf_spec.mxColWidth and .nScreenWidth |
| 75 | */ |
| 76 | #define QRF_MAX_WIDTH 10000 |
| 77 | #define QRF_MIN_WIDTH 0 |
| 78 | |
| 79 | /* |
| 80 |
| --- extsrc/qrf.h | |
| +++ extsrc/qrf.h | |
| @@ -68,12 +68,11 @@ | |
| 68 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 69 | char **pzErr /* OUT: Write error message here */ |
| 70 | ); |
| 71 | |
| 72 | /* |
| 73 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries. |
| 74 | */ |
| 75 | #define QRF_MAX_WIDTH 10000 |
| 76 | #define QRF_MIN_WIDTH 0 |
| 77 | |
| 78 | /* |
| 79 |
+440
-282
| --- extsrc/shell.c | ||
| +++ extsrc/shell.c | ||
| @@ -5,16 +5,16 @@ | ||
| 5 | 5 | ** |
| 6 | 6 | ** ext/expert/sqlite3expert.c |
| 7 | 7 | ** ext/expert/sqlite3expert.h |
| 8 | 8 | ** ext/intck/sqlite3intck.c |
| 9 | 9 | ** ext/intck/sqlite3intck.h |
| 10 | -** ext/misc/analyze.c | |
| 11 | 10 | ** ext/misc/appendvfs.c |
| 12 | 11 | ** ext/misc/base64.c |
| 13 | 12 | ** ext/misc/base85.c |
| 14 | 13 | ** ext/misc/completion.c |
| 15 | 14 | ** ext/misc/decimal.c |
| 15 | +** ext/misc/diskused.c | |
| 16 | 16 | ** ext/misc/fileio.c |
| 17 | 17 | ** ext/misc/ieee754.c |
| 18 | 18 | ** ext/misc/memtrace.c |
| 19 | 19 | ** ext/misc/pcachetrace.c |
| 20 | 20 | ** ext/misc/regexp.c |
| @@ -154,10 +154,11 @@ | ||
| 154 | 154 | #include <string.h> |
| 155 | 155 | #include <stdio.h> |
| 156 | 156 | #include <assert.h> |
| 157 | 157 | #include <math.h> |
| 158 | 158 | #include <stdint.h> |
| 159 | +#include <time.h> | |
| 159 | 160 | #include "sqlite3.h" |
| 160 | 161 | typedef sqlite3_int64 i64; |
| 161 | 162 | typedef sqlite3_uint64 u64; |
| 162 | 163 | typedef unsigned char u8; |
| 163 | 164 | #include <ctype.h> |
| @@ -190,13 +191,14 @@ | ||
| 190 | 191 | #include <sys/stat.h> |
| 191 | 192 | |
| 192 | 193 | #if HAVE_READLINE |
| 193 | 194 | # include <readline/readline.h> |
| 194 | 195 | # include <readline/history.h> |
| 195 | -#endif | |
| 196 | - | |
| 197 | -#if HAVE_EDITLINE | |
| 196 | +#elif HAVE_EDITLINE | |
| 197 | +/* If both HAVE_READLINE and HAVE_EDITLINE are true, assume that this | |
| 198 | +** libedit installation does not have its own headers, instead using | |
| 199 | +** those from libreadline. */ | |
| 198 | 200 | # include <editline/readline.h> |
| 199 | 201 | #endif |
| 200 | 202 | |
| 201 | 203 | #if HAVE_EDITLINE || HAVE_READLINE |
| 202 | 204 | |
| @@ -744,12 +746,11 @@ | ||
| 744 | 746 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 745 | 747 | char **pzErr /* OUT: Write error message here */ |
| 746 | 748 | ); |
| 747 | 749 | |
| 748 | 750 | /* |
| 749 | -** Range of values for sqlite3_qrf_spec.aWidth[] entries and for | |
| 750 | -** sqlite3_qrf_spec.mxColWidth and .nScreenWidth | |
| 751 | +** Range of values for sqlite3_qrf_spec.aWidth[] entries. | |
| 751 | 752 | */ |
| 752 | 753 | #define QRF_MAX_WIDTH 10000 |
| 753 | 754 | #define QRF_MIN_WIDTH 0 |
| 754 | 755 | |
| 755 | 756 | /* |
| @@ -1129,10 +1130,14 @@ | ||
| 1129 | 1130 | sqlite3_str_append(pOut, "-", 1); |
| 1130 | 1131 | } |
| 1131 | 1132 | if( N<10000 ){ |
| 1132 | 1133 | sqlite3_str_appendf(pOut, "%4lld ", N); |
| 1133 | 1134 | return; |
| 1135 | + } | |
| 1136 | + if( N>=9223372036854775800LL ){ | |
| 1137 | + sqlite3_str_appendf(pOut, "%.2fE", 1e-18*(double)N); | |
| 1138 | + return; | |
| 1134 | 1139 | } |
| 1135 | 1140 | for(i=1; i<=18; i++){ |
| 1136 | 1141 | N = (N+5)/10; |
| 1137 | 1142 | if( N<10000 ){ |
| 1138 | 1143 | int n = (int)N; |
| @@ -1289,12 +1294,12 @@ | ||
| 1289 | 1294 | if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ |
| 1290 | 1295 | int nSp = 0; |
| 1291 | 1296 | sqlite3_str_reset(pStats); |
| 1292 | 1297 | if( nCycle>=0 && nTotal>0 ){ |
| 1293 | 1298 | qrfApproxInt64(pStats, nCycle); |
| 1294 | - sqlite3_str_appendf(pStats, " %3d%%", | |
| 1295 | - ((nCycle*100)+nTotal/2) / nTotal | |
| 1299 | + sqlite3_str_appendf(pStats, " %3.0f%%", | |
| 1300 | + ((100.0*(double)nCycle)+nTotal/2.0) / (double)nTotal | |
| 1296 | 1301 | ); |
| 1297 | 1302 | nSp = 2; |
| 1298 | 1303 | } |
| 1299 | 1304 | if( nLoop>=0 ){ |
| 1300 | 1305 | if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); |
| @@ -1787,11 +1792,11 @@ | ||
| 1787 | 1792 | } |
| 1788 | 1793 | if( i>0 ){ |
| 1789 | 1794 | sqlite3_str_append(pOut, (const char*)z, i); |
| 1790 | 1795 | } |
| 1791 | 1796 | switch( z[i] ){ |
| 1792 | - case '>': sqlite3_str_append(pOut, "<", 4); break; | |
| 1797 | + case '>': sqlite3_str_append(pOut, ">", 4); break; | |
| 1793 | 1798 | case '&': sqlite3_str_append(pOut, "&", 5); break; |
| 1794 | 1799 | case '<': sqlite3_str_append(pOut, "<", 4); break; |
| 1795 | 1800 | case '"': sqlite3_str_append(pOut, """, 6); break; |
| 1796 | 1801 | case '\'': sqlite3_str_append(pOut, "'", 5); break; |
| 1797 | 1802 | default: i--; |
| @@ -2281,11 +2286,11 @@ | ||
| 2281 | 2286 | if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ |
| 2282 | 2287 | /* Perhaps try to back up to a better place to break the line */ |
| 2283 | 2288 | for(k=i-1; k>=i/2; k--){ |
| 2284 | 2289 | if( qrfSpace(z[k]) ) break; |
| 2285 | 2290 | } |
| 2286 | - if( k<i/2 ){ | |
| 2291 | + if( k<i/2 && i/2>0 ){ | |
| 2287 | 2292 | for(k=i; k>=i/2; k--){ |
| 2288 | 2293 | if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; |
| 2289 | 2294 | } |
| 2290 | 2295 | } |
| 2291 | 2296 | if( k>=i/2 ){ |
| @@ -2532,16 +2537,16 @@ | ||
| 2532 | 2537 | const char *azDash[2] = { |
| 2533 | 2538 | BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, |
| 2534 | 2539 | DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 |
| 2535 | 2540 | };/* 0 1 2 3 4 5 6 7 8 9 */ |
| 2536 | 2541 | const int nDash = 30; |
| 2537 | - N *= 3; | |
| 2538 | - while( N>nDash ){ | |
| 2542 | + i64 nn = 3*(i64)N; | |
| 2543 | + while( nn>nDash ){ | |
| 2539 | 2544 | sqlite3_str_append(pOut, azDash[bDbl], nDash); |
| 2540 | - N -= nDash; | |
| 2545 | + nn -= nDash; | |
| 2541 | 2546 | } |
| 2542 | - sqlite3_str_append(pOut, azDash[bDbl], N); | |
| 2547 | + sqlite3_str_append(pOut, azDash[bDbl], (int)nn); | |
| 2543 | 2548 | } |
| 2544 | 2549 | |
| 2545 | 2550 | /* |
| 2546 | 2551 | ** Draw a horizontal separator for a QRF_STYLE_Box table. |
| 2547 | 2552 | */ |
| @@ -2610,11 +2615,11 @@ | ||
| 2610 | 2615 | int nSW /* Screen width */ |
| 2611 | 2616 | ){ |
| 2612 | 2617 | int i; /* Loop counter */ |
| 2613 | 2618 | int nr; /* Number of rows */ |
| 2614 | 2619 | int w = 0; /* Width of the current column */ |
| 2615 | - int t; /* Total width of all columns */ | |
| 2620 | + i64 t; /* Total width of all columns */ | |
| 2616 | 2621 | int *aw; /* Array of individual column widths */ |
| 2617 | 2622 | |
| 2618 | 2623 | aw = sqlite3_malloc64( sizeof(int)*nCol ); |
| 2619 | 2624 | if( aw==0 ){ |
| 2620 | 2625 | qrfOom(p); |
| @@ -2748,12 +2753,15 @@ | ||
| 2748 | 2753 | }else{ |
| 2749 | 2754 | sepW = pData->nCol*3 + 1; |
| 2750 | 2755 | if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2751 | 2756 | } |
| 2752 | 2757 | nCol = pData->nCol; |
| 2753 | - for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w; | |
| 2754 | - if( p->spec.nScreenWidth >= sumW+sepW ) return; | |
| 2758 | + for(i=0, sumW=0; i<nCol; i++){ | |
| 2759 | + if( sumW > 2147483647 - pData->a[i].w ) return; | |
| 2760 | + sumW += pData->a[i].w; | |
| 2761 | + } | |
| 2762 | + if( p->spec.nScreenWidth >= (i64)sumW + sepW ) return; | |
| 2755 | 2763 | |
| 2756 | 2764 | /* First thing to do is reduce the separation between columns */ |
| 2757 | 2765 | pData->nMargin = 0; |
| 2758 | 2766 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2759 | 2767 | sepW = pData->nCol - 1; |
| @@ -3624,11 +3632,11 @@ | ||
| 3624 | 3632 | p->nRow = 0; |
| 3625 | 3633 | sz = sizeof(sqlite3_qrf_spec); |
| 3626 | 3634 | memcpy(&p->spec, pSpec, sz); |
| 3627 | 3635 | if( p->spec.zNull==0 ) p->spec.zNull = ""; |
| 3628 | 3636 | p->mxWidth = p->spec.nScreenWidth; |
| 3629 | - if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH; | |
| 3637 | + if( p->mxWidth<=0 ) p->mxWidth = 2147483647; | |
| 3630 | 3638 | p->mxHeight = p->spec.nLineLimit; |
| 3631 | 3639 | if( p->mxHeight<=0 ) p->mxHeight = 2147483647; |
| 3632 | 3640 | if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; |
| 3633 | 3641 | if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; |
| 3634 | 3642 | if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; |
| @@ -5272,10 +5280,14 @@ | ||
| 5272 | 5280 | #include <stdarg.h> |
| 5273 | 5281 | |
| 5274 | 5282 | /****************************************************************************** |
| 5275 | 5283 | ** The Hash Engine |
| 5276 | 5284 | */ |
| 5285 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 5286 | +# pragma GCC diagnostic push | |
| 5287 | +# pragma GCC diagnostic ignored "-Wstringop-overread" | |
| 5288 | +#endif | |
| 5277 | 5289 | /* Context for the SHA1 hash */ |
| 5278 | 5290 | typedef struct SHA1Context SHA1Context; |
| 5279 | 5291 | struct SHA1Context { |
| 5280 | 5292 | unsigned int state[5]; |
| 5281 | 5293 | unsigned int count[2]; |
| @@ -5412,11 +5424,11 @@ | ||
| 5412 | 5424 | } |
| 5413 | 5425 | j = 0; |
| 5414 | 5426 | }else{ |
| 5415 | 5427 | i = 0; |
| 5416 | 5428 | } |
| 5417 | - (void)memcpy(&p->buffer[j], &data[i], len - i); | |
| 5429 | + if( len-i>0 ) (void)memcpy(&p->buffer[j], &data[i], len - i); | |
| 5418 | 5430 | } |
| 5419 | 5431 | |
| 5420 | 5432 | /* Compute a string using sqlite3_vsnprintf() and hash it */ |
| 5421 | 5433 | static void hash_step_vformat( |
| 5422 | 5434 | SHA1Context *p, /* Add content to this context */ |
| @@ -5467,10 +5479,13 @@ | ||
| 5467 | 5479 | zOut[i*2+1] = zEncode[digest[i] & 0xf]; |
| 5468 | 5480 | } |
| 5469 | 5481 | zOut[i*2]= 0; |
| 5470 | 5482 | } |
| 5471 | 5483 | } |
| 5484 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 5485 | +# pragma GCC diagnostic pop | |
| 5486 | +#endif | |
| 5472 | 5487 | /* End of the hashing logic |
| 5473 | 5488 | *****************************************************************************/ |
| 5474 | 5489 | |
| 5475 | 5490 | /* |
| 5476 | 5491 | ** Two SQL functions: sha1(X) and sha1b(X). |
| @@ -6056,32 +6071,41 @@ | ||
| 6056 | 6071 | } |
| 6057 | 6072 | z[i] = 0; |
| 6058 | 6073 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6059 | 6074 | } |
| 6060 | 6075 | |
| 6076 | +/* Forward declaration */ | |
| 6077 | +static void decimal_expand(Decimal *p, int nDigit, int nFrac); | |
| 6078 | + | |
| 6061 | 6079 | /* |
| 6062 | 6080 | ** Round a decimal value to N significant digits. N must be positive. |
| 6063 | 6081 | */ |
| 6064 | 6082 | static void decimal_round(Decimal *p, int N){ |
| 6065 | 6083 | int i; |
| 6066 | - int nZero; | |
| 6084 | + int nZero; /* Number of leading zeros */ | |
| 6067 | 6085 | if( N<1 ) return; |
| 6068 | 6086 | if( p==0 ) return; |
| 6069 | 6087 | if( p->nDigit<=N ) return; |
| 6070 | 6088 | for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6071 | 6089 | N += nZero; |
| 6072 | 6090 | if( p->nDigit<=N ) return; |
| 6073 | - if( p->a[N]>4 ){ | |
| 6091 | + if( p->a[N]>=5 ){ | |
| 6092 | + /* If all leading digits are 9, increase the number of digits | |
| 6093 | + ** by adding a new 0 to the front */ | |
| 6094 | + for(i=0; i<N && p->a[i]==9; i++){} | |
| 6095 | + if( i==N ){ | |
| 6096 | + decimal_expand(p, p->nDigit+1, 0); | |
| 6097 | + if( p->oom ) return; | |
| 6098 | + } | |
| 6099 | + | |
| 6100 | + /* Do the rounding */ | |
| 6074 | 6101 | p->a[N-1]++; |
| 6075 | 6102 | for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6076 | 6103 | p->a[i] = 0; |
| 6077 | 6104 | p->a[i-1]++; |
| 6078 | 6105 | } |
| 6079 | - if( p->a[0]>9 ){ | |
| 6080 | - p->a[0] = 1; | |
| 6081 | - p->nFrac--; | |
| 6082 | - } | |
| 6106 | + assert( p->a[0]<=9 ); | |
| 6083 | 6107 | } |
| 6084 | 6108 | memset(&p->a[N], 0, p->nDigit - N); |
| 6085 | 6109 | } |
| 6086 | 6110 | |
| 6087 | 6111 | /* |
| @@ -8363,19 +8387,26 @@ | ||
| 8363 | 8387 | } |
| 8364 | 8388 | }else{ |
| 8365 | 8389 | iMin = iMax = sqlite3_value_int64(argv[iArg++]); |
| 8366 | 8390 | } |
| 8367 | 8391 | }else{ |
| 8368 | - if( idxNum & 0x0300 ){ /* value>X or value>=X */ | |
| 8392 | + if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */ | |
| 8369 | 8393 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8370 | 8394 | double r = sqlite3_value_double(argv[iArg++]); |
| 8371 | - if( r<(double)SMALLEST_INT64 ){ | |
| 8395 | + if( r<=(double)SMALLEST_INT64 ){ | |
| 8372 | 8396 | iMin = SMALLEST_INT64; |
| 8373 | - }else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ | |
| 8374 | - iMin = (sqlite3_int64)seriesCeil(r+1.0); | |
| 8397 | + }else if( r>(double)LARGEST_INT64 ){ | |
| 8398 | + goto series_no_rows; | |
| 8375 | 8399 | }else{ |
| 8376 | 8400 | iMin = (sqlite3_int64)seriesCeil(r); |
| 8401 | + if( iMin<0 && r>0.0 ){ | |
| 8402 | + iMin = LARGEST_INT64; | |
| 8403 | + } | |
| 8404 | + if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ | |
| 8405 | + if( iMin==LARGEST_INT64 ) goto series_no_rows; | |
| 8406 | + iMin++; | |
| 8407 | + } | |
| 8377 | 8408 | } |
| 8378 | 8409 | }else{ |
| 8379 | 8410 | iMin = sqlite3_value_int64(argv[iArg++]); |
| 8380 | 8411 | if( (idxNum & 0x0200)!=0 ){ |
| 8381 | 8412 | if( iMin==LARGEST_INT64 ){ |
| @@ -8384,19 +8415,25 @@ | ||
| 8384 | 8415 | iMin++; |
| 8385 | 8416 | } |
| 8386 | 8417 | } |
| 8387 | 8418 | } |
| 8388 | 8419 | } |
| 8389 | - if( idxNum & 0x3000 ){ /* value<X or value<=X */ | |
| 8420 | + if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */ | |
| 8390 | 8421 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8391 | 8422 | double r = sqlite3_value_double(argv[iArg++]); |
| 8392 | - if( r>(double)LARGEST_INT64 ){ | |
| 8423 | + if( r>=(double)LARGEST_INT64 ){ | |
| 8393 | 8424 | iMax = LARGEST_INT64; |
| 8394 | - }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ | |
| 8395 | - iMax = (sqlite3_int64)(r-1.0); | |
| 8425 | + }else if( r<=(double)SMALLEST_INT64 ){ | |
| 8426 | + goto series_no_rows; | |
| 8396 | 8427 | }else{ |
| 8397 | 8428 | iMax = (sqlite3_int64)seriesFloor(r); |
| 8429 | + if( iMax<0 && r>0.0 ){ | |
| 8430 | + iMax = LARGEST_INT64; | |
| 8431 | + }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ | |
| 8432 | + if( iMax==SMALLEST_INT64 ) goto series_no_rows; | |
| 8433 | + iMax--; | |
| 8434 | + } | |
| 8398 | 8435 | } |
| 8399 | 8436 | }else{ |
| 8400 | 8437 | iMax = sqlite3_value_int64(argv[iArg++]); |
| 8401 | 8438 | if( idxNum & 0x2000 ){ |
| 8402 | 8439 | if( iMax==SMALLEST_INT64 ){ |
| @@ -9638,11 +9675,10 @@ | ||
| 9638 | 9675 | if( pRe==0 ){ |
| 9639 | 9676 | sqlite3_result_error_nomem(context); |
| 9640 | 9677 | return; |
| 9641 | 9678 | } |
| 9642 | 9679 | pStr = sqlite3_str_new(0); |
| 9643 | - if( pStr==0 ) goto re_bytecode_func_err; | |
| 9644 | 9680 | if( pRe->nInit>0 ){ |
| 9645 | 9681 | sqlite3_str_appendf(pStr, "INIT "); |
| 9646 | 9682 | for(i=0; i<pRe->nInit; i++){ |
| 9647 | 9683 | sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); |
| 9648 | 9684 | } |
| @@ -9649,20 +9685,20 @@ | ||
| 9649 | 9685 | sqlite3_str_appendf(pStr, "\n"); |
| 9650 | 9686 | } |
| 9651 | 9687 | for(i=0; (unsigned)i<pRe->nState; i++){ |
| 9652 | 9688 | sqlite3_str_appendf(pStr, "%-8s %4d\n", |
| 9653 | 9689 | ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); |
| 9690 | + } | |
| 9691 | + if( sqlite3_str_errcode(pStr)==SQLITE_NOMEM ){ | |
| 9692 | + sqlite3_str_finish(pStr); | |
| 9693 | + re_free(pRe); | |
| 9694 | + sqlite3_result_error_nomem(context); | |
| 9695 | + return; | |
| 9654 | 9696 | } |
| 9655 | 9697 | n = sqlite3_str_length(pStr); |
| 9656 | 9698 | z = sqlite3_str_finish(pStr); |
| 9657 | - if( n==0 ){ | |
| 9658 | - sqlite3_free(z); | |
| 9659 | - }else{ | |
| 9660 | - sqlite3_result_text(context, z, n-1, sqlite3_free); | |
| 9661 | - } | |
| 9662 | - | |
| 9663 | -re_bytecode_func_err: | |
| 9699 | + sqlite3_result_text(context, z, n-1, sqlite3_free); | |
| 9664 | 9700 | re_free(pRe); |
| 9665 | 9701 | } |
| 9666 | 9702 | |
| 9667 | 9703 | #endif /* SQLITE_DEBUG */ |
| 9668 | 9704 | |
| @@ -10870,10 +10906,13 @@ | ||
| 10870 | 10906 | ** Return NULL if unable. |
| 10871 | 10907 | ** |
| 10872 | 10908 | ** The file or directory X is not required to exist. The answer is formed |
| 10873 | 10909 | ** by calling system realpath() on the prefix of X that does exist and |
| 10874 | 10910 | ** appending the tail of X that does not (yet) exist. |
| 10911 | +** | |
| 10912 | +** FIXME: This routine sometimes returns NULL rather than raising | |
| 10913 | +** an SQLITE_NOMEM error if an OOM is encountered. | |
| 10875 | 10914 | */ |
| 10876 | 10915 | static void realpathFunc( |
| 10877 | 10916 | sqlite3_context *context, |
| 10878 | 10917 | int argc, |
| 10879 | 10918 | sqlite3_value **argv |
| @@ -10892,10 +10931,11 @@ | ||
| 10892 | 10931 | (void)argc; |
| 10893 | 10932 | zPath = (const char*)sqlite3_value_text(argv[0]); |
| 10894 | 10933 | if( zPath==0 ) return; |
| 10895 | 10934 | if( zPath[0]==0 ) zPath = "."; |
| 10896 | 10935 | zCopy = sqlite3_mprintf("%s",zPath); |
| 10936 | + if( zCopy==0 ) return; | |
| 10897 | 10937 | len = strlen(zCopy); |
| 10898 | 10938 | while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 10899 | 10939 | len--; |
| 10900 | 10940 | } |
| 10901 | 10941 | zCopy[len] = 0; |
| @@ -12685,10 +12725,11 @@ | ||
| 12685 | 12725 | |
| 12686 | 12726 | for(p=pCsr->pFreeEntry; p; p=pNext){ |
| 12687 | 12727 | pNext = p->pNext; |
| 12688 | 12728 | zipfileEntryFree(p); |
| 12689 | 12729 | } |
| 12730 | + pCsr->pFreeEntry = 0; | |
| 12690 | 12731 | } |
| 12691 | 12732 | |
| 12692 | 12733 | /* |
| 12693 | 12734 | ** Destructor for an ZipfileCsr. |
| 12694 | 12735 | */ |
| @@ -13087,11 +13128,17 @@ | ||
| 13087 | 13128 | } |
| 13088 | 13129 | } |
| 13089 | 13130 | |
| 13090 | 13131 | if( rc==SQLITE_OK ){ |
| 13091 | 13132 | u32 *pt = &pNew->mUnixTime; |
| 13092 | - pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); | |
| 13133 | + /* aRead[0..nFile-1] might contain embedded \000 characters | |
| 13134 | + ** See Bug 2026-05-31T11:43:05Z */ | |
| 13135 | + pNew->cds.zFile = sqlite3_malloc64(nFile+1); | |
| 13136 | + if( pNew->cds.zFile!=0 ){ | |
| 13137 | + memcpy(pNew->cds.zFile, aRead, nFile); | |
| 13138 | + pNew->cds.zFile[nFile] = 0; | |
| 13139 | + } | |
| 13093 | 13140 | pNew->aExtra = (u8*)&pNew[1]; |
| 13094 | 13141 | memcpy(pNew->aExtra, &aRead[nFile], nExtra); |
| 13095 | 13142 | if( pNew->cds.zFile==0 ){ |
| 13096 | 13143 | rc = SQLITE_NOMEM; |
| 13097 | 13144 | }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ |
| @@ -14191,14 +14238,14 @@ | ||
| 14191 | 14238 | ZipfileBuffer body; |
| 14192 | 14239 | ZipfileBuffer cds; |
| 14193 | 14240 | }; |
| 14194 | 14241 | |
| 14195 | 14242 | static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){ |
| 14196 | - if( pBuf->n+nByte>pBuf->nAlloc ){ | |
| 14243 | + if( (pBuf->nAlloc-pBuf->n)<nByte ){ | |
| 14197 | 14244 | u8 *aNew; |
| 14198 | - sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; | |
| 14199 | - int nReq = pBuf->n + nByte; | |
| 14245 | + i64 nNew = pBuf->n ? (i64)pBuf->n*2 : 512; | |
| 14246 | + i64 nReq = pBuf->n + nByte; | |
| 14200 | 14247 | |
| 14201 | 14248 | while( nNew<nReq ) nNew = nNew*2; |
| 14202 | 14249 | aNew = sqlite3_realloc64(pBuf->a, nNew); |
| 14203 | 14250 | if( aNew==0 ) return SQLITE_NOMEM; |
| 14204 | 14251 | pBuf->a = aNew; |
| @@ -16296,11 +16343,11 @@ | ||
| 16296 | 16343 | p->pTable = pTab; |
| 16297 | 16344 | |
| 16298 | 16345 | /* The statement the vtab will pass to sqlite3_declare_vtab() */ |
| 16299 | 16346 | zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); |
| 16300 | 16347 | for(i=0; i<pTab->nCol; i++){ |
| 16301 | - zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", | |
| 16348 | + zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %Q", | |
| 16302 | 16349 | (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl |
| 16303 | 16350 | ); |
| 16304 | 16351 | } |
| 16305 | 16352 | zInner = idxAppendText(&rc, zInner, ")"); |
| 16306 | 16353 | |
| @@ -16496,11 +16543,11 @@ | ||
| 16496 | 16543 | sqlite3_free(zCols); |
| 16497 | 16544 | sqlite3_free(zOrder); |
| 16498 | 16545 | return sqlite3_reset(pIndexXInfo); |
| 16499 | 16546 | } |
| 16500 | 16547 | zCols = idxAppendText(&rc, zCols, |
| 16501 | - "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s", | |
| 16548 | + "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %Q", | |
| 16502 | 16549 | zComma, zName, nCol, zName, zColl |
| 16503 | 16550 | ); |
| 16504 | 16551 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 16505 | 16552 | } |
| 16506 | 16553 | sqlite3_reset(pIndexXInfo); |
| @@ -19464,11 +19511,11 @@ | ||
| 19464 | 19511 | sqlite3_vfs_unregister(pVfs); |
| 19465 | 19512 | sqlite3_free(pVfs); |
| 19466 | 19513 | } |
| 19467 | 19514 | |
| 19468 | 19515 | /************************* End ext/misc/vfstrace.c ********************/ |
| 19469 | -/************************* Begin ext/misc/analyze.c ******************/ | |
| 19516 | +/************************* Begin ext/misc/diskused.c ******************/ | |
| 19470 | 19517 | /* |
| 19471 | 19518 | ** 2026-04-13 |
| 19472 | 19519 | ** |
| 19473 | 19520 | ** The author disclaims copyright to this source code. In place of |
| 19474 | 19521 | ** a legal notice, here is a blessing: |
| @@ -19477,12 +19524,21 @@ | ||
| 19477 | 19524 | ** May you find forgiveness for yourself and forgive others. |
| 19478 | 19525 | ** May you share freely, never taking more than you give. |
| 19479 | 19526 | ** |
| 19480 | 19527 | ****************************************************************************** |
| 19481 | 19528 | ** |
| 19482 | -** Partial reimplement of the sqlite3_analyzer utility program as | |
| 19483 | -** loadable SQL function. | |
| 19529 | +** This extension implements an SQL function: | |
| 19530 | +** | |
| 19531 | +** diskused(X) | |
| 19532 | +** | |
| 19533 | +** Where X is the schema name (typically 'main'). The output is text | |
| 19534 | +** that describes how much filesystem space the various tables and indexes | |
| 19535 | +** of the database consume. | |
| 19536 | +** | |
| 19537 | +** This function is a replacement for the (now deprecated) | |
| 19538 | +** "sqlite3_analyzer" utility program. This function is built | |
| 19539 | +** into the CLI and is used to implement the ".diskused" command there. | |
| 19484 | 19540 | */ |
| 19485 | 19541 | /* #include "sqlite3ext.h" */ |
| 19486 | 19542 | SQLITE_EXTENSION_INIT1 |
| 19487 | 19543 | #include <assert.h> |
| 19488 | 19544 | #include <string.h> |
| @@ -19490,28 +19546,28 @@ | ||
| 19490 | 19546 | #include <math.h> |
| 19491 | 19547 | |
| 19492 | 19548 | /* |
| 19493 | 19549 | ** State information for the analysis |
| 19494 | 19550 | */ |
| 19495 | -typedef struct Analysis Analysis; | |
| 19496 | -struct Analysis { | |
| 19551 | +typedef struct DiskUsed DiskUsed; | |
| 19552 | +struct DiskUsed { | |
| 19497 | 19553 | sqlite3 *db; /* Database connection */ |
| 19498 | 19554 | sqlite3_context *context; /* SQL function context */ |
| 19499 | 19555 | sqlite3_str *pOut; /* Write output here */ |
| 19500 | 19556 | char *zSU; /* Name of the temp.space_used table */ |
| 19501 | 19557 | const char *zSchema; /* Schema to be analyzed */ |
| 19502 | 19558 | }; |
| 19503 | 19559 | |
| 19504 | 19560 | /* |
| 19505 | -** Free all resources that the Analysis object references and | |
| 19506 | -** reset the Analysis object. | |
| 19561 | +** Free all resources that the DiskUsed object references and | |
| 19562 | +** reset the DiskUsed object. | |
| 19507 | 19563 | ** |
| 19508 | -** Call this routine multiple times on the same Analysis object | |
| 19564 | +** Call this routine multiple times on the same DiskUsed object | |
| 19509 | 19565 | ** is a harmless no-op, as long as the memory for the object itself |
| 19510 | 19566 | ** has not been freed. |
| 19511 | 19567 | */ |
| 19512 | -static void analysisReset(Analysis *p){ | |
| 19568 | +static void diskusedReset(DiskUsed *p){ | |
| 19513 | 19569 | if( p->zSU ){ |
| 19514 | 19570 | char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU); |
| 19515 | 19571 | if( zSql ){ |
| 19516 | 19572 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 19517 | 19573 | sqlite3_free(zSql); |
| @@ -19524,11 +19580,11 @@ | ||
| 19524 | 19580 | |
| 19525 | 19581 | /* |
| 19526 | 19582 | ** Report an error using formatted text. If zFormat==NULL then report |
| 19527 | 19583 | ** an OOM error. |
| 19528 | 19584 | */ |
| 19529 | -static void analysisError(Analysis *p, const char *zFormat, ...){ | |
| 19585 | +static void diskusedError(DiskUsed *p, const char *zFormat, ...){ | |
| 19530 | 19586 | char *zErr; |
| 19531 | 19587 | if( zFormat ){ |
| 19532 | 19588 | va_list ap; |
| 19533 | 19589 | va_start(ap, zFormat); |
| 19534 | 19590 | zErr = sqlite3_vmprintf(zFormat, ap); |
| @@ -19540,38 +19596,38 @@ | ||
| 19540 | 19596 | sqlite3_result_error_nomem(p->context); |
| 19541 | 19597 | }else{ |
| 19542 | 19598 | sqlite3_result_error(p->context, zErr, -1); |
| 19543 | 19599 | sqlite3_free(zErr); |
| 19544 | 19600 | } |
| 19545 | - analysisReset(p); | |
| 19601 | + diskusedReset(p); | |
| 19546 | 19602 | } |
| 19547 | 19603 | |
| 19548 | 19604 | /* |
| 19549 | 19605 | ** Prepare and return an SQL statement. |
| 19550 | 19606 | */ |
| 19551 | -static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){ | |
| 19607 | +static sqlite3_stmt *diskusedVPrep(DiskUsed *p, const char *zFmt, va_list ap){ | |
| 19552 | 19608 | char *zSql; |
| 19553 | 19609 | int rc; |
| 19554 | 19610 | sqlite3_stmt *pStmt = 0; |
| 19555 | 19611 | zSql = sqlite3_vmprintf(zFmt, ap); |
| 19556 | - if( zSql==0 ){ analysisError(p,0); return 0; } | |
| 19612 | + if( zSql==0 ){ diskusedError(p,0); return 0; } | |
| 19557 | 19613 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 19558 | 19614 | if( rc ){ |
| 19559 | - analysisError(p, "SQL parse error: %s\nOriginal SQL: %s", | |
| 19615 | + diskusedError(p, "SQL parse error: %s\nOriginal SQL: %s", | |
| 19560 | 19616 | sqlite3_errmsg(p->db), zSql); |
| 19561 | 19617 | sqlite3_finalize(pStmt); |
| 19562 | - analysisReset(p); | |
| 19618 | + diskusedReset(p); | |
| 19563 | 19619 | pStmt = 0; |
| 19564 | 19620 | } |
| 19565 | 19621 | sqlite3_free(zSql); |
| 19566 | 19622 | return pStmt; |
| 19567 | 19623 | } |
| 19568 | -static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){ | |
| 19624 | +static sqlite3_stmt *diskusedPrepare(DiskUsed *p, const char *zFormat, ...){ | |
| 19569 | 19625 | va_list ap; |
| 19570 | 19626 | sqlite3_stmt *pStmt = 0; |
| 19571 | 19627 | va_start(ap, zFormat); |
| 19572 | - pStmt = analysisVPrep(p,zFormat,ap); | |
| 19628 | + pStmt = diskusedVPrep(p,zFormat,ap); | |
| 19573 | 19629 | va_end(ap); |
| 19574 | 19630 | return pStmt; |
| 19575 | 19631 | } |
| 19576 | 19632 | |
| 19577 | 19633 | /* |
| @@ -19580,60 +19636,60 @@ | ||
| 19580 | 19636 | ** |
| 19581 | 19637 | ** If rc is SQLITE_DONE or SQLITE_OK, then return false. |
| 19582 | 19638 | ** |
| 19583 | 19639 | ** The prepared statement is closed in either case. |
| 19584 | 19640 | */ |
| 19585 | -static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){ | |
| 19641 | +static int diskusedStmtFinish(DiskUsed *p, int rc, sqlite3_stmt *pStmt){ | |
| 19586 | 19642 | if( rc==SQLITE_DONE ){ |
| 19587 | 19643 | rc = SQLITE_OK; |
| 19588 | 19644 | } |
| 19589 | 19645 | if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){ |
| 19590 | - analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19646 | + diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19591 | 19647 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19592 | - analysisReset(p); | |
| 19648 | + diskusedReset(p); | |
| 19593 | 19649 | } |
| 19594 | 19650 | sqlite3_finalize(pStmt); |
| 19595 | 19651 | return rc; |
| 19596 | 19652 | } |
| 19597 | 19653 | |
| 19598 | 19654 | /* |
| 19599 | 19655 | ** Run SQL. Return the number of errors. |
| 19600 | 19656 | */ |
| 19601 | -static int analysisSql(Analysis *p, const char *zFormat, ...){ | |
| 19657 | +static int diskusedSql(DiskUsed *p, const char *zFormat, ...){ | |
| 19602 | 19658 | va_list ap; |
| 19603 | 19659 | int rc; |
| 19604 | 19660 | sqlite3_stmt *pStmt = 0; |
| 19605 | 19661 | va_start(ap, zFormat); |
| 19606 | - pStmt = analysisVPrep(p,zFormat,ap); | |
| 19662 | + pStmt = diskusedVPrep(p,zFormat,ap); | |
| 19607 | 19663 | va_end(ap); |
| 19608 | 19664 | if( pStmt==0 ) return 1; |
| 19609 | 19665 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){} |
| 19610 | 19666 | if( rc==SQLITE_DONE ){ |
| 19611 | 19667 | rc = SQLITE_OK; |
| 19612 | 19668 | }else{ |
| 19613 | - analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19669 | + diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19614 | 19670 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19615 | - analysisReset(p); | |
| 19671 | + diskusedReset(p); | |
| 19616 | 19672 | } |
| 19617 | 19673 | sqlite3_finalize(pStmt); |
| 19618 | 19674 | return rc; |
| 19619 | 19675 | } |
| 19620 | 19676 | |
| 19621 | 19677 | /* |
| 19622 | 19678 | ** Run an SQL query that returns an integer. Write that integer |
| 19623 | 19679 | ** into *piRes. Return the number of errors. |
| 19624 | 19680 | */ |
| 19625 | -static int analysisSqlInt( | |
| 19626 | - Analysis *p, | |
| 19681 | +static int diskusedSqlInt( | |
| 19682 | + DiskUsed *p, | |
| 19627 | 19683 | sqlite3_int64 *piRes, |
| 19628 | 19684 | const char *zFormat, ... |
| 19629 | 19685 | ){ |
| 19630 | 19686 | va_list ap; |
| 19631 | 19687 | int rc; |
| 19632 | 19688 | sqlite3_stmt *pStmt = 0; |
| 19633 | 19689 | va_start(ap, zFormat); |
| 19634 | - pStmt = analysisVPrep(p,zFormat,ap); | |
| 19690 | + pStmt = diskusedVPrep(p,zFormat,ap); | |
| 19635 | 19691 | va_end(ap); |
| 19636 | 19692 | if( pStmt==0 ) return 1; |
| 19637 | 19693 | rc = sqlite3_step(pStmt); |
| 19638 | 19694 | if( rc==SQLITE_ROW ){ |
| 19639 | 19695 | *piRes = sqlite3_column_int64(pStmt, 0); |
| @@ -19641,14 +19697,14 @@ | ||
| 19641 | 19697 | }else if( rc==SQLITE_DONE ){ |
| 19642 | 19698 | rc = SQLITE_OK; |
| 19643 | 19699 | }else{ |
| 19644 | 19700 | if( p->db ){ |
| 19645 | 19701 | /* p->db is NULL if there was some prior error */ |
| 19646 | - analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19702 | + diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19647 | 19703 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19648 | 19704 | } |
| 19649 | - analysisReset(p); | |
| 19705 | + diskusedReset(p); | |
| 19650 | 19706 | } |
| 19651 | 19707 | sqlite3_finalize(pStmt); |
| 19652 | 19708 | return rc; |
| 19653 | 19709 | } |
| 19654 | 19710 | |
| @@ -19657,20 +19713,20 @@ | ||
| 19657 | 19713 | ** by the format string. If the output is initially empty, begin |
| 19658 | 19714 | ** the title line with "/" so that it forms the beginning of a C-style |
| 19659 | 19715 | ** comment. Otherwise begin with a new-line. Always finish with a |
| 19660 | 19716 | ** newline. |
| 19661 | 19717 | */ |
| 19662 | -static void analysisTitle(Analysis *p, const char *zFormat, ...){ | |
| 19718 | +static void diskusedTitle(DiskUsed *p, const char *zFormat, ...){ | |
| 19663 | 19719 | char *zFirst; |
| 19664 | 19720 | char *zTitle; |
| 19665 | 19721 | size_t nTitle; |
| 19666 | 19722 | va_list ap; |
| 19667 | 19723 | va_start(ap, zFormat); |
| 19668 | 19724 | zTitle = sqlite3_vmprintf(zFormat, ap); |
| 19669 | 19725 | va_end(ap); |
| 19670 | 19726 | if( zTitle==0 ){ |
| 19671 | - analysisError(p, 0); | |
| 19727 | + diskusedError(p, 0); | |
| 19672 | 19728 | return; |
| 19673 | 19729 | } |
| 19674 | 19730 | zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*"; |
| 19675 | 19731 | nTitle = strlen(zTitle); |
| 19676 | 19732 | if( nTitle>=75 ){ |
| @@ -19685,12 +19741,12 @@ | ||
| 19685 | 19741 | /* |
| 19686 | 19742 | ** Add an output line that begins with the zDesc text extended out to |
| 19687 | 19743 | ** 50 columns with "." characters, and followed by whatever text is |
| 19688 | 19744 | ** described by zFormat. |
| 19689 | 19745 | */ |
| 19690 | -static void analysisLine( | |
| 19691 | - Analysis *p, /* Analysis context */ | |
| 19746 | +static void diskusedLine( | |
| 19747 | + DiskUsed *p, /* DiskUsed context */ | |
| 19692 | 19748 | const char *zDesc, /* Description */ |
| 19693 | 19749 | const char *zFormat, /* Argument to the description */ |
| 19694 | 19750 | ... |
| 19695 | 19751 | ){ |
| 19696 | 19752 | char *zTxt; |
| @@ -19698,14 +19754,14 @@ | ||
| 19698 | 19754 | va_list ap; |
| 19699 | 19755 | va_start(ap, zFormat); |
| 19700 | 19756 | zTxt = sqlite3_vmprintf(zFormat, ap); |
| 19701 | 19757 | va_end(ap); |
| 19702 | 19758 | if( zTxt==0 ){ |
| 19703 | - analysisError(p, 0); | |
| 19759 | + diskusedError(p, 0); | |
| 19704 | 19760 | return; |
| 19705 | 19761 | } |
| 19706 | - nDesc = strlen(zDesc); | |
| 19762 | + nDesc = zDesc ? strlen(zDesc) : 0; | |
| 19707 | 19763 | if( nDesc>=50 ){ |
| 19708 | 19764 | sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt); |
| 19709 | 19765 | }else{ |
| 19710 | 19766 | int nExtra = 50 - (int)nDesc; |
| 19711 | 19767 | sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt); |
| @@ -19715,11 +19771,11 @@ | ||
| 19715 | 19771 | /* |
| 19716 | 19772 | ** Write a percentage into the output. The number written should show |
| 19717 | 19773 | ** two or three significant digits, with the decimal point being the fourth |
| 19718 | 19774 | ** character. |
| 19719 | 19775 | */ |
| 19720 | -static void analysisPercent(Analysis *p, double r){ | |
| 19776 | +static void diskusedPercent(DiskUsed *p, double r){ | |
| 19721 | 19777 | char zNum[100]; |
| 19722 | 19778 | char *zDP; |
| 19723 | 19779 | int nLeadingDigit; |
| 19724 | 19780 | int sz; |
| 19725 | 19781 | sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r); |
| @@ -19744,12 +19800,12 @@ | ||
| 19744 | 19800 | ** |
| 19745 | 19801 | ** The title if the subreport is given by zTitle. zWhere is |
| 19746 | 19802 | ** a boolean expression that can go in the WHERE clause to select |
| 19747 | 19803 | ** the relevant rows of the s.zSU table. |
| 19748 | 19804 | */ |
| 19749 | -static int analysisSubreport( | |
| 19750 | - Analysis *p, /* Analysis context */ | |
| 19805 | +static int diskusedSubreport( | |
| 19806 | + DiskUsed *p, /* DiskUsed context */ | |
| 19751 | 19807 | char *zTitle, /* Title for this subreport */ |
| 19752 | 19808 | char *zWhere, /* WHERE clause for this subreport */ |
| 19753 | 19809 | sqlite3_int64 pgsz, /* Database page size */ |
| 19754 | 19810 | sqlite3_int64 nPage /* Number of pages in entire database */ |
| 19755 | 19811 | ){ |
| @@ -19773,14 +19829,14 @@ | ||
| 19773 | 19829 | sqlite3_int64 total_unused; /* Total unused bytes */ |
| 19774 | 19830 | sqlite3_int64 total_meta; /* Total metadata */ |
| 19775 | 19831 | int rc; |
| 19776 | 19832 | |
| 19777 | 19833 | if( zTitle==0 || zWhere==0 ){ |
| 19778 | - analysisError(p, 0); | |
| 19834 | + diskusedError(p, 0); | |
| 19779 | 19835 | return SQLITE_NOMEM; |
| 19780 | 19836 | } |
| 19781 | - pStmt = analysisPrepare(p, | |
| 19837 | + pStmt = diskusedPrepare(p, | |
| 19782 | 19838 | "SELECT\n" |
| 19783 | 19839 | " sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */ |
| 19784 | 19840 | " sum(payload),\n" /* 1 */ |
| 19785 | 19841 | " sum(ovfl_payload),\n" /* 2 */ |
| 19786 | 19842 | " max(mx_payload),\n" /* 3 */ |
| @@ -19797,11 +19853,11 @@ | ||
| 19797 | 19853 | " FROM temp.%s WHERE %s", |
| 19798 | 19854 | p->zSU, zWhere); |
| 19799 | 19855 | if( pStmt==0 ) return 1; |
| 19800 | 19856 | rc = sqlite3_step(pStmt); |
| 19801 | 19857 | if( rc==SQLITE_ROW ){ |
| 19802 | - analysisTitle(p, zTitle); | |
| 19858 | + diskusedTitle(p, "%s", zTitle); | |
| 19803 | 19859 | |
| 19804 | 19860 | nentry = sqlite3_column_int64(pStmt, 0); |
| 19805 | 19861 | payload = sqlite3_column_int64(pStmt, 1); |
| 19806 | 19862 | ovfl_payload = sqlite3_column_int64(pStmt, 2); |
| 19807 | 19863 | mx_payload = sqlite3_column_int64(pStmt, 3); |
| @@ -19816,73 +19872,73 @@ | ||
| 19816 | 19872 | cnt = sqlite3_column_int64(pStmt, 12); |
| 19817 | 19873 | int_cell = sqlite3_column_int64(pStmt, 13); |
| 19818 | 19874 | rc = SQLITE_DONE; |
| 19819 | 19875 | |
| 19820 | 19876 | total_pages = leaf_pages + int_pages + ovfl_pages; |
| 19821 | - analysisLine(p, "Percentage of total database", "%.3g%%\n", | |
| 19877 | + diskusedLine(p, "Percentage of total database", "%.3g%%\n", | |
| 19822 | 19878 | (total_pages*100.0)/(double)nPage); |
| 19823 | - analysisLine(p, "Number of entries", "%lld\n", nentry); | |
| 19879 | + diskusedLine(p, "Number of entries", "%lld\n", nentry); | |
| 19824 | 19880 | storage = total_pages*pgsz; |
| 19825 | - analysisLine(p, "Bytes of storage consumed", "%lld\n", storage); | |
| 19826 | - analysisLine(p, "Bytes of payload", "%-11lld ", payload); | |
| 19827 | - analysisPercent(p, payload*100.0/(double)storage); | |
| 19881 | + diskusedLine(p, "Bytes of storage consumed", "%lld\n", storage); | |
| 19882 | + diskusedLine(p, "Bytes of payload", "%-11lld ", payload); | |
| 19883 | + diskusedPercent(p, payload*100.0/(double)storage); | |
| 19828 | 19884 | if( ovfl_cnt>0 ){ |
| 19829 | - analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); | |
| 19830 | - analysisPercent(p, ovfl_payload*100.0/(double)payload); | |
| 19885 | + diskusedLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); | |
| 19886 | + diskusedPercent(p, ovfl_payload*100.0/(double)payload); | |
| 19831 | 19887 | } |
| 19832 | 19888 | total_unused = leaf_unused + int_unused + ovfl_unused; |
| 19833 | 19889 | total_meta = storage - payload - total_unused; |
| 19834 | - analysisLine(p, "Bytes of metadata","%-11lld ", total_meta); | |
| 19835 | - analysisPercent(p, total_meta*100.0/(double)storage); | |
| 19890 | + diskusedLine(p, "Bytes of metadata","%-11lld ", total_meta); | |
| 19891 | + diskusedPercent(p, total_meta*100.0/(double)storage); | |
| 19836 | 19892 | if( cnt==1 ){ |
| 19837 | - analysisLine(p, "B-tree depth", "%lld\n", depth); | |
| 19893 | + diskusedLine(p, "B-tree depth", "%lld\n", depth); | |
| 19838 | 19894 | if( int_cell>1 ){ |
| 19839 | - analysisLine(p, "Average fanout", "%.1f\n", | |
| 19895 | + diskusedLine(p, "Average fanout", "%.1f\n", | |
| 19840 | 19896 | (double)(int_cell+int_pages)/(double)int_pages); |
| 19841 | 19897 | } |
| 19842 | 19898 | } |
| 19843 | 19899 | if( nentry>0 ){ |
| 19844 | - analysisLine(p, "Average payload per entry", "%.1f\n", | |
| 19900 | + diskusedLine(p, "Average payload per entry", "%.1f\n", | |
| 19845 | 19901 | (double)payload/(double)nentry); |
| 19846 | - analysisLine(p, "Average unused bytes per entry", "%.1f\n", | |
| 19902 | + diskusedLine(p, "Average unused bytes per entry", "%.1f\n", | |
| 19847 | 19903 | (double)total_unused/(double)nentry); |
| 19848 | - analysisLine(p, "Average metadata per entry", "%.1f\n", | |
| 19904 | + diskusedLine(p, "Average metadata per entry", "%.1f\n", | |
| 19849 | 19905 | (double)total_meta/(double)nentry); |
| 19850 | 19906 | } |
| 19851 | - analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); | |
| 19852 | - if( nentry>0 ){ | |
| 19853 | - analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); | |
| 19854 | - analysisPercent(p, ovfl_cnt*100.0/(double)nentry); | |
| 19855 | - } | |
| 19856 | - if( int_pages>0 ){ | |
| 19857 | - analysisLine(p, "Index pages used", "%lld\n", int_pages); | |
| 19858 | - } | |
| 19859 | - analysisLine(p, "Primary pages used", "%lld\n", leaf_pages); | |
| 19860 | - if( ovfl_cnt ){ | |
| 19861 | - analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages); | |
| 19862 | - } | |
| 19863 | - analysisLine(p, "Total pages used", "%lld\n", total_pages); | |
| 19864 | - if( int_pages>0 ){ | |
| 19865 | - analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused); | |
| 19866 | - } | |
| 19867 | - analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); | |
| 19868 | - if( ovfl_cnt ){ | |
| 19869 | - analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); | |
| 19870 | - } | |
| 19871 | - analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); | |
| 19872 | - analysisPercent(p, total_unused*100.0/(double)storage); | |
| 19873 | - } | |
| 19874 | - return analysisStmtFinish(p, rc, pStmt); | |
| 19875 | -} | |
| 19876 | - | |
| 19877 | -/* | |
| 19878 | -** SQL Function: analyze(SCHEMA) | |
| 19907 | + diskusedLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); | |
| 19908 | + if( nentry>0 ){ | |
| 19909 | + diskusedLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); | |
| 19910 | + diskusedPercent(p, ovfl_cnt*100.0/(double)nentry); | |
| 19911 | + } | |
| 19912 | + if( int_pages>0 ){ | |
| 19913 | + diskusedLine(p, "Index pages used", "%lld\n", int_pages); | |
| 19914 | + } | |
| 19915 | + diskusedLine(p, "Primary pages used", "%lld\n", leaf_pages); | |
| 19916 | + if( ovfl_cnt ){ | |
| 19917 | + diskusedLine(p, "Overflow pages used", "%lld\n", ovfl_pages); | |
| 19918 | + } | |
| 19919 | + diskusedLine(p, "Total pages used", "%lld\n", total_pages); | |
| 19920 | + if( int_pages>0 ){ | |
| 19921 | + diskusedLine(p, "Unused bytes on index pages", "%lld\n", int_unused); | |
| 19922 | + } | |
| 19923 | + diskusedLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); | |
| 19924 | + if( ovfl_cnt ){ | |
| 19925 | + diskusedLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); | |
| 19926 | + } | |
| 19927 | + diskusedLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); | |
| 19928 | + diskusedPercent(p, total_unused*100.0/(double)storage); | |
| 19929 | + } | |
| 19930 | + return diskusedStmtFinish(p, rc, pStmt); | |
| 19931 | +} | |
| 19932 | + | |
| 19933 | +/* | |
| 19934 | +** SQL Function: diskused(SCHEMA) | |
| 19879 | 19935 | ** |
| 19880 | 19936 | ** Analyze the database schema named in the argument. Return text |
| 19881 | -** containing the analysis. | |
| 19937 | +** containing the space utilization stats. | |
| 19882 | 19938 | */ |
| 19883 | -static void analyzeFunc( | |
| 19939 | +static void diskusedFunc( | |
| 19884 | 19940 | sqlite3_context *context, |
| 19885 | 19941 | int argc, |
| 19886 | 19942 | sqlite3_value **argv |
| 19887 | 19943 | ){ |
| 19888 | 19944 | int rc; |
| @@ -19893,47 +19949,47 @@ | ||
| 19893 | 19949 | sqlite3_int64 nPage; |
| 19894 | 19950 | sqlite3_int64 nPageInUse; |
| 19895 | 19951 | sqlite3_int64 nFreeList; |
| 19896 | 19952 | sqlite3_int64 nIndex; |
| 19897 | 19953 | sqlite3_int64 nWORowid; |
| 19898 | - Analysis s; | |
| 19954 | + DiskUsed s; | |
| 19899 | 19955 | sqlite3_uint64 r[2]; |
| 19900 | 19956 | |
| 19901 | 19957 | (void)argc; |
| 19902 | 19958 | memset(&s, 0, sizeof(s)); |
| 19903 | 19959 | s.db = sqlite3_context_db_handle(context); |
| 19904 | 19960 | s.context = context; |
| 19905 | 19961 | s.pOut = sqlite3_str_new(0); |
| 19906 | 19962 | if( sqlite3_str_errcode(s.pOut) ){ |
| 19907 | - analysisError(&s, 0); | |
| 19963 | + diskusedError(&s, 0); | |
| 19908 | 19964 | return; |
| 19909 | 19965 | } |
| 19910 | 19966 | s.zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 19911 | 19967 | if( s.zSchema==0 ){ |
| 19912 | 19968 | s.zSchema = "main"; |
| 19913 | 19969 | }else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){ |
| 19914 | - analysisReset(&s); | |
| 19970 | + diskusedReset(&s); | |
| 19915 | 19971 | sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC); |
| 19916 | 19972 | return; |
| 19917 | 19973 | } |
| 19918 | 19974 | ii = 0; |
| 19919 | - rc = analysisSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" | |
| 19975 | + rc = diskusedSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" | |
| 19920 | 19976 | " WHERE name=%Q COLLATE nocase",s.zSchema); |
| 19921 | 19977 | if( rc || ii==0 ){ |
| 19922 | - analysisReset(&s); | |
| 19978 | + diskusedReset(&s); | |
| 19923 | 19979 | sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC); |
| 19924 | 19980 | return; |
| 19925 | 19981 | } |
| 19926 | 19982 | sqlite3_randomness(sizeof(r), &r); |
| 19927 | - s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]); | |
| 19928 | - if( s.zSU==0 ){ analysisError(&s, 0); return; } | |
| 19983 | + s.zSU = sqlite3_mprintf("diskused%016llx%016llx", r[0], r[1]); | |
| 19984 | + if( s.zSU==0 ){ diskusedError(&s, 0); return; } | |
| 19929 | 19985 | |
| 19930 | 19986 | /* The s.zSU table contains the data used for the analysis. |
| 19931 | 19987 | ** The table name contains 128-bits of randomness to avoid |
| 19932 | 19988 | ** collisions with preexisting tables in temp. |
| 19933 | 19989 | */ |
| 19934 | - rc = analysisSql(&s, | |
| 19990 | + rc = diskusedSql(&s, | |
| 19935 | 19991 | "CREATE TABLE temp.%s(\n" |
| 19936 | 19992 | " name text, -- A table or index\n" |
| 19937 | 19993 | " tblname text, -- Table that owns name\n" |
| 19938 | 19994 | " is_index boolean, -- TRUE if it is an index\n" |
| 19939 | 19995 | " is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" |
| @@ -19956,11 +20012,11 @@ | ||
| 19956 | 20012 | ); |
| 19957 | 20013 | if( rc ) return; |
| 19958 | 20014 | |
| 19959 | 20015 | /* Populate the s.zSU table |
| 19960 | 20016 | */ |
| 19961 | - rc = analysisSql(&s, | |
| 20017 | + rc = diskusedSql(&s, | |
| 19962 | 20018 | "WITH\n" |
| 19963 | 20019 | " allidx(idxname) AS (\n" |
| 19964 | 20020 | " SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n" |
| 19965 | 20021 | " ),\n" |
| 19966 | 20022 | " allobj(allname,tblname,isidx,isworowid) AS (\n" |
| @@ -20008,141 +20064,143 @@ | ||
| 20008 | 20064 | s.zSchema /* JOIN dbstat(%Q) */ |
| 20009 | 20065 | ); |
| 20010 | 20066 | if( rc ) return; |
| 20011 | 20067 | |
| 20012 | 20068 | nPage = 0; |
| 20013 | - rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); | |
| 20069 | + rc = diskusedSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); | |
| 20014 | 20070 | if( rc ) return; |
| 20015 | 20071 | if( nPage<=0 ){ |
| 20016 | 20072 | /* Very brief reply for an empty database */ |
| 20017 | - analysisReset(&s); | |
| 20073 | + diskusedReset(&s); | |
| 20018 | 20074 | sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC); |
| 20019 | 20075 | return; |
| 20020 | 20076 | } |
| 20021 | 20077 | |
| 20022 | 20078 | /* Begin generating the report */ |
| 20023 | - analysisTitle(&s, "Database storage utilization report"); | |
| 20079 | + diskusedTitle(&s, "Database storage utilization report"); | |
| 20024 | 20080 | pgsz = 0; |
| 20025 | - rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); | |
| 20081 | + rc = diskusedSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); | |
| 20026 | 20082 | if( rc ) return; |
| 20027 | - analysisLine(&s, "Page size in bytes","%lld\n",pgsz); | |
| 20028 | - analysisLine(&s, "Pages in the database", "%lld\n", nPage); | |
| 20083 | + diskusedLine(&s, "Page size in bytes","%lld\n",pgsz); | |
| 20084 | + diskusedLine(&s, "Pages in the database", "%lld\n", nPage); | |
| 20029 | 20085 | |
| 20030 | 20086 | nPageInUse = 0; |
| 20031 | - rc = analysisSqlInt(&s, &nPageInUse, | |
| 20087 | + rc = diskusedSqlInt(&s, &nPageInUse, | |
| 20032 | 20088 | "SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU); |
| 20033 | 20089 | if( rc ) return; |
| 20034 | - analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse); | |
| 20035 | - analysisPercent(&s, (nPageInUse*100.0)/(double)nPage); | |
| 20090 | + diskusedLine(&s, "Pages that store data", "%-11lld ", nPageInUse); | |
| 20091 | + diskusedPercent(&s, (nPageInUse*100.0)/(double)nPage); | |
| 20036 | 20092 | |
| 20037 | 20093 | nFreeList = 0; |
| 20038 | - rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); | |
| 20094 | + rc = diskusedSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); | |
| 20039 | 20095 | if( rc ) return; |
| 20040 | - analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); | |
| 20041 | - analysisPercent(&s, (nFreeList*100.0)/(double)nPage); | |
| 20096 | + diskusedLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); | |
| 20097 | + diskusedPercent(&s, (nFreeList*100.0)/(double)nPage); | |
| 20042 | 20098 | |
| 20043 | 20099 | ii = 0; |
| 20044 | - rc = analysisSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); | |
| 20100 | + rc = diskusedSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); | |
| 20045 | 20101 | if( rc ) return; |
| 20046 | 20102 | if( ii==0 || nPage<=1 ){ |
| 20047 | 20103 | ii = 0; |
| 20048 | 20104 | }else{ |
| 20049 | 20105 | double rPtrsPerPage = pgsz/5; |
| 20050 | 20106 | double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0); |
| 20051 | 20107 | ii = (sqlite3_int64)ceil(rAvPage); |
| 20052 | 20108 | } |
| 20053 | - analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); | |
| 20054 | - analysisPercent(&s, (ii*100.0)/(double)nPage); | |
| 20109 | + diskusedLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); | |
| 20110 | + diskusedPercent(&s, (ii*100.0)/(double)nPage); | |
| 20055 | 20111 | |
| 20056 | 20112 | ii = 0; |
| 20057 | - rc = analysisSqlInt(&s, &ii, | |
| 20113 | + rc = diskusedSqlInt(&s, &ii, | |
| 20058 | 20114 | "SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'", |
| 20059 | 20115 | s.zSchema); |
| 20060 | 20116 | if( rc ) return; |
| 20061 | - analysisLine(&s, "Number of tables", "%lld\n", ii); | |
| 20117 | + diskusedLine(&s, "Number of tables", "%lld\n", ii); | |
| 20062 | 20118 | nWORowid = 0; |
| 20063 | - rc = analysisSqlInt(&s, &nWORowid, | |
| 20119 | + rc = diskusedSqlInt(&s, &nWORowid, | |
| 20064 | 20120 | "SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr", |
| 20065 | 20121 | s.zSchema); |
| 20066 | 20122 | if( rc ) return; |
| 20067 | 20123 | if( nWORowid>0 ){ |
| 20068 | - analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); | |
| 20069 | - analysisLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); | |
| 20124 | + diskusedLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); | |
| 20125 | + diskusedLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); | |
| 20070 | 20126 | } |
| 20071 | 20127 | nIndex = 0; |
| 20072 | - rc = analysisSqlInt(&s, &nIndex, | |
| 20128 | + rc = diskusedSqlInt(&s, &nIndex, | |
| 20073 | 20129 | "SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'", |
| 20074 | 20130 | s.zSchema); |
| 20075 | 20131 | if( rc ) return; |
| 20076 | - analysisLine(&s, "Number of indexes", "%lld\n", nIndex); | |
| 20132 | + diskusedLine(&s, "Number of indexes", "%lld\n", nIndex); | |
| 20077 | 20133 | ii = 0; |
| 20078 | - rc = analysisSqlInt(&s, &ii, | |
| 20134 | + rc = diskusedSqlInt(&s, &ii, | |
| 20079 | 20135 | "SELECT count(*) FROM \"%w\".sqlite_schema" |
| 20080 | 20136 | " WHERE name GLOB 'sqlite_autoindex_*' AND type='index'", |
| 20081 | 20137 | s.zSchema); |
| 20082 | 20138 | if( rc ) return; |
| 20083 | - analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); | |
| 20084 | - analysisLine(&s, "Number of implied indexes", "%lld\n", ii); | |
| 20085 | - analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); | |
| 20139 | + diskusedLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); | |
| 20140 | + diskusedLine(&s, "Number of implied indexes", "%lld\n", ii); | |
| 20141 | + diskusedLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); | |
| 20086 | 20142 | ii = 0; |
| 20087 | - rc = analysisSqlInt(&s, &ii, | |
| 20143 | + rc = diskusedSqlInt(&s, &ii, | |
| 20088 | 20144 | "SELECT sum(payload) FROM temp.%s" |
| 20089 | 20145 | " WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'", |
| 20090 | 20146 | s.zSU); |
| 20091 | 20147 | if( rc ) return; |
| 20092 | - analysisLine(&s, "Bytes of payload", "%-11lld ", ii); | |
| 20093 | - analysisPercent(&s, ii*100.0/(double)(pgsz*nPage)); | |
| 20148 | + diskusedLine(&s, "Bytes of payload", "%-11lld ", ii); | |
| 20149 | + diskusedPercent(&s, ii*100.0/(double)(pgsz*nPage)); | |
| 20094 | 20150 | |
| 20095 | - analysisTitle(&s, "Page counts for all tables with their indexes"); | |
| 20096 | - pStmt = analysisPrepare(&s, | |
| 20151 | + diskusedTitle(&s, "Page counts for all tables with their indexes"); | |
| 20152 | + pStmt = diskusedPrepare(&s, | |
| 20097 | 20153 | "SELECT upper(tblname),\n" |
| 20098 | 20154 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20099 | 20155 | " FROM temp.%s\n" |
| 20156 | + " WHERE tblname IS NOT NULL\n" | |
| 20157 | + " GROUP BY 1\n" | |
| 20158 | + " ORDER BY 2 DESC, 1;", | |
| 20159 | + s.zSU); | |
| 20160 | + if( pStmt==0 ) return; | |
| 20161 | + while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ | |
| 20162 | + sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); | |
| 20163 | + diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20164 | + diskusedPercent(&s, (nn*100.0)/(double)nPage); | |
| 20165 | + } | |
| 20166 | + if( diskusedStmtFinish(&s, rc, pStmt) ) return; | |
| 20167 | + | |
| 20168 | + diskusedTitle(&s, "Page counts for all tables and indexes separately"); | |
| 20169 | + pStmt = diskusedPrepare(&s, | |
| 20170 | + "SELECT upper(name),\n" | |
| 20171 | + " sum(int_pages+leaf_pages+ovfl_pages)\n" | |
| 20172 | + " FROM temp.%s\n" | |
| 20173 | + " WHERE name IS NOT NULL\n" | |
| 20100 | 20174 | " GROUP BY 1\n" |
| 20101 | 20175 | " ORDER BY 2 DESC, 1;", |
| 20102 | 20176 | s.zSU); |
| 20103 | 20177 | if( pStmt==0 ) return; |
| 20104 | 20178 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20105 | 20179 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20106 | - analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20107 | - analysisPercent(&s, (nn*100.0)/(double)nPage); | |
| 20108 | - } | |
| 20109 | - if( analysisStmtFinish(&s, rc, pStmt) ) return; | |
| 20110 | - | |
| 20111 | - analysisTitle(&s, "Page counts for all tables and indexes separately"); | |
| 20112 | - pStmt = analysisPrepare(&s, | |
| 20113 | - "SELECT upper(name),\n" | |
| 20114 | - " sum(int_pages+leaf_pages+ovfl_pages)\n" | |
| 20115 | - " FROM temp.%s\n" | |
| 20116 | - " GROUP BY 1\n" | |
| 20117 | - " ORDER BY 2 DESC, 1;", | |
| 20118 | - s.zSU); | |
| 20119 | - if( pStmt==0 ) return; | |
| 20120 | - while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ | |
| 20121 | - sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); | |
| 20122 | - analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20123 | - analysisPercent(&s, (nn*100.0)/(double)nPage); | |
| 20124 | - } | |
| 20125 | - if( analysisStmtFinish(&s, rc, pStmt) ) return; | |
| 20126 | - | |
| 20127 | - rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage); | |
| 20180 | + diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20181 | + diskusedPercent(&s, (nn*100.0)/(double)nPage); | |
| 20182 | + } | |
| 20183 | + if( diskusedStmtFinish(&s, rc, pStmt) ) return; | |
| 20184 | + | |
| 20185 | + rc = diskusedSubreport(&s, "All tables and indexes", "1", pgsz, nPage); | |
| 20128 | 20186 | if( rc ) return; |
| 20129 | - rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); | |
| 20187 | + rc = diskusedSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); | |
| 20130 | 20188 | if( rc ) return; |
| 20131 | 20189 | if( nWORowid>0 ){ |
| 20132 | - rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", | |
| 20190 | + rc = diskusedSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", | |
| 20133 | 20191 | pgsz, nPage); |
| 20134 | 20192 | if( rc ) return; |
| 20135 | - rc = analysisSubreport(&s, "All rowid tables", | |
| 20193 | + rc = diskusedSubreport(&s, "All rowid tables", | |
| 20136 | 20194 | "NOT is_without_rowid AND NOT is_index", |
| 20137 | 20195 | pgsz, nPage); |
| 20138 | 20196 | if( rc ) return; |
| 20139 | 20197 | } |
| 20140 | - rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage); | |
| 20198 | + rc = diskusedSubreport(&s, "All indexes", "is_index", pgsz, nPage); | |
| 20141 | 20199 | if( rc ) return; |
| 20142 | 20200 | |
| 20143 | - pStmt = analysisPrepare(&s, | |
| 20201 | + pStmt = diskusedPrepare(&s, | |
| 20144 | 20202 | "SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s" |
| 20145 | 20203 | " GROUP BY 1 ORDER BY 1", |
| 20146 | 20204 | s.zSU); |
| 20147 | 20205 | if( pStmt==0 ) return; |
| 20148 | 20206 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| @@ -20150,37 +20208,37 @@ | ||
| 20150 | 20208 | const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 20151 | 20209 | int nSubIndex = sqlite3_column_int(pStmt, 2); |
| 20152 | 20210 | if( nSubIndex==0 ){ |
| 20153 | 20211 | char *zTitle = sqlite3_mprintf("Table %s", zUpper); |
| 20154 | 20212 | char *zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20155 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20213 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20156 | 20214 | sqlite3_free(zTitle); |
| 20157 | 20215 | sqlite3_free(zWhere); |
| 20158 | 20216 | if( rc ) break; |
| 20159 | 20217 | }else{ |
| 20160 | 20218 | sqlite3_stmt *pS2; |
| 20161 | 20219 | char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper); |
| 20162 | 20220 | char *zWhere = sqlite3_mprintf("tblname=%Q", zName); |
| 20163 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20221 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20164 | 20222 | sqlite3_free(zTitle); |
| 20165 | 20223 | sqlite3_free(zWhere); |
| 20166 | 20224 | if( rc ) break; |
| 20167 | 20225 | zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper); |
| 20168 | 20226 | zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20169 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20227 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20170 | 20228 | sqlite3_free(zTitle); |
| 20171 | 20229 | sqlite3_free(zWhere); |
| 20172 | 20230 | if( rc ) break; |
| 20173 | 20231 | if( nSubIndex>1 ){ |
| 20174 | 20232 | zTitle = sqlite3_mprintf("All indexes of table %s", zUpper); |
| 20175 | 20233 | zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName); |
| 20176 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20234 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20177 | 20235 | sqlite3_free(zTitle); |
| 20178 | 20236 | sqlite3_free(zWhere); |
| 20179 | 20237 | if( rc ) break; |
| 20180 | 20238 | } |
| 20181 | - pS2 = analysisPrepare(&s, | |
| 20239 | + pS2 = diskusedPrepare(&s, | |
| 20182 | 20240 | "SELECT name, upper(name) FROM temp.%s" |
| 20183 | 20241 | " WHERE is_index AND tblname=%Q", |
| 20184 | 20242 | s.zSU, zName); |
| 20185 | 20243 | if( pS2==0 ){ |
| 20186 | 20244 | rc = SQLITE_NOMEM; |
| @@ -20189,25 +20247,25 @@ | ||
| 20189 | 20247 | while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){ |
| 20190 | 20248 | const char *zU = (const char*)sqlite3_column_text(pS2, 1); |
| 20191 | 20249 | const char *zN = (const char*)sqlite3_column_text(pS2, 0); |
| 20192 | 20250 | zTitle = sqlite3_mprintf("Index %s", zU); |
| 20193 | 20251 | zWhere = sqlite3_mprintf("name=%Q", zN); |
| 20194 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20252 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20195 | 20253 | sqlite3_free(zTitle); |
| 20196 | 20254 | sqlite3_free(zWhere); |
| 20197 | 20255 | if( rc ) break; |
| 20198 | 20256 | } |
| 20199 | - rc = analysisStmtFinish(&s, rc, pS2); | |
| 20257 | + rc = diskusedStmtFinish(&s, rc, pS2); | |
| 20200 | 20258 | if( rc ) break; |
| 20201 | 20259 | } |
| 20202 | 20260 | } |
| 20203 | - if( analysisStmtFinish(&s, rc, pStmt) ) return; | |
| 20261 | + if( diskusedStmtFinish(&s, rc, pStmt) ) return; | |
| 20204 | 20262 | |
| 20205 | 20263 | /* Append SQL statements that will recreate the raw data used for |
| 20206 | 20264 | ** the analysis. |
| 20207 | 20265 | */ |
| 20208 | - analysisTitle(&s, "Raw data used to generate this report"); | |
| 20266 | + diskusedTitle(&s, "Raw data used to generate this report"); | |
| 20209 | 20267 | sqlite3_str_appendf(s.pOut, |
| 20210 | 20268 | "The following SQL will create a table named \"space_used\" which\n" |
| 20211 | 20269 | "contains most of the information used to generate the report above.\n" |
| 20212 | 20270 | "*/\n" |
| 20213 | 20271 | ); |
| @@ -20233,11 +20291,11 @@ | ||
| 20233 | 20291 | " ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */ |
| 20234 | 20292 | " int_entries int -- B-tree entries on internal pages\n"/* 17 */ |
| 20235 | 20293 | ");\n" |
| 20236 | 20294 | "INSERT INTO space_used VALUES\n" |
| 20237 | 20295 | ); |
| 20238 | - pStmt = analysisPrepare(&s, | |
| 20296 | + pStmt = diskusedPrepare(&s, | |
| 20239 | 20297 | "SELECT quote(name), quote(tblname),\n" /* 0..1 */ |
| 20240 | 20298 | " is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */ |
| 20241 | 20299 | " depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */ |
| 20242 | 20300 | " int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */ |
| 20243 | 20301 | " leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */ |
| @@ -20268,11 +20326,11 @@ | ||
| 20268 | 20326 | sqlite3_column_int64(pStmt, 15), |
| 20269 | 20327 | sqlite3_column_int64(pStmt, 16), |
| 20270 | 20328 | sqlite3_column_int64(pStmt, 17)); |
| 20271 | 20329 | } |
| 20272 | 20330 | if( rc!=SQLITE_DONE ){ |
| 20273 | - analysisError(&s, "SQL run-time error: %s\nSQL: %s", | |
| 20331 | + diskusedError(&s, "SQL run-time error: %s\nSQL: %s", | |
| 20274 | 20332 | sqlite3_errmsg(s.db), sqlite3_sql(pStmt)); |
| 20275 | 20333 | sqlite3_finalize(pStmt); |
| 20276 | 20334 | return; |
| 20277 | 20335 | } |
| 20278 | 20336 | sqlite3_str_appendf(s.pOut,";\nCOMMIT;"); |
| @@ -20281,32 +20339,32 @@ | ||
| 20281 | 20339 | if( sqlite3_str_length(s.pOut) ){ |
| 20282 | 20340 | sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1, |
| 20283 | 20341 | sqlite3_free); |
| 20284 | 20342 | s.pOut = 0; |
| 20285 | 20343 | } |
| 20286 | - analysisReset(&s); | |
| 20344 | + diskusedReset(&s); | |
| 20287 | 20345 | } |
| 20288 | 20346 | |
| 20289 | 20347 | |
| 20290 | 20348 | #ifdef _WIN32 |
| 20291 | 20349 | |
| 20292 | 20350 | #endif |
| 20293 | -int sqlite3_analyze_init( | |
| 20351 | +int sqlite3_diskused_init( | |
| 20294 | 20352 | sqlite3 *db, |
| 20295 | 20353 | char **pzErrMsg, |
| 20296 | 20354 | const sqlite3_api_routines *pApi |
| 20297 | 20355 | ){ |
| 20298 | 20356 | int rc = SQLITE_OK; |
| 20299 | 20357 | SQLITE_EXTENSION_INIT2(pApi); |
| 20300 | 20358 | (void)pzErrMsg; /* Unused parameter */ |
| 20301 | - rc = sqlite3_create_function(db, "analyze", 1, | |
| 20359 | + rc = sqlite3_create_function(db, "diskused", 1, | |
| 20302 | 20360 | SQLITE_UTF8|SQLITE_INNOCUOUS, |
| 20303 | - 0, analyzeFunc, 0, 0); | |
| 20361 | + 0, diskusedFunc, 0, 0); | |
| 20304 | 20362 | return rc; |
| 20305 | 20363 | } |
| 20306 | 20364 | |
| 20307 | -/************************* End ext/misc/analyze.c ********************/ | |
| 20365 | +/************************* End ext/misc/diskused.c ********************/ | |
| 20308 | 20366 | |
| 20309 | 20367 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 20310 | 20368 | #define SQLITE_SHELL_HAVE_RECOVER 1 |
| 20311 | 20369 | #else |
| 20312 | 20370 | #define SQLITE_SHELL_HAVE_RECOVER 0 |
| @@ -25138,11 +25196,11 @@ | ||
| 25138 | 25196 | /* |
| 25139 | 25197 | ** Return true if either the SQLITE_NO_COLOR compile-time option is used |
| 25140 | 25198 | ** or if the NO_COLOR environment variable exists |
| 25141 | 25199 | */ |
| 25142 | 25200 | static int shellNoColor(void){ |
| 25143 | -#ifdef SQLITE_NO_COLOR | |
| 25201 | +#if defined(SQLITE_NO_COLOR) || defined(SQLITE_SHELL_FIDDLE) | |
| 25144 | 25202 | return 1; |
| 25145 | 25203 | #else |
| 25146 | 25204 | return getenv("NO_COLOR")!=0; |
| 25147 | 25205 | #endif |
| 25148 | 25206 | } |
| @@ -25172,11 +25230,11 @@ | ||
| 25172 | 25230 | case 1: |
| 25173 | 25231 | #if defined(SQLITE_PS1) |
| 25174 | 25232 | return SQLITE_PS1; |
| 25175 | 25233 | #else |
| 25176 | 25234 | if( shellNoColor() ){ |
| 25177 | - return "/A-/v /~> "; | |
| 25235 | + return "/A-/v /f-> "; | |
| 25178 | 25236 | }else{ |
| 25179 | 25237 | return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; |
| 25180 | 25238 | } |
| 25181 | 25239 | #endif |
| 25182 | 25240 | |
| @@ -25184,11 +25242,11 @@ | ||
| 25184 | 25242 | case 2: |
| 25185 | 25243 | #if defined(SQLITE_PS2) |
| 25186 | 25244 | return SQLITE_PS2; |
| 25187 | 25245 | #else |
| 25188 | 25246 | if( shellNoColor() ){ |
| 25189 | - return "/B/C> "; | |
| 25247 | + return "/B/C-> "; | |
| 25190 | 25248 | }else{ |
| 25191 | 25249 | return "/B/e[1;/x33/:36/;m/C/e[0m-> "; |
| 25192 | 25250 | } |
| 25193 | 25251 | #endif |
| 25194 | 25252 | |
| @@ -25196,11 +25254,15 @@ | ||
| 25196 | 25254 | ** of cases 1 and 2 */ |
| 25197 | 25255 | case 3: return "SQLITE_PS1"; |
| 25198 | 25256 | case 4: return "SQLITE_PS2"; |
| 25199 | 25257 | |
| 25200 | 25258 | /* Name of the application */ |
| 25259 | +#ifndef SQLITE_CLI_APPNAME | |
| 25201 | 25260 | case 'A': return "SQLite"; |
| 25261 | +#else | |
| 25262 | + case 'A': return SHELL_STRINGIFY(SQLITE_CLI_APPNAME); | |
| 25263 | +#endif | |
| 25202 | 25264 | |
| 25203 | 25265 | /* Full version number of the application, including patch level */ |
| 25204 | 25266 | case 'V': return sqlite3_libversion(); |
| 25205 | 25267 | |
| 25206 | 25268 | /* Version number without the patch level */ |
| @@ -26303,10 +26365,47 @@ | ||
| 26303 | 26365 | if( *az ){ |
| 26304 | 26366 | memcpy(*az, zNew, n+1 ); |
| 26305 | 26367 | } |
| 26306 | 26368 | } |
| 26307 | 26369 | } |
| 26370 | + | |
| 26371 | +/* Forward reference */ | |
| 26372 | +static int pickStr(const char *zArg, char **pzErr, ...); | |
| 26373 | + | |
| 26374 | +/* | |
| 26375 | +** Change the limits on the display mode. Return 0 on | |
| 26376 | +** success. Return non-zero if zArg is mis-formatted. | |
| 26377 | +** | |
| 26378 | +** Valid arguments: | |
| 26379 | +** | |
| 26380 | +** "on" Default limits | |
| 26381 | +** "off" All limits turned off | |
| 26382 | +** L,C Line and Characters limits set | |
| 26383 | +** L,C,T Line, Character, and Title limits set | |
| 26384 | +** | |
| 26385 | +** Anything else returns non-zero | |
| 26386 | +*/ | |
| 26387 | +static int modeSetLimit(ShellState *p, const char *zArg){ | |
| 26388 | + int k = zArg==0 ? 1 : pickStr(zArg,0,"on","off",""); | |
| 26389 | + if( k==0 ){ | |
| 26390 | + p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; | |
| 26391 | + p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; | |
| 26392 | + p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; | |
| 26393 | + }else if( k==1 ){ | |
| 26394 | + p->mode.spec.nLineLimit = 0; | |
| 26395 | + p->mode.spec.nCharLimit = 0; | |
| 26396 | + p->mode.spec.nTitleLimit = 0; | |
| 26397 | + }else{ | |
| 26398 | + int L, C, T = 0; | |
| 26399 | + int nNum = sscanf(zArg, "%d,%d,%d", &L, &C, &T); | |
| 26400 | + if( nNum<2 || L<0 || C<0 || T<0) return 1; | |
| 26401 | + p->mode.spec.nLineLimit = L; | |
| 26402 | + p->mode.spec.nCharLimit = C; | |
| 26403 | + if( nNum==3 ) p->mode.spec.nTitleLimit = T; | |
| 26404 | + } | |
| 26405 | + return 0; | |
| 26406 | +} | |
| 26308 | 26407 | |
| 26309 | 26408 | /* |
| 26310 | 26409 | ** Change the mode to eMode |
| 26311 | 26410 | */ |
| 26312 | 26411 | static void modeChange(ShellState *p, unsigned char eMode){ |
| @@ -26340,10 +26439,11 @@ | ||
| 26340 | 26439 | modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode); |
| 26341 | 26440 | }else if( eMode==MODE_BATCH ){ |
| 26342 | 26441 | u8 mFlags = p->mode.mFlags; |
| 26343 | 26442 | modeFree(&p->mode); |
| 26344 | 26443 | modeChange(p, MODE_List); |
| 26444 | + modeSetLimit(p, "off"); | |
| 26345 | 26445 | p->mode.mFlags = mFlags; |
| 26346 | 26446 | }else if( eMode==MODE_TTY ){ |
| 26347 | 26447 | u8 mFlags = p->mode.mFlags; |
| 26348 | 26448 | modeFree(&p->mode); |
| 26349 | 26449 | modeChange(p, MODE_QBox); |
| @@ -26976,11 +27076,11 @@ | ||
| 26976 | 27076 | return SQLITE_OK; |
| 26977 | 27077 | } |
| 26978 | 27078 | #endif |
| 26979 | 27079 | |
| 26980 | 27080 | /* |
| 26981 | -** Print a schema statement. This is helper routine to dump_callbac(). | |
| 27081 | +** Print a schema statement. This is a helper routine to dump_callback(). | |
| 26982 | 27082 | ** |
| 26983 | 27083 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 26984 | 27084 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 26985 | 27085 | ** |
| 26986 | 27086 | ** If the schema statement in z[] contains a start-of-comment and if |
| @@ -28428,12 +28528,12 @@ | ||
| 28428 | 28528 | ".databases List names and files of attached databases", |
| 28429 | 28529 | ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", |
| 28430 | 28530 | #if SQLITE_SHELL_HAVE_RECOVER |
| 28431 | 28531 | ".dbinfo ?DB? Show status information about the database", |
| 28432 | 28532 | #endif |
| 28433 | - ".dbstat ?SCHEMA? Report database space and size stats", | |
| 28434 | 28533 | ".dbtotxt Hex dump of the database file", |
| 28534 | + ".diskused ?SCHEMA? Report database space and size stats", | |
| 28435 | 28535 | ".dump ?OBJECTS? Render database content as SQL", |
| 28436 | 28536 | " Options:", |
| 28437 | 28537 | " --data-only Output only INSERT statements", |
| 28438 | 28538 | " --newlines Allow unescaped newline characters in output", |
| 28439 | 28539 | " --nosys Omit system tables (ex: \"sqlite_stat1\")", |
| @@ -28540,10 +28640,13 @@ | ||
| 28540 | 28640 | " --reset Reset the count for each input and interrupt", |
| 28541 | 28641 | " --timeout S Halt after running for S seconds", |
| 28542 | 28642 | #endif |
| 28543 | 28643 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 28544 | 28644 | " --hard-reset Unset SQLITE_PS1/2 and then --reset", |
| 28645 | +#ifndef SQLITE_NO_COLOR | |
| 28646 | + " --no-color Disable color prompts. Use --color to re-enable", | |
| 28647 | +#endif | |
| 28545 | 28648 | " --reset Revert to default prompts", |
| 28546 | 28649 | " --show Show the current prompt strings", |
| 28547 | 28650 | " -- No more options. Subsequent args are prompts", |
| 28548 | 28651 | #ifndef SQLITE_SHELL_FIDDLE |
| 28549 | 28652 | ".quit Stop interpreting input stream, exit if primary.", |
| @@ -29440,11 +29543,11 @@ | ||
| 29440 | 29543 | sqlite3_base64_init(p->db, 0, 0); |
| 29441 | 29544 | sqlite3_base85_init(p->db, 0, 0); |
| 29442 | 29545 | sqlite3_regexp_init(p->db, 0, 0); |
| 29443 | 29546 | sqlite3_ieee_init(p->db, 0, 0); |
| 29444 | 29547 | sqlite3_series_init(p->db, 0, 0); |
| 29445 | - sqlite3_analyze_init(p->db, 0, 0); | |
| 29548 | + sqlite3_diskused_init(p->db, 0, 0); | |
| 29446 | 29549 | #ifndef SQLITE_SHELL_FIDDLE |
| 29447 | 29550 | sqlite3_fileio_init(p->db, 0, 0); |
| 29448 | 29551 | sqlite3_completion_init(p->db, 0, 0); |
| 29449 | 29552 | #endif |
| 29450 | 29553 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -31246,11 +31349,11 @@ | ||
| 31246 | 31349 | typedef struct ArCommand ArCommand; |
| 31247 | 31350 | struct ArCommand { |
| 31248 | 31351 | u8 eCmd; /* An AR_CMD_* value */ |
| 31249 | 31352 | u8 bVerbose; /* True if --verbose */ |
| 31250 | 31353 | u8 bZip; /* True if the archive is a ZIP */ |
| 31251 | - u8 bDryRun; /* True if --dry-run */ | |
| 31354 | + u8 bDryRun; /* 1 for --dry-run, 2 for --debug */ | |
| 31252 | 31355 | u8 bAppend; /* True if --append */ |
| 31253 | 31356 | u8 bGlob; /* True if --glob */ |
| 31254 | 31357 | u8 fromCmdLine; /* Run from -A instead of .archive */ |
| 31255 | 31358 | int nArg; /* Number of command arguments */ |
| 31256 | 31359 | char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| @@ -31308,10 +31411,11 @@ | ||
| 31308 | 31411 | #define AR_SWITCH_FILE 9 |
| 31309 | 31412 | #define AR_SWITCH_DIRECTORY 10 |
| 31310 | 31413 | #define AR_SWITCH_APPEND 11 |
| 31311 | 31414 | #define AR_SWITCH_DRYRUN 12 |
| 31312 | 31415 | #define AR_SWITCH_GLOB 13 |
| 31416 | +#define AR_SWITCH_DEBUG 14 | |
| 31313 | 31417 | |
| 31314 | 31418 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 31315 | 31419 | switch( eSwitch ){ |
| 31316 | 31420 | case AR_CMD_CREATE: |
| 31317 | 31421 | case AR_CMD_EXTRACT: |
| @@ -31325,11 +31429,14 @@ | ||
| 31325 | 31429 | } |
| 31326 | 31430 | pAr->eCmd = eSwitch; |
| 31327 | 31431 | break; |
| 31328 | 31432 | |
| 31329 | 31433 | case AR_SWITCH_DRYRUN: |
| 31330 | - pAr->bDryRun = 1; | |
| 31434 | + if( pAr->bDryRun<2 ) pAr->bDryRun = 1; | |
| 31435 | + break; | |
| 31436 | + case AR_SWITCH_DEBUG: | |
| 31437 | + pAr->bDryRun = 2; | |
| 31331 | 31438 | break; |
| 31332 | 31439 | case AR_SWITCH_GLOB: |
| 31333 | 31440 | pAr->bGlob = 1; |
| 31334 | 31441 | break; |
| 31335 | 31442 | case AR_SWITCH_VERBOSE: |
| @@ -31376,10 +31483,11 @@ | ||
| 31376 | 31483 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 31377 | 31484 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 31378 | 31485 | { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 31379 | 31486 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 31380 | 31487 | { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 31488 | + { "debug", 0, AR_SWITCH_DEBUG, 0 }, | |
| 31381 | 31489 | { "glob", 'g', AR_SWITCH_GLOB, 0 }, |
| 31382 | 31490 | }; |
| 31383 | 31491 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 31384 | 31492 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 31385 | 31493 | |
| @@ -31676,18 +31784,41 @@ | ||
| 31676 | 31784 | |
| 31677 | 31785 | /* |
| 31678 | 31786 | ** Implementation of .ar "eXtract" command. |
| 31679 | 31787 | */ |
| 31680 | 31788 | static int arExtractCommand(ArCommand *pAr){ |
| 31789 | + /* The zSql1[] string is a template for the query that does the | |
| 31790 | + ** extraction. Notes: | |
| 31791 | + ** | |
| 31792 | + ** * $dir is the directory into which the archive is to be extracted | |
| 31793 | + ** * $pass is the integer pass number: 0, 1, or 2 | |
| 31794 | + ** * The dest CTE is created so that realpath($dir) only needs | |
| 31795 | + ** to be called once. | |
| 31796 | + */ | |
| 31681 | 31797 | const char *zSql1 = |
| 31682 | - "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n" | |
| 31683 | - "SELECT ($dir || name),\n" | |
| 31684 | - " CASE WHEN $dryrun THEN 0\n" | |
| 31685 | - " ELSE writefile($dir||name, %s, mode, mtime) END\n" | |
| 31798 | + "WITH dest(dpath,dlen) AS (\n" | |
| 31799 | +#ifdef _WIN32 | |
| 31800 | + " SELECT realpath($dir) || '\\',\n" | |
| 31801 | +#else | |
| 31802 | + " SELECT realpath($dir) || '/',\n" | |
| 31803 | +#endif | |
| 31804 | + " 1+length(realpath($dir))\n" | |
| 31805 | + ")\n" | |
| 31806 | + "SELECT\n" | |
| 31807 | + " ($dir || name),\n" | |
| 31808 | + " CASE $dryrun\n" /* vv--- azExtraArg */ | |
| 31809 | + " WHEN 0 THEN writefile($dir||name, %s, mode, mtime)\n" | |
| 31810 | + " WHEN 1 THEN 0\n" | |
| 31811 | + " ELSE shell_putsnl(format('writefile(%%Q,%%s,%%0o,%%d)'," | |
| 31812 | + "$dir||name,quote(%s),mode,mtime)) IS NULL\n" | |
| 31813 | + " END\n" /* ^^--- azExtraArg */ | |
| 31686 | 31814 | " FROM dest CROSS JOIN %s\n" |
| 31687 | - " WHERE (%s)\n" | |
| 31688 | - " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */ | |
| 31815 | + " WHERE (%s)\n" /* ^^-- pAr->zSrcTable */ | |
| 31816 | + /* ^^--- zWhere */ | |
| 31817 | + " AND (CASE $pass WHEN 0 THEN (mode&0xf000)<>0xa000\n" | |
| 31818 | + " WHEN 1 THEN (mode&0xf000)=0xa000\n" | |
| 31819 | + " ELSE data IS NULL END)\n" | |
| 31689 | 31820 | " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 31690 | 31821 | " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 31691 | 31822 | |
| 31692 | 31823 | const char *azExtraArg[] = { |
| 31693 | 31824 | "sqlar_uncompress(data, sz)", |
| @@ -31714,39 +31845,48 @@ | ||
| 31714 | 31845 | } |
| 31715 | 31846 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 31716 | 31847 | } |
| 31717 | 31848 | |
| 31718 | 31849 | shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 31719 | - azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere | |
| 31850 | + azExtraArg[pAr->bZip], | |
| 31851 | + azExtraArg[pAr->bZip], | |
| 31852 | + pAr->zSrcTable, | |
| 31853 | + zWhere | |
| 31720 | 31854 | ); |
| 31721 | 31855 | |
| 31722 | 31856 | if( rc==SQLITE_OK ){ |
| 31723 | 31857 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 31724 | 31858 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 31725 | 31859 | j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 31726 | 31860 | sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 31727 | 31861 | |
| 31728 | 31862 | /* Run the SELECT statement twice |
| 31729 | - ** (0) writefile() all files and directories | |
| 31730 | - ** (1) writefile() for directory again | |
| 31731 | - ** The second pass is so that the timestamps for extracted directories | |
| 31863 | + ** (0) writefile() files and directories | |
| 31864 | + ** (1) writefile() symlinks | |
| 31865 | + ** (2) writefile() for directory again | |
| 31866 | + ** The third pass is so that the timestamps for extracted directories | |
| 31732 | 31867 | ** will be reset to the value in the archive, since populating them |
| 31733 | 31868 | ** in the first pass will have changed the timestamp. */ |
| 31734 | - for(i=0; i<2; i++){ | |
| 31869 | + for(i=0; i<3; i++){ | |
| 31870 | + if( pAr->bDryRun>=2 ){ | |
| 31871 | + cli_printf(pAr->out, "*** BEGIN PASS %d ***\n", i+1); | |
| 31872 | + } | |
| 31735 | 31873 | j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 31736 | 31874 | sqlite3_bind_int(pSql, j, i); |
| 31737 | - if( pAr->bDryRun ){ | |
| 31875 | + if( pAr->bDryRun && i==0 ){ | |
| 31738 | 31876 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 31739 | - if( pAr->bVerbose==0 ) break; | |
| 31740 | 31877 | } |
| 31741 | 31878 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 31742 | 31879 | if( i==0 && pAr->bVerbose ){ |
| 31743 | 31880 | cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 31744 | 31881 | } |
| 31745 | 31882 | } |
| 31746 | - if( pAr->bDryRun ) break; | |
| 31883 | + if( pAr->bDryRun==1 ) break; | |
| 31747 | 31884 | shellReset(&rc, pSql); |
| 31885 | + if( pAr->bDryRun>=2 ){ | |
| 31886 | + cli_printf(pAr->out, "*** END PASS %d ***\n", i+1); | |
| 31887 | + } | |
| 31748 | 31888 | } |
| 31749 | 31889 | shellFinalize(&rc, pSql); |
| 31750 | 31890 | } |
| 31751 | 31891 | |
| 31752 | 31892 | sqlite3_free(zDir); |
| @@ -32257,11 +32397,11 @@ | ||
| 32257 | 32397 | ; |
| 32258 | 32398 | static const char * const zCollectVar = "\ |
| 32259 | 32399 | SELECT\ |
| 32260 | 32400 | '('||x'0a'\ |
| 32261 | 32401 | || group_concat(\ |
| 32262 | - cname||' ANY',\ | |
| 32402 | + cname,\ | |
| 32263 | 32403 | ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\ |
| 32264 | 32404 | ||')' AS ColsSpec \ |
| 32265 | 32405 | FROM (\ |
| 32266 | 32406 | SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \ |
| 32267 | 32407 | FROM ColNames ORDER BY cpos\ |
| @@ -33102,30 +33242,14 @@ | ||
| 33102 | 33242 | }else if( optionMatch(z,"limits") ){ |
| 33103 | 33243 | if( (++i)>=nArg ){ |
| 33104 | 33244 | dotCmdError(p, i-1, "missing argument", 0); |
| 33105 | 33245 | return 1; |
| 33106 | 33246 | } |
| 33107 | - k = pickStr(azArg[i],0,"on","off",""); | |
| 33108 | - if( k==0 ){ | |
| 33109 | - p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; | |
| 33110 | - p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; | |
| 33111 | - p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; | |
| 33112 | - }else if( k==1 ){ | |
| 33113 | - p->mode.spec.nLineLimit = 0; | |
| 33114 | - p->mode.spec.nCharLimit = 0; | |
| 33115 | - p->mode.spec.nTitleLimit = 0; | |
| 33116 | - }else{ | |
| 33117 | - int L, C, T = 0; | |
| 33118 | - int nNum = sscanf(azArg[i], "%d,%d,%d", &L, &C, &T); | |
| 33119 | - if( nNum<2 || L<0 || C<0 || T<0){ | |
| 33120 | - dotCmdError(p, i, "bad argument", "Should be \"L,C,T\" where L, C" | |
| 33121 | - " and T are unsigned integers"); | |
| 33122 | - return 1; | |
| 33123 | - } | |
| 33124 | - p->mode.spec.nLineLimit = L; | |
| 33125 | - p->mode.spec.nCharLimit = C; | |
| 33126 | - if( nNum==3 ) p->mode.spec.nTitleLimit = T; | |
| 33247 | + if( modeSetLimit(p, azArg[i]) ){ | |
| 33248 | + dotCmdError(p, i, "bad argument", "Should be \"on\" or \"off\" or " | |
| 33249 | + "\"L,C,T\" where L, C, and T are unsigned integers"); | |
| 33250 | + return 1; | |
| 33127 | 33251 | } |
| 33128 | 33252 | chng = 1; |
| 33129 | 33253 | }else if( optionMatch(z,"list") ){ |
| 33130 | 33254 | int ii; |
| 33131 | 33255 | cli_puts("available modes:", p->out); |
| @@ -34339,11 +34463,16 @@ | ||
| 34339 | 34463 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 34340 | 34464 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 34341 | 34465 | }else |
| 34342 | 34466 | #endif /* SQLITE_SHELL_HAVE_RECOVER */ |
| 34343 | 34467 | |
| 34344 | - if( c=='d' && n==6 && cli_strncmp(azArg[0], "dbstat", n)==0 ){ | |
| 34468 | + if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ | |
| 34469 | + open_db(p, 0); | |
| 34470 | + rc = shell_dbtotxt_command(p, nArg, azArg); | |
| 34471 | + }else | |
| 34472 | + | |
| 34473 | + if( c=='d' && n==8 && cli_strncmp(azArg[0], "diskused", n)==0 ){ | |
| 34345 | 34474 | const char *zSchema = 0; |
| 34346 | 34475 | int ii; |
| 34347 | 34476 | char *zSql; |
| 34348 | 34477 | open_db(p, 0); |
| 34349 | 34478 | for(ii=1; ii<nArg; ii++){ |
| @@ -34358,27 +34487,19 @@ | ||
| 34358 | 34487 | rc = 1; |
| 34359 | 34488 | goto meta_command_exit; |
| 34360 | 34489 | } |
| 34361 | 34490 | zSchema = z; |
| 34362 | 34491 | } |
| 34363 | - zSql = sqlite3_mprintf("SELECT analyze(%Q)", zSchema); | |
| 34492 | + zSql = sqlite3_mprintf("SELECT diskused(%Q)", zSchema); | |
| 34364 | 34493 | shell_check_oom(zSql); |
| 34365 | 34494 | modePush(p); |
| 34366 | 34495 | modeChange(p, MODE_BATCH); |
| 34367 | - p->mode.spec.nLineLimit = 0; | |
| 34368 | - p->mode.spec.nCharLimit = 0; | |
| 34369 | - p->mode.spec.nTitleLimit = 0; | |
| 34370 | 34496 | shell_exec(p, zSql, 0); |
| 34371 | 34497 | modePop(p); |
| 34372 | 34498 | sqlite3_free(zSql); |
| 34373 | 34499 | }else |
| 34374 | 34500 | |
| 34375 | - if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ | |
| 34376 | - open_db(p, 0); | |
| 34377 | - rc = shell_dbtotxt_command(p, nArg, azArg); | |
| 34378 | - }else | |
| 34379 | - | |
| 34380 | 34501 | if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){ |
| 34381 | 34502 | char *zLike = 0; |
| 34382 | 34503 | char *zSql; |
| 34383 | 34504 | int i; |
| 34384 | 34505 | int savedShellFlags = p->shellFlgs; |
| @@ -35491,10 +35612,26 @@ | ||
| 35491 | 35612 | }else |
| 35492 | 35613 | if( strcmp(z,"-show")==0 ){ |
| 35493 | 35614 | cli_printf(stdout,"Main prompt: '%s'\n", prompt_string(p, 0)); |
| 35494 | 35615 | cli_printf(stdout,"Continuation: '%s'\n", prompt_string(p, 1)); |
| 35495 | 35616 | }else |
| 35617 | +#ifndef SQLITE_NO_COLOR | |
| 35618 | + if( strcmp(z,"-color")==0 ){ | |
| 35619 | +#ifdef _WIN32 | |
| 35620 | + _putenv("NO_COLOR="); | |
| 35621 | +#else | |
| 35622 | + unsetenv("NO_COLOR"); | |
| 35623 | +#endif | |
| 35624 | + }else | |
| 35625 | + if( strcmp(z,"-no-color")==0 ){ | |
| 35626 | +#ifdef _WIN32 | |
| 35627 | + _putenv("NO_COLOR=1"); | |
| 35628 | +#else | |
| 35629 | + setenv("NO_COLOR","1",1); | |
| 35630 | +#endif | |
| 35631 | + }else | |
| 35632 | +#endif | |
| 35496 | 35633 | if( strcmp(z,"-")==0 ){ |
| 35497 | 35634 | noOpt = 1; |
| 35498 | 35635 | }else |
| 35499 | 35636 | { |
| 35500 | 35637 | dotCmdError(p, i, "unknown option", 0); |
| @@ -35505,10 +35642,11 @@ | ||
| 35505 | 35642 | dotCmdError(p, i, "extra argument", 0); |
| 35506 | 35643 | rc = 1; |
| 35507 | 35644 | goto meta_command_exit; |
| 35508 | 35645 | }else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){ |
| 35509 | 35646 | dotCmdError(p, i, "use quotes around the prompt string", 0); |
| 35647 | + rc = 1; | |
| 35510 | 35648 | }else{ |
| 35511 | 35649 | free(p->azPrompt[cnt]); |
| 35512 | 35650 | p->azPrompt[cnt] = strdup(z); |
| 35513 | 35651 | cnt++; |
| 35514 | 35652 | } |
| @@ -37717,17 +37855,17 @@ | ||
| 37717 | 37855 | " -- treat no subsequent arguments as options\n" |
| 37718 | 37856 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 37719 | 37857 | " -A ARGS... run \".archive ARGS\" and exit\n" |
| 37720 | 37858 | #endif |
| 37721 | 37859 | " -append append the database to the end of the file\n" |
| 37722 | - " -ascii set output mode to 'ascii'\n" | |
| 37860 | + " -ascii set '.mode ascii'\n" | |
| 37723 | 37861 | " -bail stop after hitting an error\n" |
| 37724 | 37862 | " -batch force batch I/O\n" |
| 37725 | - " -box set output mode to 'box'\n" | |
| 37863 | + " -box set '.mode box'\n" | |
| 37726 | 37864 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 37727 | - " -column set output mode to 'column'\n" | |
| 37728 | - " -csv set output mode to 'csv'\n" | |
| 37865 | + " -column set '.mode column'\n" | |
| 37866 | + " -csv set '.mode csv -limits off'\n" | |
| 37729 | 37867 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37730 | 37868 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 37731 | 37869 | #endif |
| 37732 | 37870 | " -echo print inputs before execution\n" |
| 37733 | 37871 | " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" |
| @@ -37735,18 +37873,18 @@ | ||
| 37735 | 37873 | " -[no]header turn headers on or off\n" |
| 37736 | 37874 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 37737 | 37875 | " -heap SIZE Size of heap for memsys3 or memsys5\n" |
| 37738 | 37876 | #endif |
| 37739 | 37877 | " -help show this message\n" |
| 37740 | - " -html set output mode to HTML\n" | |
| 37878 | + " -html set '.mode html'\n" | |
| 37741 | 37879 | " -ifexists only open if database already exists\n" |
| 37742 | 37880 | " -interactive force interactive I/O\n" |
| 37743 | - " -json set output mode to 'json'\n" | |
| 37744 | - " -line set output mode to 'line'\n" | |
| 37745 | - " -list set output mode to 'list'\n" | |
| 37881 | + " -json set '.mode json'\n" | |
| 37882 | + " -line set '.mode line'\n" | |
| 37883 | + " -list set '.mode list'\n" | |
| 37746 | 37884 | " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
| 37747 | - " -markdown set output mode to 'markdown'\n" | |
| 37885 | + " -markdown set '.mode markdown'\n" | |
| 37748 | 37886 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37749 | 37887 | " -maxsize N maximum size for a --deserialize database\n" |
| 37750 | 37888 | #endif |
| 37751 | 37889 | " -memtrace trace all memory allocations and deallocations\n" |
| 37752 | 37890 | " -mmap N default mmap size set to N\n" |
| @@ -37759,21 +37897,21 @@ | ||
| 37759 | 37897 | " -nonce STRING set the safe-mode escape nonce\n" |
| 37760 | 37898 | " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" |
| 37761 | 37899 | " -nullvalue TEXT set text string for NULL values. Default ''\n" |
| 37762 | 37900 | " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
| 37763 | 37901 | " -pcachetrace trace all page cache operations\n" |
| 37764 | - " -quote set output mode to 'quote'\n" | |
| 37902 | + " -quote set '.mode quote'\n" | |
| 37765 | 37903 | " -readonly open the database read-only\n" |
| 37766 | 37904 | " -safe enable safe-mode\n" |
| 37767 | 37905 | " -screenwidth N use N as the default screenwidth \n" |
| 37768 | 37906 | " -separator SEP set output column separator. Default: '|'\n" |
| 37769 | 37907 | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| 37770 | 37908 | " -sorterref SIZE sorter references threshold size\n" |
| 37771 | 37909 | #endif |
| 37772 | 37910 | " -stats print memory stats before each finalize\n" |
| 37773 | - " -table set output mode to 'table'\n" | |
| 37774 | - " -tabs set output mode to 'tabs'\n" | |
| 37911 | + " -table set '.mode table'\n" | |
| 37912 | + " -tabs set '.mode tabs'\n" | |
| 37775 | 37913 | " -unsafe-testing allow unsafe commands and modes for testing\n" |
| 37776 | 37914 | " -version show SQLite version\n" |
| 37777 | 37915 | " -vfs NAME use NAME as the default VFS\n" |
| 37778 | 37916 | " -vfstrace enable tracing of all VFS calls\n" |
| 37779 | 37917 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -37801,10 +37939,23 @@ | ||
| 37801 | 37939 | sputz(stdout, "WARNING: attempt to configure SQLite after" |
| 37802 | 37940 | " initialization.\n"); |
| 37803 | 37941 | } |
| 37804 | 37942 | } |
| 37805 | 37943 | |
| 37944 | +#if HAVE_EDITLINE | |
| 37945 | +/* | |
| 37946 | +** https://sqlite.org/forum/forumpost/aad7a634916ff050: | |
| 37947 | +** | |
| 37948 | +** Calling setlocale(LC_...,"") is required to get libedit to accept | |
| 37949 | +** non-ASCII input. | |
| 37950 | +*/ | |
| 37951 | +#define DO_SET_LOCALE 1 | |
| 37952 | +#include <locale.h> | |
| 37953 | +#else | |
| 37954 | +#define DO_SET_LOCALE 0 | |
| 37955 | +#endif | |
| 37956 | + | |
| 37806 | 37957 | /* |
| 37807 | 37958 | ** Initialize the state information in data |
| 37808 | 37959 | */ |
| 37809 | 37960 | static void main_init(ShellState *p) { |
| 37810 | 37961 | memset(p, 0, sizeof(*p)); |
| @@ -37825,10 +37976,14 @@ | ||
| 37825 | 37976 | #else |
| 37826 | 37977 | /* No \001...\002 escapes required for linenoise or when not using a |
| 37827 | 37978 | ** command-line editing library */ |
| 37828 | 37979 | p->bDelimitNonprint = 0; |
| 37829 | 37980 | #endif |
| 37981 | +#if DO_SET_LOCALE | |
| 37982 | + setlocale(LC_CTYPE,""); | |
| 37983 | +#endif | |
| 37984 | +#undef DO_SET_LOCALE | |
| 37830 | 37985 | } |
| 37831 | 37986 | |
| 37832 | 37987 | /* |
| 37833 | 37988 | ** Output text to the console in a font that attracts extra attention. |
| 37834 | 37989 | */ |
| @@ -37854,11 +38009,11 @@ | ||
| 37854 | 38009 | } |
| 37855 | 38010 | |
| 37856 | 38011 | /* |
| 37857 | 38012 | ** The callback from atexit(). |
| 37858 | 38013 | */ |
| 37859 | -static void abnormalExit(void){ | |
| 38014 | +static void SQLITE_CDECL abnormalExit(void){ | |
| 37860 | 38015 | if( seenInterrupt ) eputz("Program interrupted.\n"); |
| 37861 | 38016 | if( globalShellState ){ |
| 37862 | 38017 | clearTempFile(globalShellState, 1, 1); |
| 37863 | 38018 | } |
| 37864 | 38019 | } |
| @@ -38065,11 +38220,11 @@ | ||
| 38065 | 38220 | stdin_is_interactive = 0; |
| 38066 | 38221 | nCmd++; |
| 38067 | 38222 | azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); |
| 38068 | 38223 | shell_check_oom(azCmd); |
| 38069 | 38224 | aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd); |
| 38070 | - shell_check_oom(azCmd); | |
| 38225 | + shell_check_oom(aiCmd); | |
| 38071 | 38226 | azCmd[nCmd-1] = z; |
| 38072 | 38227 | aiCmd[nCmd-1] = i; |
| 38073 | 38228 | } |
| 38074 | 38229 | continue; |
| 38075 | 38230 | } |
| @@ -38354,10 +38509,11 @@ | ||
| 38354 | 38509 | modeChange(&data, MODE_Psql); |
| 38355 | 38510 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 38356 | 38511 | modeChange(&data, MODE_Box); |
| 38357 | 38512 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 38358 | 38513 | modeChange(&data, MODE_Csv); |
| 38514 | + modeSetLimit(&data, "off"); | |
| 38359 | 38515 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38360 | 38516 | /* See similar code at tag-20250224-1 */ |
| 38361 | 38517 | const char *zEsc = argv[++i]; |
| 38362 | 38518 | int k; |
| 38363 | 38519 | for(k=0; k<ArraySize(qrfEscNames); k++){ |
| @@ -38412,12 +38568,14 @@ | ||
| 38412 | 38568 | }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
| 38413 | 38569 | modeSetStr(&data.mode.spec.zNull, |
| 38414 | 38570 | cmdline_option_value(argc,argv,++i)); |
| 38415 | 38571 | }else if( cli_strcmp(z,"-header")==0 ){ |
| 38416 | 38572 | data.mode.spec.bTitles = QRF_Yes; |
| 38573 | + data.mode.mFlags |= MFLG_HDR; | |
| 38417 | 38574 | }else if( cli_strcmp(z,"-noheader")==0 ){ |
| 38418 | 38575 | data.mode.spec.bTitles = QRF_No; |
| 38576 | + data.mode.mFlags |= MFLG_HDR; | |
| 38419 | 38577 | }else if( cli_strcmp(z,"-echo")==0 ){ |
| 38420 | 38578 | data.mode.mFlags |= MFLG_ECHO; |
| 38421 | 38579 | }else if( cli_strcmp(z,"-eqp")==0 ){ |
| 38422 | 38580 | data.mode.autoEQP = AUTOEQP_on; |
| 38423 | 38581 | }else if( cli_strcmp(z,"-eqpfull")==0 ){ |
| 38424 | 38582 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -5,16 +5,16 @@ | |
| 5 | ** |
| 6 | ** ext/expert/sqlite3expert.c |
| 7 | ** ext/expert/sqlite3expert.h |
| 8 | ** ext/intck/sqlite3intck.c |
| 9 | ** ext/intck/sqlite3intck.h |
| 10 | ** ext/misc/analyze.c |
| 11 | ** ext/misc/appendvfs.c |
| 12 | ** ext/misc/base64.c |
| 13 | ** ext/misc/base85.c |
| 14 | ** ext/misc/completion.c |
| 15 | ** ext/misc/decimal.c |
| 16 | ** ext/misc/fileio.c |
| 17 | ** ext/misc/ieee754.c |
| 18 | ** ext/misc/memtrace.c |
| 19 | ** ext/misc/pcachetrace.c |
| 20 | ** ext/misc/regexp.c |
| @@ -154,10 +154,11 @@ | |
| 154 | #include <string.h> |
| 155 | #include <stdio.h> |
| 156 | #include <assert.h> |
| 157 | #include <math.h> |
| 158 | #include <stdint.h> |
| 159 | #include "sqlite3.h" |
| 160 | typedef sqlite3_int64 i64; |
| 161 | typedef sqlite3_uint64 u64; |
| 162 | typedef unsigned char u8; |
| 163 | #include <ctype.h> |
| @@ -190,13 +191,14 @@ | |
| 190 | #include <sys/stat.h> |
| 191 | |
| 192 | #if HAVE_READLINE |
| 193 | # include <readline/readline.h> |
| 194 | # include <readline/history.h> |
| 195 | #endif |
| 196 | |
| 197 | #if HAVE_EDITLINE |
| 198 | # include <editline/readline.h> |
| 199 | #endif |
| 200 | |
| 201 | #if HAVE_EDITLINE || HAVE_READLINE |
| 202 | |
| @@ -744,12 +746,11 @@ | |
| 744 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 745 | char **pzErr /* OUT: Write error message here */ |
| 746 | ); |
| 747 | |
| 748 | /* |
| 749 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries and for |
| 750 | ** sqlite3_qrf_spec.mxColWidth and .nScreenWidth |
| 751 | */ |
| 752 | #define QRF_MAX_WIDTH 10000 |
| 753 | #define QRF_MIN_WIDTH 0 |
| 754 | |
| 755 | /* |
| @@ -1129,10 +1130,14 @@ | |
| 1129 | sqlite3_str_append(pOut, "-", 1); |
| 1130 | } |
| 1131 | if( N<10000 ){ |
| 1132 | sqlite3_str_appendf(pOut, "%4lld ", N); |
| 1133 | return; |
| 1134 | } |
| 1135 | for(i=1; i<=18; i++){ |
| 1136 | N = (N+5)/10; |
| 1137 | if( N<10000 ){ |
| 1138 | int n = (int)N; |
| @@ -1289,12 +1294,12 @@ | |
| 1289 | if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ |
| 1290 | int nSp = 0; |
| 1291 | sqlite3_str_reset(pStats); |
| 1292 | if( nCycle>=0 && nTotal>0 ){ |
| 1293 | qrfApproxInt64(pStats, nCycle); |
| 1294 | sqlite3_str_appendf(pStats, " %3d%%", |
| 1295 | ((nCycle*100)+nTotal/2) / nTotal |
| 1296 | ); |
| 1297 | nSp = 2; |
| 1298 | } |
| 1299 | if( nLoop>=0 ){ |
| 1300 | if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); |
| @@ -1787,11 +1792,11 @@ | |
| 1787 | } |
| 1788 | if( i>0 ){ |
| 1789 | sqlite3_str_append(pOut, (const char*)z, i); |
| 1790 | } |
| 1791 | switch( z[i] ){ |
| 1792 | case '>': sqlite3_str_append(pOut, "<", 4); break; |
| 1793 | case '&': sqlite3_str_append(pOut, "&", 5); break; |
| 1794 | case '<': sqlite3_str_append(pOut, "<", 4); break; |
| 1795 | case '"': sqlite3_str_append(pOut, """, 6); break; |
| 1796 | case '\'': sqlite3_str_append(pOut, "'", 5); break; |
| 1797 | default: i--; |
| @@ -2281,11 +2286,11 @@ | |
| 2281 | if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ |
| 2282 | /* Perhaps try to back up to a better place to break the line */ |
| 2283 | for(k=i-1; k>=i/2; k--){ |
| 2284 | if( qrfSpace(z[k]) ) break; |
| 2285 | } |
| 2286 | if( k<i/2 ){ |
| 2287 | for(k=i; k>=i/2; k--){ |
| 2288 | if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; |
| 2289 | } |
| 2290 | } |
| 2291 | if( k>=i/2 ){ |
| @@ -2532,16 +2537,16 @@ | |
| 2532 | const char *azDash[2] = { |
| 2533 | BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, |
| 2534 | DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 |
| 2535 | };/* 0 1 2 3 4 5 6 7 8 9 */ |
| 2536 | const int nDash = 30; |
| 2537 | N *= 3; |
| 2538 | while( N>nDash ){ |
| 2539 | sqlite3_str_append(pOut, azDash[bDbl], nDash); |
| 2540 | N -= nDash; |
| 2541 | } |
| 2542 | sqlite3_str_append(pOut, azDash[bDbl], N); |
| 2543 | } |
| 2544 | |
| 2545 | /* |
| 2546 | ** Draw a horizontal separator for a QRF_STYLE_Box table. |
| 2547 | */ |
| @@ -2610,11 +2615,11 @@ | |
| 2610 | int nSW /* Screen width */ |
| 2611 | ){ |
| 2612 | int i; /* Loop counter */ |
| 2613 | int nr; /* Number of rows */ |
| 2614 | int w = 0; /* Width of the current column */ |
| 2615 | int t; /* Total width of all columns */ |
| 2616 | int *aw; /* Array of individual column widths */ |
| 2617 | |
| 2618 | aw = sqlite3_malloc64( sizeof(int)*nCol ); |
| 2619 | if( aw==0 ){ |
| 2620 | qrfOom(p); |
| @@ -2748,12 +2753,15 @@ | |
| 2748 | }else{ |
| 2749 | sepW = pData->nCol*3 + 1; |
| 2750 | if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2751 | } |
| 2752 | nCol = pData->nCol; |
| 2753 | for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w; |
| 2754 | if( p->spec.nScreenWidth >= sumW+sepW ) return; |
| 2755 | |
| 2756 | /* First thing to do is reduce the separation between columns */ |
| 2757 | pData->nMargin = 0; |
| 2758 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2759 | sepW = pData->nCol - 1; |
| @@ -3624,11 +3632,11 @@ | |
| 3624 | p->nRow = 0; |
| 3625 | sz = sizeof(sqlite3_qrf_spec); |
| 3626 | memcpy(&p->spec, pSpec, sz); |
| 3627 | if( p->spec.zNull==0 ) p->spec.zNull = ""; |
| 3628 | p->mxWidth = p->spec.nScreenWidth; |
| 3629 | if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH; |
| 3630 | p->mxHeight = p->spec.nLineLimit; |
| 3631 | if( p->mxHeight<=0 ) p->mxHeight = 2147483647; |
| 3632 | if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; |
| 3633 | if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; |
| 3634 | if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; |
| @@ -5272,10 +5280,14 @@ | |
| 5272 | #include <stdarg.h> |
| 5273 | |
| 5274 | /****************************************************************************** |
| 5275 | ** The Hash Engine |
| 5276 | */ |
| 5277 | /* Context for the SHA1 hash */ |
| 5278 | typedef struct SHA1Context SHA1Context; |
| 5279 | struct SHA1Context { |
| 5280 | unsigned int state[5]; |
| 5281 | unsigned int count[2]; |
| @@ -5412,11 +5424,11 @@ | |
| 5412 | } |
| 5413 | j = 0; |
| 5414 | }else{ |
| 5415 | i = 0; |
| 5416 | } |
| 5417 | (void)memcpy(&p->buffer[j], &data[i], len - i); |
| 5418 | } |
| 5419 | |
| 5420 | /* Compute a string using sqlite3_vsnprintf() and hash it */ |
| 5421 | static void hash_step_vformat( |
| 5422 | SHA1Context *p, /* Add content to this context */ |
| @@ -5467,10 +5479,13 @@ | |
| 5467 | zOut[i*2+1] = zEncode[digest[i] & 0xf]; |
| 5468 | } |
| 5469 | zOut[i*2]= 0; |
| 5470 | } |
| 5471 | } |
| 5472 | /* End of the hashing logic |
| 5473 | *****************************************************************************/ |
| 5474 | |
| 5475 | /* |
| 5476 | ** Two SQL functions: sha1(X) and sha1b(X). |
| @@ -6056,32 +6071,41 @@ | |
| 6056 | } |
| 6057 | z[i] = 0; |
| 6058 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6059 | } |
| 6060 | |
| 6061 | /* |
| 6062 | ** Round a decimal value to N significant digits. N must be positive. |
| 6063 | */ |
| 6064 | static void decimal_round(Decimal *p, int N){ |
| 6065 | int i; |
| 6066 | int nZero; |
| 6067 | if( N<1 ) return; |
| 6068 | if( p==0 ) return; |
| 6069 | if( p->nDigit<=N ) return; |
| 6070 | for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6071 | N += nZero; |
| 6072 | if( p->nDigit<=N ) return; |
| 6073 | if( p->a[N]>4 ){ |
| 6074 | p->a[N-1]++; |
| 6075 | for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6076 | p->a[i] = 0; |
| 6077 | p->a[i-1]++; |
| 6078 | } |
| 6079 | if( p->a[0]>9 ){ |
| 6080 | p->a[0] = 1; |
| 6081 | p->nFrac--; |
| 6082 | } |
| 6083 | } |
| 6084 | memset(&p->a[N], 0, p->nDigit - N); |
| 6085 | } |
| 6086 | |
| 6087 | /* |
| @@ -8363,19 +8387,26 @@ | |
| 8363 | } |
| 8364 | }else{ |
| 8365 | iMin = iMax = sqlite3_value_int64(argv[iArg++]); |
| 8366 | } |
| 8367 | }else{ |
| 8368 | if( idxNum & 0x0300 ){ /* value>X or value>=X */ |
| 8369 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8370 | double r = sqlite3_value_double(argv[iArg++]); |
| 8371 | if( r<(double)SMALLEST_INT64 ){ |
| 8372 | iMin = SMALLEST_INT64; |
| 8373 | }else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ |
| 8374 | iMin = (sqlite3_int64)seriesCeil(r+1.0); |
| 8375 | }else{ |
| 8376 | iMin = (sqlite3_int64)seriesCeil(r); |
| 8377 | } |
| 8378 | }else{ |
| 8379 | iMin = sqlite3_value_int64(argv[iArg++]); |
| 8380 | if( (idxNum & 0x0200)!=0 ){ |
| 8381 | if( iMin==LARGEST_INT64 ){ |
| @@ -8384,19 +8415,25 @@ | |
| 8384 | iMin++; |
| 8385 | } |
| 8386 | } |
| 8387 | } |
| 8388 | } |
| 8389 | if( idxNum & 0x3000 ){ /* value<X or value<=X */ |
| 8390 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8391 | double r = sqlite3_value_double(argv[iArg++]); |
| 8392 | if( r>(double)LARGEST_INT64 ){ |
| 8393 | iMax = LARGEST_INT64; |
| 8394 | }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ |
| 8395 | iMax = (sqlite3_int64)(r-1.0); |
| 8396 | }else{ |
| 8397 | iMax = (sqlite3_int64)seriesFloor(r); |
| 8398 | } |
| 8399 | }else{ |
| 8400 | iMax = sqlite3_value_int64(argv[iArg++]); |
| 8401 | if( idxNum & 0x2000 ){ |
| 8402 | if( iMax==SMALLEST_INT64 ){ |
| @@ -9638,11 +9675,10 @@ | |
| 9638 | if( pRe==0 ){ |
| 9639 | sqlite3_result_error_nomem(context); |
| 9640 | return; |
| 9641 | } |
| 9642 | pStr = sqlite3_str_new(0); |
| 9643 | if( pStr==0 ) goto re_bytecode_func_err; |
| 9644 | if( pRe->nInit>0 ){ |
| 9645 | sqlite3_str_appendf(pStr, "INIT "); |
| 9646 | for(i=0; i<pRe->nInit; i++){ |
| 9647 | sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); |
| 9648 | } |
| @@ -9649,20 +9685,20 @@ | |
| 9649 | sqlite3_str_appendf(pStr, "\n"); |
| 9650 | } |
| 9651 | for(i=0; (unsigned)i<pRe->nState; i++){ |
| 9652 | sqlite3_str_appendf(pStr, "%-8s %4d\n", |
| 9653 | ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); |
| 9654 | } |
| 9655 | n = sqlite3_str_length(pStr); |
| 9656 | z = sqlite3_str_finish(pStr); |
| 9657 | if( n==0 ){ |
| 9658 | sqlite3_free(z); |
| 9659 | }else{ |
| 9660 | sqlite3_result_text(context, z, n-1, sqlite3_free); |
| 9661 | } |
| 9662 | |
| 9663 | re_bytecode_func_err: |
| 9664 | re_free(pRe); |
| 9665 | } |
| 9666 | |
| 9667 | #endif /* SQLITE_DEBUG */ |
| 9668 | |
| @@ -10870,10 +10906,13 @@ | |
| 10870 | ** Return NULL if unable. |
| 10871 | ** |
| 10872 | ** The file or directory X is not required to exist. The answer is formed |
| 10873 | ** by calling system realpath() on the prefix of X that does exist and |
| 10874 | ** appending the tail of X that does not (yet) exist. |
| 10875 | */ |
| 10876 | static void realpathFunc( |
| 10877 | sqlite3_context *context, |
| 10878 | int argc, |
| 10879 | sqlite3_value **argv |
| @@ -10892,10 +10931,11 @@ | |
| 10892 | (void)argc; |
| 10893 | zPath = (const char*)sqlite3_value_text(argv[0]); |
| 10894 | if( zPath==0 ) return; |
| 10895 | if( zPath[0]==0 ) zPath = "."; |
| 10896 | zCopy = sqlite3_mprintf("%s",zPath); |
| 10897 | len = strlen(zCopy); |
| 10898 | while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 10899 | len--; |
| 10900 | } |
| 10901 | zCopy[len] = 0; |
| @@ -12685,10 +12725,11 @@ | |
| 12685 | |
| 12686 | for(p=pCsr->pFreeEntry; p; p=pNext){ |
| 12687 | pNext = p->pNext; |
| 12688 | zipfileEntryFree(p); |
| 12689 | } |
| 12690 | } |
| 12691 | |
| 12692 | /* |
| 12693 | ** Destructor for an ZipfileCsr. |
| 12694 | */ |
| @@ -13087,11 +13128,17 @@ | |
| 13087 | } |
| 13088 | } |
| 13089 | |
| 13090 | if( rc==SQLITE_OK ){ |
| 13091 | u32 *pt = &pNew->mUnixTime; |
| 13092 | pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); |
| 13093 | pNew->aExtra = (u8*)&pNew[1]; |
| 13094 | memcpy(pNew->aExtra, &aRead[nFile], nExtra); |
| 13095 | if( pNew->cds.zFile==0 ){ |
| 13096 | rc = SQLITE_NOMEM; |
| 13097 | }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ |
| @@ -14191,14 +14238,14 @@ | |
| 14191 | ZipfileBuffer body; |
| 14192 | ZipfileBuffer cds; |
| 14193 | }; |
| 14194 | |
| 14195 | static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){ |
| 14196 | if( pBuf->n+nByte>pBuf->nAlloc ){ |
| 14197 | u8 *aNew; |
| 14198 | sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; |
| 14199 | int nReq = pBuf->n + nByte; |
| 14200 | |
| 14201 | while( nNew<nReq ) nNew = nNew*2; |
| 14202 | aNew = sqlite3_realloc64(pBuf->a, nNew); |
| 14203 | if( aNew==0 ) return SQLITE_NOMEM; |
| 14204 | pBuf->a = aNew; |
| @@ -16296,11 +16343,11 @@ | |
| 16296 | p->pTable = pTab; |
| 16297 | |
| 16298 | /* The statement the vtab will pass to sqlite3_declare_vtab() */ |
| 16299 | zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); |
| 16300 | for(i=0; i<pTab->nCol; i++){ |
| 16301 | zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", |
| 16302 | (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl |
| 16303 | ); |
| 16304 | } |
| 16305 | zInner = idxAppendText(&rc, zInner, ")"); |
| 16306 | |
| @@ -16496,11 +16543,11 @@ | |
| 16496 | sqlite3_free(zCols); |
| 16497 | sqlite3_free(zOrder); |
| 16498 | return sqlite3_reset(pIndexXInfo); |
| 16499 | } |
| 16500 | zCols = idxAppendText(&rc, zCols, |
| 16501 | "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s", |
| 16502 | zComma, zName, nCol, zName, zColl |
| 16503 | ); |
| 16504 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 16505 | } |
| 16506 | sqlite3_reset(pIndexXInfo); |
| @@ -19464,11 +19511,11 @@ | |
| 19464 | sqlite3_vfs_unregister(pVfs); |
| 19465 | sqlite3_free(pVfs); |
| 19466 | } |
| 19467 | |
| 19468 | /************************* End ext/misc/vfstrace.c ********************/ |
| 19469 | /************************* Begin ext/misc/analyze.c ******************/ |
| 19470 | /* |
| 19471 | ** 2026-04-13 |
| 19472 | ** |
| 19473 | ** The author disclaims copyright to this source code. In place of |
| 19474 | ** a legal notice, here is a blessing: |
| @@ -19477,12 +19524,21 @@ | |
| 19477 | ** May you find forgiveness for yourself and forgive others. |
| 19478 | ** May you share freely, never taking more than you give. |
| 19479 | ** |
| 19480 | ****************************************************************************** |
| 19481 | ** |
| 19482 | ** Partial reimplement of the sqlite3_analyzer utility program as |
| 19483 | ** loadable SQL function. |
| 19484 | */ |
| 19485 | /* #include "sqlite3ext.h" */ |
| 19486 | SQLITE_EXTENSION_INIT1 |
| 19487 | #include <assert.h> |
| 19488 | #include <string.h> |
| @@ -19490,28 +19546,28 @@ | |
| 19490 | #include <math.h> |
| 19491 | |
| 19492 | /* |
| 19493 | ** State information for the analysis |
| 19494 | */ |
| 19495 | typedef struct Analysis Analysis; |
| 19496 | struct Analysis { |
| 19497 | sqlite3 *db; /* Database connection */ |
| 19498 | sqlite3_context *context; /* SQL function context */ |
| 19499 | sqlite3_str *pOut; /* Write output here */ |
| 19500 | char *zSU; /* Name of the temp.space_used table */ |
| 19501 | const char *zSchema; /* Schema to be analyzed */ |
| 19502 | }; |
| 19503 | |
| 19504 | /* |
| 19505 | ** Free all resources that the Analysis object references and |
| 19506 | ** reset the Analysis object. |
| 19507 | ** |
| 19508 | ** Call this routine multiple times on the same Analysis object |
| 19509 | ** is a harmless no-op, as long as the memory for the object itself |
| 19510 | ** has not been freed. |
| 19511 | */ |
| 19512 | static void analysisReset(Analysis *p){ |
| 19513 | if( p->zSU ){ |
| 19514 | char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU); |
| 19515 | if( zSql ){ |
| 19516 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 19517 | sqlite3_free(zSql); |
| @@ -19524,11 +19580,11 @@ | |
| 19524 | |
| 19525 | /* |
| 19526 | ** Report an error using formatted text. If zFormat==NULL then report |
| 19527 | ** an OOM error. |
| 19528 | */ |
| 19529 | static void analysisError(Analysis *p, const char *zFormat, ...){ |
| 19530 | char *zErr; |
| 19531 | if( zFormat ){ |
| 19532 | va_list ap; |
| 19533 | va_start(ap, zFormat); |
| 19534 | zErr = sqlite3_vmprintf(zFormat, ap); |
| @@ -19540,38 +19596,38 @@ | |
| 19540 | sqlite3_result_error_nomem(p->context); |
| 19541 | }else{ |
| 19542 | sqlite3_result_error(p->context, zErr, -1); |
| 19543 | sqlite3_free(zErr); |
| 19544 | } |
| 19545 | analysisReset(p); |
| 19546 | } |
| 19547 | |
| 19548 | /* |
| 19549 | ** Prepare and return an SQL statement. |
| 19550 | */ |
| 19551 | static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){ |
| 19552 | char *zSql; |
| 19553 | int rc; |
| 19554 | sqlite3_stmt *pStmt = 0; |
| 19555 | zSql = sqlite3_vmprintf(zFmt, ap); |
| 19556 | if( zSql==0 ){ analysisError(p,0); return 0; } |
| 19557 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 19558 | if( rc ){ |
| 19559 | analysisError(p, "SQL parse error: %s\nOriginal SQL: %s", |
| 19560 | sqlite3_errmsg(p->db), zSql); |
| 19561 | sqlite3_finalize(pStmt); |
| 19562 | analysisReset(p); |
| 19563 | pStmt = 0; |
| 19564 | } |
| 19565 | sqlite3_free(zSql); |
| 19566 | return pStmt; |
| 19567 | } |
| 19568 | static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){ |
| 19569 | va_list ap; |
| 19570 | sqlite3_stmt *pStmt = 0; |
| 19571 | va_start(ap, zFormat); |
| 19572 | pStmt = analysisVPrep(p,zFormat,ap); |
| 19573 | va_end(ap); |
| 19574 | return pStmt; |
| 19575 | } |
| 19576 | |
| 19577 | /* |
| @@ -19580,60 +19636,60 @@ | |
| 19580 | ** |
| 19581 | ** If rc is SQLITE_DONE or SQLITE_OK, then return false. |
| 19582 | ** |
| 19583 | ** The prepared statement is closed in either case. |
| 19584 | */ |
| 19585 | static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){ |
| 19586 | if( rc==SQLITE_DONE ){ |
| 19587 | rc = SQLITE_OK; |
| 19588 | } |
| 19589 | if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){ |
| 19590 | analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19591 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19592 | analysisReset(p); |
| 19593 | } |
| 19594 | sqlite3_finalize(pStmt); |
| 19595 | return rc; |
| 19596 | } |
| 19597 | |
| 19598 | /* |
| 19599 | ** Run SQL. Return the number of errors. |
| 19600 | */ |
| 19601 | static int analysisSql(Analysis *p, const char *zFormat, ...){ |
| 19602 | va_list ap; |
| 19603 | int rc; |
| 19604 | sqlite3_stmt *pStmt = 0; |
| 19605 | va_start(ap, zFormat); |
| 19606 | pStmt = analysisVPrep(p,zFormat,ap); |
| 19607 | va_end(ap); |
| 19608 | if( pStmt==0 ) return 1; |
| 19609 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){} |
| 19610 | if( rc==SQLITE_DONE ){ |
| 19611 | rc = SQLITE_OK; |
| 19612 | }else{ |
| 19613 | analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19614 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19615 | analysisReset(p); |
| 19616 | } |
| 19617 | sqlite3_finalize(pStmt); |
| 19618 | return rc; |
| 19619 | } |
| 19620 | |
| 19621 | /* |
| 19622 | ** Run an SQL query that returns an integer. Write that integer |
| 19623 | ** into *piRes. Return the number of errors. |
| 19624 | */ |
| 19625 | static int analysisSqlInt( |
| 19626 | Analysis *p, |
| 19627 | sqlite3_int64 *piRes, |
| 19628 | const char *zFormat, ... |
| 19629 | ){ |
| 19630 | va_list ap; |
| 19631 | int rc; |
| 19632 | sqlite3_stmt *pStmt = 0; |
| 19633 | va_start(ap, zFormat); |
| 19634 | pStmt = analysisVPrep(p,zFormat,ap); |
| 19635 | va_end(ap); |
| 19636 | if( pStmt==0 ) return 1; |
| 19637 | rc = sqlite3_step(pStmt); |
| 19638 | if( rc==SQLITE_ROW ){ |
| 19639 | *piRes = sqlite3_column_int64(pStmt, 0); |
| @@ -19641,14 +19697,14 @@ | |
| 19641 | }else if( rc==SQLITE_DONE ){ |
| 19642 | rc = SQLITE_OK; |
| 19643 | }else{ |
| 19644 | if( p->db ){ |
| 19645 | /* p->db is NULL if there was some prior error */ |
| 19646 | analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19647 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19648 | } |
| 19649 | analysisReset(p); |
| 19650 | } |
| 19651 | sqlite3_finalize(pStmt); |
| 19652 | return rc; |
| 19653 | } |
| 19654 | |
| @@ -19657,20 +19713,20 @@ | |
| 19657 | ** by the format string. If the output is initially empty, begin |
| 19658 | ** the title line with "/" so that it forms the beginning of a C-style |
| 19659 | ** comment. Otherwise begin with a new-line. Always finish with a |
| 19660 | ** newline. |
| 19661 | */ |
| 19662 | static void analysisTitle(Analysis *p, const char *zFormat, ...){ |
| 19663 | char *zFirst; |
| 19664 | char *zTitle; |
| 19665 | size_t nTitle; |
| 19666 | va_list ap; |
| 19667 | va_start(ap, zFormat); |
| 19668 | zTitle = sqlite3_vmprintf(zFormat, ap); |
| 19669 | va_end(ap); |
| 19670 | if( zTitle==0 ){ |
| 19671 | analysisError(p, 0); |
| 19672 | return; |
| 19673 | } |
| 19674 | zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*"; |
| 19675 | nTitle = strlen(zTitle); |
| 19676 | if( nTitle>=75 ){ |
| @@ -19685,12 +19741,12 @@ | |
| 19685 | /* |
| 19686 | ** Add an output line that begins with the zDesc text extended out to |
| 19687 | ** 50 columns with "." characters, and followed by whatever text is |
| 19688 | ** described by zFormat. |
| 19689 | */ |
| 19690 | static void analysisLine( |
| 19691 | Analysis *p, /* Analysis context */ |
| 19692 | const char *zDesc, /* Description */ |
| 19693 | const char *zFormat, /* Argument to the description */ |
| 19694 | ... |
| 19695 | ){ |
| 19696 | char *zTxt; |
| @@ -19698,14 +19754,14 @@ | |
| 19698 | va_list ap; |
| 19699 | va_start(ap, zFormat); |
| 19700 | zTxt = sqlite3_vmprintf(zFormat, ap); |
| 19701 | va_end(ap); |
| 19702 | if( zTxt==0 ){ |
| 19703 | analysisError(p, 0); |
| 19704 | return; |
| 19705 | } |
| 19706 | nDesc = strlen(zDesc); |
| 19707 | if( nDesc>=50 ){ |
| 19708 | sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt); |
| 19709 | }else{ |
| 19710 | int nExtra = 50 - (int)nDesc; |
| 19711 | sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt); |
| @@ -19715,11 +19771,11 @@ | |
| 19715 | /* |
| 19716 | ** Write a percentage into the output. The number written should show |
| 19717 | ** two or three significant digits, with the decimal point being the fourth |
| 19718 | ** character. |
| 19719 | */ |
| 19720 | static void analysisPercent(Analysis *p, double r){ |
| 19721 | char zNum[100]; |
| 19722 | char *zDP; |
| 19723 | int nLeadingDigit; |
| 19724 | int sz; |
| 19725 | sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r); |
| @@ -19744,12 +19800,12 @@ | |
| 19744 | ** |
| 19745 | ** The title if the subreport is given by zTitle. zWhere is |
| 19746 | ** a boolean expression that can go in the WHERE clause to select |
| 19747 | ** the relevant rows of the s.zSU table. |
| 19748 | */ |
| 19749 | static int analysisSubreport( |
| 19750 | Analysis *p, /* Analysis context */ |
| 19751 | char *zTitle, /* Title for this subreport */ |
| 19752 | char *zWhere, /* WHERE clause for this subreport */ |
| 19753 | sqlite3_int64 pgsz, /* Database page size */ |
| 19754 | sqlite3_int64 nPage /* Number of pages in entire database */ |
| 19755 | ){ |
| @@ -19773,14 +19829,14 @@ | |
| 19773 | sqlite3_int64 total_unused; /* Total unused bytes */ |
| 19774 | sqlite3_int64 total_meta; /* Total metadata */ |
| 19775 | int rc; |
| 19776 | |
| 19777 | if( zTitle==0 || zWhere==0 ){ |
| 19778 | analysisError(p, 0); |
| 19779 | return SQLITE_NOMEM; |
| 19780 | } |
| 19781 | pStmt = analysisPrepare(p, |
| 19782 | "SELECT\n" |
| 19783 | " sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */ |
| 19784 | " sum(payload),\n" /* 1 */ |
| 19785 | " sum(ovfl_payload),\n" /* 2 */ |
| 19786 | " max(mx_payload),\n" /* 3 */ |
| @@ -19797,11 +19853,11 @@ | |
| 19797 | " FROM temp.%s WHERE %s", |
| 19798 | p->zSU, zWhere); |
| 19799 | if( pStmt==0 ) return 1; |
| 19800 | rc = sqlite3_step(pStmt); |
| 19801 | if( rc==SQLITE_ROW ){ |
| 19802 | analysisTitle(p, zTitle); |
| 19803 | |
| 19804 | nentry = sqlite3_column_int64(pStmt, 0); |
| 19805 | payload = sqlite3_column_int64(pStmt, 1); |
| 19806 | ovfl_payload = sqlite3_column_int64(pStmt, 2); |
| 19807 | mx_payload = sqlite3_column_int64(pStmt, 3); |
| @@ -19816,73 +19872,73 @@ | |
| 19816 | cnt = sqlite3_column_int64(pStmt, 12); |
| 19817 | int_cell = sqlite3_column_int64(pStmt, 13); |
| 19818 | rc = SQLITE_DONE; |
| 19819 | |
| 19820 | total_pages = leaf_pages + int_pages + ovfl_pages; |
| 19821 | analysisLine(p, "Percentage of total database", "%.3g%%\n", |
| 19822 | (total_pages*100.0)/(double)nPage); |
| 19823 | analysisLine(p, "Number of entries", "%lld\n", nentry); |
| 19824 | storage = total_pages*pgsz; |
| 19825 | analysisLine(p, "Bytes of storage consumed", "%lld\n", storage); |
| 19826 | analysisLine(p, "Bytes of payload", "%-11lld ", payload); |
| 19827 | analysisPercent(p, payload*100.0/(double)storage); |
| 19828 | if( ovfl_cnt>0 ){ |
| 19829 | analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); |
| 19830 | analysisPercent(p, ovfl_payload*100.0/(double)payload); |
| 19831 | } |
| 19832 | total_unused = leaf_unused + int_unused + ovfl_unused; |
| 19833 | total_meta = storage - payload - total_unused; |
| 19834 | analysisLine(p, "Bytes of metadata","%-11lld ", total_meta); |
| 19835 | analysisPercent(p, total_meta*100.0/(double)storage); |
| 19836 | if( cnt==1 ){ |
| 19837 | analysisLine(p, "B-tree depth", "%lld\n", depth); |
| 19838 | if( int_cell>1 ){ |
| 19839 | analysisLine(p, "Average fanout", "%.1f\n", |
| 19840 | (double)(int_cell+int_pages)/(double)int_pages); |
| 19841 | } |
| 19842 | } |
| 19843 | if( nentry>0 ){ |
| 19844 | analysisLine(p, "Average payload per entry", "%.1f\n", |
| 19845 | (double)payload/(double)nentry); |
| 19846 | analysisLine(p, "Average unused bytes per entry", "%.1f\n", |
| 19847 | (double)total_unused/(double)nentry); |
| 19848 | analysisLine(p, "Average metadata per entry", "%.1f\n", |
| 19849 | (double)total_meta/(double)nentry); |
| 19850 | } |
| 19851 | analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); |
| 19852 | if( nentry>0 ){ |
| 19853 | analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); |
| 19854 | analysisPercent(p, ovfl_cnt*100.0/(double)nentry); |
| 19855 | } |
| 19856 | if( int_pages>0 ){ |
| 19857 | analysisLine(p, "Index pages used", "%lld\n", int_pages); |
| 19858 | } |
| 19859 | analysisLine(p, "Primary pages used", "%lld\n", leaf_pages); |
| 19860 | if( ovfl_cnt ){ |
| 19861 | analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages); |
| 19862 | } |
| 19863 | analysisLine(p, "Total pages used", "%lld\n", total_pages); |
| 19864 | if( int_pages>0 ){ |
| 19865 | analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused); |
| 19866 | } |
| 19867 | analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); |
| 19868 | if( ovfl_cnt ){ |
| 19869 | analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); |
| 19870 | } |
| 19871 | analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); |
| 19872 | analysisPercent(p, total_unused*100.0/(double)storage); |
| 19873 | } |
| 19874 | return analysisStmtFinish(p, rc, pStmt); |
| 19875 | } |
| 19876 | |
| 19877 | /* |
| 19878 | ** SQL Function: analyze(SCHEMA) |
| 19879 | ** |
| 19880 | ** Analyze the database schema named in the argument. Return text |
| 19881 | ** containing the analysis. |
| 19882 | */ |
| 19883 | static void analyzeFunc( |
| 19884 | sqlite3_context *context, |
| 19885 | int argc, |
| 19886 | sqlite3_value **argv |
| 19887 | ){ |
| 19888 | int rc; |
| @@ -19893,47 +19949,47 @@ | |
| 19893 | sqlite3_int64 nPage; |
| 19894 | sqlite3_int64 nPageInUse; |
| 19895 | sqlite3_int64 nFreeList; |
| 19896 | sqlite3_int64 nIndex; |
| 19897 | sqlite3_int64 nWORowid; |
| 19898 | Analysis s; |
| 19899 | sqlite3_uint64 r[2]; |
| 19900 | |
| 19901 | (void)argc; |
| 19902 | memset(&s, 0, sizeof(s)); |
| 19903 | s.db = sqlite3_context_db_handle(context); |
| 19904 | s.context = context; |
| 19905 | s.pOut = sqlite3_str_new(0); |
| 19906 | if( sqlite3_str_errcode(s.pOut) ){ |
| 19907 | analysisError(&s, 0); |
| 19908 | return; |
| 19909 | } |
| 19910 | s.zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 19911 | if( s.zSchema==0 ){ |
| 19912 | s.zSchema = "main"; |
| 19913 | }else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){ |
| 19914 | analysisReset(&s); |
| 19915 | sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC); |
| 19916 | return; |
| 19917 | } |
| 19918 | ii = 0; |
| 19919 | rc = analysisSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" |
| 19920 | " WHERE name=%Q COLLATE nocase",s.zSchema); |
| 19921 | if( rc || ii==0 ){ |
| 19922 | analysisReset(&s); |
| 19923 | sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC); |
| 19924 | return; |
| 19925 | } |
| 19926 | sqlite3_randomness(sizeof(r), &r); |
| 19927 | s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]); |
| 19928 | if( s.zSU==0 ){ analysisError(&s, 0); return; } |
| 19929 | |
| 19930 | /* The s.zSU table contains the data used for the analysis. |
| 19931 | ** The table name contains 128-bits of randomness to avoid |
| 19932 | ** collisions with preexisting tables in temp. |
| 19933 | */ |
| 19934 | rc = analysisSql(&s, |
| 19935 | "CREATE TABLE temp.%s(\n" |
| 19936 | " name text, -- A table or index\n" |
| 19937 | " tblname text, -- Table that owns name\n" |
| 19938 | " is_index boolean, -- TRUE if it is an index\n" |
| 19939 | " is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" |
| @@ -19956,11 +20012,11 @@ | |
| 19956 | ); |
| 19957 | if( rc ) return; |
| 19958 | |
| 19959 | /* Populate the s.zSU table |
| 19960 | */ |
| 19961 | rc = analysisSql(&s, |
| 19962 | "WITH\n" |
| 19963 | " allidx(idxname) AS (\n" |
| 19964 | " SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n" |
| 19965 | " ),\n" |
| 19966 | " allobj(allname,tblname,isidx,isworowid) AS (\n" |
| @@ -20008,141 +20064,143 @@ | |
| 20008 | s.zSchema /* JOIN dbstat(%Q) */ |
| 20009 | ); |
| 20010 | if( rc ) return; |
| 20011 | |
| 20012 | nPage = 0; |
| 20013 | rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); |
| 20014 | if( rc ) return; |
| 20015 | if( nPage<=0 ){ |
| 20016 | /* Very brief reply for an empty database */ |
| 20017 | analysisReset(&s); |
| 20018 | sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC); |
| 20019 | return; |
| 20020 | } |
| 20021 | |
| 20022 | /* Begin generating the report */ |
| 20023 | analysisTitle(&s, "Database storage utilization report"); |
| 20024 | pgsz = 0; |
| 20025 | rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); |
| 20026 | if( rc ) return; |
| 20027 | analysisLine(&s, "Page size in bytes","%lld\n",pgsz); |
| 20028 | analysisLine(&s, "Pages in the database", "%lld\n", nPage); |
| 20029 | |
| 20030 | nPageInUse = 0; |
| 20031 | rc = analysisSqlInt(&s, &nPageInUse, |
| 20032 | "SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU); |
| 20033 | if( rc ) return; |
| 20034 | analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse); |
| 20035 | analysisPercent(&s, (nPageInUse*100.0)/(double)nPage); |
| 20036 | |
| 20037 | nFreeList = 0; |
| 20038 | rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); |
| 20039 | if( rc ) return; |
| 20040 | analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); |
| 20041 | analysisPercent(&s, (nFreeList*100.0)/(double)nPage); |
| 20042 | |
| 20043 | ii = 0; |
| 20044 | rc = analysisSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); |
| 20045 | if( rc ) return; |
| 20046 | if( ii==0 || nPage<=1 ){ |
| 20047 | ii = 0; |
| 20048 | }else{ |
| 20049 | double rPtrsPerPage = pgsz/5; |
| 20050 | double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0); |
| 20051 | ii = (sqlite3_int64)ceil(rAvPage); |
| 20052 | } |
| 20053 | analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); |
| 20054 | analysisPercent(&s, (ii*100.0)/(double)nPage); |
| 20055 | |
| 20056 | ii = 0; |
| 20057 | rc = analysisSqlInt(&s, &ii, |
| 20058 | "SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'", |
| 20059 | s.zSchema); |
| 20060 | if( rc ) return; |
| 20061 | analysisLine(&s, "Number of tables", "%lld\n", ii); |
| 20062 | nWORowid = 0; |
| 20063 | rc = analysisSqlInt(&s, &nWORowid, |
| 20064 | "SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr", |
| 20065 | s.zSchema); |
| 20066 | if( rc ) return; |
| 20067 | if( nWORowid>0 ){ |
| 20068 | analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); |
| 20069 | analysisLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); |
| 20070 | } |
| 20071 | nIndex = 0; |
| 20072 | rc = analysisSqlInt(&s, &nIndex, |
| 20073 | "SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'", |
| 20074 | s.zSchema); |
| 20075 | if( rc ) return; |
| 20076 | analysisLine(&s, "Number of indexes", "%lld\n", nIndex); |
| 20077 | ii = 0; |
| 20078 | rc = analysisSqlInt(&s, &ii, |
| 20079 | "SELECT count(*) FROM \"%w\".sqlite_schema" |
| 20080 | " WHERE name GLOB 'sqlite_autoindex_*' AND type='index'", |
| 20081 | s.zSchema); |
| 20082 | if( rc ) return; |
| 20083 | analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); |
| 20084 | analysisLine(&s, "Number of implied indexes", "%lld\n", ii); |
| 20085 | analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); |
| 20086 | ii = 0; |
| 20087 | rc = analysisSqlInt(&s, &ii, |
| 20088 | "SELECT sum(payload) FROM temp.%s" |
| 20089 | " WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'", |
| 20090 | s.zSU); |
| 20091 | if( rc ) return; |
| 20092 | analysisLine(&s, "Bytes of payload", "%-11lld ", ii); |
| 20093 | analysisPercent(&s, ii*100.0/(double)(pgsz*nPage)); |
| 20094 | |
| 20095 | analysisTitle(&s, "Page counts for all tables with their indexes"); |
| 20096 | pStmt = analysisPrepare(&s, |
| 20097 | "SELECT upper(tblname),\n" |
| 20098 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20099 | " FROM temp.%s\n" |
| 20100 | " GROUP BY 1\n" |
| 20101 | " ORDER BY 2 DESC, 1;", |
| 20102 | s.zSU); |
| 20103 | if( pStmt==0 ) return; |
| 20104 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20105 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20106 | analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20107 | analysisPercent(&s, (nn*100.0)/(double)nPage); |
| 20108 | } |
| 20109 | if( analysisStmtFinish(&s, rc, pStmt) ) return; |
| 20110 | |
| 20111 | analysisTitle(&s, "Page counts for all tables and indexes separately"); |
| 20112 | pStmt = analysisPrepare(&s, |
| 20113 | "SELECT upper(name),\n" |
| 20114 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20115 | " FROM temp.%s\n" |
| 20116 | " GROUP BY 1\n" |
| 20117 | " ORDER BY 2 DESC, 1;", |
| 20118 | s.zSU); |
| 20119 | if( pStmt==0 ) return; |
| 20120 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20121 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20122 | analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20123 | analysisPercent(&s, (nn*100.0)/(double)nPage); |
| 20124 | } |
| 20125 | if( analysisStmtFinish(&s, rc, pStmt) ) return; |
| 20126 | |
| 20127 | rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage); |
| 20128 | if( rc ) return; |
| 20129 | rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); |
| 20130 | if( rc ) return; |
| 20131 | if( nWORowid>0 ){ |
| 20132 | rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", |
| 20133 | pgsz, nPage); |
| 20134 | if( rc ) return; |
| 20135 | rc = analysisSubreport(&s, "All rowid tables", |
| 20136 | "NOT is_without_rowid AND NOT is_index", |
| 20137 | pgsz, nPage); |
| 20138 | if( rc ) return; |
| 20139 | } |
| 20140 | rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage); |
| 20141 | if( rc ) return; |
| 20142 | |
| 20143 | pStmt = analysisPrepare(&s, |
| 20144 | "SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s" |
| 20145 | " GROUP BY 1 ORDER BY 1", |
| 20146 | s.zSU); |
| 20147 | if( pStmt==0 ) return; |
| 20148 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| @@ -20150,37 +20208,37 @@ | |
| 20150 | const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 20151 | int nSubIndex = sqlite3_column_int(pStmt, 2); |
| 20152 | if( nSubIndex==0 ){ |
| 20153 | char *zTitle = sqlite3_mprintf("Table %s", zUpper); |
| 20154 | char *zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20155 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20156 | sqlite3_free(zTitle); |
| 20157 | sqlite3_free(zWhere); |
| 20158 | if( rc ) break; |
| 20159 | }else{ |
| 20160 | sqlite3_stmt *pS2; |
| 20161 | char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper); |
| 20162 | char *zWhere = sqlite3_mprintf("tblname=%Q", zName); |
| 20163 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20164 | sqlite3_free(zTitle); |
| 20165 | sqlite3_free(zWhere); |
| 20166 | if( rc ) break; |
| 20167 | zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper); |
| 20168 | zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20169 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20170 | sqlite3_free(zTitle); |
| 20171 | sqlite3_free(zWhere); |
| 20172 | if( rc ) break; |
| 20173 | if( nSubIndex>1 ){ |
| 20174 | zTitle = sqlite3_mprintf("All indexes of table %s", zUpper); |
| 20175 | zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName); |
| 20176 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20177 | sqlite3_free(zTitle); |
| 20178 | sqlite3_free(zWhere); |
| 20179 | if( rc ) break; |
| 20180 | } |
| 20181 | pS2 = analysisPrepare(&s, |
| 20182 | "SELECT name, upper(name) FROM temp.%s" |
| 20183 | " WHERE is_index AND tblname=%Q", |
| 20184 | s.zSU, zName); |
| 20185 | if( pS2==0 ){ |
| 20186 | rc = SQLITE_NOMEM; |
| @@ -20189,25 +20247,25 @@ | |
| 20189 | while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){ |
| 20190 | const char *zU = (const char*)sqlite3_column_text(pS2, 1); |
| 20191 | const char *zN = (const char*)sqlite3_column_text(pS2, 0); |
| 20192 | zTitle = sqlite3_mprintf("Index %s", zU); |
| 20193 | zWhere = sqlite3_mprintf("name=%Q", zN); |
| 20194 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20195 | sqlite3_free(zTitle); |
| 20196 | sqlite3_free(zWhere); |
| 20197 | if( rc ) break; |
| 20198 | } |
| 20199 | rc = analysisStmtFinish(&s, rc, pS2); |
| 20200 | if( rc ) break; |
| 20201 | } |
| 20202 | } |
| 20203 | if( analysisStmtFinish(&s, rc, pStmt) ) return; |
| 20204 | |
| 20205 | /* Append SQL statements that will recreate the raw data used for |
| 20206 | ** the analysis. |
| 20207 | */ |
| 20208 | analysisTitle(&s, "Raw data used to generate this report"); |
| 20209 | sqlite3_str_appendf(s.pOut, |
| 20210 | "The following SQL will create a table named \"space_used\" which\n" |
| 20211 | "contains most of the information used to generate the report above.\n" |
| 20212 | "*/\n" |
| 20213 | ); |
| @@ -20233,11 +20291,11 @@ | |
| 20233 | " ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */ |
| 20234 | " int_entries int -- B-tree entries on internal pages\n"/* 17 */ |
| 20235 | ");\n" |
| 20236 | "INSERT INTO space_used VALUES\n" |
| 20237 | ); |
| 20238 | pStmt = analysisPrepare(&s, |
| 20239 | "SELECT quote(name), quote(tblname),\n" /* 0..1 */ |
| 20240 | " is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */ |
| 20241 | " depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */ |
| 20242 | " int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */ |
| 20243 | " leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */ |
| @@ -20268,11 +20326,11 @@ | |
| 20268 | sqlite3_column_int64(pStmt, 15), |
| 20269 | sqlite3_column_int64(pStmt, 16), |
| 20270 | sqlite3_column_int64(pStmt, 17)); |
| 20271 | } |
| 20272 | if( rc!=SQLITE_DONE ){ |
| 20273 | analysisError(&s, "SQL run-time error: %s\nSQL: %s", |
| 20274 | sqlite3_errmsg(s.db), sqlite3_sql(pStmt)); |
| 20275 | sqlite3_finalize(pStmt); |
| 20276 | return; |
| 20277 | } |
| 20278 | sqlite3_str_appendf(s.pOut,";\nCOMMIT;"); |
| @@ -20281,32 +20339,32 @@ | |
| 20281 | if( sqlite3_str_length(s.pOut) ){ |
| 20282 | sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1, |
| 20283 | sqlite3_free); |
| 20284 | s.pOut = 0; |
| 20285 | } |
| 20286 | analysisReset(&s); |
| 20287 | } |
| 20288 | |
| 20289 | |
| 20290 | #ifdef _WIN32 |
| 20291 | |
| 20292 | #endif |
| 20293 | int sqlite3_analyze_init( |
| 20294 | sqlite3 *db, |
| 20295 | char **pzErrMsg, |
| 20296 | const sqlite3_api_routines *pApi |
| 20297 | ){ |
| 20298 | int rc = SQLITE_OK; |
| 20299 | SQLITE_EXTENSION_INIT2(pApi); |
| 20300 | (void)pzErrMsg; /* Unused parameter */ |
| 20301 | rc = sqlite3_create_function(db, "analyze", 1, |
| 20302 | SQLITE_UTF8|SQLITE_INNOCUOUS, |
| 20303 | 0, analyzeFunc, 0, 0); |
| 20304 | return rc; |
| 20305 | } |
| 20306 | |
| 20307 | /************************* End ext/misc/analyze.c ********************/ |
| 20308 | |
| 20309 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 20310 | #define SQLITE_SHELL_HAVE_RECOVER 1 |
| 20311 | #else |
| 20312 | #define SQLITE_SHELL_HAVE_RECOVER 0 |
| @@ -25138,11 +25196,11 @@ | |
| 25138 | /* |
| 25139 | ** Return true if either the SQLITE_NO_COLOR compile-time option is used |
| 25140 | ** or if the NO_COLOR environment variable exists |
| 25141 | */ |
| 25142 | static int shellNoColor(void){ |
| 25143 | #ifdef SQLITE_NO_COLOR |
| 25144 | return 1; |
| 25145 | #else |
| 25146 | return getenv("NO_COLOR")!=0; |
| 25147 | #endif |
| 25148 | } |
| @@ -25172,11 +25230,11 @@ | |
| 25172 | case 1: |
| 25173 | #if defined(SQLITE_PS1) |
| 25174 | return SQLITE_PS1; |
| 25175 | #else |
| 25176 | if( shellNoColor() ){ |
| 25177 | return "/A-/v /~> "; |
| 25178 | }else{ |
| 25179 | return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; |
| 25180 | } |
| 25181 | #endif |
| 25182 | |
| @@ -25184,11 +25242,11 @@ | |
| 25184 | case 2: |
| 25185 | #if defined(SQLITE_PS2) |
| 25186 | return SQLITE_PS2; |
| 25187 | #else |
| 25188 | if( shellNoColor() ){ |
| 25189 | return "/B/C> "; |
| 25190 | }else{ |
| 25191 | return "/B/e[1;/x33/:36/;m/C/e[0m-> "; |
| 25192 | } |
| 25193 | #endif |
| 25194 | |
| @@ -25196,11 +25254,15 @@ | |
| 25196 | ** of cases 1 and 2 */ |
| 25197 | case 3: return "SQLITE_PS1"; |
| 25198 | case 4: return "SQLITE_PS2"; |
| 25199 | |
| 25200 | /* Name of the application */ |
| 25201 | case 'A': return "SQLite"; |
| 25202 | |
| 25203 | /* Full version number of the application, including patch level */ |
| 25204 | case 'V': return sqlite3_libversion(); |
| 25205 | |
| 25206 | /* Version number without the patch level */ |
| @@ -26303,10 +26365,47 @@ | |
| 26303 | if( *az ){ |
| 26304 | memcpy(*az, zNew, n+1 ); |
| 26305 | } |
| 26306 | } |
| 26307 | } |
| 26308 | |
| 26309 | /* |
| 26310 | ** Change the mode to eMode |
| 26311 | */ |
| 26312 | static void modeChange(ShellState *p, unsigned char eMode){ |
| @@ -26340,10 +26439,11 @@ | |
| 26340 | modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode); |
| 26341 | }else if( eMode==MODE_BATCH ){ |
| 26342 | u8 mFlags = p->mode.mFlags; |
| 26343 | modeFree(&p->mode); |
| 26344 | modeChange(p, MODE_List); |
| 26345 | p->mode.mFlags = mFlags; |
| 26346 | }else if( eMode==MODE_TTY ){ |
| 26347 | u8 mFlags = p->mode.mFlags; |
| 26348 | modeFree(&p->mode); |
| 26349 | modeChange(p, MODE_QBox); |
| @@ -26976,11 +27076,11 @@ | |
| 26976 | return SQLITE_OK; |
| 26977 | } |
| 26978 | #endif |
| 26979 | |
| 26980 | /* |
| 26981 | ** Print a schema statement. This is helper routine to dump_callbac(). |
| 26982 | ** |
| 26983 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 26984 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 26985 | ** |
| 26986 | ** If the schema statement in z[] contains a start-of-comment and if |
| @@ -28428,12 +28528,12 @@ | |
| 28428 | ".databases List names and files of attached databases", |
| 28429 | ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", |
| 28430 | #if SQLITE_SHELL_HAVE_RECOVER |
| 28431 | ".dbinfo ?DB? Show status information about the database", |
| 28432 | #endif |
| 28433 | ".dbstat ?SCHEMA? Report database space and size stats", |
| 28434 | ".dbtotxt Hex dump of the database file", |
| 28435 | ".dump ?OBJECTS? Render database content as SQL", |
| 28436 | " Options:", |
| 28437 | " --data-only Output only INSERT statements", |
| 28438 | " --newlines Allow unescaped newline characters in output", |
| 28439 | " --nosys Omit system tables (ex: \"sqlite_stat1\")", |
| @@ -28540,10 +28640,13 @@ | |
| 28540 | " --reset Reset the count for each input and interrupt", |
| 28541 | " --timeout S Halt after running for S seconds", |
| 28542 | #endif |
| 28543 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 28544 | " --hard-reset Unset SQLITE_PS1/2 and then --reset", |
| 28545 | " --reset Revert to default prompts", |
| 28546 | " --show Show the current prompt strings", |
| 28547 | " -- No more options. Subsequent args are prompts", |
| 28548 | #ifndef SQLITE_SHELL_FIDDLE |
| 28549 | ".quit Stop interpreting input stream, exit if primary.", |
| @@ -29440,11 +29543,11 @@ | |
| 29440 | sqlite3_base64_init(p->db, 0, 0); |
| 29441 | sqlite3_base85_init(p->db, 0, 0); |
| 29442 | sqlite3_regexp_init(p->db, 0, 0); |
| 29443 | sqlite3_ieee_init(p->db, 0, 0); |
| 29444 | sqlite3_series_init(p->db, 0, 0); |
| 29445 | sqlite3_analyze_init(p->db, 0, 0); |
| 29446 | #ifndef SQLITE_SHELL_FIDDLE |
| 29447 | sqlite3_fileio_init(p->db, 0, 0); |
| 29448 | sqlite3_completion_init(p->db, 0, 0); |
| 29449 | #endif |
| 29450 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -31246,11 +31349,11 @@ | |
| 31246 | typedef struct ArCommand ArCommand; |
| 31247 | struct ArCommand { |
| 31248 | u8 eCmd; /* An AR_CMD_* value */ |
| 31249 | u8 bVerbose; /* True if --verbose */ |
| 31250 | u8 bZip; /* True if the archive is a ZIP */ |
| 31251 | u8 bDryRun; /* True if --dry-run */ |
| 31252 | u8 bAppend; /* True if --append */ |
| 31253 | u8 bGlob; /* True if --glob */ |
| 31254 | u8 fromCmdLine; /* Run from -A instead of .archive */ |
| 31255 | int nArg; /* Number of command arguments */ |
| 31256 | char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| @@ -31308,10 +31411,11 @@ | |
| 31308 | #define AR_SWITCH_FILE 9 |
| 31309 | #define AR_SWITCH_DIRECTORY 10 |
| 31310 | #define AR_SWITCH_APPEND 11 |
| 31311 | #define AR_SWITCH_DRYRUN 12 |
| 31312 | #define AR_SWITCH_GLOB 13 |
| 31313 | |
| 31314 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 31315 | switch( eSwitch ){ |
| 31316 | case AR_CMD_CREATE: |
| 31317 | case AR_CMD_EXTRACT: |
| @@ -31325,11 +31429,14 @@ | |
| 31325 | } |
| 31326 | pAr->eCmd = eSwitch; |
| 31327 | break; |
| 31328 | |
| 31329 | case AR_SWITCH_DRYRUN: |
| 31330 | pAr->bDryRun = 1; |
| 31331 | break; |
| 31332 | case AR_SWITCH_GLOB: |
| 31333 | pAr->bGlob = 1; |
| 31334 | break; |
| 31335 | case AR_SWITCH_VERBOSE: |
| @@ -31376,10 +31483,11 @@ | |
| 31376 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 31377 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 31378 | { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 31379 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 31380 | { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 31381 | { "glob", 'g', AR_SWITCH_GLOB, 0 }, |
| 31382 | }; |
| 31383 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 31384 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 31385 | |
| @@ -31676,18 +31784,41 @@ | |
| 31676 | |
| 31677 | /* |
| 31678 | ** Implementation of .ar "eXtract" command. |
| 31679 | */ |
| 31680 | static int arExtractCommand(ArCommand *pAr){ |
| 31681 | const char *zSql1 = |
| 31682 | "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n" |
| 31683 | "SELECT ($dir || name),\n" |
| 31684 | " CASE WHEN $dryrun THEN 0\n" |
| 31685 | " ELSE writefile($dir||name, %s, mode, mtime) END\n" |
| 31686 | " FROM dest CROSS JOIN %s\n" |
| 31687 | " WHERE (%s)\n" |
| 31688 | " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */ |
| 31689 | " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 31690 | " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 31691 | |
| 31692 | const char *azExtraArg[] = { |
| 31693 | "sqlar_uncompress(data, sz)", |
| @@ -31714,39 +31845,48 @@ | |
| 31714 | } |
| 31715 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 31716 | } |
| 31717 | |
| 31718 | shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 31719 | azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere |
| 31720 | ); |
| 31721 | |
| 31722 | if( rc==SQLITE_OK ){ |
| 31723 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 31724 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 31725 | j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 31726 | sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 31727 | |
| 31728 | /* Run the SELECT statement twice |
| 31729 | ** (0) writefile() all files and directories |
| 31730 | ** (1) writefile() for directory again |
| 31731 | ** The second pass is so that the timestamps for extracted directories |
| 31732 | ** will be reset to the value in the archive, since populating them |
| 31733 | ** in the first pass will have changed the timestamp. */ |
| 31734 | for(i=0; i<2; i++){ |
| 31735 | j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 31736 | sqlite3_bind_int(pSql, j, i); |
| 31737 | if( pAr->bDryRun ){ |
| 31738 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 31739 | if( pAr->bVerbose==0 ) break; |
| 31740 | } |
| 31741 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 31742 | if( i==0 && pAr->bVerbose ){ |
| 31743 | cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 31744 | } |
| 31745 | } |
| 31746 | if( pAr->bDryRun ) break; |
| 31747 | shellReset(&rc, pSql); |
| 31748 | } |
| 31749 | shellFinalize(&rc, pSql); |
| 31750 | } |
| 31751 | |
| 31752 | sqlite3_free(zDir); |
| @@ -32257,11 +32397,11 @@ | |
| 32257 | ; |
| 32258 | static const char * const zCollectVar = "\ |
| 32259 | SELECT\ |
| 32260 | '('||x'0a'\ |
| 32261 | || group_concat(\ |
| 32262 | cname||' ANY',\ |
| 32263 | ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\ |
| 32264 | ||')' AS ColsSpec \ |
| 32265 | FROM (\ |
| 32266 | SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \ |
| 32267 | FROM ColNames ORDER BY cpos\ |
| @@ -33102,30 +33242,14 @@ | |
| 33102 | }else if( optionMatch(z,"limits") ){ |
| 33103 | if( (++i)>=nArg ){ |
| 33104 | dotCmdError(p, i-1, "missing argument", 0); |
| 33105 | return 1; |
| 33106 | } |
| 33107 | k = pickStr(azArg[i],0,"on","off",""); |
| 33108 | if( k==0 ){ |
| 33109 | p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; |
| 33110 | p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; |
| 33111 | p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; |
| 33112 | }else if( k==1 ){ |
| 33113 | p->mode.spec.nLineLimit = 0; |
| 33114 | p->mode.spec.nCharLimit = 0; |
| 33115 | p->mode.spec.nTitleLimit = 0; |
| 33116 | }else{ |
| 33117 | int L, C, T = 0; |
| 33118 | int nNum = sscanf(azArg[i], "%d,%d,%d", &L, &C, &T); |
| 33119 | if( nNum<2 || L<0 || C<0 || T<0){ |
| 33120 | dotCmdError(p, i, "bad argument", "Should be \"L,C,T\" where L, C" |
| 33121 | " and T are unsigned integers"); |
| 33122 | return 1; |
| 33123 | } |
| 33124 | p->mode.spec.nLineLimit = L; |
| 33125 | p->mode.spec.nCharLimit = C; |
| 33126 | if( nNum==3 ) p->mode.spec.nTitleLimit = T; |
| 33127 | } |
| 33128 | chng = 1; |
| 33129 | }else if( optionMatch(z,"list") ){ |
| 33130 | int ii; |
| 33131 | cli_puts("available modes:", p->out); |
| @@ -34339,11 +34463,16 @@ | |
| 34339 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 34340 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 34341 | }else |
| 34342 | #endif /* SQLITE_SHELL_HAVE_RECOVER */ |
| 34343 | |
| 34344 | if( c=='d' && n==6 && cli_strncmp(azArg[0], "dbstat", n)==0 ){ |
| 34345 | const char *zSchema = 0; |
| 34346 | int ii; |
| 34347 | char *zSql; |
| 34348 | open_db(p, 0); |
| 34349 | for(ii=1; ii<nArg; ii++){ |
| @@ -34358,27 +34487,19 @@ | |
| 34358 | rc = 1; |
| 34359 | goto meta_command_exit; |
| 34360 | } |
| 34361 | zSchema = z; |
| 34362 | } |
| 34363 | zSql = sqlite3_mprintf("SELECT analyze(%Q)", zSchema); |
| 34364 | shell_check_oom(zSql); |
| 34365 | modePush(p); |
| 34366 | modeChange(p, MODE_BATCH); |
| 34367 | p->mode.spec.nLineLimit = 0; |
| 34368 | p->mode.spec.nCharLimit = 0; |
| 34369 | p->mode.spec.nTitleLimit = 0; |
| 34370 | shell_exec(p, zSql, 0); |
| 34371 | modePop(p); |
| 34372 | sqlite3_free(zSql); |
| 34373 | }else |
| 34374 | |
| 34375 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ |
| 34376 | open_db(p, 0); |
| 34377 | rc = shell_dbtotxt_command(p, nArg, azArg); |
| 34378 | }else |
| 34379 | |
| 34380 | if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){ |
| 34381 | char *zLike = 0; |
| 34382 | char *zSql; |
| 34383 | int i; |
| 34384 | int savedShellFlags = p->shellFlgs; |
| @@ -35491,10 +35612,26 @@ | |
| 35491 | }else |
| 35492 | if( strcmp(z,"-show")==0 ){ |
| 35493 | cli_printf(stdout,"Main prompt: '%s'\n", prompt_string(p, 0)); |
| 35494 | cli_printf(stdout,"Continuation: '%s'\n", prompt_string(p, 1)); |
| 35495 | }else |
| 35496 | if( strcmp(z,"-")==0 ){ |
| 35497 | noOpt = 1; |
| 35498 | }else |
| 35499 | { |
| 35500 | dotCmdError(p, i, "unknown option", 0); |
| @@ -35505,10 +35642,11 @@ | |
| 35505 | dotCmdError(p, i, "extra argument", 0); |
| 35506 | rc = 1; |
| 35507 | goto meta_command_exit; |
| 35508 | }else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){ |
| 35509 | dotCmdError(p, i, "use quotes around the prompt string", 0); |
| 35510 | }else{ |
| 35511 | free(p->azPrompt[cnt]); |
| 35512 | p->azPrompt[cnt] = strdup(z); |
| 35513 | cnt++; |
| 35514 | } |
| @@ -37717,17 +37855,17 @@ | |
| 37717 | " -- treat no subsequent arguments as options\n" |
| 37718 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 37719 | " -A ARGS... run \".archive ARGS\" and exit\n" |
| 37720 | #endif |
| 37721 | " -append append the database to the end of the file\n" |
| 37722 | " -ascii set output mode to 'ascii'\n" |
| 37723 | " -bail stop after hitting an error\n" |
| 37724 | " -batch force batch I/O\n" |
| 37725 | " -box set output mode to 'box'\n" |
| 37726 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 37727 | " -column set output mode to 'column'\n" |
| 37728 | " -csv set output mode to 'csv'\n" |
| 37729 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37730 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 37731 | #endif |
| 37732 | " -echo print inputs before execution\n" |
| 37733 | " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" |
| @@ -37735,18 +37873,18 @@ | |
| 37735 | " -[no]header turn headers on or off\n" |
| 37736 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 37737 | " -heap SIZE Size of heap for memsys3 or memsys5\n" |
| 37738 | #endif |
| 37739 | " -help show this message\n" |
| 37740 | " -html set output mode to HTML\n" |
| 37741 | " -ifexists only open if database already exists\n" |
| 37742 | " -interactive force interactive I/O\n" |
| 37743 | " -json set output mode to 'json'\n" |
| 37744 | " -line set output mode to 'line'\n" |
| 37745 | " -list set output mode to 'list'\n" |
| 37746 | " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
| 37747 | " -markdown set output mode to 'markdown'\n" |
| 37748 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37749 | " -maxsize N maximum size for a --deserialize database\n" |
| 37750 | #endif |
| 37751 | " -memtrace trace all memory allocations and deallocations\n" |
| 37752 | " -mmap N default mmap size set to N\n" |
| @@ -37759,21 +37897,21 @@ | |
| 37759 | " -nonce STRING set the safe-mode escape nonce\n" |
| 37760 | " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" |
| 37761 | " -nullvalue TEXT set text string for NULL values. Default ''\n" |
| 37762 | " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
| 37763 | " -pcachetrace trace all page cache operations\n" |
| 37764 | " -quote set output mode to 'quote'\n" |
| 37765 | " -readonly open the database read-only\n" |
| 37766 | " -safe enable safe-mode\n" |
| 37767 | " -screenwidth N use N as the default screenwidth \n" |
| 37768 | " -separator SEP set output column separator. Default: '|'\n" |
| 37769 | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| 37770 | " -sorterref SIZE sorter references threshold size\n" |
| 37771 | #endif |
| 37772 | " -stats print memory stats before each finalize\n" |
| 37773 | " -table set output mode to 'table'\n" |
| 37774 | " -tabs set output mode to 'tabs'\n" |
| 37775 | " -unsafe-testing allow unsafe commands and modes for testing\n" |
| 37776 | " -version show SQLite version\n" |
| 37777 | " -vfs NAME use NAME as the default VFS\n" |
| 37778 | " -vfstrace enable tracing of all VFS calls\n" |
| 37779 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -37801,10 +37939,23 @@ | |
| 37801 | sputz(stdout, "WARNING: attempt to configure SQLite after" |
| 37802 | " initialization.\n"); |
| 37803 | } |
| 37804 | } |
| 37805 | |
| 37806 | /* |
| 37807 | ** Initialize the state information in data |
| 37808 | */ |
| 37809 | static void main_init(ShellState *p) { |
| 37810 | memset(p, 0, sizeof(*p)); |
| @@ -37825,10 +37976,14 @@ | |
| 37825 | #else |
| 37826 | /* No \001...\002 escapes required for linenoise or when not using a |
| 37827 | ** command-line editing library */ |
| 37828 | p->bDelimitNonprint = 0; |
| 37829 | #endif |
| 37830 | } |
| 37831 | |
| 37832 | /* |
| 37833 | ** Output text to the console in a font that attracts extra attention. |
| 37834 | */ |
| @@ -37854,11 +38009,11 @@ | |
| 37854 | } |
| 37855 | |
| 37856 | /* |
| 37857 | ** The callback from atexit(). |
| 37858 | */ |
| 37859 | static void abnormalExit(void){ |
| 37860 | if( seenInterrupt ) eputz("Program interrupted.\n"); |
| 37861 | if( globalShellState ){ |
| 37862 | clearTempFile(globalShellState, 1, 1); |
| 37863 | } |
| 37864 | } |
| @@ -38065,11 +38220,11 @@ | |
| 38065 | stdin_is_interactive = 0; |
| 38066 | nCmd++; |
| 38067 | azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); |
| 38068 | shell_check_oom(azCmd); |
| 38069 | aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd); |
| 38070 | shell_check_oom(azCmd); |
| 38071 | azCmd[nCmd-1] = z; |
| 38072 | aiCmd[nCmd-1] = i; |
| 38073 | } |
| 38074 | continue; |
| 38075 | } |
| @@ -38354,10 +38509,11 @@ | |
| 38354 | modeChange(&data, MODE_Psql); |
| 38355 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 38356 | modeChange(&data, MODE_Box); |
| 38357 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 38358 | modeChange(&data, MODE_Csv); |
| 38359 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38360 | /* See similar code at tag-20250224-1 */ |
| 38361 | const char *zEsc = argv[++i]; |
| 38362 | int k; |
| 38363 | for(k=0; k<ArraySize(qrfEscNames); k++){ |
| @@ -38412,12 +38568,14 @@ | |
| 38412 | }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
| 38413 | modeSetStr(&data.mode.spec.zNull, |
| 38414 | cmdline_option_value(argc,argv,++i)); |
| 38415 | }else if( cli_strcmp(z,"-header")==0 ){ |
| 38416 | data.mode.spec.bTitles = QRF_Yes; |
| 38417 | }else if( cli_strcmp(z,"-noheader")==0 ){ |
| 38418 | data.mode.spec.bTitles = QRF_No; |
| 38419 | }else if( cli_strcmp(z,"-echo")==0 ){ |
| 38420 | data.mode.mFlags |= MFLG_ECHO; |
| 38421 | }else if( cli_strcmp(z,"-eqp")==0 ){ |
| 38422 | data.mode.autoEQP = AUTOEQP_on; |
| 38423 | }else if( cli_strcmp(z,"-eqpfull")==0 ){ |
| 38424 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -5,16 +5,16 @@ | |
| 5 | ** |
| 6 | ** ext/expert/sqlite3expert.c |
| 7 | ** ext/expert/sqlite3expert.h |
| 8 | ** ext/intck/sqlite3intck.c |
| 9 | ** ext/intck/sqlite3intck.h |
| 10 | ** ext/misc/appendvfs.c |
| 11 | ** ext/misc/base64.c |
| 12 | ** ext/misc/base85.c |
| 13 | ** ext/misc/completion.c |
| 14 | ** ext/misc/decimal.c |
| 15 | ** ext/misc/diskused.c |
| 16 | ** ext/misc/fileio.c |
| 17 | ** ext/misc/ieee754.c |
| 18 | ** ext/misc/memtrace.c |
| 19 | ** ext/misc/pcachetrace.c |
| 20 | ** ext/misc/regexp.c |
| @@ -154,10 +154,11 @@ | |
| 154 | #include <string.h> |
| 155 | #include <stdio.h> |
| 156 | #include <assert.h> |
| 157 | #include <math.h> |
| 158 | #include <stdint.h> |
| 159 | #include <time.h> |
| 160 | #include "sqlite3.h" |
| 161 | typedef sqlite3_int64 i64; |
| 162 | typedef sqlite3_uint64 u64; |
| 163 | typedef unsigned char u8; |
| 164 | #include <ctype.h> |
| @@ -190,13 +191,14 @@ | |
| 191 | #include <sys/stat.h> |
| 192 | |
| 193 | #if HAVE_READLINE |
| 194 | # include <readline/readline.h> |
| 195 | # include <readline/history.h> |
| 196 | #elif HAVE_EDITLINE |
| 197 | /* If both HAVE_READLINE and HAVE_EDITLINE are true, assume that this |
| 198 | ** libedit installation does not have its own headers, instead using |
| 199 | ** those from libreadline. */ |
| 200 | # include <editline/readline.h> |
| 201 | #endif |
| 202 | |
| 203 | #if HAVE_EDITLINE || HAVE_READLINE |
| 204 | |
| @@ -744,12 +746,11 @@ | |
| 746 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 747 | char **pzErr /* OUT: Write error message here */ |
| 748 | ); |
| 749 | |
| 750 | /* |
| 751 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries. |
| 752 | */ |
| 753 | #define QRF_MAX_WIDTH 10000 |
| 754 | #define QRF_MIN_WIDTH 0 |
| 755 | |
| 756 | /* |
| @@ -1129,10 +1130,14 @@ | |
| 1130 | sqlite3_str_append(pOut, "-", 1); |
| 1131 | } |
| 1132 | if( N<10000 ){ |
| 1133 | sqlite3_str_appendf(pOut, "%4lld ", N); |
| 1134 | return; |
| 1135 | } |
| 1136 | if( N>=9223372036854775800LL ){ |
| 1137 | sqlite3_str_appendf(pOut, "%.2fE", 1e-18*(double)N); |
| 1138 | return; |
| 1139 | } |
| 1140 | for(i=1; i<=18; i++){ |
| 1141 | N = (N+5)/10; |
| 1142 | if( N<10000 ){ |
| 1143 | int n = (int)N; |
| @@ -1289,12 +1294,12 @@ | |
| 1294 | if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ |
| 1295 | int nSp = 0; |
| 1296 | sqlite3_str_reset(pStats); |
| 1297 | if( nCycle>=0 && nTotal>0 ){ |
| 1298 | qrfApproxInt64(pStats, nCycle); |
| 1299 | sqlite3_str_appendf(pStats, " %3.0f%%", |
| 1300 | ((100.0*(double)nCycle)+nTotal/2.0) / (double)nTotal |
| 1301 | ); |
| 1302 | nSp = 2; |
| 1303 | } |
| 1304 | if( nLoop>=0 ){ |
| 1305 | if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); |
| @@ -1787,11 +1792,11 @@ | |
| 1792 | } |
| 1793 | if( i>0 ){ |
| 1794 | sqlite3_str_append(pOut, (const char*)z, i); |
| 1795 | } |
| 1796 | switch( z[i] ){ |
| 1797 | case '>': sqlite3_str_append(pOut, ">", 4); break; |
| 1798 | case '&': sqlite3_str_append(pOut, "&", 5); break; |
| 1799 | case '<': sqlite3_str_append(pOut, "<", 4); break; |
| 1800 | case '"': sqlite3_str_append(pOut, """, 6); break; |
| 1801 | case '\'': sqlite3_str_append(pOut, "'", 5); break; |
| 1802 | default: i--; |
| @@ -2281,11 +2286,11 @@ | |
| 2286 | if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ |
| 2287 | /* Perhaps try to back up to a better place to break the line */ |
| 2288 | for(k=i-1; k>=i/2; k--){ |
| 2289 | if( qrfSpace(z[k]) ) break; |
| 2290 | } |
| 2291 | if( k<i/2 && i/2>0 ){ |
| 2292 | for(k=i; k>=i/2; k--){ |
| 2293 | if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; |
| 2294 | } |
| 2295 | } |
| 2296 | if( k>=i/2 ){ |
| @@ -2532,16 +2537,16 @@ | |
| 2537 | const char *azDash[2] = { |
| 2538 | BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, |
| 2539 | DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 |
| 2540 | };/* 0 1 2 3 4 5 6 7 8 9 */ |
| 2541 | const int nDash = 30; |
| 2542 | i64 nn = 3*(i64)N; |
| 2543 | while( nn>nDash ){ |
| 2544 | sqlite3_str_append(pOut, azDash[bDbl], nDash); |
| 2545 | nn -= nDash; |
| 2546 | } |
| 2547 | sqlite3_str_append(pOut, azDash[bDbl], (int)nn); |
| 2548 | } |
| 2549 | |
| 2550 | /* |
| 2551 | ** Draw a horizontal separator for a QRF_STYLE_Box table. |
| 2552 | */ |
| @@ -2610,11 +2615,11 @@ | |
| 2615 | int nSW /* Screen width */ |
| 2616 | ){ |
| 2617 | int i; /* Loop counter */ |
| 2618 | int nr; /* Number of rows */ |
| 2619 | int w = 0; /* Width of the current column */ |
| 2620 | i64 t; /* Total width of all columns */ |
| 2621 | int *aw; /* Array of individual column widths */ |
| 2622 | |
| 2623 | aw = sqlite3_malloc64( sizeof(int)*nCol ); |
| 2624 | if( aw==0 ){ |
| 2625 | qrfOom(p); |
| @@ -2748,12 +2753,15 @@ | |
| 2753 | }else{ |
| 2754 | sepW = pData->nCol*3 + 1; |
| 2755 | if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2756 | } |
| 2757 | nCol = pData->nCol; |
| 2758 | for(i=0, sumW=0; i<nCol; i++){ |
| 2759 | if( sumW > 2147483647 - pData->a[i].w ) return; |
| 2760 | sumW += pData->a[i].w; |
| 2761 | } |
| 2762 | if( p->spec.nScreenWidth >= (i64)sumW + sepW ) return; |
| 2763 | |
| 2764 | /* First thing to do is reduce the separation between columns */ |
| 2765 | pData->nMargin = 0; |
| 2766 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2767 | sepW = pData->nCol - 1; |
| @@ -3624,11 +3632,11 @@ | |
| 3632 | p->nRow = 0; |
| 3633 | sz = sizeof(sqlite3_qrf_spec); |
| 3634 | memcpy(&p->spec, pSpec, sz); |
| 3635 | if( p->spec.zNull==0 ) p->spec.zNull = ""; |
| 3636 | p->mxWidth = p->spec.nScreenWidth; |
| 3637 | if( p->mxWidth<=0 ) p->mxWidth = 2147483647; |
| 3638 | p->mxHeight = p->spec.nLineLimit; |
| 3639 | if( p->mxHeight<=0 ) p->mxHeight = 2147483647; |
| 3640 | if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; |
| 3641 | if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; |
| 3642 | if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; |
| @@ -5272,10 +5280,14 @@ | |
| 5280 | #include <stdarg.h> |
| 5281 | |
| 5282 | /****************************************************************************** |
| 5283 | ** The Hash Engine |
| 5284 | */ |
| 5285 | #if defined(__GNUC__) && __GNUC__>=11 |
| 5286 | # pragma GCC diagnostic push |
| 5287 | # pragma GCC diagnostic ignored "-Wstringop-overread" |
| 5288 | #endif |
| 5289 | /* Context for the SHA1 hash */ |
| 5290 | typedef struct SHA1Context SHA1Context; |
| 5291 | struct SHA1Context { |
| 5292 | unsigned int state[5]; |
| 5293 | unsigned int count[2]; |
| @@ -5412,11 +5424,11 @@ | |
| 5424 | } |
| 5425 | j = 0; |
| 5426 | }else{ |
| 5427 | i = 0; |
| 5428 | } |
| 5429 | if( len-i>0 ) (void)memcpy(&p->buffer[j], &data[i], len - i); |
| 5430 | } |
| 5431 | |
| 5432 | /* Compute a string using sqlite3_vsnprintf() and hash it */ |
| 5433 | static void hash_step_vformat( |
| 5434 | SHA1Context *p, /* Add content to this context */ |
| @@ -5467,10 +5479,13 @@ | |
| 5479 | zOut[i*2+1] = zEncode[digest[i] & 0xf]; |
| 5480 | } |
| 5481 | zOut[i*2]= 0; |
| 5482 | } |
| 5483 | } |
| 5484 | #if defined(__GNUC__) && __GNUC__>=11 |
| 5485 | # pragma GCC diagnostic pop |
| 5486 | #endif |
| 5487 | /* End of the hashing logic |
| 5488 | *****************************************************************************/ |
| 5489 | |
| 5490 | /* |
| 5491 | ** Two SQL functions: sha1(X) and sha1b(X). |
| @@ -6056,32 +6071,41 @@ | |
| 6071 | } |
| 6072 | z[i] = 0; |
| 6073 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6074 | } |
| 6075 | |
| 6076 | /* Forward declaration */ |
| 6077 | static void decimal_expand(Decimal *p, int nDigit, int nFrac); |
| 6078 | |
| 6079 | /* |
| 6080 | ** Round a decimal value to N significant digits. N must be positive. |
| 6081 | */ |
| 6082 | static void decimal_round(Decimal *p, int N){ |
| 6083 | int i; |
| 6084 | int nZero; /* Number of leading zeros */ |
| 6085 | if( N<1 ) return; |
| 6086 | if( p==0 ) return; |
| 6087 | if( p->nDigit<=N ) return; |
| 6088 | for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6089 | N += nZero; |
| 6090 | if( p->nDigit<=N ) return; |
| 6091 | if( p->a[N]>=5 ){ |
| 6092 | /* If all leading digits are 9, increase the number of digits |
| 6093 | ** by adding a new 0 to the front */ |
| 6094 | for(i=0; i<N && p->a[i]==9; i++){} |
| 6095 | if( i==N ){ |
| 6096 | decimal_expand(p, p->nDigit+1, 0); |
| 6097 | if( p->oom ) return; |
| 6098 | } |
| 6099 | |
| 6100 | /* Do the rounding */ |
| 6101 | p->a[N-1]++; |
| 6102 | for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6103 | p->a[i] = 0; |
| 6104 | p->a[i-1]++; |
| 6105 | } |
| 6106 | assert( p->a[0]<=9 ); |
| 6107 | } |
| 6108 | memset(&p->a[N], 0, p->nDigit - N); |
| 6109 | } |
| 6110 | |
| 6111 | /* |
| @@ -8363,19 +8387,26 @@ | |
| 8387 | } |
| 8388 | }else{ |
| 8389 | iMin = iMax = sqlite3_value_int64(argv[iArg++]); |
| 8390 | } |
| 8391 | }else{ |
| 8392 | if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */ |
| 8393 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8394 | double r = sqlite3_value_double(argv[iArg++]); |
| 8395 | if( r<=(double)SMALLEST_INT64 ){ |
| 8396 | iMin = SMALLEST_INT64; |
| 8397 | }else if( r>(double)LARGEST_INT64 ){ |
| 8398 | goto series_no_rows; |
| 8399 | }else{ |
| 8400 | iMin = (sqlite3_int64)seriesCeil(r); |
| 8401 | if( iMin<0 && r>0.0 ){ |
| 8402 | iMin = LARGEST_INT64; |
| 8403 | } |
| 8404 | if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ |
| 8405 | if( iMin==LARGEST_INT64 ) goto series_no_rows; |
| 8406 | iMin++; |
| 8407 | } |
| 8408 | } |
| 8409 | }else{ |
| 8410 | iMin = sqlite3_value_int64(argv[iArg++]); |
| 8411 | if( (idxNum & 0x0200)!=0 ){ |
| 8412 | if( iMin==LARGEST_INT64 ){ |
| @@ -8384,19 +8415,25 @@ | |
| 8415 | iMin++; |
| 8416 | } |
| 8417 | } |
| 8418 | } |
| 8419 | } |
| 8420 | if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */ |
| 8421 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8422 | double r = sqlite3_value_double(argv[iArg++]); |
| 8423 | if( r>=(double)LARGEST_INT64 ){ |
| 8424 | iMax = LARGEST_INT64; |
| 8425 | }else if( r<=(double)SMALLEST_INT64 ){ |
| 8426 | goto series_no_rows; |
| 8427 | }else{ |
| 8428 | iMax = (sqlite3_int64)seriesFloor(r); |
| 8429 | if( iMax<0 && r>0.0 ){ |
| 8430 | iMax = LARGEST_INT64; |
| 8431 | }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ |
| 8432 | if( iMax==SMALLEST_INT64 ) goto series_no_rows; |
| 8433 | iMax--; |
| 8434 | } |
| 8435 | } |
| 8436 | }else{ |
| 8437 | iMax = sqlite3_value_int64(argv[iArg++]); |
| 8438 | if( idxNum & 0x2000 ){ |
| 8439 | if( iMax==SMALLEST_INT64 ){ |
| @@ -9638,11 +9675,10 @@ | |
| 9675 | if( pRe==0 ){ |
| 9676 | sqlite3_result_error_nomem(context); |
| 9677 | return; |
| 9678 | } |
| 9679 | pStr = sqlite3_str_new(0); |
| 9680 | if( pRe->nInit>0 ){ |
| 9681 | sqlite3_str_appendf(pStr, "INIT "); |
| 9682 | for(i=0; i<pRe->nInit; i++){ |
| 9683 | sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); |
| 9684 | } |
| @@ -9649,20 +9685,20 @@ | |
| 9685 | sqlite3_str_appendf(pStr, "\n"); |
| 9686 | } |
| 9687 | for(i=0; (unsigned)i<pRe->nState; i++){ |
| 9688 | sqlite3_str_appendf(pStr, "%-8s %4d\n", |
| 9689 | ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); |
| 9690 | } |
| 9691 | if( sqlite3_str_errcode(pStr)==SQLITE_NOMEM ){ |
| 9692 | sqlite3_str_finish(pStr); |
| 9693 | re_free(pRe); |
| 9694 | sqlite3_result_error_nomem(context); |
| 9695 | return; |
| 9696 | } |
| 9697 | n = sqlite3_str_length(pStr); |
| 9698 | z = sqlite3_str_finish(pStr); |
| 9699 | sqlite3_result_text(context, z, n-1, sqlite3_free); |
| 9700 | re_free(pRe); |
| 9701 | } |
| 9702 | |
| 9703 | #endif /* SQLITE_DEBUG */ |
| 9704 | |
| @@ -10870,10 +10906,13 @@ | |
| 10906 | ** Return NULL if unable. |
| 10907 | ** |
| 10908 | ** The file or directory X is not required to exist. The answer is formed |
| 10909 | ** by calling system realpath() on the prefix of X that does exist and |
| 10910 | ** appending the tail of X that does not (yet) exist. |
| 10911 | ** |
| 10912 | ** FIXME: This routine sometimes returns NULL rather than raising |
| 10913 | ** an SQLITE_NOMEM error if an OOM is encountered. |
| 10914 | */ |
| 10915 | static void realpathFunc( |
| 10916 | sqlite3_context *context, |
| 10917 | int argc, |
| 10918 | sqlite3_value **argv |
| @@ -10892,10 +10931,11 @@ | |
| 10931 | (void)argc; |
| 10932 | zPath = (const char*)sqlite3_value_text(argv[0]); |
| 10933 | if( zPath==0 ) return; |
| 10934 | if( zPath[0]==0 ) zPath = "."; |
| 10935 | zCopy = sqlite3_mprintf("%s",zPath); |
| 10936 | if( zCopy==0 ) return; |
| 10937 | len = strlen(zCopy); |
| 10938 | while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 10939 | len--; |
| 10940 | } |
| 10941 | zCopy[len] = 0; |
| @@ -12685,10 +12725,11 @@ | |
| 12725 | |
| 12726 | for(p=pCsr->pFreeEntry; p; p=pNext){ |
| 12727 | pNext = p->pNext; |
| 12728 | zipfileEntryFree(p); |
| 12729 | } |
| 12730 | pCsr->pFreeEntry = 0; |
| 12731 | } |
| 12732 | |
| 12733 | /* |
| 12734 | ** Destructor for an ZipfileCsr. |
| 12735 | */ |
| @@ -13087,11 +13128,17 @@ | |
| 13128 | } |
| 13129 | } |
| 13130 | |
| 13131 | if( rc==SQLITE_OK ){ |
| 13132 | u32 *pt = &pNew->mUnixTime; |
| 13133 | /* aRead[0..nFile-1] might contain embedded \000 characters |
| 13134 | ** See Bug 2026-05-31T11:43:05Z */ |
| 13135 | pNew->cds.zFile = sqlite3_malloc64(nFile+1); |
| 13136 | if( pNew->cds.zFile!=0 ){ |
| 13137 | memcpy(pNew->cds.zFile, aRead, nFile); |
| 13138 | pNew->cds.zFile[nFile] = 0; |
| 13139 | } |
| 13140 | pNew->aExtra = (u8*)&pNew[1]; |
| 13141 | memcpy(pNew->aExtra, &aRead[nFile], nExtra); |
| 13142 | if( pNew->cds.zFile==0 ){ |
| 13143 | rc = SQLITE_NOMEM; |
| 13144 | }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ |
| @@ -14191,14 +14238,14 @@ | |
| 14238 | ZipfileBuffer body; |
| 14239 | ZipfileBuffer cds; |
| 14240 | }; |
| 14241 | |
| 14242 | static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){ |
| 14243 | if( (pBuf->nAlloc-pBuf->n)<nByte ){ |
| 14244 | u8 *aNew; |
| 14245 | i64 nNew = pBuf->n ? (i64)pBuf->n*2 : 512; |
| 14246 | i64 nReq = pBuf->n + nByte; |
| 14247 | |
| 14248 | while( nNew<nReq ) nNew = nNew*2; |
| 14249 | aNew = sqlite3_realloc64(pBuf->a, nNew); |
| 14250 | if( aNew==0 ) return SQLITE_NOMEM; |
| 14251 | pBuf->a = aNew; |
| @@ -16296,11 +16343,11 @@ | |
| 16343 | p->pTable = pTab; |
| 16344 | |
| 16345 | /* The statement the vtab will pass to sqlite3_declare_vtab() */ |
| 16346 | zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); |
| 16347 | for(i=0; i<pTab->nCol; i++){ |
| 16348 | zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %Q", |
| 16349 | (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl |
| 16350 | ); |
| 16351 | } |
| 16352 | zInner = idxAppendText(&rc, zInner, ")"); |
| 16353 | |
| @@ -16496,11 +16543,11 @@ | |
| 16543 | sqlite3_free(zCols); |
| 16544 | sqlite3_free(zOrder); |
| 16545 | return sqlite3_reset(pIndexXInfo); |
| 16546 | } |
| 16547 | zCols = idxAppendText(&rc, zCols, |
| 16548 | "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %Q", |
| 16549 | zComma, zName, nCol, zName, zColl |
| 16550 | ); |
| 16551 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 16552 | } |
| 16553 | sqlite3_reset(pIndexXInfo); |
| @@ -19464,11 +19511,11 @@ | |
| 19511 | sqlite3_vfs_unregister(pVfs); |
| 19512 | sqlite3_free(pVfs); |
| 19513 | } |
| 19514 | |
| 19515 | /************************* End ext/misc/vfstrace.c ********************/ |
| 19516 | /************************* Begin ext/misc/diskused.c ******************/ |
| 19517 | /* |
| 19518 | ** 2026-04-13 |
| 19519 | ** |
| 19520 | ** The author disclaims copyright to this source code. In place of |
| 19521 | ** a legal notice, here is a blessing: |
| @@ -19477,12 +19524,21 @@ | |
| 19524 | ** May you find forgiveness for yourself and forgive others. |
| 19525 | ** May you share freely, never taking more than you give. |
| 19526 | ** |
| 19527 | ****************************************************************************** |
| 19528 | ** |
| 19529 | ** This extension implements an SQL function: |
| 19530 | ** |
| 19531 | ** diskused(X) |
| 19532 | ** |
| 19533 | ** Where X is the schema name (typically 'main'). The output is text |
| 19534 | ** that describes how much filesystem space the various tables and indexes |
| 19535 | ** of the database consume. |
| 19536 | ** |
| 19537 | ** This function is a replacement for the (now deprecated) |
| 19538 | ** "sqlite3_analyzer" utility program. This function is built |
| 19539 | ** into the CLI and is used to implement the ".diskused" command there. |
| 19540 | */ |
| 19541 | /* #include "sqlite3ext.h" */ |
| 19542 | SQLITE_EXTENSION_INIT1 |
| 19543 | #include <assert.h> |
| 19544 | #include <string.h> |
| @@ -19490,28 +19546,28 @@ | |
| 19546 | #include <math.h> |
| 19547 | |
| 19548 | /* |
| 19549 | ** State information for the analysis |
| 19550 | */ |
| 19551 | typedef struct DiskUsed DiskUsed; |
| 19552 | struct DiskUsed { |
| 19553 | sqlite3 *db; /* Database connection */ |
| 19554 | sqlite3_context *context; /* SQL function context */ |
| 19555 | sqlite3_str *pOut; /* Write output here */ |
| 19556 | char *zSU; /* Name of the temp.space_used table */ |
| 19557 | const char *zSchema; /* Schema to be analyzed */ |
| 19558 | }; |
| 19559 | |
| 19560 | /* |
| 19561 | ** Free all resources that the DiskUsed object references and |
| 19562 | ** reset the DiskUsed object. |
| 19563 | ** |
| 19564 | ** Call this routine multiple times on the same DiskUsed object |
| 19565 | ** is a harmless no-op, as long as the memory for the object itself |
| 19566 | ** has not been freed. |
| 19567 | */ |
| 19568 | static void diskusedReset(DiskUsed *p){ |
| 19569 | if( p->zSU ){ |
| 19570 | char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU); |
| 19571 | if( zSql ){ |
| 19572 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 19573 | sqlite3_free(zSql); |
| @@ -19524,11 +19580,11 @@ | |
| 19580 | |
| 19581 | /* |
| 19582 | ** Report an error using formatted text. If zFormat==NULL then report |
| 19583 | ** an OOM error. |
| 19584 | */ |
| 19585 | static void diskusedError(DiskUsed *p, const char *zFormat, ...){ |
| 19586 | char *zErr; |
| 19587 | if( zFormat ){ |
| 19588 | va_list ap; |
| 19589 | va_start(ap, zFormat); |
| 19590 | zErr = sqlite3_vmprintf(zFormat, ap); |
| @@ -19540,38 +19596,38 @@ | |
| 19596 | sqlite3_result_error_nomem(p->context); |
| 19597 | }else{ |
| 19598 | sqlite3_result_error(p->context, zErr, -1); |
| 19599 | sqlite3_free(zErr); |
| 19600 | } |
| 19601 | diskusedReset(p); |
| 19602 | } |
| 19603 | |
| 19604 | /* |
| 19605 | ** Prepare and return an SQL statement. |
| 19606 | */ |
| 19607 | static sqlite3_stmt *diskusedVPrep(DiskUsed *p, const char *zFmt, va_list ap){ |
| 19608 | char *zSql; |
| 19609 | int rc; |
| 19610 | sqlite3_stmt *pStmt = 0; |
| 19611 | zSql = sqlite3_vmprintf(zFmt, ap); |
| 19612 | if( zSql==0 ){ diskusedError(p,0); return 0; } |
| 19613 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 19614 | if( rc ){ |
| 19615 | diskusedError(p, "SQL parse error: %s\nOriginal SQL: %s", |
| 19616 | sqlite3_errmsg(p->db), zSql); |
| 19617 | sqlite3_finalize(pStmt); |
| 19618 | diskusedReset(p); |
| 19619 | pStmt = 0; |
| 19620 | } |
| 19621 | sqlite3_free(zSql); |
| 19622 | return pStmt; |
| 19623 | } |
| 19624 | static sqlite3_stmt *diskusedPrepare(DiskUsed *p, const char *zFormat, ...){ |
| 19625 | va_list ap; |
| 19626 | sqlite3_stmt *pStmt = 0; |
| 19627 | va_start(ap, zFormat); |
| 19628 | pStmt = diskusedVPrep(p,zFormat,ap); |
| 19629 | va_end(ap); |
| 19630 | return pStmt; |
| 19631 | } |
| 19632 | |
| 19633 | /* |
| @@ -19580,60 +19636,60 @@ | |
| 19636 | ** |
| 19637 | ** If rc is SQLITE_DONE or SQLITE_OK, then return false. |
| 19638 | ** |
| 19639 | ** The prepared statement is closed in either case. |
| 19640 | */ |
| 19641 | static int diskusedStmtFinish(DiskUsed *p, int rc, sqlite3_stmt *pStmt){ |
| 19642 | if( rc==SQLITE_DONE ){ |
| 19643 | rc = SQLITE_OK; |
| 19644 | } |
| 19645 | if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){ |
| 19646 | diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19647 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19648 | diskusedReset(p); |
| 19649 | } |
| 19650 | sqlite3_finalize(pStmt); |
| 19651 | return rc; |
| 19652 | } |
| 19653 | |
| 19654 | /* |
| 19655 | ** Run SQL. Return the number of errors. |
| 19656 | */ |
| 19657 | static int diskusedSql(DiskUsed *p, const char *zFormat, ...){ |
| 19658 | va_list ap; |
| 19659 | int rc; |
| 19660 | sqlite3_stmt *pStmt = 0; |
| 19661 | va_start(ap, zFormat); |
| 19662 | pStmt = diskusedVPrep(p,zFormat,ap); |
| 19663 | va_end(ap); |
| 19664 | if( pStmt==0 ) return 1; |
| 19665 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){} |
| 19666 | if( rc==SQLITE_DONE ){ |
| 19667 | rc = SQLITE_OK; |
| 19668 | }else{ |
| 19669 | diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19670 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19671 | diskusedReset(p); |
| 19672 | } |
| 19673 | sqlite3_finalize(pStmt); |
| 19674 | return rc; |
| 19675 | } |
| 19676 | |
| 19677 | /* |
| 19678 | ** Run an SQL query that returns an integer. Write that integer |
| 19679 | ** into *piRes. Return the number of errors. |
| 19680 | */ |
| 19681 | static int diskusedSqlInt( |
| 19682 | DiskUsed *p, |
| 19683 | sqlite3_int64 *piRes, |
| 19684 | const char *zFormat, ... |
| 19685 | ){ |
| 19686 | va_list ap; |
| 19687 | int rc; |
| 19688 | sqlite3_stmt *pStmt = 0; |
| 19689 | va_start(ap, zFormat); |
| 19690 | pStmt = diskusedVPrep(p,zFormat,ap); |
| 19691 | va_end(ap); |
| 19692 | if( pStmt==0 ) return 1; |
| 19693 | rc = sqlite3_step(pStmt); |
| 19694 | if( rc==SQLITE_ROW ){ |
| 19695 | *piRes = sqlite3_column_int64(pStmt, 0); |
| @@ -19641,14 +19697,14 @@ | |
| 19697 | }else if( rc==SQLITE_DONE ){ |
| 19698 | rc = SQLITE_OK; |
| 19699 | }else{ |
| 19700 | if( p->db ){ |
| 19701 | /* p->db is NULL if there was some prior error */ |
| 19702 | diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19703 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19704 | } |
| 19705 | diskusedReset(p); |
| 19706 | } |
| 19707 | sqlite3_finalize(pStmt); |
| 19708 | return rc; |
| 19709 | } |
| 19710 | |
| @@ -19657,20 +19713,20 @@ | |
| 19713 | ** by the format string. If the output is initially empty, begin |
| 19714 | ** the title line with "/" so that it forms the beginning of a C-style |
| 19715 | ** comment. Otherwise begin with a new-line. Always finish with a |
| 19716 | ** newline. |
| 19717 | */ |
| 19718 | static void diskusedTitle(DiskUsed *p, const char *zFormat, ...){ |
| 19719 | char *zFirst; |
| 19720 | char *zTitle; |
| 19721 | size_t nTitle; |
| 19722 | va_list ap; |
| 19723 | va_start(ap, zFormat); |
| 19724 | zTitle = sqlite3_vmprintf(zFormat, ap); |
| 19725 | va_end(ap); |
| 19726 | if( zTitle==0 ){ |
| 19727 | diskusedError(p, 0); |
| 19728 | return; |
| 19729 | } |
| 19730 | zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*"; |
| 19731 | nTitle = strlen(zTitle); |
| 19732 | if( nTitle>=75 ){ |
| @@ -19685,12 +19741,12 @@ | |
| 19741 | /* |
| 19742 | ** Add an output line that begins with the zDesc text extended out to |
| 19743 | ** 50 columns with "." characters, and followed by whatever text is |
| 19744 | ** described by zFormat. |
| 19745 | */ |
| 19746 | static void diskusedLine( |
| 19747 | DiskUsed *p, /* DiskUsed context */ |
| 19748 | const char *zDesc, /* Description */ |
| 19749 | const char *zFormat, /* Argument to the description */ |
| 19750 | ... |
| 19751 | ){ |
| 19752 | char *zTxt; |
| @@ -19698,14 +19754,14 @@ | |
| 19754 | va_list ap; |
| 19755 | va_start(ap, zFormat); |
| 19756 | zTxt = sqlite3_vmprintf(zFormat, ap); |
| 19757 | va_end(ap); |
| 19758 | if( zTxt==0 ){ |
| 19759 | diskusedError(p, 0); |
| 19760 | return; |
| 19761 | } |
| 19762 | nDesc = zDesc ? strlen(zDesc) : 0; |
| 19763 | if( nDesc>=50 ){ |
| 19764 | sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt); |
| 19765 | }else{ |
| 19766 | int nExtra = 50 - (int)nDesc; |
| 19767 | sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt); |
| @@ -19715,11 +19771,11 @@ | |
| 19771 | /* |
| 19772 | ** Write a percentage into the output. The number written should show |
| 19773 | ** two or three significant digits, with the decimal point being the fourth |
| 19774 | ** character. |
| 19775 | */ |
| 19776 | static void diskusedPercent(DiskUsed *p, double r){ |
| 19777 | char zNum[100]; |
| 19778 | char *zDP; |
| 19779 | int nLeadingDigit; |
| 19780 | int sz; |
| 19781 | sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r); |
| @@ -19744,12 +19800,12 @@ | |
| 19800 | ** |
| 19801 | ** The title if the subreport is given by zTitle. zWhere is |
| 19802 | ** a boolean expression that can go in the WHERE clause to select |
| 19803 | ** the relevant rows of the s.zSU table. |
| 19804 | */ |
| 19805 | static int diskusedSubreport( |
| 19806 | DiskUsed *p, /* DiskUsed context */ |
| 19807 | char *zTitle, /* Title for this subreport */ |
| 19808 | char *zWhere, /* WHERE clause for this subreport */ |
| 19809 | sqlite3_int64 pgsz, /* Database page size */ |
| 19810 | sqlite3_int64 nPage /* Number of pages in entire database */ |
| 19811 | ){ |
| @@ -19773,14 +19829,14 @@ | |
| 19829 | sqlite3_int64 total_unused; /* Total unused bytes */ |
| 19830 | sqlite3_int64 total_meta; /* Total metadata */ |
| 19831 | int rc; |
| 19832 | |
| 19833 | if( zTitle==0 || zWhere==0 ){ |
| 19834 | diskusedError(p, 0); |
| 19835 | return SQLITE_NOMEM; |
| 19836 | } |
| 19837 | pStmt = diskusedPrepare(p, |
| 19838 | "SELECT\n" |
| 19839 | " sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */ |
| 19840 | " sum(payload),\n" /* 1 */ |
| 19841 | " sum(ovfl_payload),\n" /* 2 */ |
| 19842 | " max(mx_payload),\n" /* 3 */ |
| @@ -19797,11 +19853,11 @@ | |
| 19853 | " FROM temp.%s WHERE %s", |
| 19854 | p->zSU, zWhere); |
| 19855 | if( pStmt==0 ) return 1; |
| 19856 | rc = sqlite3_step(pStmt); |
| 19857 | if( rc==SQLITE_ROW ){ |
| 19858 | diskusedTitle(p, "%s", zTitle); |
| 19859 | |
| 19860 | nentry = sqlite3_column_int64(pStmt, 0); |
| 19861 | payload = sqlite3_column_int64(pStmt, 1); |
| 19862 | ovfl_payload = sqlite3_column_int64(pStmt, 2); |
| 19863 | mx_payload = sqlite3_column_int64(pStmt, 3); |
| @@ -19816,73 +19872,73 @@ | |
| 19872 | cnt = sqlite3_column_int64(pStmt, 12); |
| 19873 | int_cell = sqlite3_column_int64(pStmt, 13); |
| 19874 | rc = SQLITE_DONE; |
| 19875 | |
| 19876 | total_pages = leaf_pages + int_pages + ovfl_pages; |
| 19877 | diskusedLine(p, "Percentage of total database", "%.3g%%\n", |
| 19878 | (total_pages*100.0)/(double)nPage); |
| 19879 | diskusedLine(p, "Number of entries", "%lld\n", nentry); |
| 19880 | storage = total_pages*pgsz; |
| 19881 | diskusedLine(p, "Bytes of storage consumed", "%lld\n", storage); |
| 19882 | diskusedLine(p, "Bytes of payload", "%-11lld ", payload); |
| 19883 | diskusedPercent(p, payload*100.0/(double)storage); |
| 19884 | if( ovfl_cnt>0 ){ |
| 19885 | diskusedLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); |
| 19886 | diskusedPercent(p, ovfl_payload*100.0/(double)payload); |
| 19887 | } |
| 19888 | total_unused = leaf_unused + int_unused + ovfl_unused; |
| 19889 | total_meta = storage - payload - total_unused; |
| 19890 | diskusedLine(p, "Bytes of metadata","%-11lld ", total_meta); |
| 19891 | diskusedPercent(p, total_meta*100.0/(double)storage); |
| 19892 | if( cnt==1 ){ |
| 19893 | diskusedLine(p, "B-tree depth", "%lld\n", depth); |
| 19894 | if( int_cell>1 ){ |
| 19895 | diskusedLine(p, "Average fanout", "%.1f\n", |
| 19896 | (double)(int_cell+int_pages)/(double)int_pages); |
| 19897 | } |
| 19898 | } |
| 19899 | if( nentry>0 ){ |
| 19900 | diskusedLine(p, "Average payload per entry", "%.1f\n", |
| 19901 | (double)payload/(double)nentry); |
| 19902 | diskusedLine(p, "Average unused bytes per entry", "%.1f\n", |
| 19903 | (double)total_unused/(double)nentry); |
| 19904 | diskusedLine(p, "Average metadata per entry", "%.1f\n", |
| 19905 | (double)total_meta/(double)nentry); |
| 19906 | } |
| 19907 | diskusedLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); |
| 19908 | if( nentry>0 ){ |
| 19909 | diskusedLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); |
| 19910 | diskusedPercent(p, ovfl_cnt*100.0/(double)nentry); |
| 19911 | } |
| 19912 | if( int_pages>0 ){ |
| 19913 | diskusedLine(p, "Index pages used", "%lld\n", int_pages); |
| 19914 | } |
| 19915 | diskusedLine(p, "Primary pages used", "%lld\n", leaf_pages); |
| 19916 | if( ovfl_cnt ){ |
| 19917 | diskusedLine(p, "Overflow pages used", "%lld\n", ovfl_pages); |
| 19918 | } |
| 19919 | diskusedLine(p, "Total pages used", "%lld\n", total_pages); |
| 19920 | if( int_pages>0 ){ |
| 19921 | diskusedLine(p, "Unused bytes on index pages", "%lld\n", int_unused); |
| 19922 | } |
| 19923 | diskusedLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); |
| 19924 | if( ovfl_cnt ){ |
| 19925 | diskusedLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); |
| 19926 | } |
| 19927 | diskusedLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); |
| 19928 | diskusedPercent(p, total_unused*100.0/(double)storage); |
| 19929 | } |
| 19930 | return diskusedStmtFinish(p, rc, pStmt); |
| 19931 | } |
| 19932 | |
| 19933 | /* |
| 19934 | ** SQL Function: diskused(SCHEMA) |
| 19935 | ** |
| 19936 | ** Analyze the database schema named in the argument. Return text |
| 19937 | ** containing the space utilization stats. |
| 19938 | */ |
| 19939 | static void diskusedFunc( |
| 19940 | sqlite3_context *context, |
| 19941 | int argc, |
| 19942 | sqlite3_value **argv |
| 19943 | ){ |
| 19944 | int rc; |
| @@ -19893,47 +19949,47 @@ | |
| 19949 | sqlite3_int64 nPage; |
| 19950 | sqlite3_int64 nPageInUse; |
| 19951 | sqlite3_int64 nFreeList; |
| 19952 | sqlite3_int64 nIndex; |
| 19953 | sqlite3_int64 nWORowid; |
| 19954 | DiskUsed s; |
| 19955 | sqlite3_uint64 r[2]; |
| 19956 | |
| 19957 | (void)argc; |
| 19958 | memset(&s, 0, sizeof(s)); |
| 19959 | s.db = sqlite3_context_db_handle(context); |
| 19960 | s.context = context; |
| 19961 | s.pOut = sqlite3_str_new(0); |
| 19962 | if( sqlite3_str_errcode(s.pOut) ){ |
| 19963 | diskusedError(&s, 0); |
| 19964 | return; |
| 19965 | } |
| 19966 | s.zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 19967 | if( s.zSchema==0 ){ |
| 19968 | s.zSchema = "main"; |
| 19969 | }else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){ |
| 19970 | diskusedReset(&s); |
| 19971 | sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC); |
| 19972 | return; |
| 19973 | } |
| 19974 | ii = 0; |
| 19975 | rc = diskusedSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" |
| 19976 | " WHERE name=%Q COLLATE nocase",s.zSchema); |
| 19977 | if( rc || ii==0 ){ |
| 19978 | diskusedReset(&s); |
| 19979 | sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC); |
| 19980 | return; |
| 19981 | } |
| 19982 | sqlite3_randomness(sizeof(r), &r); |
| 19983 | s.zSU = sqlite3_mprintf("diskused%016llx%016llx", r[0], r[1]); |
| 19984 | if( s.zSU==0 ){ diskusedError(&s, 0); return; } |
| 19985 | |
| 19986 | /* The s.zSU table contains the data used for the analysis. |
| 19987 | ** The table name contains 128-bits of randomness to avoid |
| 19988 | ** collisions with preexisting tables in temp. |
| 19989 | */ |
| 19990 | rc = diskusedSql(&s, |
| 19991 | "CREATE TABLE temp.%s(\n" |
| 19992 | " name text, -- A table or index\n" |
| 19993 | " tblname text, -- Table that owns name\n" |
| 19994 | " is_index boolean, -- TRUE if it is an index\n" |
| 19995 | " is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" |
| @@ -19956,11 +20012,11 @@ | |
| 20012 | ); |
| 20013 | if( rc ) return; |
| 20014 | |
| 20015 | /* Populate the s.zSU table |
| 20016 | */ |
| 20017 | rc = diskusedSql(&s, |
| 20018 | "WITH\n" |
| 20019 | " allidx(idxname) AS (\n" |
| 20020 | " SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n" |
| 20021 | " ),\n" |
| 20022 | " allobj(allname,tblname,isidx,isworowid) AS (\n" |
| @@ -20008,141 +20064,143 @@ | |
| 20064 | s.zSchema /* JOIN dbstat(%Q) */ |
| 20065 | ); |
| 20066 | if( rc ) return; |
| 20067 | |
| 20068 | nPage = 0; |
| 20069 | rc = diskusedSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); |
| 20070 | if( rc ) return; |
| 20071 | if( nPage<=0 ){ |
| 20072 | /* Very brief reply for an empty database */ |
| 20073 | diskusedReset(&s); |
| 20074 | sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC); |
| 20075 | return; |
| 20076 | } |
| 20077 | |
| 20078 | /* Begin generating the report */ |
| 20079 | diskusedTitle(&s, "Database storage utilization report"); |
| 20080 | pgsz = 0; |
| 20081 | rc = diskusedSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); |
| 20082 | if( rc ) return; |
| 20083 | diskusedLine(&s, "Page size in bytes","%lld\n",pgsz); |
| 20084 | diskusedLine(&s, "Pages in the database", "%lld\n", nPage); |
| 20085 | |
| 20086 | nPageInUse = 0; |
| 20087 | rc = diskusedSqlInt(&s, &nPageInUse, |
| 20088 | "SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU); |
| 20089 | if( rc ) return; |
| 20090 | diskusedLine(&s, "Pages that store data", "%-11lld ", nPageInUse); |
| 20091 | diskusedPercent(&s, (nPageInUse*100.0)/(double)nPage); |
| 20092 | |
| 20093 | nFreeList = 0; |
| 20094 | rc = diskusedSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); |
| 20095 | if( rc ) return; |
| 20096 | diskusedLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); |
| 20097 | diskusedPercent(&s, (nFreeList*100.0)/(double)nPage); |
| 20098 | |
| 20099 | ii = 0; |
| 20100 | rc = diskusedSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); |
| 20101 | if( rc ) return; |
| 20102 | if( ii==0 || nPage<=1 ){ |
| 20103 | ii = 0; |
| 20104 | }else{ |
| 20105 | double rPtrsPerPage = pgsz/5; |
| 20106 | double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0); |
| 20107 | ii = (sqlite3_int64)ceil(rAvPage); |
| 20108 | } |
| 20109 | diskusedLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); |
| 20110 | diskusedPercent(&s, (ii*100.0)/(double)nPage); |
| 20111 | |
| 20112 | ii = 0; |
| 20113 | rc = diskusedSqlInt(&s, &ii, |
| 20114 | "SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'", |
| 20115 | s.zSchema); |
| 20116 | if( rc ) return; |
| 20117 | diskusedLine(&s, "Number of tables", "%lld\n", ii); |
| 20118 | nWORowid = 0; |
| 20119 | rc = diskusedSqlInt(&s, &nWORowid, |
| 20120 | "SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr", |
| 20121 | s.zSchema); |
| 20122 | if( rc ) return; |
| 20123 | if( nWORowid>0 ){ |
| 20124 | diskusedLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); |
| 20125 | diskusedLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); |
| 20126 | } |
| 20127 | nIndex = 0; |
| 20128 | rc = diskusedSqlInt(&s, &nIndex, |
| 20129 | "SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'", |
| 20130 | s.zSchema); |
| 20131 | if( rc ) return; |
| 20132 | diskusedLine(&s, "Number of indexes", "%lld\n", nIndex); |
| 20133 | ii = 0; |
| 20134 | rc = diskusedSqlInt(&s, &ii, |
| 20135 | "SELECT count(*) FROM \"%w\".sqlite_schema" |
| 20136 | " WHERE name GLOB 'sqlite_autoindex_*' AND type='index'", |
| 20137 | s.zSchema); |
| 20138 | if( rc ) return; |
| 20139 | diskusedLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); |
| 20140 | diskusedLine(&s, "Number of implied indexes", "%lld\n", ii); |
| 20141 | diskusedLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); |
| 20142 | ii = 0; |
| 20143 | rc = diskusedSqlInt(&s, &ii, |
| 20144 | "SELECT sum(payload) FROM temp.%s" |
| 20145 | " WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'", |
| 20146 | s.zSU); |
| 20147 | if( rc ) return; |
| 20148 | diskusedLine(&s, "Bytes of payload", "%-11lld ", ii); |
| 20149 | diskusedPercent(&s, ii*100.0/(double)(pgsz*nPage)); |
| 20150 | |
| 20151 | diskusedTitle(&s, "Page counts for all tables with their indexes"); |
| 20152 | pStmt = diskusedPrepare(&s, |
| 20153 | "SELECT upper(tblname),\n" |
| 20154 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20155 | " FROM temp.%s\n" |
| 20156 | " WHERE tblname IS NOT NULL\n" |
| 20157 | " GROUP BY 1\n" |
| 20158 | " ORDER BY 2 DESC, 1;", |
| 20159 | s.zSU); |
| 20160 | if( pStmt==0 ) return; |
| 20161 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20162 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20163 | diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20164 | diskusedPercent(&s, (nn*100.0)/(double)nPage); |
| 20165 | } |
| 20166 | if( diskusedStmtFinish(&s, rc, pStmt) ) return; |
| 20167 | |
| 20168 | diskusedTitle(&s, "Page counts for all tables and indexes separately"); |
| 20169 | pStmt = diskusedPrepare(&s, |
| 20170 | "SELECT upper(name),\n" |
| 20171 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20172 | " FROM temp.%s\n" |
| 20173 | " WHERE name IS NOT NULL\n" |
| 20174 | " GROUP BY 1\n" |
| 20175 | " ORDER BY 2 DESC, 1;", |
| 20176 | s.zSU); |
| 20177 | if( pStmt==0 ) return; |
| 20178 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20179 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20180 | diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20181 | diskusedPercent(&s, (nn*100.0)/(double)nPage); |
| 20182 | } |
| 20183 | if( diskusedStmtFinish(&s, rc, pStmt) ) return; |
| 20184 | |
| 20185 | rc = diskusedSubreport(&s, "All tables and indexes", "1", pgsz, nPage); |
| 20186 | if( rc ) return; |
| 20187 | rc = diskusedSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); |
| 20188 | if( rc ) return; |
| 20189 | if( nWORowid>0 ){ |
| 20190 | rc = diskusedSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", |
| 20191 | pgsz, nPage); |
| 20192 | if( rc ) return; |
| 20193 | rc = diskusedSubreport(&s, "All rowid tables", |
| 20194 | "NOT is_without_rowid AND NOT is_index", |
| 20195 | pgsz, nPage); |
| 20196 | if( rc ) return; |
| 20197 | } |
| 20198 | rc = diskusedSubreport(&s, "All indexes", "is_index", pgsz, nPage); |
| 20199 | if( rc ) return; |
| 20200 | |
| 20201 | pStmt = diskusedPrepare(&s, |
| 20202 | "SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s" |
| 20203 | " GROUP BY 1 ORDER BY 1", |
| 20204 | s.zSU); |
| 20205 | if( pStmt==0 ) return; |
| 20206 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| @@ -20150,37 +20208,37 @@ | |
| 20208 | const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 20209 | int nSubIndex = sqlite3_column_int(pStmt, 2); |
| 20210 | if( nSubIndex==0 ){ |
| 20211 | char *zTitle = sqlite3_mprintf("Table %s", zUpper); |
| 20212 | char *zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20213 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20214 | sqlite3_free(zTitle); |
| 20215 | sqlite3_free(zWhere); |
| 20216 | if( rc ) break; |
| 20217 | }else{ |
| 20218 | sqlite3_stmt *pS2; |
| 20219 | char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper); |
| 20220 | char *zWhere = sqlite3_mprintf("tblname=%Q", zName); |
| 20221 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20222 | sqlite3_free(zTitle); |
| 20223 | sqlite3_free(zWhere); |
| 20224 | if( rc ) break; |
| 20225 | zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper); |
| 20226 | zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20227 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20228 | sqlite3_free(zTitle); |
| 20229 | sqlite3_free(zWhere); |
| 20230 | if( rc ) break; |
| 20231 | if( nSubIndex>1 ){ |
| 20232 | zTitle = sqlite3_mprintf("All indexes of table %s", zUpper); |
| 20233 | zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName); |
| 20234 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20235 | sqlite3_free(zTitle); |
| 20236 | sqlite3_free(zWhere); |
| 20237 | if( rc ) break; |
| 20238 | } |
| 20239 | pS2 = diskusedPrepare(&s, |
| 20240 | "SELECT name, upper(name) FROM temp.%s" |
| 20241 | " WHERE is_index AND tblname=%Q", |
| 20242 | s.zSU, zName); |
| 20243 | if( pS2==0 ){ |
| 20244 | rc = SQLITE_NOMEM; |
| @@ -20189,25 +20247,25 @@ | |
| 20247 | while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){ |
| 20248 | const char *zU = (const char*)sqlite3_column_text(pS2, 1); |
| 20249 | const char *zN = (const char*)sqlite3_column_text(pS2, 0); |
| 20250 | zTitle = sqlite3_mprintf("Index %s", zU); |
| 20251 | zWhere = sqlite3_mprintf("name=%Q", zN); |
| 20252 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20253 | sqlite3_free(zTitle); |
| 20254 | sqlite3_free(zWhere); |
| 20255 | if( rc ) break; |
| 20256 | } |
| 20257 | rc = diskusedStmtFinish(&s, rc, pS2); |
| 20258 | if( rc ) break; |
| 20259 | } |
| 20260 | } |
| 20261 | if( diskusedStmtFinish(&s, rc, pStmt) ) return; |
| 20262 | |
| 20263 | /* Append SQL statements that will recreate the raw data used for |
| 20264 | ** the analysis. |
| 20265 | */ |
| 20266 | diskusedTitle(&s, "Raw data used to generate this report"); |
| 20267 | sqlite3_str_appendf(s.pOut, |
| 20268 | "The following SQL will create a table named \"space_used\" which\n" |
| 20269 | "contains most of the information used to generate the report above.\n" |
| 20270 | "*/\n" |
| 20271 | ); |
| @@ -20233,11 +20291,11 @@ | |
| 20291 | " ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */ |
| 20292 | " int_entries int -- B-tree entries on internal pages\n"/* 17 */ |
| 20293 | ");\n" |
| 20294 | "INSERT INTO space_used VALUES\n" |
| 20295 | ); |
| 20296 | pStmt = diskusedPrepare(&s, |
| 20297 | "SELECT quote(name), quote(tblname),\n" /* 0..1 */ |
| 20298 | " is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */ |
| 20299 | " depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */ |
| 20300 | " int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */ |
| 20301 | " leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */ |
| @@ -20268,11 +20326,11 @@ | |
| 20326 | sqlite3_column_int64(pStmt, 15), |
| 20327 | sqlite3_column_int64(pStmt, 16), |
| 20328 | sqlite3_column_int64(pStmt, 17)); |
| 20329 | } |
| 20330 | if( rc!=SQLITE_DONE ){ |
| 20331 | diskusedError(&s, "SQL run-time error: %s\nSQL: %s", |
| 20332 | sqlite3_errmsg(s.db), sqlite3_sql(pStmt)); |
| 20333 | sqlite3_finalize(pStmt); |
| 20334 | return; |
| 20335 | } |
| 20336 | sqlite3_str_appendf(s.pOut,";\nCOMMIT;"); |
| @@ -20281,32 +20339,32 @@ | |
| 20339 | if( sqlite3_str_length(s.pOut) ){ |
| 20340 | sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1, |
| 20341 | sqlite3_free); |
| 20342 | s.pOut = 0; |
| 20343 | } |
| 20344 | diskusedReset(&s); |
| 20345 | } |
| 20346 | |
| 20347 | |
| 20348 | #ifdef _WIN32 |
| 20349 | |
| 20350 | #endif |
| 20351 | int sqlite3_diskused_init( |
| 20352 | sqlite3 *db, |
| 20353 | char **pzErrMsg, |
| 20354 | const sqlite3_api_routines *pApi |
| 20355 | ){ |
| 20356 | int rc = SQLITE_OK; |
| 20357 | SQLITE_EXTENSION_INIT2(pApi); |
| 20358 | (void)pzErrMsg; /* Unused parameter */ |
| 20359 | rc = sqlite3_create_function(db, "diskused", 1, |
| 20360 | SQLITE_UTF8|SQLITE_INNOCUOUS, |
| 20361 | 0, diskusedFunc, 0, 0); |
| 20362 | return rc; |
| 20363 | } |
| 20364 | |
| 20365 | /************************* End ext/misc/diskused.c ********************/ |
| 20366 | |
| 20367 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 20368 | #define SQLITE_SHELL_HAVE_RECOVER 1 |
| 20369 | #else |
| 20370 | #define SQLITE_SHELL_HAVE_RECOVER 0 |
| @@ -25138,11 +25196,11 @@ | |
| 25196 | /* |
| 25197 | ** Return true if either the SQLITE_NO_COLOR compile-time option is used |
| 25198 | ** or if the NO_COLOR environment variable exists |
| 25199 | */ |
| 25200 | static int shellNoColor(void){ |
| 25201 | #if defined(SQLITE_NO_COLOR) || defined(SQLITE_SHELL_FIDDLE) |
| 25202 | return 1; |
| 25203 | #else |
| 25204 | return getenv("NO_COLOR")!=0; |
| 25205 | #endif |
| 25206 | } |
| @@ -25172,11 +25230,11 @@ | |
| 25230 | case 1: |
| 25231 | #if defined(SQLITE_PS1) |
| 25232 | return SQLITE_PS1; |
| 25233 | #else |
| 25234 | if( shellNoColor() ){ |
| 25235 | return "/A-/v /f-> "; |
| 25236 | }else{ |
| 25237 | return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; |
| 25238 | } |
| 25239 | #endif |
| 25240 | |
| @@ -25184,11 +25242,11 @@ | |
| 25242 | case 2: |
| 25243 | #if defined(SQLITE_PS2) |
| 25244 | return SQLITE_PS2; |
| 25245 | #else |
| 25246 | if( shellNoColor() ){ |
| 25247 | return "/B/C-> "; |
| 25248 | }else{ |
| 25249 | return "/B/e[1;/x33/:36/;m/C/e[0m-> "; |
| 25250 | } |
| 25251 | #endif |
| 25252 | |
| @@ -25196,11 +25254,15 @@ | |
| 25254 | ** of cases 1 and 2 */ |
| 25255 | case 3: return "SQLITE_PS1"; |
| 25256 | case 4: return "SQLITE_PS2"; |
| 25257 | |
| 25258 | /* Name of the application */ |
| 25259 | #ifndef SQLITE_CLI_APPNAME |
| 25260 | case 'A': return "SQLite"; |
| 25261 | #else |
| 25262 | case 'A': return SHELL_STRINGIFY(SQLITE_CLI_APPNAME); |
| 25263 | #endif |
| 25264 | |
| 25265 | /* Full version number of the application, including patch level */ |
| 25266 | case 'V': return sqlite3_libversion(); |
| 25267 | |
| 25268 | /* Version number without the patch level */ |
| @@ -26303,10 +26365,47 @@ | |
| 26365 | if( *az ){ |
| 26366 | memcpy(*az, zNew, n+1 ); |
| 26367 | } |
| 26368 | } |
| 26369 | } |
| 26370 | |
| 26371 | /* Forward reference */ |
| 26372 | static int pickStr(const char *zArg, char **pzErr, ...); |
| 26373 | |
| 26374 | /* |
| 26375 | ** Change the limits on the display mode. Return 0 on |
| 26376 | ** success. Return non-zero if zArg is mis-formatted. |
| 26377 | ** |
| 26378 | ** Valid arguments: |
| 26379 | ** |
| 26380 | ** "on" Default limits |
| 26381 | ** "off" All limits turned off |
| 26382 | ** L,C Line and Characters limits set |
| 26383 | ** L,C,T Line, Character, and Title limits set |
| 26384 | ** |
| 26385 | ** Anything else returns non-zero |
| 26386 | */ |
| 26387 | static int modeSetLimit(ShellState *p, const char *zArg){ |
| 26388 | int k = zArg==0 ? 1 : pickStr(zArg,0,"on","off",""); |
| 26389 | if( k==0 ){ |
| 26390 | p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; |
| 26391 | p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; |
| 26392 | p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; |
| 26393 | }else if( k==1 ){ |
| 26394 | p->mode.spec.nLineLimit = 0; |
| 26395 | p->mode.spec.nCharLimit = 0; |
| 26396 | p->mode.spec.nTitleLimit = 0; |
| 26397 | }else{ |
| 26398 | int L, C, T = 0; |
| 26399 | int nNum = sscanf(zArg, "%d,%d,%d", &L, &C, &T); |
| 26400 | if( nNum<2 || L<0 || C<0 || T<0) return 1; |
| 26401 | p->mode.spec.nLineLimit = L; |
| 26402 | p->mode.spec.nCharLimit = C; |
| 26403 | if( nNum==3 ) p->mode.spec.nTitleLimit = T; |
| 26404 | } |
| 26405 | return 0; |
| 26406 | } |
| 26407 | |
| 26408 | /* |
| 26409 | ** Change the mode to eMode |
| 26410 | */ |
| 26411 | static void modeChange(ShellState *p, unsigned char eMode){ |
| @@ -26340,10 +26439,11 @@ | |
| 26439 | modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode); |
| 26440 | }else if( eMode==MODE_BATCH ){ |
| 26441 | u8 mFlags = p->mode.mFlags; |
| 26442 | modeFree(&p->mode); |
| 26443 | modeChange(p, MODE_List); |
| 26444 | modeSetLimit(p, "off"); |
| 26445 | p->mode.mFlags = mFlags; |
| 26446 | }else if( eMode==MODE_TTY ){ |
| 26447 | u8 mFlags = p->mode.mFlags; |
| 26448 | modeFree(&p->mode); |
| 26449 | modeChange(p, MODE_QBox); |
| @@ -26976,11 +27076,11 @@ | |
| 27076 | return SQLITE_OK; |
| 27077 | } |
| 27078 | #endif |
| 27079 | |
| 27080 | /* |
| 27081 | ** Print a schema statement. This is a helper routine to dump_callback(). |
| 27082 | ** |
| 27083 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 27084 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 27085 | ** |
| 27086 | ** If the schema statement in z[] contains a start-of-comment and if |
| @@ -28428,12 +28528,12 @@ | |
| 28528 | ".databases List names and files of attached databases", |
| 28529 | ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", |
| 28530 | #if SQLITE_SHELL_HAVE_RECOVER |
| 28531 | ".dbinfo ?DB? Show status information about the database", |
| 28532 | #endif |
| 28533 | ".dbtotxt Hex dump of the database file", |
| 28534 | ".diskused ?SCHEMA? Report database space and size stats", |
| 28535 | ".dump ?OBJECTS? Render database content as SQL", |
| 28536 | " Options:", |
| 28537 | " --data-only Output only INSERT statements", |
| 28538 | " --newlines Allow unescaped newline characters in output", |
| 28539 | " --nosys Omit system tables (ex: \"sqlite_stat1\")", |
| @@ -28540,10 +28640,13 @@ | |
| 28640 | " --reset Reset the count for each input and interrupt", |
| 28641 | " --timeout S Halt after running for S seconds", |
| 28642 | #endif |
| 28643 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 28644 | " --hard-reset Unset SQLITE_PS1/2 and then --reset", |
| 28645 | #ifndef SQLITE_NO_COLOR |
| 28646 | " --no-color Disable color prompts. Use --color to re-enable", |
| 28647 | #endif |
| 28648 | " --reset Revert to default prompts", |
| 28649 | " --show Show the current prompt strings", |
| 28650 | " -- No more options. Subsequent args are prompts", |
| 28651 | #ifndef SQLITE_SHELL_FIDDLE |
| 28652 | ".quit Stop interpreting input stream, exit if primary.", |
| @@ -29440,11 +29543,11 @@ | |
| 29543 | sqlite3_base64_init(p->db, 0, 0); |
| 29544 | sqlite3_base85_init(p->db, 0, 0); |
| 29545 | sqlite3_regexp_init(p->db, 0, 0); |
| 29546 | sqlite3_ieee_init(p->db, 0, 0); |
| 29547 | sqlite3_series_init(p->db, 0, 0); |
| 29548 | sqlite3_diskused_init(p->db, 0, 0); |
| 29549 | #ifndef SQLITE_SHELL_FIDDLE |
| 29550 | sqlite3_fileio_init(p->db, 0, 0); |
| 29551 | sqlite3_completion_init(p->db, 0, 0); |
| 29552 | #endif |
| 29553 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -31246,11 +31349,11 @@ | |
| 31349 | typedef struct ArCommand ArCommand; |
| 31350 | struct ArCommand { |
| 31351 | u8 eCmd; /* An AR_CMD_* value */ |
| 31352 | u8 bVerbose; /* True if --verbose */ |
| 31353 | u8 bZip; /* True if the archive is a ZIP */ |
| 31354 | u8 bDryRun; /* 1 for --dry-run, 2 for --debug */ |
| 31355 | u8 bAppend; /* True if --append */ |
| 31356 | u8 bGlob; /* True if --glob */ |
| 31357 | u8 fromCmdLine; /* Run from -A instead of .archive */ |
| 31358 | int nArg; /* Number of command arguments */ |
| 31359 | char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| @@ -31308,10 +31411,11 @@ | |
| 31411 | #define AR_SWITCH_FILE 9 |
| 31412 | #define AR_SWITCH_DIRECTORY 10 |
| 31413 | #define AR_SWITCH_APPEND 11 |
| 31414 | #define AR_SWITCH_DRYRUN 12 |
| 31415 | #define AR_SWITCH_GLOB 13 |
| 31416 | #define AR_SWITCH_DEBUG 14 |
| 31417 | |
| 31418 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 31419 | switch( eSwitch ){ |
| 31420 | case AR_CMD_CREATE: |
| 31421 | case AR_CMD_EXTRACT: |
| @@ -31325,11 +31429,14 @@ | |
| 31429 | } |
| 31430 | pAr->eCmd = eSwitch; |
| 31431 | break; |
| 31432 | |
| 31433 | case AR_SWITCH_DRYRUN: |
| 31434 | if( pAr->bDryRun<2 ) pAr->bDryRun = 1; |
| 31435 | break; |
| 31436 | case AR_SWITCH_DEBUG: |
| 31437 | pAr->bDryRun = 2; |
| 31438 | break; |
| 31439 | case AR_SWITCH_GLOB: |
| 31440 | pAr->bGlob = 1; |
| 31441 | break; |
| 31442 | case AR_SWITCH_VERBOSE: |
| @@ -31376,10 +31483,11 @@ | |
| 31483 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 31484 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 31485 | { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 31486 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 31487 | { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 31488 | { "debug", 0, AR_SWITCH_DEBUG, 0 }, |
| 31489 | { "glob", 'g', AR_SWITCH_GLOB, 0 }, |
| 31490 | }; |
| 31491 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 31492 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 31493 | |
| @@ -31676,18 +31784,41 @@ | |
| 31784 | |
| 31785 | /* |
| 31786 | ** Implementation of .ar "eXtract" command. |
| 31787 | */ |
| 31788 | static int arExtractCommand(ArCommand *pAr){ |
| 31789 | /* The zSql1[] string is a template for the query that does the |
| 31790 | ** extraction. Notes: |
| 31791 | ** |
| 31792 | ** * $dir is the directory into which the archive is to be extracted |
| 31793 | ** * $pass is the integer pass number: 0, 1, or 2 |
| 31794 | ** * The dest CTE is created so that realpath($dir) only needs |
| 31795 | ** to be called once. |
| 31796 | */ |
| 31797 | const char *zSql1 = |
| 31798 | "WITH dest(dpath,dlen) AS (\n" |
| 31799 | #ifdef _WIN32 |
| 31800 | " SELECT realpath($dir) || '\\',\n" |
| 31801 | #else |
| 31802 | " SELECT realpath($dir) || '/',\n" |
| 31803 | #endif |
| 31804 | " 1+length(realpath($dir))\n" |
| 31805 | ")\n" |
| 31806 | "SELECT\n" |
| 31807 | " ($dir || name),\n" |
| 31808 | " CASE $dryrun\n" /* vv--- azExtraArg */ |
| 31809 | " WHEN 0 THEN writefile($dir||name, %s, mode, mtime)\n" |
| 31810 | " WHEN 1 THEN 0\n" |
| 31811 | " ELSE shell_putsnl(format('writefile(%%Q,%%s,%%0o,%%d)'," |
| 31812 | "$dir||name,quote(%s),mode,mtime)) IS NULL\n" |
| 31813 | " END\n" /* ^^--- azExtraArg */ |
| 31814 | " FROM dest CROSS JOIN %s\n" |
| 31815 | " WHERE (%s)\n" /* ^^-- pAr->zSrcTable */ |
| 31816 | /* ^^--- zWhere */ |
| 31817 | " AND (CASE $pass WHEN 0 THEN (mode&0xf000)<>0xa000\n" |
| 31818 | " WHEN 1 THEN (mode&0xf000)=0xa000\n" |
| 31819 | " ELSE data IS NULL END)\n" |
| 31820 | " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 31821 | " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 31822 | |
| 31823 | const char *azExtraArg[] = { |
| 31824 | "sqlar_uncompress(data, sz)", |
| @@ -31714,39 +31845,48 @@ | |
| 31845 | } |
| 31846 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 31847 | } |
| 31848 | |
| 31849 | shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 31850 | azExtraArg[pAr->bZip], |
| 31851 | azExtraArg[pAr->bZip], |
| 31852 | pAr->zSrcTable, |
| 31853 | zWhere |
| 31854 | ); |
| 31855 | |
| 31856 | if( rc==SQLITE_OK ){ |
| 31857 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 31858 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 31859 | j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 31860 | sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 31861 | |
| 31862 | /* Run the SELECT statement twice |
| 31863 | ** (0) writefile() files and directories |
| 31864 | ** (1) writefile() symlinks |
| 31865 | ** (2) writefile() for directory again |
| 31866 | ** The third pass is so that the timestamps for extracted directories |
| 31867 | ** will be reset to the value in the archive, since populating them |
| 31868 | ** in the first pass will have changed the timestamp. */ |
| 31869 | for(i=0; i<3; i++){ |
| 31870 | if( pAr->bDryRun>=2 ){ |
| 31871 | cli_printf(pAr->out, "*** BEGIN PASS %d ***\n", i+1); |
| 31872 | } |
| 31873 | j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 31874 | sqlite3_bind_int(pSql, j, i); |
| 31875 | if( pAr->bDryRun && i==0 ){ |
| 31876 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 31877 | } |
| 31878 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 31879 | if( i==0 && pAr->bVerbose ){ |
| 31880 | cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 31881 | } |
| 31882 | } |
| 31883 | if( pAr->bDryRun==1 ) break; |
| 31884 | shellReset(&rc, pSql); |
| 31885 | if( pAr->bDryRun>=2 ){ |
| 31886 | cli_printf(pAr->out, "*** END PASS %d ***\n", i+1); |
| 31887 | } |
| 31888 | } |
| 31889 | shellFinalize(&rc, pSql); |
| 31890 | } |
| 31891 | |
| 31892 | sqlite3_free(zDir); |
| @@ -32257,11 +32397,11 @@ | |
| 32397 | ; |
| 32398 | static const char * const zCollectVar = "\ |
| 32399 | SELECT\ |
| 32400 | '('||x'0a'\ |
| 32401 | || group_concat(\ |
| 32402 | cname,\ |
| 32403 | ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\ |
| 32404 | ||')' AS ColsSpec \ |
| 32405 | FROM (\ |
| 32406 | SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \ |
| 32407 | FROM ColNames ORDER BY cpos\ |
| @@ -33102,30 +33242,14 @@ | |
| 33242 | }else if( optionMatch(z,"limits") ){ |
| 33243 | if( (++i)>=nArg ){ |
| 33244 | dotCmdError(p, i-1, "missing argument", 0); |
| 33245 | return 1; |
| 33246 | } |
| 33247 | if( modeSetLimit(p, azArg[i]) ){ |
| 33248 | dotCmdError(p, i, "bad argument", "Should be \"on\" or \"off\" or " |
| 33249 | "\"L,C,T\" where L, C, and T are unsigned integers"); |
| 33250 | return 1; |
| 33251 | } |
| 33252 | chng = 1; |
| 33253 | }else if( optionMatch(z,"list") ){ |
| 33254 | int ii; |
| 33255 | cli_puts("available modes:", p->out); |
| @@ -34339,11 +34463,16 @@ | |
| 34463 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 34464 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 34465 | }else |
| 34466 | #endif /* SQLITE_SHELL_HAVE_RECOVER */ |
| 34467 | |
| 34468 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ |
| 34469 | open_db(p, 0); |
| 34470 | rc = shell_dbtotxt_command(p, nArg, azArg); |
| 34471 | }else |
| 34472 | |
| 34473 | if( c=='d' && n==8 && cli_strncmp(azArg[0], "diskused", n)==0 ){ |
| 34474 | const char *zSchema = 0; |
| 34475 | int ii; |
| 34476 | char *zSql; |
| 34477 | open_db(p, 0); |
| 34478 | for(ii=1; ii<nArg; ii++){ |
| @@ -34358,27 +34487,19 @@ | |
| 34487 | rc = 1; |
| 34488 | goto meta_command_exit; |
| 34489 | } |
| 34490 | zSchema = z; |
| 34491 | } |
| 34492 | zSql = sqlite3_mprintf("SELECT diskused(%Q)", zSchema); |
| 34493 | shell_check_oom(zSql); |
| 34494 | modePush(p); |
| 34495 | modeChange(p, MODE_BATCH); |
| 34496 | shell_exec(p, zSql, 0); |
| 34497 | modePop(p); |
| 34498 | sqlite3_free(zSql); |
| 34499 | }else |
| 34500 | |
| 34501 | if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){ |
| 34502 | char *zLike = 0; |
| 34503 | char *zSql; |
| 34504 | int i; |
| 34505 | int savedShellFlags = p->shellFlgs; |
| @@ -35491,10 +35612,26 @@ | |
| 35612 | }else |
| 35613 | if( strcmp(z,"-show")==0 ){ |
| 35614 | cli_printf(stdout,"Main prompt: '%s'\n", prompt_string(p, 0)); |
| 35615 | cli_printf(stdout,"Continuation: '%s'\n", prompt_string(p, 1)); |
| 35616 | }else |
| 35617 | #ifndef SQLITE_NO_COLOR |
| 35618 | if( strcmp(z,"-color")==0 ){ |
| 35619 | #ifdef _WIN32 |
| 35620 | _putenv("NO_COLOR="); |
| 35621 | #else |
| 35622 | unsetenv("NO_COLOR"); |
| 35623 | #endif |
| 35624 | }else |
| 35625 | if( strcmp(z,"-no-color")==0 ){ |
| 35626 | #ifdef _WIN32 |
| 35627 | _putenv("NO_COLOR=1"); |
| 35628 | #else |
| 35629 | setenv("NO_COLOR","1",1); |
| 35630 | #endif |
| 35631 | }else |
| 35632 | #endif |
| 35633 | if( strcmp(z,"-")==0 ){ |
| 35634 | noOpt = 1; |
| 35635 | }else |
| 35636 | { |
| 35637 | dotCmdError(p, i, "unknown option", 0); |
| @@ -35505,10 +35642,11 @@ | |
| 35642 | dotCmdError(p, i, "extra argument", 0); |
| 35643 | rc = 1; |
| 35644 | goto meta_command_exit; |
| 35645 | }else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){ |
| 35646 | dotCmdError(p, i, "use quotes around the prompt string", 0); |
| 35647 | rc = 1; |
| 35648 | }else{ |
| 35649 | free(p->azPrompt[cnt]); |
| 35650 | p->azPrompt[cnt] = strdup(z); |
| 35651 | cnt++; |
| 35652 | } |
| @@ -37717,17 +37855,17 @@ | |
| 37855 | " -- treat no subsequent arguments as options\n" |
| 37856 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 37857 | " -A ARGS... run \".archive ARGS\" and exit\n" |
| 37858 | #endif |
| 37859 | " -append append the database to the end of the file\n" |
| 37860 | " -ascii set '.mode ascii'\n" |
| 37861 | " -bail stop after hitting an error\n" |
| 37862 | " -batch force batch I/O\n" |
| 37863 | " -box set '.mode box'\n" |
| 37864 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 37865 | " -column set '.mode column'\n" |
| 37866 | " -csv set '.mode csv -limits off'\n" |
| 37867 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37868 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 37869 | #endif |
| 37870 | " -echo print inputs before execution\n" |
| 37871 | " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" |
| @@ -37735,18 +37873,18 @@ | |
| 37873 | " -[no]header turn headers on or off\n" |
| 37874 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 37875 | " -heap SIZE Size of heap for memsys3 or memsys5\n" |
| 37876 | #endif |
| 37877 | " -help show this message\n" |
| 37878 | " -html set '.mode html'\n" |
| 37879 | " -ifexists only open if database already exists\n" |
| 37880 | " -interactive force interactive I/O\n" |
| 37881 | " -json set '.mode json'\n" |
| 37882 | " -line set '.mode line'\n" |
| 37883 | " -list set '.mode list'\n" |
| 37884 | " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
| 37885 | " -markdown set '.mode markdown'\n" |
| 37886 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37887 | " -maxsize N maximum size for a --deserialize database\n" |
| 37888 | #endif |
| 37889 | " -memtrace trace all memory allocations and deallocations\n" |
| 37890 | " -mmap N default mmap size set to N\n" |
| @@ -37759,21 +37897,21 @@ | |
| 37897 | " -nonce STRING set the safe-mode escape nonce\n" |
| 37898 | " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" |
| 37899 | " -nullvalue TEXT set text string for NULL values. Default ''\n" |
| 37900 | " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
| 37901 | " -pcachetrace trace all page cache operations\n" |
| 37902 | " -quote set '.mode quote'\n" |
| 37903 | " -readonly open the database read-only\n" |
| 37904 | " -safe enable safe-mode\n" |
| 37905 | " -screenwidth N use N as the default screenwidth \n" |
| 37906 | " -separator SEP set output column separator. Default: '|'\n" |
| 37907 | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| 37908 | " -sorterref SIZE sorter references threshold size\n" |
| 37909 | #endif |
| 37910 | " -stats print memory stats before each finalize\n" |
| 37911 | " -table set '.mode table'\n" |
| 37912 | " -tabs set '.mode tabs'\n" |
| 37913 | " -unsafe-testing allow unsafe commands and modes for testing\n" |
| 37914 | " -version show SQLite version\n" |
| 37915 | " -vfs NAME use NAME as the default VFS\n" |
| 37916 | " -vfstrace enable tracing of all VFS calls\n" |
| 37917 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -37801,10 +37939,23 @@ | |
| 37939 | sputz(stdout, "WARNING: attempt to configure SQLite after" |
| 37940 | " initialization.\n"); |
| 37941 | } |
| 37942 | } |
| 37943 | |
| 37944 | #if HAVE_EDITLINE |
| 37945 | /* |
| 37946 | ** https://sqlite.org/forum/forumpost/aad7a634916ff050: |
| 37947 | ** |
| 37948 | ** Calling setlocale(LC_...,"") is required to get libedit to accept |
| 37949 | ** non-ASCII input. |
| 37950 | */ |
| 37951 | #define DO_SET_LOCALE 1 |
| 37952 | #include <locale.h> |
| 37953 | #else |
| 37954 | #define DO_SET_LOCALE 0 |
| 37955 | #endif |
| 37956 | |
| 37957 | /* |
| 37958 | ** Initialize the state information in data |
| 37959 | */ |
| 37960 | static void main_init(ShellState *p) { |
| 37961 | memset(p, 0, sizeof(*p)); |
| @@ -37825,10 +37976,14 @@ | |
| 37976 | #else |
| 37977 | /* No \001...\002 escapes required for linenoise or when not using a |
| 37978 | ** command-line editing library */ |
| 37979 | p->bDelimitNonprint = 0; |
| 37980 | #endif |
| 37981 | #if DO_SET_LOCALE |
| 37982 | setlocale(LC_CTYPE,""); |
| 37983 | #endif |
| 37984 | #undef DO_SET_LOCALE |
| 37985 | } |
| 37986 | |
| 37987 | /* |
| 37988 | ** Output text to the console in a font that attracts extra attention. |
| 37989 | */ |
| @@ -37854,11 +38009,11 @@ | |
| 38009 | } |
| 38010 | |
| 38011 | /* |
| 38012 | ** The callback from atexit(). |
| 38013 | */ |
| 38014 | static void SQLITE_CDECL abnormalExit(void){ |
| 38015 | if( seenInterrupt ) eputz("Program interrupted.\n"); |
| 38016 | if( globalShellState ){ |
| 38017 | clearTempFile(globalShellState, 1, 1); |
| 38018 | } |
| 38019 | } |
| @@ -38065,11 +38220,11 @@ | |
| 38220 | stdin_is_interactive = 0; |
| 38221 | nCmd++; |
| 38222 | azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); |
| 38223 | shell_check_oom(azCmd); |
| 38224 | aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd); |
| 38225 | shell_check_oom(aiCmd); |
| 38226 | azCmd[nCmd-1] = z; |
| 38227 | aiCmd[nCmd-1] = i; |
| 38228 | } |
| 38229 | continue; |
| 38230 | } |
| @@ -38354,10 +38509,11 @@ | |
| 38509 | modeChange(&data, MODE_Psql); |
| 38510 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 38511 | modeChange(&data, MODE_Box); |
| 38512 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 38513 | modeChange(&data, MODE_Csv); |
| 38514 | modeSetLimit(&data, "off"); |
| 38515 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38516 | /* See similar code at tag-20250224-1 */ |
| 38517 | const char *zEsc = argv[++i]; |
| 38518 | int k; |
| 38519 | for(k=0; k<ArraySize(qrfEscNames); k++){ |
| @@ -38412,12 +38568,14 @@ | |
| 38568 | }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
| 38569 | modeSetStr(&data.mode.spec.zNull, |
| 38570 | cmdline_option_value(argc,argv,++i)); |
| 38571 | }else if( cli_strcmp(z,"-header")==0 ){ |
| 38572 | data.mode.spec.bTitles = QRF_Yes; |
| 38573 | data.mode.mFlags |= MFLG_HDR; |
| 38574 | }else if( cli_strcmp(z,"-noheader")==0 ){ |
| 38575 | data.mode.spec.bTitles = QRF_No; |
| 38576 | data.mode.mFlags |= MFLG_HDR; |
| 38577 | }else if( cli_strcmp(z,"-echo")==0 ){ |
| 38578 | data.mode.mFlags |= MFLG_ECHO; |
| 38579 | }else if( cli_strcmp(z,"-eqp")==0 ){ |
| 38580 | data.mode.autoEQP = AUTOEQP_on; |
| 38581 | }else if( cli_strcmp(z,"-eqpfull")==0 ){ |
| 38582 |
+1551
-532
| --- 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 | -** 7e4134e3ff1ca8712f5fc78fadae66554945 with changes in files: | |
| 21 | +** 3f3fb9b638f59ad982beafb7c117f24ddd3d 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.54.0" |
| 471 | 471 | #define SQLITE_VERSION_NUMBER 3054000 |
| 472 | -#define SQLITE_SOURCE_ID "2026-05-04 10:14:13 7e4134e3ff1ca8712f5fc78fadae665549450988dc43af27c7fe0c77f10ce3fb" | |
| 472 | +#define SQLITE_SOURCE_ID "2026-06-16 13:43:08 3f3fb9b638f59ad982beafb7c117f24ddd3da612e62c862510805fa672ffae06" | |
| 473 | 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | 474 | #define SQLITE_SCM_TAGS "" |
| 475 | -#define SQLITE_SCM_DATETIME "2026-05-04T10:14:13.819Z" | |
| 475 | +#define SQLITE_SCM_DATETIME "2026-06-16T13:43:08.110Z" | |
| 476 | 476 | |
| 477 | 477 | /* |
| 478 | 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | 480 | ** |
| @@ -4373,12 +4373,11 @@ | ||
| 4373 | 4373 | ** parameter on F or if the value of P does not match any of the |
| 4374 | 4374 | ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). |
| 4375 | 4375 | ** |
| 4376 | 4376 | ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a |
| 4377 | 4377 | ** 64-bit signed integer and returns that integer, or D if P does not |
| 4378 | -** exist. If the value of P is something other than an integer, then | |
| 4379 | -** zero is returned. | |
| 4378 | +** exist or ff the value of P is something other than an integer. | |
| 4380 | 4379 | ** |
| 4381 | 4380 | ** The sqlite3_uri_key(F,N) returns a pointer to the name (not |
| 4382 | 4381 | ** the value) of the N-th query parameter for filename F, or a NULL |
| 4383 | 4382 | ** pointer if N is less than zero or greater than the number of query |
| 4384 | 4383 | ** parameters minus 1. The N value is zero-based so N should be 0 to obtain |
| @@ -4697,11 +4696,12 @@ | ||
| 4697 | 4696 | ** <dd>The maximum number of columns in a table definition or in the |
| 4698 | 4697 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 4699 | 4698 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 4700 | 4699 | ** |
| 4701 | 4700 | ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> |
| 4702 | -** <dd>The maximum depth of the parse tree on any expression.</dd>)^ | |
| 4701 | +** <dd>The maximum depth of the parse tree on any expression and | |
| 4702 | +** the maximum nesting depth for subqueries and VIEWs</dd>)^ | |
| 4703 | 4703 | ** |
| 4704 | 4704 | ** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(<dt>SQLITE_LIMIT_PARSER_DEPTH</dt> |
| 4705 | 4705 | ** <dd>The maximum depth of the LALR(1) parser stack used to analyze |
| 4706 | 4706 | ** input SQL statements.</dd>)^ |
| 4707 | 4707 | ** |
| @@ -4728,11 +4728,12 @@ | ||
| 4728 | 4728 | ** [[SQLITE_LIMIT_VARIABLE_NUMBER]] |
| 4729 | 4729 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 4730 | 4730 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 4731 | 4731 | ** |
| 4732 | 4732 | ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> |
| 4733 | -** <dd>The maximum depth of recursion for triggers.</dd>)^ | |
| 4733 | +** <dd>The maximum depth of recursion for triggers, and the maximum | |
| 4734 | +** nesting depth for separate triggers.</dd>)^ | |
| 4734 | 4735 | ** |
| 4735 | 4736 | ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt> |
| 4736 | 4737 | ** <dd>The maximum number of auxiliary worker threads that a single |
| 4737 | 4738 | ** [prepared statement] may start.</dd>)^ |
| 4738 | 4739 | ** </dl> |
| @@ -11534,12 +11535,23 @@ | ||
| 11534 | 11535 | ** reopen S as an in-memory database based on the serialization |
| 11535 | 11536 | ** contained in P. If S is a NULL pointer, the main database is |
| 11536 | 11537 | ** used. The serialized database P is N bytes in size. M is the size |
| 11537 | 11538 | ** of the buffer P, which might be larger than N. If M is larger than |
| 11538 | 11539 | ** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then |
| 11539 | -** SQLite is permitted to add content to the in-memory database as | |
| 11540 | -** long as the total size does not exceed M bytes. | |
| 11540 | +** SQLite is permitted to add content to the in-memory database, in | |
| 11541 | +** page-sized chunks, as long as the total size does not exceed M bytes. | |
| 11542 | +** | |
| 11543 | +** The parameter M must be greater than or equal to N. Ideally, M | |
| 11544 | +** should have a value which is N+(512×K)+20 where K determines how | |
| 11545 | +** must extra space is available to hold new content as the database | |
| 11546 | +** grows. K can be 0 if the database is read-only. | |
| 11547 | +** | |
| 11548 | +** If the database content in P is malformed in a malicious way then | |
| 11549 | +** it is possible that SQLite might try to read a few more than N bytes | |
| 11550 | +** from P. If the veracity of the database content P is uncertain, | |
| 11551 | +** then applications are advised to allocate about 20 extra bytes on | |
| 11552 | +** the end of the P buffer to avoid a memory error. | |
| 11541 | 11553 | ** |
| 11542 | 11554 | ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will |
| 11543 | 11555 | ** invoke sqlite3_free() on the serialization buffer when the database |
| 11544 | 11556 | ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then |
| 11545 | 11557 | ** SQLite will try to increase the buffer size using sqlite3_realloc64() |
| @@ -13184,15 +13196,27 @@ | ||
| 13184 | 13196 | ** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd> |
| 13185 | 13197 | ** If this flag it set, then all foreign key constraints in the target |
| 13186 | 13198 | ** database behave as if they were declared with "ON UPDATE NO ACTION ON |
| 13187 | 13199 | ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL |
| 13188 | 13200 | ** or SET DEFAULT. |
| 13201 | +** | |
| 13202 | +** <dt>SQLITE_CHANGESETAPPLY_NOUPDATELOOP <dd> | |
| 13203 | +** Sometimes, a changeset contains two or more update statements such that | |
| 13204 | +** although after applying all updates the database will contain no | |
| 13205 | +** constraint violations, no single update can be applied before the others. | |
| 13206 | +** The simplest example of this is a pair of UPDATEs that have "swapped" | |
| 13207 | +** two column values with a UNIQUE constraint. | |
| 13208 | +** <p> | |
| 13209 | +** Usually, sqlite3changeset_apply() and similar functions work hard to try | |
| 13210 | +** to find a way to apply such a changeset. However, if this flag is set, | |
| 13211 | +** then all such updates are considered CONSTRAINT conflicts. | |
| 13189 | 13212 | */ |
| 13190 | 13213 | #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 |
| 13191 | 13214 | #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 |
| 13192 | 13215 | #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 |
| 13193 | 13216 | #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 |
| 13217 | +#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010 | |
| 13194 | 13218 | |
| 13195 | 13219 | /* |
| 13196 | 13220 | ** CAPI3REF: Constants Passed To The Conflict Handler |
| 13197 | 13221 | ** |
| 13198 | 13222 | ** Values that may be passed as the second argument to a conflict-handler. |
| @@ -15798,10 +15822,17 @@ | ||
| 15798 | 15822 | */ |
| 15799 | 15823 | #ifndef offsetof |
| 15800 | 15824 | # define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) |
| 15801 | 15825 | #endif |
| 15802 | 15826 | |
| 15827 | +/* | |
| 15828 | +** sizeof64() is like sizeof(), but always returns a 64-bit value, even | |
| 15829 | +** on 32-bit builds. This can help to avoid overflow by ensuring 64-bit | |
| 15830 | +** arithmetic is used consistently in both 32-bit and 64-bit builds. | |
| 15831 | +*/ | |
| 15832 | +#define sizeof64(X) ((sqlite3_int64)sizeof(X)) | |
| 15833 | + | |
| 15803 | 15834 | /* |
| 15804 | 15835 | ** Work around C99 "flex-array" syntax for pre-C99 compilers, so as |
| 15805 | 15836 | ** to avoid complaints from -fsanitize=strict-bounds. |
| 15806 | 15837 | */ |
| 15807 | 15838 | #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) |
| @@ -18705,11 +18736,11 @@ | ||
| 18705 | 18736 | int aLimit[SQLITE_N_LIMIT]; /* Limits */ |
| 18706 | 18737 | int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ |
| 18707 | 18738 | struct sqlite3InitInfo { /* Information used during initialization */ |
| 18708 | 18739 | Pgno newTnum; /* Rootpage of table being initialized */ |
| 18709 | 18740 | u8 iDb; /* Which db file is being initialized */ |
| 18710 | - u8 busy; /* TRUE if currently initializing */ | |
| 18741 | + u8 busy; /* TRUE if initing. 2 if due to ADD COLUMN */ | |
| 18711 | 18742 | unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ |
| 18712 | 18743 | unsigned imposterTable : 2; /* Building an imposter table */ |
| 18713 | 18744 | unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ |
| 18714 | 18745 | const char **azInit; /* "type", "name", and "tbl_name" columns */ |
| 18715 | 18746 | } init; |
| @@ -20917,10 +20948,11 @@ | ||
| 20917 | 20948 | int nTab; /* Number of previously allocated VDBE cursors */ |
| 20918 | 20949 | int nMem; /* Number of memory cells used so far */ |
| 20919 | 20950 | int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ |
| 20920 | 20951 | int iSelfTab; /* Table associated with an index on expr, or negative |
| 20921 | 20952 | ** of the base register during check-constraint eval */ |
| 20953 | + int nNestSel; /* Number of nested SELECT statements and/or VIEWs */ | |
| 20922 | 20954 | int nLabel; /* The *negative* of the number of labels used */ |
| 20923 | 20955 | int nLabelAlloc; /* Number of slots in aLabel */ |
| 20924 | 20956 | int *aLabel; /* Space to hold the labels */ |
| 20925 | 20957 | ExprList *pConstExpr;/* Constant expressions */ |
| 20926 | 20958 | IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */ |
| @@ -21256,11 +21288,11 @@ | ||
| 21256 | 21288 | */ |
| 21257 | 21289 | #define INITFLAG_AlterMask 0x0007 /* Types of ALTER */ |
| 21258 | 21290 | #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ |
| 21259 | 21291 | #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ |
| 21260 | 21292 | #define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ |
| 21261 | -#define INITFLAG_AlterDropCons 0x0004 /* Reparse after an ADD COLUMN */ | |
| 21293 | +#define INITFLAG_AlterDropCons 0x0004 /* Reparse after a DROP CONSTRAINT */ | |
| 21262 | 21294 | |
| 21263 | 21295 | /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled |
| 21264 | 21296 | ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning |
| 21265 | 21297 | ** parameters are for temporary use during development, to help find |
| 21266 | 21298 | ** optimal values for parameters in the query planner. The should not |
| @@ -22509,11 +22541,19 @@ | ||
| 22509 | 22541 | SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); |
| 22510 | 22542 | SQLITE_PRIVATE void sqlite3AlterFunctions(void); |
| 22511 | 22543 | SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); |
| 22512 | 22544 | SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); |
| 22513 | 22545 | SQLITE_PRIVATE void sqlite3AlterDropConstraint(Parse*,SrcList*,Token*,Token*); |
| 22514 | -SQLITE_PRIVATE void sqlite3AlterAddConstraint(Parse*,SrcList*,Token*,Token*,const char*,int); | |
| 22546 | +SQLITE_PRIVATE void sqlite3AlterAddConstraint( | |
| 22547 | + Parse *pParse, /* Parse context */ | |
| 22548 | + SrcList *pSrc, /* Table to add constraint to */ | |
| 22549 | + Token *pFirst, /* First token of new constraint */ | |
| 22550 | + Token *pName, /* Name of new constraint. NULL if name omitted. */ | |
| 22551 | + const char *zExpr, /* Text of CHECK expression */ | |
| 22552 | + int nExpr, /* Size of pExpr in bytes */ | |
| 22553 | + Expr *pExpr /* The parsed CHECK expression */ | |
| 22554 | +); | |
| 22515 | 22555 | SQLITE_PRIVATE void sqlite3AlterSetNotNull(Parse*, SrcList*, Token*, Token*); |
| 22516 | 22556 | SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *, int *); |
| 22517 | 22557 | SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); |
| 22518 | 22558 | SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); |
| 22519 | 22559 | SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int); |
| @@ -32413,12 +32453,14 @@ | ||
| 32413 | 32453 | #define etSRCITEM 12 /* a pointer to a SrcItem */ |
| 32414 | 32454 | #define etPOINTER 13 /* The %p conversion */ |
| 32415 | 32455 | #define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */ |
| 32416 | 32456 | #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ |
| 32417 | 32457 | #define etDECIMAL 16 /* %d or %u, but not %x, %o */ |
| 32458 | +#define etESCAPE_j 17 /* %j -> JSON string literal w/o "..." */ | |
| 32459 | +#define etESCAPE_J 18 /* %J -> JSON string literal with "..." */ | |
| 32418 | 32460 | |
| 32419 | -#define etINVALID 17 /* Any unrecognized conversion type */ | |
| 32461 | +#define etINVALID 19 /* Any unrecognized conversion type */ | |
| 32420 | 32462 | |
| 32421 | 32463 | |
| 32422 | 32464 | /* |
| 32423 | 32465 | ** An "etByte" is an 8-bit unsigned value. |
| 32424 | 32466 | */ |
| @@ -32444,24 +32486,24 @@ | ||
| 32444 | 32486 | #define FLAG_SIGNED 1 /* True if the value to convert is signed */ |
| 32445 | 32487 | #define FLAG_STRING 4 /* Allow infinite precision */ |
| 32446 | 32488 | |
| 32447 | 32489 | /* |
| 32448 | 32490 | ** The table is searched by hash. In the case of %C where C is the character |
| 32449 | -** and that character has ASCII value j, then the hash is j%23. | |
| 32491 | +** and that character has ASCII value j, then the hash is j%25. | |
| 32450 | 32492 | ** |
| 32451 | 32493 | ** The order of the entries in fmtinfo[] and the hash chain was entered |
| 32452 | 32494 | ** manually, but based on the output of the following TCL script: |
| 32453 | 32495 | */ |
| 32454 | 32496 | #if 0 /***** Beginning of script ******/ |
| 32455 | -foreach c {d s g z q Q w c o u x X f e E G i n % p T S r} { | |
| 32497 | +foreach c {d s g z q Q w c o u x X f e E G i n % p T S r J j} { | |
| 32456 | 32498 | scan $c %c x |
| 32457 | 32499 | set n($c) $x |
| 32458 | 32500 | } |
| 32459 | 32501 | set mx [llength [array names n]] |
| 32460 | 32502 | puts "count: $mx" |
| 32461 | 32503 | |
| 32462 | -set mx 27 | |
| 32504 | +set mx 25 | |
| 32463 | 32505 | puts "*********** mx=$mx ************" |
| 32464 | 32506 | for {set r 0} {$r<$mx} {incr r} { |
| 32465 | 32507 | puts -nonewline [format %2d: $r] |
| 32466 | 32508 | foreach c [array names n] { |
| 32467 | 32509 | if {($n($c))%$mx==$r} {puts -nonewline " $c"} |
| @@ -32469,35 +32511,38 @@ | ||
| 32469 | 32511 | puts "" |
| 32470 | 32512 | } |
| 32471 | 32513 | #endif /***** End of script ********/ |
| 32472 | 32514 | |
| 32473 | 32515 | static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; |
| 32516 | +static const char aHex[] = "0123456789abcdef"; | |
| 32474 | 32517 | static const char aPrefix[] = "-x0\000X0"; |
| 32475 | -static const et_info fmtinfo[23] = { | |
| 32476 | - /* 0 */ { 's', 0, 4, etSTRING, 0, 0, 1 }, | |
| 32477 | - /* 1 */ { 'E', 0, 1, etEXP, 14, 0, 0 }, /* Hash: 0 */ | |
| 32478 | - /* 2 */ { 'u', 10, 0, etDECIMAL, 0, 0, 3 }, | |
| 32479 | - /* 3 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, /* Hash: 2 */ | |
| 32480 | - /* 4 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 0 }, | |
| 32481 | - /* 5 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, | |
| 32482 | - /* 6 */ { 'c', 0, 0, etCHARX, 0, 0, 0 }, /* Hash: 7 */ | |
| 32483 | - /* 7 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 6 }, | |
| 32484 | - /* 8 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, | |
| 32485 | - /* 9 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, | |
| 32486 | - /* 10 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, | |
| 32487 | - /* 11 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, | |
| 32488 | - /* 12 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 0 }, | |
| 32489 | - /* 13 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, | |
| 32490 | - /* 14 */ { '%', 0, 0, etPERCENT, 0, 0, 16 }, | |
| 32491 | - /* 15 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, | |
| 32492 | - /* 16 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, /* Hash: 14 */ | |
| 32493 | - /* 17 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 19 */ | |
| 32494 | - /* 18 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, | |
| 32495 | - /* 19 */ { 'o', 8, 0, etRADIX, 0, 2, 17 }, | |
| 32496 | - /* 20 */ { 'p', 16, 0, etPOINTER, 0, 1, 0 }, | |
| 32497 | - /* 21 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 0 }, | |
| 32498 | - /* 22 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 } | |
| 32518 | +static const et_info fmtinfo[25] = { | |
| 32519 | + /* 0 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, | |
| 32520 | + /* 1 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, | |
| 32521 | + /* 2 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, | |
| 32522 | + /* 3 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, | |
| 32523 | + /* 4 */ { 'j', 0, 0, etESCAPE_j, 0, 0, 0 }, /* Hash: 6 */ | |
| 32524 | + /* 5 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, | |
| 32525 | + /* 6 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 4 }, | |
| 32526 | + /* 7 */ { 'p', 16, 0, etPOINTER, 0, 1, 0 }, /* Hash: 12 */ | |
| 32527 | + /* 8 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, | |
| 32528 | + /* 9 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, | |
| 32529 | + /* 10 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, | |
| 32530 | + /* 11 */ { 'o', 8, 0, etRADIX, 0, 2, 0 }, | |
| 32531 | + /* 12 */ { '%', 0, 0, etPERCENT, 0, 0, 7 }, | |
| 32532 | + /* 13 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 16 }, | |
| 32533 | + /* 14 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 }, | |
| 32534 | + /* 15 */ { 's', 0, 4, etSTRING, 0, 0, 0 }, | |
| 32535 | + /* 16 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 13 */ | |
| 32536 | + /* 17 */ { 'u', 10, 0, etDECIMAL, 0, 0, 0 }, | |
| 32537 | + /* 18 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 0 }, /* Hash: 19 */ | |
| 32538 | + /* 19 */ { 'E', 0, 1, etEXP, 14, 0, 18 }, | |
| 32539 | + /* 20 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, | |
| 32540 | + /* 21 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, | |
| 32541 | + /* 22 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 0 }, | |
| 32542 | + /* 23 */ { 'J', 0, 0, etESCAPE_J, 0, 0, 0 }, /* Hash: 24 */ | |
| 32543 | + /* 24 */ { 'c', 0, 0, etCHARX, 0, 0, 23 } | |
| 32499 | 32544 | }; |
| 32500 | 32545 | |
| 32501 | 32546 | /* Additional Notes: |
| 32502 | 32547 | ** |
| 32503 | 32548 | ** %S Takes a pointer to SrcItem. Shows name or database.name |
| @@ -32754,12 +32799,12 @@ | ||
| 32754 | 32799 | break; |
| 32755 | 32800 | } |
| 32756 | 32801 | } |
| 32757 | 32802 | #else |
| 32758 | 32803 | /* Fast hash-table lookup */ |
| 32759 | - assert( ArraySize(fmtinfo)==23 ); | |
| 32760 | - idx = ((unsigned)c) % 23; | |
| 32804 | + assert( ArraySize(fmtinfo)==25 ); | |
| 32805 | + idx = ((unsigned)c) % 25; | |
| 32761 | 32806 | if( fmtinfo[idx].fmttype==c |
| 32762 | 32807 | || fmtinfo[idx = fmtinfo[idx].iNxt].fmttype==c |
| 32763 | 32808 | ){ |
| 32764 | 32809 | infop = &fmtinfo[idx]; |
| 32765 | 32810 | xtype = infop->type; |
| @@ -33126,11 +33171,11 @@ | ||
| 33126 | 33171 | length = width; |
| 33127 | 33172 | } |
| 33128 | 33173 | |
| 33129 | 33174 | if( zExtra==0 ){ |
| 33130 | 33175 | /* The result is being rendered directory into pAccum. This |
| 33131 | - ** is the command and fast case */ | |
| 33176 | + ** is the common and fast case */ | |
| 33132 | 33177 | pAccum->nChar += length; |
| 33133 | 33178 | zOut[length] = 0; |
| 33134 | 33179 | continue; |
| 33135 | 33180 | }else{ |
| 33136 | 33181 | /* We were unable to render directly into pAccum because we |
| @@ -33246,10 +33291,87 @@ | ||
| 33246 | 33291 | /* Adjust width to account for extra bytes in UTF-8 characters */ |
| 33247 | 33292 | int ii = length - 1; |
| 33248 | 33293 | while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; |
| 33249 | 33294 | } |
| 33250 | 33295 | break; |
| 33296 | + case etESCAPE_j: /* %j: JSON string literal w/o "..." */ | |
| 33297 | + case etESCAPE_J: { /* %J: Generate a JSON string literal */ | |
| 33298 | + char *escarg; | |
| 33299 | + i64 i, j, px, iStart; | |
| 33300 | + unsigned char ch; | |
| 33301 | + | |
| 33302 | + if( bArgList ){ | |
| 33303 | + escarg = getTextArg(pArgList); | |
| 33304 | + }else{ | |
| 33305 | + escarg = va_arg(ap,char*); | |
| 33306 | + } | |
| 33307 | + iStart = sqlite3_str_length(pAccum); | |
| 33308 | + if( escarg==0 ){ | |
| 33309 | + if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "null", 4); | |
| 33310 | + }else{ | |
| 33311 | + if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "\"", 1); | |
| 33312 | + px = precision; | |
| 33313 | + testcase( px==0 ); | |
| 33314 | + if( px<0 ){ | |
| 33315 | + px = 0x7fffffff; | |
| 33316 | + }else if( flag_altform2 ){ | |
| 33317 | + /* Convert precision from code-points to bytes */ | |
| 33318 | + for(i=0; i<px && escarg[i]; i++){ | |
| 33319 | + if( (escarg[i]&0xc0)==0x80 ) px++; | |
| 33320 | + } | |
| 33321 | + if( i==px ){ | |
| 33322 | + while( (escarg[px]&0xc0)==0x80 ) px++; | |
| 33323 | + } | |
| 33324 | + } | |
| 33325 | + for(i=j=0; i<px; i++){ | |
| 33326 | + if( (ch = ((u8*)escarg)[i])<=0x1f || ch=='"' || ch=='\\' ){ | |
| 33327 | + if( j<i ) sqlite3_str_append(pAccum, &escarg[j], i-j); | |
| 33328 | + j = i+1; | |
| 33329 | + if( ch==0 ) break; | |
| 33330 | + sqlite3_str_appendchar(pAccum, 1, '\\'); | |
| 33331 | + if( ch>0x1f ){ | |
| 33332 | + sqlite3_str_appendchar(pAccum, 1, ch); | |
| 33333 | + }else if( ((1u<<ch)&0x3700)!=0 ){ | |
| 33334 | + ch = "btn?fr"[ch-8]; | |
| 33335 | + sqlite3_str_appendchar(pAccum, 1, ch); | |
| 33336 | + }else{ | |
| 33337 | + sqlite3_str_append(pAccum, "u00", 3); | |
| 33338 | + sqlite3_str_appendchar(pAccum, 1, aHex[ch>>4]); | |
| 33339 | + sqlite3_str_appendchar(pAccum, 1, aHex[ch&0xf]); | |
| 33340 | + } | |
| 33341 | + } | |
| 33342 | + } | |
| 33343 | + if( j<i ) sqlite3_str_append(pAccum, &escarg[j], i-j); | |
| 33344 | + if( xtype==etESCAPE_J ) sqlite3_str_append(pAccum, "\"", 1); | |
| 33345 | + } | |
| 33346 | + if( width>0 && sqlite3_str_errcode(pAccum)==SQLITE_OK ){ | |
| 33347 | + sqlite3_int64 n = sqlite3_str_length(pAccum) - iStart; | |
| 33348 | + sqlite3_int64 len = n; | |
| 33349 | + char *zz; | |
| 33350 | + if( flag_altform2 && n>0 ){ | |
| 33351 | + zz = sqlite3_str_value(pAccum); | |
| 33352 | + for(i=iStart; zz[i]; i++){ | |
| 33353 | + if( (zz[i]&0xc0)==0x80 ) len--; | |
| 33354 | + } | |
| 33355 | + } | |
| 33356 | + if( width>len ){ | |
| 33357 | + sqlite3_int64 sp = width-len; | |
| 33358 | + assert( sp>0 && sp<0x7fffffff ); | |
| 33359 | + sqlite3_str_appendchar(pAccum, (int)sp, ' '); | |
| 33360 | + if( !flag_leftjustify | |
| 33361 | + && n>0 | |
| 33362 | + && sqlite3_str_errcode(pAccum)==0 | |
| 33363 | + ){ | |
| 33364 | + zz = sqlite3_str_value(pAccum); | |
| 33365 | + zz += iStart; | |
| 33366 | + memmove(zz+sp, zz, n); | |
| 33367 | + memset(zz, ' ', sp); | |
| 33368 | + } | |
| 33369 | + } | |
| 33370 | + } | |
| 33371 | + continue; | |
| 33372 | + } | |
| 33251 | 33373 | case etESCAPE_q: /* %q: Escape ' characters */ |
| 33252 | 33374 | case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */ |
| 33253 | 33375 | case etESCAPE_w: { /* %w: Escape " characters */ |
| 33254 | 33376 | i64 i, j, k, n; |
| 33255 | 33377 | int needQuote = 0; |
| @@ -33288,12 +33410,12 @@ | ||
| 33288 | 33410 | if( flag_alternateform ){ |
| 33289 | 33411 | /* For %#q, do unistr()-style backslash escapes for |
| 33290 | 33412 | ** all control characters, and for backslash itself. |
| 33291 | 33413 | ** For %#Q, do the same but only if there is at least |
| 33292 | 33414 | ** one control character. */ |
| 33293 | - u32 nBack = 0; | |
| 33294 | - u32 nCtrl = 0; | |
| 33415 | + i64 nBack = 0; | |
| 33416 | + i64 nCtrl = 0; | |
| 33295 | 33417 | for(k=0; k<i; k++){ |
| 33296 | 33418 | if( escarg[k]=='\\' ){ |
| 33297 | 33419 | nBack++; |
| 33298 | 33420 | }else if( ((u8*)escarg)[k]<=0x1f ){ |
| 33299 | 33421 | nCtrl++; |
| @@ -33337,11 +33459,11 @@ | ||
| 33337 | 33459 | bufpt[j-1] = '\\'; |
| 33338 | 33460 | bufpt[j++] = 'u'; |
| 33339 | 33461 | bufpt[j++] = '0'; |
| 33340 | 33462 | bufpt[j++] = '0'; |
| 33341 | 33463 | bufpt[j++] = ch>=0x10 ? '1' : '0'; |
| 33342 | - bufpt[j++] = "0123456789abcdef"[ch&0xf]; | |
| 33464 | + bufpt[j++] = aHex[ch&0xf]; | |
| 33343 | 33465 | } |
| 33344 | 33466 | } |
| 33345 | 33467 | }else{ |
| 33346 | 33468 | for(i=0; i<k; i++){ |
| 33347 | 33469 | bufpt[j++] = ch = escarg[i]; |
| @@ -39154,10 +39276,26 @@ | ||
| 39154 | 39276 | ****************************************************************************** |
| 39155 | 39277 | ** |
| 39156 | 39278 | ** This file contains an experimental VFS layer that operates on a |
| 39157 | 39279 | ** Key/Value storage engine where both keys and values must be pure |
| 39158 | 39280 | ** text. |
| 39281 | +** | |
| 39282 | +** DEBUG AND TEST | |
| 39283 | +** | |
| 39284 | +** For testing on Unix, compile using: | |
| 39285 | +** | |
| 39286 | +** make clean sqlite3d CFLAGS='-DSQLITE_OS_KV_OPTIONAL' | |
| 39287 | +** | |
| 39288 | +** Then start up a shell using something like: | |
| 39289 | +** | |
| 39290 | +** ./sqlite3d 'file:dbname?vfs=kvvfs' | |
| 39291 | +** | |
| 39292 | +** Each K/V entry is stored in a separate file in the working | |
| 39293 | +** directory that has a name like "kvvfs-dbname-*". Due to limitations | |
| 39294 | +** on the key size, the name of the database must be very short - just | |
| 39295 | +** a few characters. If the database name is too long, the VFS will | |
| 39296 | +** malfunction and you will get SQLITE_CORRUPT errors. | |
| 39159 | 39297 | */ |
| 39160 | 39298 | /* #include <sqliteInt.h> */ |
| 39161 | 39299 | #if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)) |
| 39162 | 39300 | |
| 39163 | 39301 | /***************************************************************************** |
| @@ -39606,16 +39744,18 @@ | ||
| 39606 | 39744 | } |
| 39607 | 39745 | if( j+n>nOut ) return -1; |
| 39608 | 39746 | memset(&aOut[j], 0, n); |
| 39609 | 39747 | j += n; |
| 39610 | 39748 | if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */ |
| 39611 | - }else{ | |
| 39749 | + }else if( j<nOut ){ | |
| 39612 | 39750 | aOut[j] = c<<4; |
| 39613 | 39751 | c = kvvfsHexValue[aIn[++i]]; |
| 39614 | 39752 | if( c<0 ) return -1 /* hex bytes are always in pairs */; |
| 39615 | 39753 | aOut[j++] += c; |
| 39616 | 39754 | i++; |
| 39755 | + }else{ | |
| 39756 | + return -1; | |
| 39617 | 39757 | } |
| 39618 | 39758 | } |
| 39619 | 39759 | return j; |
| 39620 | 39760 | } |
| 39621 | 39761 | |
| @@ -40037,10 +40177,22 @@ | ||
| 40037 | 40177 | }else{ |
| 40038 | 40178 | pFile->isJournal = 0; |
| 40039 | 40179 | pFile->base.pMethods = &kvvfs_db_io_methods; |
| 40040 | 40180 | } |
| 40041 | 40181 | if( !pFile->zClass ){ |
| 40182 | +#ifdef SQLITE_WASM | |
| 40183 | + if( strlen(zName) >= (KVRECORD_KEY_SZ | |
| 40184 | + - 6 /* "kvvfs-" */ | |
| 40185 | + - 11 /* "-##########" */) ){ | |
| 40186 | + return SQLITE_CANTOPEN; | |
| 40187 | + } | |
| 40188 | +#else | |
| 40189 | + if( 0!=strcmp(zName, "local") && 0!=strcmp(zName, "session") ){ | |
| 40190 | + /* Historical naming restriction which journaling depends on. */ | |
| 40191 | + return SQLITE_CANTOPEN; | |
| 40192 | + } | |
| 40193 | +#endif | |
| 40042 | 40194 | pFile->zClass = zName; |
| 40043 | 40195 | } |
| 40044 | 40196 | pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ); |
| 40045 | 40197 | if( pFile->aData==0 ){ |
| 40046 | 40198 | return SQLITE_NOMEM; |
| @@ -45345,13 +45497,13 @@ | ||
| 45345 | 45497 | |
| 45346 | 45498 | /* Minimum number of regions required to be mapped. */ |
| 45347 | 45499 | nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; |
| 45348 | 45500 | |
| 45349 | 45501 | if( pShmNode->nRegion<nReqRegion ){ |
| 45350 | - char **apNew; /* New apRegion[] array */ | |
| 45351 | - int nByte = nReqRegion*szRegion; /* Minimum required file size */ | |
| 45352 | - struct stat sStat; /* Used by fstat() */ | |
| 45502 | + char **apNew; /* New apRegion[] array */ | |
| 45503 | + i64 nByte = nReqRegion*(i64)szRegion; /* Minimum required file size */ | |
| 45504 | + struct stat sStat; /* Used by fstat() */ | |
| 45353 | 45505 | |
| 45354 | 45506 | pShmNode->szRegion = szRegion; |
| 45355 | 45507 | |
| 45356 | 45508 | if( pShmNode->hShm>=0 ){ |
| 45357 | 45509 | /* The requested region is not mapped into this processes address space. |
| @@ -45378,11 +45530,11 @@ | ||
| 45378 | 45530 | ** pages forces the OS to allocate them immediately, which reduces |
| 45379 | 45531 | ** the chances of SIGBUS while accessing the mapped region later on. |
| 45380 | 45532 | */ |
| 45381 | 45533 | else{ |
| 45382 | 45534 | static const int pgsz = 4096; |
| 45383 | - int iPg; | |
| 45535 | + i64 iPg; | |
| 45384 | 45536 | |
| 45385 | 45537 | /* Write to the last byte of each newly allocated or extended page */ |
| 45386 | 45538 | assert( (nByte % pgsz)==0 ); |
| 45387 | 45539 | for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ |
| 45388 | 45540 | int x = 0; |
| @@ -45404,12 +45556,12 @@ | ||
| 45404 | 45556 | rc = SQLITE_IOERR_NOMEM_BKPT; |
| 45405 | 45557 | goto shmpage_out; |
| 45406 | 45558 | } |
| 45407 | 45559 | pShmNode->apRegion = apNew; |
| 45408 | 45560 | while( pShmNode->nRegion<nReqRegion ){ |
| 45409 | - int nMap = szRegion*nShmPerMap; | |
| 45410 | - int i; | |
| 45561 | + i64 nMap = (i64)szRegion*(i64)nShmPerMap; | |
| 45562 | + i64 i; | |
| 45411 | 45563 | void *pMem; |
| 45412 | 45564 | if( pShmNode->hShm>=0 ){ |
| 45413 | 45565 | pMem = osMmap(0, nMap, |
| 45414 | 45566 | pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, |
| 45415 | 45567 | MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion |
| @@ -49195,107 +49347,154 @@ | ||
| 49195 | 49347 | |
| 49196 | 49348 | { "CreateFileW", (SYSCALL)CreateFileW, 0 }, |
| 49197 | 49349 | #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ |
| 49198 | 49350 | LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[2].pCurrent) |
| 49199 | 49351 | |
| 49352 | +#if defined(SQLITE_UWP) | |
| 49353 | + { "CreateFileMappingFromApp",(SYSCALL)CreateFileMappingFromApp,0 }, | |
| 49354 | +#else | |
| 49355 | + { "CreateFileMappingFromApp",(SYSCALL)0, 0 }, | |
| 49356 | +#endif | |
| 49357 | +#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE,\ | |
| 49358 | + PSECURITY_ATTRIBUTES, \ | |
| 49359 | + ULONG,ULONG64,PCWSTR))aSyscall[3].pCurrent) | |
| 49360 | + | |
| 49361 | +#if !defined(SQLITE_UWP) | |
| 49200 | 49362 | { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, |
| 49363 | +#else | |
| 49364 | + { "CreateFileMappingW", (SYSCALL)0, 0 }, | |
| 49365 | +#endif | |
| 49201 | 49366 | #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ |
| 49202 | - DWORD,DWORD,DWORD,LPCWSTR))aSyscall[3].pCurrent) | |
| 49367 | + DWORD,DWORD,DWORD,LPCWSTR))aSyscall[4].pCurrent) | |
| 49203 | 49368 | |
| 49204 | 49369 | { "DeleteFileW", (SYSCALL)DeleteFileW, 0 }, |
| 49205 | -#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[4].pCurrent) | |
| 49370 | +#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[5].pCurrent) | |
| 49206 | 49371 | |
| 49207 | 49372 | { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, |
| 49208 | -#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[5].pCurrent) | |
| 49373 | +#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[6].pCurrent) | |
| 49209 | 49374 | |
| 49210 | 49375 | { "FormatMessageW", (SYSCALL)FormatMessageW, 0 }, |
| 49211 | 49376 | #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ |
| 49212 | - DWORD,va_list*))aSyscall[6].pCurrent) | |
| 49377 | + DWORD,va_list*))aSyscall[7].pCurrent) | |
| 49213 | 49378 | |
| 49214 | -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) | |
| 49379 | +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_UWP) | |
| 49215 | 49380 | { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, |
| 49216 | 49381 | #else |
| 49217 | 49382 | { "FreeLibrary", (SYSCALL)0, 0 }, |
| 49218 | 49383 | #endif |
| 49219 | 49384 | |
| 49220 | -#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[7].pCurrent) | |
| 49385 | +#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[8].pCurrent) | |
| 49221 | 49386 | |
| 49222 | 49387 | { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, |
| 49223 | -#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[8].pCurrent) | |
| 49388 | +#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[9].pCurrent) | |
| 49224 | 49389 | |
| 49225 | 49390 | { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, |
| 49226 | -#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[9].pCurrent) | |
| 49391 | +#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) | |
| 49227 | 49392 | |
| 49228 | 49393 | { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 }, |
| 49229 | 49394 | #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ |
| 49230 | - LPVOID))aSyscall[10].pCurrent) | |
| 49395 | + LPVOID))aSyscall[11].pCurrent) | |
| 49231 | 49396 | |
| 49232 | - { "GetFileSize", (SYSCALL)GetFileSize, 0 }, | |
| 49233 | -#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[11].pCurrent) | |
| 49397 | + { "GetFileSizeEx", (SYSCALL)GetFileSizeEx, 0 }, | |
| 49398 | +#define osGetFileSizeEx ((BOOL(WINAPI*)(HANDLE, \ | |
| 49399 | + PLARGE_INTEGER))aSyscall[12].pCurrent) | |
| 49234 | 49400 | |
| 49235 | 49401 | { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, |
| 49236 | 49402 | #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ |
| 49237 | - LPWSTR*))aSyscall[12].pCurrent) | |
| 49403 | + LPWSTR*))aSyscall[13].pCurrent) | |
| 49238 | 49404 | |
| 49239 | 49405 | { "GetLastError", (SYSCALL)GetLastError, 0 }, |
| 49240 | -#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[13].pCurrent) | |
| 49406 | +#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[14].pCurrent) | |
| 49241 | 49407 | |
| 49242 | -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) | |
| 49408 | +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_UWP) | |
| 49243 | 49409 | { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 }, |
| 49244 | 49410 | #else |
| 49245 | 49411 | { "GetProcAddressA", (SYSCALL)0, 0 }, |
| 49246 | 49412 | #endif |
| 49247 | 49413 | #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ |
| 49248 | - LPCSTR))aSyscall[14].pCurrent) | |
| 49414 | + LPCSTR))aSyscall[15].pCurrent) | |
| 49249 | 49415 | |
| 49250 | 49416 | { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, |
| 49251 | -#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[15].pCurrent) | |
| 49252 | - | |
| 49253 | - { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, | |
| 49254 | -#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[16].pCurrent) | |
| 49417 | +#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[16].pCurrent) | |
| 49255 | 49418 | |
| 49256 | 49419 | { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 }, |
| 49257 | 49420 | #define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \ |
| 49258 | 49421 | LPFILETIME))aSyscall[17].pCurrent) |
| 49259 | 49422 | |
| 49423 | +#ifdef SQLITE_UWP | |
| 49424 | + { "GetTempPathW", (SYSCALL)0, 0 }, | |
| 49425 | +#else | |
| 49260 | 49426 | { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, |
| 49427 | +#endif | |
| 49261 | 49428 | #define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[18].pCurrent) |
| 49262 | 49429 | |
| 49263 | - { "GetTickCount", (SYSCALL)GetTickCount, 0 }, | |
| 49264 | -#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[19].pCurrent) | |
| 49430 | + { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, | |
| 49431 | +#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[19].pCurrent) | |
| 49265 | 49432 | |
| 49433 | +#ifdef SQLITE_UWP | |
| 49434 | + { "HeapAlloc", (SYSCALL)0, 0 }, | |
| 49435 | +#else | |
| 49266 | 49436 | { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, |
| 49437 | +#endif | |
| 49267 | 49438 | #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ |
| 49268 | 49439 | SIZE_T))aSyscall[20].pCurrent) |
| 49269 | 49440 | |
| 49441 | +#ifdef SQLITE_UWP | |
| 49442 | + { "HeapCreate", (SYSCALL)0, 0 }, | |
| 49443 | +#else | |
| 49270 | 49444 | { "HeapCreate", (SYSCALL)HeapCreate, 0 }, |
| 49445 | +#endif | |
| 49271 | 49446 | #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ |
| 49272 | 49447 | SIZE_T))aSyscall[21].pCurrent) |
| 49273 | 49448 | |
| 49449 | +#ifdef SQLITE_UWP | |
| 49450 | + { "HeapDestroy", (SYSCALL)0, 0 }, | |
| 49451 | +#else | |
| 49274 | 49452 | { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, |
| 49453 | +#endif | |
| 49275 | 49454 | #define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[22].pCurrent) |
| 49276 | 49455 | |
| 49456 | +#ifdef SQLITE_UWP | |
| 49457 | + { "HeapFree", (SYSCALL)0, 0 }, | |
| 49458 | +#else | |
| 49277 | 49459 | { "HeapFree", (SYSCALL)HeapFree, 0 }, |
| 49460 | +#endif | |
| 49278 | 49461 | #define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[23].pCurrent) |
| 49279 | 49462 | |
| 49463 | +#ifdef SQLITE_UWP | |
| 49464 | + { "HeapReAlloc", (SYSCALL)0, 0 }, | |
| 49465 | +#else | |
| 49280 | 49466 | { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, |
| 49467 | +#endif | |
| 49281 | 49468 | #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ |
| 49282 | 49469 | SIZE_T))aSyscall[24].pCurrent) |
| 49283 | 49470 | |
| 49471 | +#ifdef SQLITE_UWP | |
| 49472 | + { "HeapSize", (SYSCALL)0, 0 }, | |
| 49473 | +#else | |
| 49284 | 49474 | { "HeapSize", (SYSCALL)HeapSize, 0 }, |
| 49475 | +#endif | |
| 49285 | 49476 | #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ |
| 49286 | 49477 | LPCVOID))aSyscall[25].pCurrent) |
| 49287 | 49478 | |
| 49479 | +#ifdef SQLITE_UWP | |
| 49480 | + { "HeapValidate", (SYSCALL)0, 0 }, | |
| 49481 | +#else | |
| 49288 | 49482 | { "HeapValidate", (SYSCALL)HeapValidate, 0 }, |
| 49483 | +#endif | |
| 49289 | 49484 | #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ |
| 49290 | 49485 | LPCVOID))aSyscall[26].pCurrent) |
| 49291 | 49486 | |
| 49487 | +#ifdef SQLITE_UWP | |
| 49488 | + { "HeapCompact", (SYSCALL)0, 0 }, | |
| 49489 | +#else | |
| 49292 | 49490 | { "HeapCompact", (SYSCALL)HeapCompact, 0 }, |
| 49491 | +#endif | |
| 49293 | 49492 | #define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[27].pCurrent) |
| 49294 | 49493 | |
| 49295 | 49494 | |
| 49296 | -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) | |
| 49495 | +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_UWP) | |
| 49297 | 49496 | { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, |
| 49298 | 49497 | #else |
| 49299 | 49498 | { "LoadLibraryW", (SYSCALL)0, 0 }, |
| 49300 | 49499 | #endif |
| 49301 | 49500 | #define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[28].pCurrent) |
| @@ -49305,72 +49504,82 @@ | ||
| 49305 | 49504 | |
| 49306 | 49505 | { "LockFileEx", (SYSCALL)LockFileEx, 0 }, |
| 49307 | 49506 | #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ |
| 49308 | 49507 | LPOVERLAPPED))aSyscall[30].pCurrent) |
| 49309 | 49508 | |
| 49310 | -#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 | |
| 49509 | +#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ | |
| 49510 | + && !defined(SQLITE_UWP) | |
| 49311 | 49511 | { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, |
| 49312 | 49512 | #else |
| 49313 | 49513 | { "MapViewOfFile", (SYSCALL)0, 0 }, |
| 49314 | 49514 | #endif |
| 49315 | 49515 | #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ |
| 49316 | 49516 | SIZE_T))aSyscall[31].pCurrent) |
| 49517 | + | |
| 49518 | +#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ | |
| 49519 | + && defined(SQLITE_UWP) | |
| 49520 | + { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, | |
| 49521 | +#else | |
| 49522 | + { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, | |
| 49523 | +#endif | |
| 49524 | +#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ | |
| 49525 | + SIZE_T))aSyscall[32].pCurrent) | |
| 49317 | 49526 | |
| 49318 | 49527 | { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, |
| 49319 | 49528 | #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ |
| 49320 | - int))aSyscall[32].pCurrent) | |
| 49529 | + int))aSyscall[33].pCurrent) | |
| 49321 | 49530 | |
| 49322 | 49531 | { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, |
| 49323 | 49532 | #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ |
| 49324 | - LARGE_INTEGER*))aSyscall[33].pCurrent) | |
| 49533 | + LARGE_INTEGER*))aSyscall[34].pCurrent) | |
| 49325 | 49534 | |
| 49326 | 49535 | { "ReadFile", (SYSCALL)ReadFile, 0 }, |
| 49327 | 49536 | #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ |
| 49328 | - LPOVERLAPPED))aSyscall[34].pCurrent) | |
| 49537 | + LPOVERLAPPED))aSyscall[35].pCurrent) | |
| 49329 | 49538 | |
| 49330 | 49539 | { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, |
| 49331 | -#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[35].pCurrent) | |
| 49540 | +#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[36].pCurrent) | |
| 49332 | 49541 | |
| 49333 | - { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, | |
| 49334 | -#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ | |
| 49335 | - DWORD))aSyscall[36].pCurrent) | |
| 49542 | + { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, | |
| 49543 | +#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER,\ | |
| 49544 | + PLARGE_INTEGER,DWORD))aSyscall[37].pCurrent) | |
| 49336 | 49545 | |
| 49337 | 49546 | { "Sleep", (SYSCALL)Sleep, 0 }, |
| 49338 | -#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[37].pCurrent) | |
| 49547 | +#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[38].pCurrent) | |
| 49339 | 49548 | |
| 49340 | 49549 | { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 }, |
| 49341 | 49550 | #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ |
| 49342 | - LPOVERLAPPED))aSyscall[38].pCurrent) | |
| 49551 | + LPOVERLAPPED))aSyscall[39].pCurrent) | |
| 49343 | 49552 | |
| 49344 | 49553 | #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 49345 | 49554 | { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, |
| 49346 | 49555 | #else |
| 49347 | 49556 | { "UnmapViewOfFile", (SYSCALL)0, 0 }, |
| 49348 | 49557 | #endif |
| 49349 | -#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[39].pCurrent) | |
| 49558 | +#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[40].pCurrent) | |
| 49350 | 49559 | |
| 49351 | 49560 | { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, |
| 49352 | 49561 | #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ |
| 49353 | - LPCSTR,LPBOOL))aSyscall[40].pCurrent) | |
| 49562 | + LPCSTR,LPBOOL))aSyscall[41].pCurrent) | |
| 49354 | 49563 | |
| 49355 | 49564 | { "WriteFile", (SYSCALL)WriteFile, 0 }, |
| 49356 | 49565 | #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ |
| 49357 | - LPOVERLAPPED))aSyscall[41].pCurrent) | |
| 49566 | + LPOVERLAPPED))aSyscall[42].pCurrent) | |
| 49358 | 49567 | |
| 49359 | 49568 | { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, |
| 49360 | 49569 | #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ |
| 49361 | - DWORD))aSyscall[42].pCurrent) | |
| 49570 | + DWORD))aSyscall[43].pCurrent) | |
| 49362 | 49571 | |
| 49363 | 49572 | { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, |
| 49364 | 49573 | #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ |
| 49365 | - BOOL))aSyscall[43].pCurrent) | |
| 49574 | + BOOL))aSyscall[44].pCurrent) | |
| 49366 | 49575 | |
| 49367 | 49576 | { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, |
| 49368 | -#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) | |
| 49577 | +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[45].pCurrent) | |
| 49369 | 49578 | |
| 49370 | 49579 | { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, |
| 49371 | -#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[45].pCurrent) | |
| 49580 | +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[46].pCurrent) | |
| 49372 | 49581 | |
| 49373 | 49582 | /* |
| 49374 | 49583 | ** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" |
| 49375 | 49584 | ** is really just a macro that uses a compiler intrinsic (e.g. x64). |
| 49376 | 49585 | ** So do not try to make this is into a redefinable interface. |
| @@ -49379,95 +49588,93 @@ | ||
| 49379 | 49588 | { "InterlockedCompareExchange", (SYSCALL)0, 0 }, |
| 49380 | 49589 | #define osInterlockedCompareExchange InterlockedCompareExchange |
| 49381 | 49590 | #else |
| 49382 | 49591 | { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, |
| 49383 | 49592 | #define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*,\ |
| 49384 | - LONG,LONG))aSyscall[46].pCurrent) | |
| 49593 | + LONG,LONG))aSyscall[47].pCurrent) | |
| 49385 | 49594 | #endif /* defined(InterlockedCompareExchange) */ |
| 49386 | 49595 | |
| 49387 | 49596 | #if SQLITE_WIN32_USE_UUID |
| 49388 | 49597 | { "UuidCreate", (SYSCALL)UuidCreate, 0 }, |
| 49389 | 49598 | #else |
| 49390 | 49599 | { "UuidCreate", (SYSCALL)0, 0 }, |
| 49391 | 49600 | #endif |
| 49392 | -#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[47].pCurrent) | |
| 49601 | +#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[48].pCurrent) | |
| 49393 | 49602 | |
| 49394 | 49603 | #if SQLITE_WIN32_USE_UUID |
| 49395 | 49604 | { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, |
| 49396 | 49605 | #else |
| 49397 | 49606 | { "UuidCreateSequential", (SYSCALL)0, 0 }, |
| 49398 | 49607 | #endif |
| 49399 | 49608 | #define osUuidCreateSequential \ |
| 49400 | - ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[48].pCurrent) | |
| 49609 | + ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[49].pCurrent) | |
| 49401 | 49610 | |
| 49402 | 49611 | #if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 |
| 49403 | 49612 | { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, |
| 49404 | 49613 | #else |
| 49405 | 49614 | { "FlushViewOfFile", (SYSCALL)0, 0 }, |
| 49406 | 49615 | #endif |
| 49407 | 49616 | #define osFlushViewOfFile \ |
| 49408 | - ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[49].pCurrent) | |
| 49617 | + ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[50].pCurrent) | |
| 49409 | 49618 | |
| 49410 | 49619 | #ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 49411 | 49620 | { "CreateEvent", (SYSCALL)CreateEvent, 0 }, |
| 49412 | 49621 | #else |
| 49413 | 49622 | { "CreateEvent", (SYSCALL)0, 0 }, |
| 49414 | 49623 | #endif |
| 49415 | -#define osCreateEvent ( \ | |
| 49416 | - (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \ | |
| 49417 | - aSyscall[50].pCurrent \ | |
| 49418 | -) | |
| 49624 | +#define osCreateEvent ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ | |
| 49625 | + BOOL,LPCSTR))aSyscall[51].pCurrent) | |
| 49419 | 49626 | |
| 49420 | 49627 | #ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 49421 | 49628 | { "CancelIo", (SYSCALL)CancelIo, 0 }, |
| 49422 | 49629 | #else |
| 49423 | 49630 | { "CancelIo", (SYSCALL)0, 0 }, |
| 49424 | 49631 | #endif |
| 49425 | -#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent) | |
| 49632 | +#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[52].pCurrent) | |
| 49426 | 49633 | |
| 49427 | 49634 | #ifndef _WIN32 |
| 49428 | 49635 | { "getenv", (SYSCALL)getenv, 0 }, |
| 49429 | 49636 | #else |
| 49430 | 49637 | { "getenv", (SYSCALL)0, 0 }, |
| 49431 | 49638 | #endif |
| 49432 | -#define osGetenv ((const char *(*)(const char *))aSyscall[52].pCurrent) | |
| 49639 | +#define osGetenv ((const char *(*)(const char *))aSyscall[53].pCurrent) | |
| 49433 | 49640 | |
| 49434 | 49641 | #ifndef _WIN32 |
| 49435 | 49642 | { "getcwd", (SYSCALL)getcwd, 0 }, |
| 49436 | 49643 | #else |
| 49437 | 49644 | { "getcwd", (SYSCALL)0, 0 }, |
| 49438 | 49645 | #endif |
| 49439 | -#define osGetcwd ((char*(*)(char*,size_t))aSyscall[53].pCurrent) | |
| 49646 | +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[54].pCurrent) | |
| 49440 | 49647 | |
| 49441 | 49648 | #ifndef _WIN32 |
| 49442 | 49649 | { "readlink", (SYSCALL)readlink, 0 }, |
| 49443 | 49650 | #else |
| 49444 | 49651 | { "readlink", (SYSCALL)0, 0 }, |
| 49445 | 49652 | #endif |
| 49446 | -#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[54].pCurrent) | |
| 49653 | +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[55].pCurrent) | |
| 49447 | 49654 | |
| 49448 | 49655 | #ifndef _WIN32 |
| 49449 | 49656 | { "lstat", (SYSCALL)lstat, 0 }, |
| 49450 | 49657 | #else |
| 49451 | 49658 | { "lstat", (SYSCALL)0, 0 }, |
| 49452 | 49659 | #endif |
| 49453 | -#define osLstat ((int(*)(const char*,struct stat*))aSyscall[55].pCurrent) | |
| 49660 | +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[56].pCurrent) | |
| 49454 | 49661 | |
| 49455 | 49662 | #ifndef _WIN32 |
| 49456 | 49663 | { "__errno", (SYSCALL)__errno, 0 }, |
| 49457 | 49664 | #else |
| 49458 | 49665 | { "__errno", (SYSCALL)0, 0 }, |
| 49459 | 49666 | #endif |
| 49460 | -#define osErrno (*((int*(*)(void))aSyscall[56].pCurrent)()) | |
| 49667 | +#define osErrno (*((int*(*)(void))aSyscall[57].pCurrent)()) | |
| 49461 | 49668 | |
| 49462 | 49669 | #ifndef _WIN32 |
| 49463 | 49670 | { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 }, |
| 49464 | 49671 | #else |
| 49465 | 49672 | { "cygwin_conv_path", (SYSCALL)0, 0 }, |
| 49466 | 49673 | #endif |
| 49467 | 49674 | #define osCygwin_conv_path ((size_t(*)(unsigned int, \ |
| 49468 | - const void *, void *, size_t))aSyscall[57].pCurrent) | |
| 49675 | + const void *, void *, size_t))aSyscall[58].pCurrent) | |
| 49469 | 49676 | |
| 49470 | 49677 | }; /* End of the overrideable system calls */ |
| 49471 | 49678 | |
| 49472 | 49679 | /* |
| 49473 | 49680 | ** This is the xSetSystemCall() method of sqlite3_vfs for all of the |
| @@ -49551,10 +49758,13 @@ | ||
| 49551 | 49758 | } |
| 49552 | 49759 | return 0; |
| 49553 | 49760 | } |
| 49554 | 49761 | |
| 49555 | 49762 | #ifdef SQLITE_WIN32_MALLOC |
| 49763 | +#ifdef SQLITE_UWP | |
| 49764 | +# error SQLITE_WIN32_MALLOC is incompatible with SQLITE_UWP | |
| 49765 | +#endif | |
| 49556 | 49766 | /* |
| 49557 | 49767 | ** If a Win32 native heap has been configured, this function will attempt to |
| 49558 | 49768 | ** compact it. Upon success, SQLITE_OK will be returned. Upon failure, one |
| 49559 | 49769 | ** of SQLITE_NOMEM, SQLITE_ERROR, or SQLITE_NOTFOUND will be returned. The |
| 49560 | 49770 | ** "pnLargest" argument, if non-zero, will be used to return the size of the |
| @@ -50509,31 +50719,15 @@ | ||
| 50509 | 50719 | ** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite |
| 50510 | 50720 | ** error code. |
| 50511 | 50721 | */ |
| 50512 | 50722 | static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ |
| 50513 | 50723 | int rc = SQLITE_OK; /* Return value */ |
| 50514 | - | |
| 50515 | - LONG upperBits; /* Most sig. 32 bits of new offset */ | |
| 50516 | - LONG lowerBits; /* Least sig. 32 bits of new offset */ | |
| 50517 | - DWORD dwRet; /* Value returned by SetFilePointer() */ | |
| 50518 | - | |
| 50519 | - upperBits = (LONG)((iOffset>>32) & 0x7fffffff); | |
| 50520 | - lowerBits = (LONG)(iOffset & 0xffffffff); | |
| 50521 | - | |
| 50522 | - dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN); | |
| 50523 | - | |
| 50524 | - /* API oddity: If successful, SetFilePointer() returns a dword | |
| 50525 | - ** containing the lower 32-bits of the new file-offset. Or, if it fails, | |
| 50526 | - ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, | |
| 50527 | - ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine | |
| 50528 | - ** whether an error has actually occurred, it is also necessary to call | |
| 50529 | - ** GetLastError(). */ | |
| 50530 | - if( dwRet==INVALID_SET_FILE_POINTER ){ | |
| 50531 | - DWORD lastErrno = osGetLastError(); | |
| 50532 | - if( lastErrno!=NO_ERROR ){ | |
| 50533 | - rc = SQLITE_IOERR_SEEK; | |
| 50534 | - } | |
| 50724 | + LARGE_INTEGER x; /* The offset */ | |
| 50725 | + | |
| 50726 | + x.QuadPart = iOffset; | |
| 50727 | + if( osSetFilePointerEx(h, x, 0, FILE_BEGIN)==0 ){ | |
| 50728 | + rc = SQLITE_IOERR_SEEK; | |
| 50535 | 50729 | } |
| 50536 | 50730 | OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset,sqlite3ErrName(rc))); |
| 50537 | 50731 | return rc; |
| 50538 | 50732 | } |
| 50539 | 50733 | |
| @@ -50812,18 +51006,17 @@ | ||
| 50812 | 51006 | ** Determine the size in bytes of the file opened by the handle passed as |
| 50813 | 51007 | ** the first argument. |
| 50814 | 51008 | */ |
| 50815 | 51009 | static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ |
| 50816 | 51010 | int rc = SQLITE_OK; |
| 50817 | - DWORD upperBits = 0; | |
| 50818 | - DWORD lowerBits = 0; | |
| 50819 | - | |
| 51011 | + LARGE_INTEGER x; | |
| 50820 | 51012 | assert( pnByte ); |
| 50821 | - lowerBits = osGetFileSize(h, &upperBits); | |
| 50822 | - *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits; | |
| 50823 | - if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){ | |
| 51013 | + if( osGetFileSizeEx(h, &x)==0 ){ | |
| 50824 | 51014 | rc = SQLITE_IOERR_FSTAT; |
| 51015 | + *pnByte = 0; | |
| 51016 | + }else{ | |
| 51017 | + *pnByte = x.QuadPart; | |
| 50825 | 51018 | } |
| 50826 | 51019 | return rc; |
| 50827 | 51020 | } |
| 50828 | 51021 | |
| 50829 | 51022 | /* |
| @@ -51020,21 +51213,18 @@ | ||
| 51020 | 51213 | assert( id!=0 ); |
| 51021 | 51214 | assert( pSize!=0 ); |
| 51022 | 51215 | SimulateIOError(return SQLITE_IOERR_FSTAT); |
| 51023 | 51216 | OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); |
| 51024 | 51217 | { |
| 51025 | - DWORD upperBits; | |
| 51026 | - DWORD lowerBits; | |
| 51027 | - DWORD lastErrno; | |
| 51028 | - | |
| 51029 | - lowerBits = osGetFileSize(pFile->h, &upperBits); | |
| 51030 | - *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; | |
| 51031 | - if( (lowerBits == INVALID_FILE_SIZE) | |
| 51032 | - && ((lastErrno = osGetLastError())!=NO_ERROR) ){ | |
| 51033 | - pFile->lastErrno = lastErrno; | |
| 51218 | + LARGE_INTEGER x; | |
| 51219 | + if( osGetFileSizeEx(pFile->h, &x)==0 ){ | |
| 51220 | + *pSize = 0; | |
| 51221 | + pFile->lastErrno = osGetLastError(); | |
| 51034 | 51222 | rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, |
| 51035 | 51223 | "winFileSize", pFile->zPath); |
| 51224 | + }else{ | |
| 51225 | + *pSize = x.QuadPart; | |
| 51036 | 51226 | } |
| 51037 | 51227 | } |
| 51038 | 51228 | OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", |
| 51039 | 51229 | pFile->h, pSize, *pSize, sqlite3ErrName(rc))); |
| 51040 | 51230 | return rc; |
| @@ -52031,15 +52221,33 @@ | ||
| 52031 | 52221 | # define sqlite3_win_test_unc_locking 0 |
| 52032 | 52222 | #endif |
| 52033 | 52223 | |
| 52034 | 52224 | /* |
| 52035 | 52225 | ** Return true if the string passed as the only argument is likely |
| 52036 | -** to be a UNC path. In other words, if it starts with "\\". | |
| 52226 | +** to be a UNC path. Return false if note. | |
| 52227 | +** | |
| 52228 | +** Return true if: | |
| 52229 | +** | |
| 52230 | +** (1) The name begins with "\\" | |
| 52231 | +** (2) But does not begin with "\\?\C:\" where C can be any alphabetic | |
| 52232 | +** character. | |
| 52233 | +** | |
| 52234 | +** For testing, also return true in all cases if the global variable | |
| 52235 | +** sqlite3_win_test_unc_locking is true. | |
| 52037 | 52236 | */ |
| 52038 | 52237 | static int winIsUNCPath(const char *zFile){ |
| 52039 | 52238 | if( zFile[0]=='\\' && zFile[1]=='\\' ){ |
| 52040 | - return 1; | |
| 52239 | + if( zFile[2]=='?' | |
| 52240 | + && zFile[3]=='\\' | |
| 52241 | + && sqlite3Isalpha(zFile[4]) | |
| 52242 | + && zFile[5]==':' | |
| 52243 | + && winIsDirSep(zFile[6]) | |
| 52244 | + ){ | |
| 52245 | + return sqlite3_win_test_unc_locking; | |
| 52246 | + }else{ | |
| 52247 | + return 1; | |
| 52248 | + } | |
| 52041 | 52249 | } |
| 52042 | 52250 | return sqlite3_win_test_unc_locking; |
| 52043 | 52251 | } |
| 52044 | 52252 | |
| 52045 | 52253 | /* |
| @@ -52373,11 +52581,11 @@ | ||
| 52373 | 52581 | |
| 52374 | 52582 | assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); |
| 52375 | 52583 | if( pShmNode->nRegion<=iRegion ){ |
| 52376 | 52584 | HANDLE hShared = pShmNode->hSharedShm; |
| 52377 | 52585 | struct ShmRegion *apNew; /* New aRegion[] array */ |
| 52378 | - int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ | |
| 52586 | + i64 nByte = ((i64)iRegion+1)*(i64)szRegion; /* Minimum file size */ | |
| 52379 | 52587 | sqlite3_int64 sz; /* Current size of wal-index file */ |
| 52380 | 52588 | |
| 52381 | 52589 | pShmNode->szRegion = szRegion; |
| 52382 | 52590 | |
| 52383 | 52591 | /* The requested region is not mapped into this processes address space. |
| @@ -52404,11 +52612,11 @@ | ||
| 52404 | 52612 | } |
| 52405 | 52613 | } |
| 52406 | 52614 | |
| 52407 | 52615 | /* Map the requested memory region into this processes address space. */ |
| 52408 | 52616 | apNew = (struct ShmRegion*)sqlite3_realloc64( |
| 52409 | - pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) | |
| 52617 | + pShmNode->aRegion, ((i64)iRegion+1)*sizeof(apNew[0]) | |
| 52410 | 52618 | ); |
| 52411 | 52619 | if( !apNew ){ |
| 52412 | 52620 | rc = SQLITE_IOERR_NOMEM_BKPT; |
| 52413 | 52621 | goto shmpage_out; |
| 52414 | 52622 | } |
| @@ -52421,20 +52629,30 @@ | ||
| 52421 | 52629 | |
| 52422 | 52630 | while( pShmNode->nRegion<=iRegion ){ |
| 52423 | 52631 | HANDLE hMap = NULL; /* file-mapping handle */ |
| 52424 | 52632 | void *pMap = 0; /* Mapped memory region */ |
| 52425 | 52633 | |
| 52634 | +#ifdef SQLITE_UWP | |
| 52635 | + hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL); | |
| 52636 | +#else | |
| 52426 | 52637 | hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL); |
| 52427 | - OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", | |
| 52638 | +#endif | |
| 52639 | + OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%lld, rc=%s\n", | |
| 52428 | 52640 | osGetCurrentProcessId(), pShmNode->nRegion, nByte, |
| 52429 | 52641 | hMap ? "ok" : "failed")); |
| 52430 | 52642 | if( hMap ){ |
| 52431 | - int iOffset = pShmNode->nRegion*szRegion; | |
| 52643 | + i64 iOffset = pShmNode->nRegion*szRegion; | |
| 52432 | 52644 | int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; |
| 52645 | +#ifdef SQLITE_UWP | |
| 52646 | + pMap = osMapViewOfFileFromApp(hMap, flags, | |
| 52647 | + iOffset - iOffsetShift, (i64)szRegion + iOffsetShift | |
| 52648 | + ); | |
| 52649 | +#else | |
| 52433 | 52650 | pMap = osMapViewOfFile(hMap, flags, |
| 52434 | - 0, iOffset - iOffsetShift, szRegion + iOffsetShift | |
| 52651 | + 0, iOffset - iOffsetShift, (i64)szRegion + iOffsetShift | |
| 52435 | 52652 | ); |
| 52653 | +#endif | |
| 52436 | 52654 | OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", |
| 52437 | 52655 | osGetCurrentProcessId(), pShmNode->nRegion, iOffset, |
| 52438 | 52656 | szRegion, pMap ? "ok" : "failed")); |
| 52439 | 52657 | } |
| 52440 | 52658 | if( !pMap ){ |
| @@ -52451,11 +52669,11 @@ | ||
| 52451 | 52669 | } |
| 52452 | 52670 | } |
| 52453 | 52671 | |
| 52454 | 52672 | shmpage_out: |
| 52455 | 52673 | if( pShmNode->nRegion>iRegion ){ |
| 52456 | - int iOffset = iRegion*szRegion; | |
| 52674 | + i64 iOffset = (i64)iRegion*(i64)szRegion; | |
| 52457 | 52675 | int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; |
| 52458 | 52676 | char *p = (char *)pShmNode->aRegion[iRegion].pMap; |
| 52459 | 52677 | *pp = (void *)&p[iOffsetShift]; |
| 52460 | 52678 | }else{ |
| 52461 | 52679 | *pp = 0; |
| @@ -52563,13 +52781,17 @@ | ||
| 52563 | 52781 | if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){ |
| 52564 | 52782 | protect = PAGE_READWRITE; |
| 52565 | 52783 | flags |= FILE_MAP_WRITE; |
| 52566 | 52784 | } |
| 52567 | 52785 | #endif |
| 52786 | +#ifdef SQLITE_UWP | |
| 52787 | + pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); | |
| 52788 | +#else | |
| 52568 | 52789 | pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, |
| 52569 | 52790 | (DWORD)((nMap>>32) & 0xffffffff), |
| 52570 | 52791 | (DWORD)(nMap & 0xffffffff), NULL); |
| 52792 | +#endif | |
| 52571 | 52793 | if( pFd->hMap==NULL ){ |
| 52572 | 52794 | pFd->lastErrno = osGetLastError(); |
| 52573 | 52795 | rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, |
| 52574 | 52796 | "winMapfile1", pFd->zPath); |
| 52575 | 52797 | /* Log the error, but continue normal operation using xRead/xWrite */ |
| @@ -52577,11 +52799,15 @@ | ||
| 52577 | 52799 | osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); |
| 52578 | 52800 | return SQLITE_OK; |
| 52579 | 52801 | } |
| 52580 | 52802 | assert( (nMap % winSysInfo.dwPageSize)==0 ); |
| 52581 | 52803 | assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); |
| 52804 | +#ifdef SQLITE_UWP | |
| 52805 | + pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); | |
| 52806 | +#else | |
| 52582 | 52807 | pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); |
| 52808 | +#endif | |
| 52583 | 52809 | if( pNew==NULL ){ |
| 52584 | 52810 | osCloseHandle(pFd->hMap); |
| 52585 | 52811 | pFd->hMap = NULL; |
| 52586 | 52812 | pFd->lastErrno = osGetLastError(); |
| 52587 | 52813 | rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, |
| @@ -52920,11 +53146,11 @@ | ||
| 52920 | 53146 | if( !zWidePath ){ |
| 52921 | 53147 | sqlite3_free(zBuf); |
| 52922 | 53148 | OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
| 52923 | 53149 | return SQLITE_IOERR_NOMEM_BKPT; |
| 52924 | 53150 | } |
| 52925 | - if( osGetTempPathW(nMax, zWidePath)==0 ){ | |
| 53151 | + if( osGetTempPathW==0 || osGetTempPathW(nMax, zWidePath)==0 ){ | |
| 52926 | 53152 | sqlite3_free(zWidePath); |
| 52927 | 53153 | sqlite3_free(zBuf); |
| 52928 | 53154 | OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); |
| 52929 | 53155 | return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(), |
| 52930 | 53156 | "winGetTempname2", 0); |
| @@ -53723,37 +53949,37 @@ | ||
| 53723 | 53949 | /* |
| 53724 | 53950 | ** Interfaces for opening a shared library, finding entry points |
| 53725 | 53951 | ** within the shared library, and closing the shared library. |
| 53726 | 53952 | */ |
| 53727 | 53953 | static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
| 53728 | - HANDLE h; | |
| 53954 | + HANDLE h = 0; | |
| 53729 | 53955 | void *zConverted = winConvertFromUtf8Filename(zFilename); |
| 53730 | 53956 | UNUSED_PARAMETER(pVfs); |
| 53731 | 53957 | if( zConverted==0 ){ |
| 53732 | 53958 | OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); |
| 53733 | 53959 | return 0; |
| 53734 | 53960 | } |
| 53735 | - h = osLoadLibraryW((LPCWSTR)zConverted); | |
| 53961 | + h = osLoadLibraryW ? osLoadLibraryW((LPCWSTR)zConverted) : 0; | |
| 53736 | 53962 | OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h)); |
| 53737 | 53963 | sqlite3_free(zConverted); |
| 53738 | 53964 | return (void*)h; |
| 53739 | 53965 | } |
| 53740 | 53966 | static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ |
| 53741 | 53967 | UNUSED_PARAMETER(pVfs); |
| 53742 | 53968 | winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); |
| 53743 | 53969 | } |
| 53744 | 53970 | static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ |
| 53745 | - FARPROC proc; | |
| 53971 | + FARPROC proc = 0; | |
| 53746 | 53972 | UNUSED_PARAMETER(pVfs); |
| 53747 | - proc = osGetProcAddressA((HANDLE)pH, zSym); | |
| 53973 | + proc = osGetProcAddressA ? osGetProcAddressA((HANDLE)pH, zSym) : 0; | |
| 53748 | 53974 | OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n", |
| 53749 | 53975 | (void*)pH, zSym, (void*)proc)); |
| 53750 | 53976 | return (void(*)(void))proc; |
| 53751 | 53977 | } |
| 53752 | 53978 | static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ |
| 53753 | 53979 | UNUSED_PARAMETER(pVfs); |
| 53754 | - osFreeLibrary((HANDLE)pHandle); | |
| 53980 | + if( osFreeLibrary!=0 ) osFreeLibrary((HANDLE)pHandle); | |
| 53755 | 53981 | OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle)); |
| 53756 | 53982 | } |
| 53757 | 53983 | #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ |
| 53758 | 53984 | #define winDlOpen 0 |
| 53759 | 53985 | #define winDlError 0 |
| @@ -53798,36 +54024,39 @@ | ||
| 53798 | 54024 | e.a = (unsigned char*)zBuf; |
| 53799 | 54025 | e.na = nBuf; |
| 53800 | 54026 | e.nXor = 0; |
| 53801 | 54027 | e.i = 0; |
| 53802 | 54028 | { |
| 53803 | - SYSTEMTIME x; | |
| 53804 | - osGetSystemTime(&x); | |
| 53805 | - xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME)); | |
| 54029 | + FILETIME x; | |
| 54030 | + osGetSystemTimeAsFileTime(&x); | |
| 54031 | + xorMemory(&e, (unsigned char*)&x, sizeof(x)); | |
| 53806 | 54032 | } |
| 53807 | 54033 | { |
| 53808 | 54034 | DWORD pid = osGetCurrentProcessId(); |
| 53809 | - xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); | |
| 54035 | + xorMemory(&e, (unsigned char*)&pid, sizeof(pid)); | |
| 53810 | 54036 | } |
| 53811 | 54037 | { |
| 53812 | - DWORD cnt = osGetTickCount(); | |
| 53813 | - xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); | |
| 54038 | + ULONGLONG cnt = osGetTickCount64(); | |
| 54039 | + xorMemory(&e, (unsigned char*)&cnt, sizeof(cnt)); | |
| 53814 | 54040 | } |
| 53815 | 54041 | { |
| 53816 | 54042 | LARGE_INTEGER i; |
| 53817 | 54043 | osQueryPerformanceCounter(&i); |
| 53818 | - xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); | |
| 54044 | + xorMemory(&e, (unsigned char*)&i, sizeof(i)); | |
| 53819 | 54045 | } |
| 53820 | 54046 | #if SQLITE_WIN32_USE_UUID |
| 54047 | +#ifdef SQLITE_UWP | |
| 54048 | +# error SQLITE_WIN32_USE_UUID is incompatible with SQLITE_UWP | |
| 54049 | +#endif | |
| 53821 | 54050 | { |
| 53822 | 54051 | UUID id; |
| 53823 | - memset(&id, 0, sizeof(UUID)); | |
| 54052 | + memset(&id, 0, sizeof(id)); | |
| 53824 | 54053 | osUuidCreate(&id); |
| 53825 | - xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); | |
| 54054 | + xorMemory(&e, (unsigned char*)&id, sizeof(id)); | |
| 53826 | 54055 | memset(&id, 0, sizeof(UUID)); |
| 53827 | 54056 | osUuidCreateSequential(&id); |
| 53828 | - xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); | |
| 54057 | + xorMemory(&e, (unsigned char*)&id, sizeof(id)); | |
| 53829 | 54058 | } |
| 53830 | 54059 | #endif /* SQLITE_WIN32_USE_UUID */ |
| 53831 | 54060 | return e.nXor>nBuf ? nBuf : e.nXor; |
| 53832 | 54061 | #endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ |
| 53833 | 54062 | } |
| @@ -54042,15 +54271,19 @@ | ||
| 54042 | 54271 | winNextSystemCall, /* xNextSystemCall */ |
| 54043 | 54272 | }; |
| 54044 | 54273 | |
| 54045 | 54274 | /* Double-check that the aSyscall[] array has been constructed |
| 54046 | 54275 | ** correctly. See ticket [bb3a86e890c8e96ab] */ |
| 54047 | - assert( ArraySize(aSyscall)==58 ); | |
| 54276 | + assert( ArraySize(aSyscall)==59 ); | |
| 54048 | 54277 | assert( strcmp(aSyscall[0].zName,"AreFileApisANSI")==0 ); |
| 54049 | - assert( strcmp(aSyscall[20].zName,"HeapAlloc")==0 ); | |
| 54050 | - assert( strcmp(aSyscall[40].zName,"WideCharToMultiByte")==0 ); | |
| 54051 | - assert( strcmp(aSyscall[57].zName,"cygwin_conv_path")==0 ); | |
| 54278 | + assert( strcmp(aSyscall[8].zName,"FreeLibrary")==0 ); | |
| 54279 | + assert( strcmp(aSyscall[16].zName,"GetSystemInfo")==0 ); | |
| 54280 | + assert( strcmp(aSyscall[24].zName,"HeapReAlloc")==0 ); | |
| 54281 | + assert( strcmp(aSyscall[32].zName,"MapViewOfFileFromApp")==0 ); | |
| 54282 | + assert( strcmp(aSyscall[40].zName,"UnmapViewOfFile")==0 ); | |
| 54283 | + assert( strcmp(aSyscall[48].zName,"UuidCreate")==0 ); | |
| 54284 | + assert( strcmp(aSyscall[56].zName,"lstat")==0 ); | |
| 54052 | 54285 | |
| 54053 | 54286 | /* get memory map allocation granularity */ |
| 54054 | 54287 | memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); |
| 54055 | 54288 | osGetSystemInfo(&winSysInfo); |
| 54056 | 54289 | assert( winSysInfo.dwAllocationGranularity>0 ); |
| @@ -56762,26 +56995,28 @@ | ||
| 56762 | 56995 | szBulk = -1024 * (i64)pcache1.nInitPage; |
| 56763 | 56996 | } |
| 56764 | 56997 | if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){ |
| 56765 | 56998 | szBulk = pCache->szAlloc*(i64)pCache->nMax; |
| 56766 | 56999 | } |
| 56767 | - zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); | |
| 56768 | - sqlite3EndBenignMalloc(); | |
| 56769 | - if( zBulk ){ | |
| 56770 | - int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; | |
| 56771 | - do{ | |
| 56772 | - PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; | |
| 56773 | - pX->page.pBuf = zBulk; | |
| 56774 | - pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); | |
| 56775 | - assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); | |
| 56776 | - pX->isBulkLocal = 1; | |
| 56777 | - pX->isAnchor = 0; | |
| 56778 | - pX->pNext = pCache->pFree; | |
| 56779 | - pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ | |
| 56780 | - pCache->pFree = pX; | |
| 56781 | - zBulk += pCache->szAlloc; | |
| 56782 | - }while( --nBulk ); | |
| 57000 | + if( szBulk>=pCache->szAlloc ){ | |
| 57001 | + zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); | |
| 57002 | + sqlite3EndBenignMalloc(); | |
| 57003 | + if( zBulk ){ | |
| 57004 | + int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; | |
| 57005 | + do{ | |
| 57006 | + PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; | |
| 57007 | + pX->page.pBuf = zBulk; | |
| 57008 | + pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); | |
| 57009 | + assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); | |
| 57010 | + pX->isBulkLocal = 1; | |
| 57011 | + pX->isAnchor = 0; | |
| 57012 | + pX->pNext = pCache->pFree; | |
| 57013 | + pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ | |
| 57014 | + pCache->pFree = pX; | |
| 57015 | + zBulk += pCache->szAlloc; | |
| 57016 | + }while( --nBulk ); | |
| 57017 | + } | |
| 56783 | 57018 | } |
| 56784 | 57019 | return pCache->pFree!=0; |
| 56785 | 57020 | } |
| 56786 | 57021 | |
| 56787 | 57022 | /* |
| @@ -59675,73 +59910,84 @@ | ||
| 59675 | 59910 | #define pager_set_pagehash(X) |
| 59676 | 59911 | #define CHECK_PAGE(x) |
| 59677 | 59912 | #endif /* SQLITE_CHECK_PAGES */ |
| 59678 | 59913 | |
| 59679 | 59914 | /* |
| 59680 | -** When this is called the journal file for pager pPager must be open. | |
| 59681 | -** This function attempts to read a super-journal file name from the | |
| 59682 | -** end of the file and, if successful, copies it into memory supplied | |
| 59683 | -** by the caller. See comments above writeSuperJournal() for the format | |
| 59684 | -** used to store a super-journal file name at the end of a journal file. | |
| 59685 | -** | |
| 59686 | -** zSuper must point to a buffer of at least nSuper bytes allocated by | |
| 59687 | -** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is | |
| 59688 | -** enough space to write the super-journal name). If the super-journal | |
| 59689 | -** name in the journal is longer than nSuper bytes (including a | |
| 59690 | -** nul-terminator), then this is handled as if no super-journal name | |
| 59691 | -** were present in the journal. | |
| 59692 | -** | |
| 59693 | -** If a super-journal file name is present at the end of the journal | |
| 59694 | -** file, then it is copied into the buffer pointed to by zSuper. A | |
| 59695 | -** nul-terminator byte is appended to the buffer following the | |
| 59696 | -** super-journal file name. | |
| 59697 | -** | |
| 59698 | -** If it is determined that no super-journal file name is present | |
| 59699 | -** zSuper[0] is set to 0 and SQLITE_OK returned. | |
| 59700 | -** | |
| 59701 | -** If an error occurs while reading from the journal file, an SQLite | |
| 59702 | -** error code is returned. | |
| 59703 | -*/ | |
| 59704 | -static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){ | |
| 59915 | +** Free a buffer allocated by the readSuperJournal() function. | |
| 59916 | +*/ | |
| 59917 | +static void freeSuperJournal(char *zSuper){ | |
| 59918 | + if( zSuper ){ | |
| 59919 | + sqlite3_free(&zSuper[-4]); | |
| 59920 | + } | |
| 59921 | +} | |
| 59922 | + | |
| 59923 | +/* | |
| 59924 | +** Parameter pJrnl is a file-handle open on a journal file. This function | |
| 59925 | +** attempts to read a super-journal file name from the end of the journal | |
| 59926 | +** file. If successful, it sets output parameter (*pzSuper) to point to a | |
| 59927 | +** buffer containing the super-journal name as a nul-terminated string. | |
| 59928 | +** The caller is responsible for freeing the buffer using freeSuperJournal(). | |
| 59929 | +** | |
| 59930 | +** Refer to comments above writeSuperJournal() for the format used to store | |
| 59931 | +** a super-journal file name at the end of a journal file. | |
| 59932 | +** | |
| 59933 | +** Parameter nSuper is passed the maximum allowable size of the super journal | |
| 59934 | +** name in bytes. If the super-journal name in the journal is longer than | |
| 59935 | +** nSuper bytes (including a nul-terminator), then this is handled as if no | |
| 59936 | +** super-journal name were present in the journal. | |
| 59937 | +** | |
| 59938 | +** If there is no super-journal name at the end of pJrnl, (*pzSuper) is | |
| 59939 | +** set to 0 and SQLITE_OK is returned. Or, if an error occurs while reading | |
| 59940 | +** the super-journal name, an SQLite error code is returned and (*pzSuper) | |
| 59941 | +** is set to 0. | |
| 59942 | +*/ | |
| 59943 | +static int readSuperJournal(sqlite3_file *pJrnl, u64 nSuper, char **pzSuper){ | |
| 59705 | 59944 | int rc; /* Return code */ |
| 59706 | 59945 | u32 len; /* Length in bytes of super-journal name */ |
| 59707 | 59946 | i64 szJ; /* Total size in bytes of journal file pJrnl */ |
| 59708 | 59947 | u32 cksum; /* MJ checksum value read from journal */ |
| 59709 | - u32 u; /* Unsigned loop counter */ | |
| 59710 | 59948 | unsigned char aMagic[8]; /* A buffer to hold the magic header */ |
| 59711 | - zSuper[0] = '\0'; | |
| 59949 | + char *zOut = 0; | |
| 59712 | 59950 | |
| 59951 | + *pzSuper = 0; | |
| 59713 | 59952 | if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) |
| 59714 | 59953 | || szJ<16 |
| 59715 | 59954 | || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) |
| 59716 | 59955 | || len>=nSuper |
| 59717 | 59956 | || len>szJ-16 |
| 59718 | 59957 | || len==0 |
| 59719 | 59958 | || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) |
| 59720 | 59959 | || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) |
| 59721 | 59960 | || memcmp(aMagic, aJournalMagic, 8) |
| 59722 | - || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len)) | |
| 59723 | 59961 | ){ |
| 59724 | 59962 | return rc; |
| 59725 | 59963 | } |
| 59726 | 59964 | |
| 59727 | - /* See if the checksum matches the super-journal name */ | |
| 59728 | - for(u=0; u<len; u++){ | |
| 59729 | - cksum -= zSuper[u]; | |
| 59730 | - } | |
| 59731 | - if( cksum ){ | |
| 59732 | - /* If the checksum doesn't add up, then one or more of the disk sectors | |
| 59733 | - ** containing the super-journal filename is corrupted. This means | |
| 59734 | - ** definitely roll back, so just return SQLITE_OK and report a (nul) | |
| 59735 | - ** super-journal filename. | |
| 59736 | - */ | |
| 59737 | - len = 0; | |
| 59738 | - } | |
| 59739 | - zSuper[len] = '\0'; | |
| 59740 | - zSuper[len+1] = '\0'; | |
| 59741 | - | |
| 59742 | - return SQLITE_OK; | |
| 59965 | + zOut = (char*)sqlite3MallocZero(4 + len + 2); | |
| 59966 | + if( !zOut ){ | |
| 59967 | + rc = SQLITE_NOMEM_BKPT; | |
| 59968 | + }else{ | |
| 59969 | + zOut = &zOut[4]; | |
| 59970 | + if( SQLITE_OK==(rc = sqlite3OsRead(pJrnl, zOut, len, szJ-16-len)) ){ | |
| 59971 | + u32 u; /* Unsigned loop counter */ | |
| 59972 | + /* See if the checksum matches the super-journal name */ | |
| 59973 | + for(u=0; u<len; u++){ | |
| 59974 | + cksum -= zOut[u]; | |
| 59975 | + } | |
| 59976 | + } | |
| 59977 | + if( rc!=SQLITE_OK || cksum ){ | |
| 59978 | + /* If the checksum doesn't add up, then one or more of the disk sectors | |
| 59979 | + ** containing the super-journal filename is corrupted. This means | |
| 59980 | + ** definitely roll back, so just return SQLITE_OK and report a (nul) | |
| 59981 | + ** super-journal filename. */ | |
| 59982 | + freeSuperJournal(zOut); | |
| 59983 | + zOut = 0; | |
| 59984 | + } | |
| 59985 | + } | |
| 59986 | + | |
| 59987 | + *pzSuper = zOut; | |
| 59988 | + return rc; | |
| 59743 | 59989 | } |
| 59744 | 59990 | |
| 59745 | 59991 | /* |
| 59746 | 59992 | ** Return the offset of the sector boundary at or immediately |
| 59747 | 59993 | ** following the value in pPager->journalOff, assuming a sector |
| @@ -60942,13 +61188,11 @@ | ||
| 60942 | 61188 | sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */ |
| 60943 | 61189 | sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */ |
| 60944 | 61190 | char *zSuperJournal = 0; /* Contents of super-journal file */ |
| 60945 | 61191 | i64 nSuperJournal; /* Size of super-journal file */ |
| 60946 | 61192 | char *zJournal; /* Pointer to one journal within MJ file */ |
| 60947 | - char *zSuperPtr; /* Space to hold super-journal filename */ | |
| 60948 | 61193 | char *zFree = 0; /* Free this buffer */ |
| 60949 | - i64 nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ | |
| 60950 | 61194 | |
| 60951 | 61195 | /* Allocate space for both the pJournal and pSuper file descriptors. |
| 60952 | 61196 | ** If successful, open the super-journal file for reading. |
| 60953 | 61197 | */ |
| 60954 | 61198 | pSuper = (sqlite3_file *)sqlite3MallocZero(2 * (i64)pVfs->szOsFile); |
| @@ -60967,22 +61211,20 @@ | ||
| 60967 | 61211 | ** sufficient space (in zSuperPtr) to hold the names of super-journal |
| 60968 | 61212 | ** files extracted from regular rollback-journals. |
| 60969 | 61213 | */ |
| 60970 | 61214 | rc = sqlite3OsFileSize(pSuper, &nSuperJournal); |
| 60971 | 61215 | if( rc!=SQLITE_OK ) goto delsuper_out; |
| 60972 | - nSuperPtr = 1 + (i64)pVfs->mxPathname; | |
| 60973 | - assert( nSuperJournal>=0 && nSuperPtr>0 ); | |
| 60974 | - zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); | |
| 61216 | + assert( nSuperJournal>=0 ); | |
| 61217 | + zFree = sqlite3Malloc(4 + nSuperJournal + 2); | |
| 60975 | 61218 | if( !zFree ){ |
| 60976 | 61219 | rc = SQLITE_NOMEM_BKPT; |
| 60977 | 61220 | goto delsuper_out; |
| 60978 | 61221 | }else{ |
| 60979 | 61222 | assert( nSuperJournal<=0x7fffffff ); |
| 60980 | 61223 | } |
| 60981 | 61224 | zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; |
| 60982 | 61225 | zSuperJournal = &zFree[4]; |
| 60983 | - zSuperPtr = &zSuperJournal[nSuperJournal+2]; | |
| 60984 | 61226 | rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0); |
| 60985 | 61227 | if( rc!=SQLITE_OK ) goto delsuper_out; |
| 60986 | 61228 | zSuperJournal[nSuperJournal] = 0; |
| 60987 | 61229 | zSuperJournal[nSuperJournal+1] = 0; |
| 60988 | 61230 | |
| @@ -60992,10 +61234,12 @@ | ||
| 60992 | 61234 | rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists); |
| 60993 | 61235 | if( rc!=SQLITE_OK ){ |
| 60994 | 61236 | goto delsuper_out; |
| 60995 | 61237 | } |
| 60996 | 61238 | if( exists ){ |
| 61239 | + char *zSuperPtr = 0; | |
| 61240 | + | |
| 60997 | 61241 | /* One of the journals pointed to by the super-journal exists. |
| 60998 | 61242 | ** Open it and check if it points at the super-journal. If |
| 60999 | 61243 | ** so, return without deleting the super-journal file. |
| 61000 | 61244 | ** NB: zJournal is really a MAIN_JOURNAL. But call it a |
| 61001 | 61245 | ** SUPER_JOURNAL here so that the VFS will not send the zJournal |
| @@ -61006,17 +61250,19 @@ | ||
| 61006 | 61250 | rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); |
| 61007 | 61251 | if( rc!=SQLITE_OK ){ |
| 61008 | 61252 | goto delsuper_out; |
| 61009 | 61253 | } |
| 61010 | 61254 | |
| 61011 | - rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr); | |
| 61255 | + rc = readSuperJournal(pJournal, 1+(u64)pVfs->mxPathname, &zSuperPtr); | |
| 61012 | 61256 | sqlite3OsClose(pJournal); |
| 61013 | 61257 | if( rc!=SQLITE_OK ){ |
| 61258 | + assert( zSuperPtr==0 ); | |
| 61014 | 61259 | goto delsuper_out; |
| 61015 | 61260 | } |
| 61016 | 61261 | |
| 61017 | - c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0; | |
| 61262 | + c = zSuperPtr!=0 && strcmp(zSuperPtr, zSuper)==0; | |
| 61263 | + freeSuperJournal(zSuperPtr); | |
| 61018 | 61264 | if( c ){ |
| 61019 | 61265 | /* We have a match. Do not delete the super-journal file. */ |
| 61020 | 61266 | goto delsuper_out; |
| 61021 | 61267 | } |
| 61022 | 61268 | } |
| @@ -61227,23 +61473,15 @@ | ||
| 61227 | 61473 | |
| 61228 | 61474 | /* Read the super-journal name from the journal, if it is present. |
| 61229 | 61475 | ** If a super-journal file name is specified, but the file is not |
| 61230 | 61476 | ** present on disk, then the journal is not hot and does not need to be |
| 61231 | 61477 | ** played back. |
| 61232 | - ** | |
| 61233 | - ** TODO: Technically the following is an error because it assumes that | |
| 61234 | - ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that | |
| 61235 | - ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c, | |
| 61236 | - ** mxPathname is 512, which is the same as the minimum allowable value | |
| 61237 | - ** for pageSize. | |
| 61238 | 61478 | */ |
| 61239 | - zSuper = pPager->pTmpSpace; | |
| 61240 | - rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); | |
| 61241 | - if( rc==SQLITE_OK && zSuper[0] ){ | |
| 61479 | + rc = readSuperJournal(pPager->jfd, 1+(i64)pPager->pVfs->mxPathname, &zSuper); | |
| 61480 | + if( rc==SQLITE_OK && zSuper ){ | |
| 61242 | 61481 | rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); |
| 61243 | 61482 | } |
| 61244 | - zSuper = 0; | |
| 61245 | 61483 | if( rc!=SQLITE_OK || !res ){ |
| 61246 | 61484 | goto end_playback; |
| 61247 | 61485 | } |
| 61248 | 61486 | pPager->journalOff = 0; |
| 61249 | 61487 | needPagerReset = isHot; |
| @@ -61368,34 +61606,24 @@ | ||
| 61368 | 61606 | ** problems for other processes at some point in the future. So, just |
| 61369 | 61607 | ** in case this has happened, clear the changeCountDone flag now. |
| 61370 | 61608 | */ |
| 61371 | 61609 | pPager->changeCountDone = pPager->tempFile; |
| 61372 | 61610 | |
| 61373 | - if( rc==SQLITE_OK ){ | |
| 61374 | - /* Leave 4 bytes of space before the super-journal filename in memory. | |
| 61375 | - ** This is because it may end up being passed to sqlite3OsOpen(), in | |
| 61376 | - ** which case it requires 4 0x00 bytes in memory immediately before | |
| 61377 | - ** the filename. */ | |
| 61378 | - zSuper = &pPager->pTmpSpace[4]; | |
| 61379 | - rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); | |
| 61380 | - testcase( rc!=SQLITE_OK ); | |
| 61381 | - } | |
| 61382 | 61611 | if( rc==SQLITE_OK |
| 61383 | 61612 | && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) |
| 61384 | 61613 | ){ |
| 61385 | 61614 | rc = sqlite3PagerSync(pPager, 0); |
| 61386 | 61615 | } |
| 61387 | 61616 | if( rc==SQLITE_OK ){ |
| 61388 | - rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0); | |
| 61617 | + rc = pager_end_transaction(pPager, zSuper!=0, 0); | |
| 61389 | 61618 | testcase( rc!=SQLITE_OK ); |
| 61390 | 61619 | } |
| 61391 | - if( rc==SQLITE_OK && zSuper[0] && res ){ | |
| 61620 | + if( rc==SQLITE_OK && zSuper && res ){ | |
| 61392 | 61621 | /* If there was a super-journal and this routine will return success, |
| 61393 | 61622 | ** see if it is possible to delete the super-journal. |
| 61394 | 61623 | */ |
| 61395 | - assert( zSuper==&pPager->pTmpSpace[4] ); | |
| 61396 | - memset(pPager->pTmpSpace, 0, 4); | |
| 61624 | + assert( memcmp(&zSuper[-4], "\0\0\0\0", 4)==0 ); | |
| 61397 | 61625 | rc = pager_delsuper(pPager, zSuper); |
| 61398 | 61626 | testcase( rc!=SQLITE_OK ); |
| 61399 | 61627 | } |
| 61400 | 61628 | if( isHot && nPlayback ){ |
| 61401 | 61629 | sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", |
| @@ -61404,10 +61632,11 @@ | ||
| 61404 | 61632 | |
| 61405 | 61633 | /* The Pager.sectorSize variable may have been updated while rolling |
| 61406 | 61634 | ** back a journal created by a process with a different sector size |
| 61407 | 61635 | ** value. Reset it to the correct value for this process. |
| 61408 | 61636 | */ |
| 61637 | + freeSuperJournal(zSuper); | |
| 61409 | 61638 | setSectorSize(pPager); |
| 61410 | 61639 | return rc; |
| 61411 | 61640 | } |
| 61412 | 61641 | |
| 61413 | 61642 | |
| @@ -67262,10 +67491,16 @@ | ||
| 67262 | 67491 | */ |
| 67263 | 67492 | pgno = sqlite3Get4byte(&aFrame[0]); |
| 67264 | 67493 | if( pgno==0 ){ |
| 67265 | 67494 | return 0; |
| 67266 | 67495 | } |
| 67496 | + | |
| 67497 | + /* Need a valid page size | |
| 67498 | + */ | |
| 67499 | + if( !pWal->szPage ){ | |
| 67500 | + return 0; | |
| 67501 | + } | |
| 67267 | 67502 | |
| 67268 | 67503 | /* A frame is only valid if a checksum of the WAL header, |
| 67269 | 67504 | ** all prior frames, the first 16 bytes of this frame-header, |
| 67270 | 67505 | ** and the frame-data matches the checksum in the last 8 |
| 67271 | 67506 | ** bytes of this frame-header. |
| @@ -69117,11 +69352,11 @@ | ||
| 69117 | 69352 | goto begin_unreliable_shm_out; |
| 69118 | 69353 | } |
| 69119 | 69354 | |
| 69120 | 69355 | /* Allocate a buffer to read frames into */ |
| 69121 | 69356 | assert( (pWal->szPage & (pWal->szPage-1))==0 ); |
| 69122 | - assert( pWal->szPage>=512 && pWal->szPage<=65536 ); | |
| 69357 | + assert( (pWal->szPage>=512 && pWal->szPage<=65536) || pWal->szPage==0 ); | |
| 69123 | 69358 | szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; |
| 69124 | 69359 | aFrame = (u8 *)sqlite3_malloc64(szFrame); |
| 69125 | 69360 | if( aFrame==0 ){ |
| 69126 | 69361 | rc = SQLITE_NOMEM_BKPT; |
| 69127 | 69362 | goto begin_unreliable_shm_out; |
| @@ -71953,10 +72188,20 @@ | ||
| 71953 | 72188 | ** See the header comment on "btreeInt.h" for additional information. |
| 71954 | 72189 | ** Including a description of file format and an overview of operation. |
| 71955 | 72190 | */ |
| 71956 | 72191 | /* #include "btreeInt.h" */ |
| 71957 | 72192 | |
| 72193 | +/* | |
| 72194 | +** Suppress false-positive compiler warnings from GCC. Warnings are | |
| 72195 | +** re-enabled at the bottom of this source file. | |
| 72196 | +*/ | |
| 72197 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 72198 | +# pragma GCC diagnostic push | |
| 72199 | +# pragma GCC diagnostic ignored "-Wstringop-overread" | |
| 72200 | +# pragma GCC diagnostic ignored "-Wstringop-overflow" | |
| 72201 | +#endif | |
| 72202 | + | |
| 71958 | 72203 | /* |
| 71959 | 72204 | ** The header string that appears at the beginning of every |
| 71960 | 72205 | ** SQLite database. |
| 71961 | 72206 | */ |
| 71962 | 72207 | static const char zMagicHeader[] = SQLITE_FILE_HEADER; |
| @@ -77123,11 +77368,13 @@ | ||
| 77123 | 77368 | ** in the overflow chain. The page number of the first overflow page is |
| 77124 | 77369 | ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array |
| 77125 | 77370 | ** means "not yet known" (the cache is lazily populated). |
| 77126 | 77371 | */ |
| 77127 | 77372 | if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ |
| 77128 | - int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; | |
| 77373 | + i64 nOvfl = pCur->info.nPayload; | |
| 77374 | + testcase( nOvfl - pCur->info.nLocal + ovflSize - 1 > 0xffffffffU ); | |
| 77375 | + nOvfl = (nOvfl - pCur->info.nLocal + ovflSize-1)/ovflSize; | |
| 77129 | 77376 | if( pCur->aOverflow==0 |
| 77130 | 77377 | || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) |
| 77131 | 77378 | ){ |
| 77132 | 77379 | Pgno *aNew; |
| 77133 | 77380 | if( sqlite3FaultSim(413) ){ |
| @@ -77228,10 +77475,18 @@ | ||
| 77228 | 77475 | DbPage *pDbPage; |
| 77229 | 77476 | rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage, |
| 77230 | 77477 | (eOp==0 ? PAGER_GET_READONLY : 0) |
| 77231 | 77478 | ); |
| 77232 | 77479 | if( rc==SQLITE_OK ){ |
| 77480 | + if( eOp!=0 | |
| 77481 | + && (sqlite3PagerPageRefcount(pDbPage)!=1 | |
| 77482 | + || NEVER(((MemPage*)sqlite3PagerGetExtra(pDbPage))->isInit)) | |
| 77483 | + && sqlite3FaultSim(411)==SQLITE_OK | |
| 77484 | + ){ | |
| 77485 | + sqlite3PagerUnref(pDbPage); | |
| 77486 | + return SQLITE_CORRUPT_PAGE(pPage); | |
| 77487 | + } | |
| 77233 | 77488 | aPayload = sqlite3PagerGetData(pDbPage); |
| 77234 | 77489 | nextPage = get4byte(aPayload); |
| 77235 | 77490 | rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); |
| 77236 | 77491 | sqlite3PagerUnref(pDbPage); |
| 77237 | 77492 | offset = 0; |
| @@ -82902,10 +83157,15 @@ | ||
| 82902 | 83157 | if( pc+info.nSize>usableSize ){ |
| 82903 | 83158 | checkAppendMsg(pCheck, "Extends off end of page"); |
| 82904 | 83159 | doCoverageCheck = 0; |
| 82905 | 83160 | continue; |
| 82906 | 83161 | } |
| 83162 | + if( info.nPayload && info.pPayload[0]<2 ){ | |
| 83163 | + checkAppendMsg(pCheck, "Bad cell header size"); | |
| 83164 | + doCoverageCheck = 0; | |
| 83165 | + continue; | |
| 83166 | + } | |
| 82907 | 83167 | |
| 82908 | 83168 | /* Check for integer primary key out of range */ |
| 82909 | 83169 | if( pPage->intKey ){ |
| 82910 | 83170 | if( keyCanBeEqual ? (info.nKey > maxKey) : (info.nKey >= maxKey) ){ |
| 82911 | 83171 | checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey); |
| @@ -83504,10 +83764,17 @@ | ||
| 83504 | 83764 | SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ |
| 83505 | 83765 | testcase( p->sharable ); |
| 83506 | 83766 | return p->pBt->nRef; |
| 83507 | 83767 | } |
| 83508 | 83768 | #endif |
| 83769 | + | |
| 83770 | +/* Re-enable GCC compiler warnings that were suppressed at the top | |
| 83771 | +** of this source file to prevent annoying false-positives. | |
| 83772 | +*/ | |
| 83773 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 83774 | +# pragma GCC diagnostic pop | |
| 83775 | +#endif | |
| 83509 | 83776 | |
| 83510 | 83777 | /************** End of btree.c ***********************************************/ |
| 83511 | 83778 | /************** Begin file backup.c ******************************************/ |
| 83512 | 83779 | /* |
| 83513 | 83780 | ** 2009 January 28 |
| @@ -84405,12 +84672,12 @@ | ||
| 84405 | 84672 | /* Work-around for GCC bug or bugs: |
| 84406 | 84673 | ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 |
| 84407 | 84674 | ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 |
| 84408 | 84675 | ** The problem appears to be fixed in GCC 15 */ |
| 84409 | 84676 | i64 x; |
| 84410 | - assert( (MEM_Str&~p->flags)*4==sizeof(x) ); | |
| 84411 | - memcpy(&x, (char*)&p->u, (MEM_Str&~p->flags)*4); | |
| 84677 | + assert( (sqlite3Config.bSmallMalloc!=0xee)*8==sizeof(x) ); | |
| 84678 | + memcpy(&x, (char*)&p->u.i, (sqlite3Config.bSmallMalloc!=0xee)*8); | |
| 84412 | 84679 | p->n = sqlite3Int64ToText(x, zBuf); |
| 84413 | 84680 | #else |
| 84414 | 84681 | p->n = sqlite3Int64ToText(p->u.i, zBuf); |
| 84415 | 84682 | #endif |
| 84416 | 84683 | if( p->flags & MEM_IntReal ){ |
| @@ -87107,15 +87374,25 @@ | ||
| 87107 | 87374 | /* |
| 87108 | 87375 | ** Add an OP_ParseSchema opcode. This routine is broken out from |
| 87109 | 87376 | ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees |
| 87110 | 87377 | ** as having been used. |
| 87111 | 87378 | ** |
| 87112 | -** The zWhere string must have been obtained from sqlite3_malloc(). | |
| 87379 | +** zWhere is a WHERE clause that defines which entries of the schema | |
| 87380 | +** to reparse. If zWhere==0, that means all entries. p5 is a mask | |
| 87381 | +** of INITFLAG_* values for the parse. | |
| 87382 | +** | |
| 87383 | +** In the current usage, the following are always true: | |
| 87384 | +** | |
| 87385 | +** ALTER TABLE: zWhere==0, p5!=0 | |
| 87386 | +** Otherwise: zWhere!=0, p5==0 | |
| 87387 | +** | |
| 87388 | +** The zWhere string must have been obtained from sqlite3DbMalloc(). | |
| 87113 | 87389 | ** This routine will take ownership of the allocated memory. |
| 87114 | 87390 | */ |
| 87115 | 87391 | SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){ |
| 87116 | 87392 | int j; |
| 87393 | + assert( p5==0 || zWhere==0 ); | |
| 87117 | 87394 | sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); |
| 87118 | 87395 | sqlite3VdbeChangeP5(p, p5); |
| 87119 | 87396 | for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); |
| 87120 | 87397 | sqlite3MayAbort(p->pParse); |
| 87121 | 87398 | } |
| @@ -95247,11 +95524,11 @@ | ||
| 95247 | 95524 | QueryPerformanceCounter(&tm); |
| 95248 | 95525 | return (sqlite3_uint64)tm.QuadPart; |
| 95249 | 95526 | } |
| 95250 | 95527 | |
| 95251 | 95528 | #elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && \ |
| 95252 | - (defined(i386) || defined(__i386__) || defined(_M_IX86)) | |
| 95529 | + (defined(i586) || defined(__i586__) || defined(_M_IX86)) | |
| 95253 | 95530 | |
| 95254 | 95531 | __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
| 95255 | 95532 | unsigned int lo, hi; |
| 95256 | 95533 | __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
| 95257 | 95534 | return (sqlite_uint64)hi << 32 | lo; |
| @@ -95713,14 +95990,16 @@ | ||
| 95713 | 95990 | */ |
| 95714 | 95991 | SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ |
| 95715 | 95992 | int eType = sqlite3_value_type(pVal); |
| 95716 | 95993 | if( eType==SQLITE_TEXT ){ |
| 95717 | 95994 | Mem *pMem = (Mem*)pVal; |
| 95718 | - assert( pMem->db!=0 ); | |
| 95719 | - sqlite3_mutex_enter(pMem->db->mutex); | |
| 95995 | +#if SQLITE_THREADSAFE>0 | |
| 95996 | + sqlite3_mutex *pMutex = pMem->db ? pMem->db->mutex : 0; | |
| 95997 | +#endif | |
| 95998 | + sqlite3_mutex_enter(pMutex); | |
| 95720 | 95999 | applyNumericAffinity(pMem, 0); |
| 95721 | - sqlite3_mutex_leave(pMem->db->mutex); | |
| 96000 | + sqlite3_mutex_leave(pMutex); | |
| 95722 | 96001 | eType = sqlite3_value_type(pVal); |
| 95723 | 96002 | } |
| 95724 | 96003 | return eType; |
| 95725 | 96004 | } |
| 95726 | 96005 | |
| @@ -102423,15 +102702,22 @@ | ||
| 102423 | 102702 | goto abort_due_to_error; |
| 102424 | 102703 | } |
| 102425 | 102704 | break; |
| 102426 | 102705 | } |
| 102427 | 102706 | |
| 102428 | -/* Opcode: ParseSchema P1 * * P4 * | |
| 102707 | +/* Opcode: ParseSchema P1 * * P4 P5 | |
| 102429 | 102708 | ** |
| 102430 | 102709 | ** Read and parse all entries from the schema table of database P1 |
| 102431 | 102710 | ** that match the WHERE clause P4. If P4 is a NULL pointer, then the |
| 102432 | 102711 | ** entire schema for P1 is reparsed. |
| 102712 | +** | |
| 102713 | +** When P4 is NULL, the P5 value is used as the mFlags argument | |
| 102714 | +** to sqlite3InitOne(). In other words, P5 should be a mask composed | |
| 102715 | +** of INITFLAG_* values. | |
| 102716 | +** | |
| 102717 | +** The P4==0 case is only used by ALTER TABLE and P5!=0 for all such | |
| 102718 | +** cases. For uses other than ALTER TABLE, P4<>0 and P5==0. | |
| 102433 | 102719 | ** |
| 102434 | 102720 | ** This opcode invokes the parser to create a new virtual machine, |
| 102435 | 102721 | ** then runs the new virtual machine. It is thus a re-entrant opcode. |
| 102436 | 102722 | */ |
| 102437 | 102723 | case OP_ParseSchema: { |
| @@ -102456,18 +102742,20 @@ | ||
| 102456 | 102742 | || db->mallocFailed |
| 102457 | 102743 | || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) ); |
| 102458 | 102744 | |
| 102459 | 102745 | #ifndef SQLITE_OMIT_ALTERTABLE |
| 102460 | 102746 | if( pOp->p4.z==0 ){ |
| 102747 | + assert( pOp->p5!=0 ); | |
| 102461 | 102748 | sqlite3SchemaClear(db->aDb[iDb].pSchema); |
| 102462 | 102749 | db->mDbFlags &= ~DBFLAG_SchemaKnownOk; |
| 102463 | 102750 | rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5); |
| 102464 | 102751 | db->mDbFlags |= DBFLAG_SchemaChange; |
| 102465 | 102752 | p->expired = 0; |
| 102466 | 102753 | }else |
| 102467 | 102754 | #endif |
| 102468 | 102755 | { |
| 102756 | + assert( pOp->p5==0 ); | |
| 102469 | 102757 | zSchema = LEGACY_SCHEMA_TABLE; |
| 102470 | 102758 | initData.db = db; |
| 102471 | 102759 | initData.iDb = iDb; |
| 102472 | 102760 | initData.pzErrMsg = &p->zErrMsg; |
| 102473 | 102761 | initData.mInitFlags = 0; |
| @@ -102825,11 +103113,11 @@ | ||
| 102825 | 103113 | if( pFrame ) break; |
| 102826 | 103114 | } |
| 102827 | 103115 | |
| 102828 | 103116 | if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ |
| 102829 | 103117 | rc = SQLITE_ERROR; |
| 102830 | - sqlite3VdbeError(p, "too many levels of trigger recursion"); | |
| 103118 | + sqlite3VdbeError(p, "triggers nested too deep"); | |
| 102831 | 103119 | goto abort_due_to_error; |
| 102832 | 103120 | } |
| 102833 | 103121 | |
| 102834 | 103122 | /* Register pRt is used to store the memory required to save the state |
| 102835 | 103123 | ** of the current program, and the memory required at runtime to execute |
| @@ -109952,11 +110240,11 @@ | ||
| 109952 | 110240 | /* |
| 109953 | 110241 | ** cnt==0 means there was not match. |
| 109954 | 110242 | ** cnt>1 means there were two or more matches. |
| 109955 | 110243 | ** |
| 109956 | 110244 | ** cnt==0 is always an error. cnt>1 is often an error, but might |
| 109957 | - ** be multiple matches for a NATURAL LEFT JOIN or a LEFT JOIN USING. | |
| 110245 | + ** be multiple matches for a NATURAL OUTER JOIN or a OUTER JOIN USING. | |
| 109958 | 110246 | */ |
| 109959 | 110247 | assert( pFJMatch==0 || cnt>0 ); |
| 109960 | 110248 | assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); |
| 109961 | 110249 | if( cnt!=1 ){ |
| 109962 | 110250 | const char *zErr; |
| @@ -109972,10 +110260,11 @@ | ||
| 109972 | 110260 | } |
| 109973 | 110261 | extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); |
| 109974 | 110262 | pExpr->op = TK_FUNCTION; |
| 109975 | 110263 | pExpr->u.zToken = "coalesce"; |
| 109976 | 110264 | pExpr->x.pList = pFJMatch; |
| 110265 | + pExpr->affExpr = SQLITE_AFF_DEFER; | |
| 109977 | 110266 | cnt = 1; |
| 109978 | 110267 | goto lookupname_end; |
| 109979 | 110268 | }else{ |
| 109980 | 110269 | sqlite3ExprListDelete(db, pFJMatch); |
| 109981 | 110270 | pFJMatch = 0; |
| @@ -110034,12 +110323,21 @@ | ||
| 110034 | 110323 | pExpr->op = eNewExprOp; |
| 110035 | 110324 | lookupname_end: |
| 110036 | 110325 | if( cnt==1 ){ |
| 110037 | 110326 | assert( pNC!=0 ); |
| 110038 | 110327 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 110039 | - if( db->xAuth && (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER) ){ | |
| 110040 | - sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); | |
| 110328 | + if( db->xAuth ){ | |
| 110329 | + if( pFJMatch ){ | |
| 110330 | + assert( pExpr->op==TK_FUNCTION ); | |
| 110331 | + assert( sqlite3_stricmp(pExpr->u.zToken,"coalesce")==0 ); | |
| 110332 | + assert( pExpr->x.pList==pFJMatch ); | |
| 110333 | + assert( pFJMatch->nExpr>0 ); | |
| 110334 | + pExpr = pFJMatch->a[0].pExpr; | |
| 110335 | + } | |
| 110336 | + if( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ){ | |
| 110337 | + sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); | |
| 110338 | + } | |
| 110041 | 110339 | } |
| 110042 | 110340 | #endif |
| 110043 | 110341 | /* Increment the nRef value on all name contexts from TopNC up to |
| 110044 | 110342 | ** the point where the name matched. */ |
| 110045 | 110343 | for(;;){ |
| @@ -110137,10 +110435,30 @@ | ||
| 110137 | 110435 | sqlite3AtoF(p->u.zToken, &r); |
| 110138 | 110436 | assert( r>=0.0 ); |
| 110139 | 110437 | if( r>1.0 ) return -1; |
| 110140 | 110438 | return (int)(r*134217728.0); |
| 110141 | 110439 | } |
| 110440 | + | |
| 110441 | +/* | |
| 110442 | +** Set the EP_SubtArg property on every expression inside of | |
| 110443 | +** pList. If any subexpression is actually a subquery, then | |
| 110444 | +** also set the EP_SubtArg property on the first result-set | |
| 110445 | +** column of that subquery. | |
| 110446 | +*/ | |
| 110447 | +static SQLITE_NOINLINE void resolveSetExprSubtypeArg(ExprList *pList){ | |
| 110448 | + int nn, ii; | |
| 110449 | + nn = pList ? pList->nExpr : 0; | |
| 110450 | + for(ii=0; ii<nn; ii++){ | |
| 110451 | + Expr *pExpr = pList->a[ii].pExpr; | |
| 110452 | + ExprSetProperty(pExpr, EP_SubtArg); | |
| 110453 | + if( pExpr->op==TK_SELECT ){ | |
| 110454 | + assert( ExprUseXSelect(pExpr) ); | |
| 110455 | + assert( pExpr->x.pSelect!=0 ); | |
| 110456 | + resolveSetExprSubtypeArg(pExpr->x.pSelect->pEList); | |
| 110457 | + } | |
| 110458 | + } | |
| 110459 | +} | |
| 110142 | 110460 | |
| 110143 | 110461 | /* |
| 110144 | 110462 | ** This routine is callback for sqlite3WalkExpr(). |
| 110145 | 110463 | ** |
| 110146 | 110464 | ** Resolve symbolic names into TK_COLUMN operators for the current |
| @@ -110382,14 +110700,11 @@ | ||
| 110382 | 110700 | ** the function may return a value with a subtype back to its |
| 110383 | 110701 | ** caller using sqlite3_result_value(). */ |
| 110384 | 110702 | if( (pDef->funcFlags & SQLITE_SUBTYPE) |
| 110385 | 110703 | || ExprHasProperty(pExpr, EP_SubtArg) |
| 110386 | 110704 | ){ |
| 110387 | - int ii; | |
| 110388 | - for(ii=0; ii<n; ii++){ | |
| 110389 | - ExprSetProperty(pList->a[ii].pExpr, EP_SubtArg); | |
| 110390 | - } | |
| 110705 | + resolveSetExprSubtypeArg(pList); | |
| 110391 | 110706 | } |
| 110392 | 110707 | |
| 110393 | 110708 | if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ |
| 110394 | 110709 | /* For the purposes of the EP_ConstFunc flag, date and time |
| 110395 | 110710 | ** functions and other functions that change slowly are considered |
| @@ -110415,12 +110730,17 @@ | ||
| 110415 | 110730 | && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 |
| 110416 | 110731 | ){ |
| 110417 | 110732 | /* Internal-use-only functions are disallowed unless the |
| 110418 | 110733 | ** SQL is being compiled using sqlite3NestedParse() or |
| 110419 | 110734 | ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be |
| 110420 | - ** used to activate internal functions for testing purposes */ | |
| 110421 | - no_such_func = 1; | |
| 110735 | + ** used to activate internal functions for testing purposes. | |
| 110736 | + ** | |
| 110737 | + ** The 2 value for no_such_func means that the function is | |
| 110738 | + ** an internal-use-only function which should be treated as a | |
| 110739 | + ** non-existant function for name resolution purposes. | |
| 110740 | + */ | |
| 110741 | + no_such_func = 2; | |
| 110422 | 110742 | pDef = 0; |
| 110423 | 110743 | }else |
| 110424 | 110744 | if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 |
| 110425 | 110745 | && !IN_RENAME_OBJECT |
| 110426 | 110746 | ){ |
| @@ -110460,13 +110780,20 @@ | ||
| 110460 | 110780 | sqlite3ErrorMsg(pParse,"misuse of aggregate function %#T()",pExpr); |
| 110461 | 110781 | pNC->nNcErr++; |
| 110462 | 110782 | is_agg = 0; |
| 110463 | 110783 | } |
| 110464 | 110784 | #endif |
| 110465 | - else if( no_such_func && pParse->db->init.busy==0 | |
| 110785 | + else if( no_such_func | |
| 110786 | + && (pParse->db->init.busy==0 || | |
| 110787 | + (no_such_func==2 && pParse->db->init.busy==2)) | |
| 110788 | + /* Suppress "no such function" errors when reading | |
| 110789 | + ** the sqlite_schema table. Except, do raise the error | |
| 110790 | + ** if init.busy is 2, meaning the schema parse is due | |
| 110791 | + ** to an ALTER TABLE ADD COLUMN statement, and the function | |
| 110792 | + ** is an internal-use-only function (no_such_func==2). */ | |
| 110466 | 110793 | #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
| 110467 | - && pParse->explain==0 | |
| 110794 | + && pParse->explain==0 | |
| 110468 | 110795 | #endif |
| 110469 | 110796 | ){ |
| 110470 | 110797 | sqlite3ErrorMsg(pParse, "no such function: %#T", pExpr); |
| 110471 | 110798 | pNC->nNcErr++; |
| 110472 | 110799 | }else if( wrong_num_args ){ |
| @@ -111849,11 +112176,13 @@ | ||
| 111849 | 112176 | ** Return TRUE if the two expressions have equivalent collating sequences. |
| 111850 | 112177 | */ |
| 111851 | 112178 | SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){ |
| 111852 | 112179 | CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); |
| 111853 | 112180 | CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); |
| 111854 | - return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; | |
| 112181 | + assert( (pColl1==pColl2) == | |
| 112182 | + (sqlite3_stricmp(pColl1->zName,pColl2->zName)==0) ); | |
| 112183 | + return pColl1==pColl2; | |
| 111855 | 112184 | } |
| 111856 | 112185 | |
| 111857 | 112186 | /* |
| 111858 | 112187 | ** pExpr is an operand of a comparison operator. aff2 is the |
| 111859 | 112188 | ** type affinity of the other operand. This routine returns the |
| @@ -115686,10 +116015,11 @@ | ||
| 115686 | 116015 | if( i!=nVector ){ |
| 115687 | 116016 | /* Need to reorder the LHS fields according to aiMap */ |
| 115688 | 116017 | int rLhsOrig = rLhs; |
| 115689 | 116018 | rLhs = sqlite3GetTempRange(pParse, nVector); |
| 115690 | 116019 | for(i=0; i<nVector; i++){ |
| 116020 | + testcase( aiMap[i]!=i ); | |
| 115691 | 116021 | sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0); |
| 115692 | 116022 | } |
| 115693 | 116023 | sqlite3ReleaseTempReg(pParse, rLhsOrig); |
| 115694 | 116024 | } |
| 115695 | 116025 | } |
| @@ -115706,11 +116036,12 @@ | ||
| 115706 | 116036 | } |
| 115707 | 116037 | for(i=0; i<nVector; i++){ |
| 115708 | 116038 | Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); |
| 115709 | 116039 | if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; |
| 115710 | 116040 | if( sqlite3ExprCanBeNull(p) ){ |
| 115711 | - sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); | |
| 116041 | + testcase( aiMap[i]!=i ); | |
| 116042 | + sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+aiMap[i], destStep2); | |
| 115712 | 116043 | VdbeCoverage(v); |
| 115713 | 116044 | } |
| 115714 | 116045 | } |
| 115715 | 116046 | |
| 115716 | 116047 | /* Step 3. The LHS is now known to be non-NULL. Do the binary search |
| @@ -115780,13 +116111,23 @@ | ||
| 115780 | 116111 | for(i=0; i<nVector; i++){ |
| 115781 | 116112 | Expr *p; |
| 115782 | 116113 | CollSeq *pColl; |
| 115783 | 116114 | int r3 = sqlite3GetTempReg(pParse); |
| 115784 | 116115 | p = sqlite3VectorFieldSubexpr(pLeft, i); |
| 115785 | - pColl = sqlite3ExprCollSeq(pParse, p); | |
| 115786 | - sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3); | |
| 115787 | - sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, | |
| 116116 | + if( ExprUseXSelect(pExpr) ){ | |
| 116117 | + Expr *pRhs = pExpr->x.pSelect->pEList->a[i].pExpr; | |
| 116118 | + pColl = sqlite3BinaryCompareCollSeq(pParse, p, pRhs); | |
| 116119 | + }else{ | |
| 116120 | + /* If the RHS of the IN(...) expression are scalar expressions, do | |
| 116121 | + ** not consider their collation sequences. The documentation says | |
| 116122 | + ** "The collating sequence used for expressions of the form "x IN (y, z, | |
| 116123 | + ** ...)" is the collating sequence of x.". */ | |
| 116124 | + pColl = sqlite3ExprCollSeq(pParse, p); | |
| 116125 | + } | |
| 116126 | + testcase( aiMap[i]!=i ); | |
| 116127 | + sqlite3VdbeAddOp3(v, OP_Column, iTab, aiMap[i], r3); | |
| 116128 | + sqlite3VdbeAddOp4(v, OP_Ne, rLhs+aiMap[i], destNotNull, r3, | |
| 115788 | 116129 | (void*)pColl, P4_COLLSEQ); |
| 115789 | 116130 | VdbeCoverage(v); |
| 115790 | 116131 | sqlite3ReleaseTempReg(pParse, r3); |
| 115791 | 116132 | } |
| 115792 | 116133 | sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); |
| @@ -116203,40 +116544,51 @@ | ||
| 116203 | 116544 | } |
| 116204 | 116545 | return target; |
| 116205 | 116546 | } |
| 116206 | 116547 | |
| 116207 | 116548 | /* |
| 116208 | -** Expression Node callback for sqlite3ExprCanReturnSubtype(). | |
| 116209 | -** | |
| 116210 | -** Only a function call is able to return a subtype. So if the node | |
| 116211 | -** is not a function call, return WRC_Prune immediately. | |
| 116212 | -** | |
| 116213 | -** A function call is able to return a subtype if it has the | |
| 116214 | -** SQLITE_RESULT_SUBTYPE property. | |
| 116215 | -** | |
| 116216 | -** Assume that every function is able to pass-through a subtype from | |
| 116217 | -** one of its argument (using sqlite3_result_value()). Most functions | |
| 116218 | -** are not this way, but we don't have a mechanism to distinguish those | |
| 116219 | -** that are from those that are not, so assume they all work this way. | |
| 116220 | -** That means that if one of its arguments is another function and that | |
| 116221 | -** other function is able to return a subtype, then this function is | |
| 116222 | -** able to return a subtype. | |
| 116549 | +** Expression Node callback for sqlite3ExprCanReturnSubtype(). If | |
| 116550 | +** pExpr is able to return a subtype, set pWalker->eCode and abort | |
| 116551 | +** the search. If pExpr can never return a subtype, prune search. | |
| 116552 | +** | |
| 116553 | +** The only expressions that can return a subtype are: | |
| 116554 | +** | |
| 116555 | +** 1. A function | |
| 116556 | +** 2. The no-op "+" operator | |
| 116557 | +** 3. A CASE...END expression | |
| 116558 | +** 4. A CAST() expression | |
| 116559 | +** 5. A "expr COLLATE colseq" expression. | |
| 116560 | +** | |
| 116561 | +** For any other kind of expression, prune the search. | |
| 116562 | +** | |
| 116563 | +** For case 1, the expression can yield a subtype if the function has | |
| 116564 | +** the SQLITE_RESULT_SUBTYPE property. Functions can also return | |
| 116565 | +** a subtype (via sqlite3_result_value()) if any of the arguments can | |
| 116566 | +** return a subtype. | |
| 116567 | +** | |
| 116568 | +** In all cases 1 through 5, the expression might also return a subtype | |
| 116569 | +** if any operand can return a subtype. | |
| 116223 | 116570 | */ |
| 116224 | 116571 | static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ |
| 116225 | 116572 | int n; |
| 116226 | 116573 | FuncDef *pDef; |
| 116227 | 116574 | sqlite3 *db; |
| 116575 | + if( pExpr->op==TK_CASE || pExpr->op==TK_UPLUS | |
| 116576 | + || pExpr->op==TK_COLLATE || pExpr->op==TK_CAST | |
| 116577 | + ){ | |
| 116578 | + return WRC_Continue; | |
| 116579 | + } | |
| 116228 | 116580 | if( pExpr->op!=TK_FUNCTION ){ |
| 116229 | 116581 | return WRC_Prune; |
| 116230 | 116582 | } |
| 116231 | 116583 | assert( ExprUseXList(pExpr) ); |
| 116232 | 116584 | db = pWalker->pParse->db; |
| 116233 | 116585 | n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; |
| 116234 | 116586 | pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); |
| 116235 | 116587 | if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ |
| 116236 | 116588 | pWalker->eCode = 1; |
| 116237 | - return WRC_Prune; | |
| 116589 | + return WRC_Abort; | |
| 116238 | 116590 | } |
| 116239 | 116591 | return WRC_Continue; |
| 116240 | 116592 | } |
| 116241 | 116593 | |
| 116242 | 116594 | /* |
| @@ -122210,23 +122562,35 @@ | ||
| 122210 | 122562 | SQLITE_PRIVATE void sqlite3AlterAddConstraint( |
| 122211 | 122563 | Parse *pParse, /* Parse context */ |
| 122212 | 122564 | SrcList *pSrc, /* Table to add constraint to */ |
| 122213 | 122565 | Token *pFirst, /* First token of new constraint */ |
| 122214 | 122566 | Token *pName, /* Name of new constraint. NULL if name omitted. */ |
| 122215 | - const char *pExpr, /* Text of CHECK expression */ | |
| 122216 | - int nExpr /* Size of pExpr in bytes */ | |
| 122567 | + const char *zExpr, /* Text of CHECK expression */ | |
| 122568 | + int nExpr, /* Size of pExpr in bytes */ | |
| 122569 | + Expr *pExpr /* The parsed CHECK expression */ | |
| 122217 | 122570 | ){ |
| 122218 | 122571 | Table *pTab = 0; /* Table identified by pSrc */ |
| 122219 | 122572 | int iDb = 0; /* Which schema does pTab live in */ |
| 122220 | 122573 | const char *zDb = 0; /* Name of the schema in which pTab lives */ |
| 122221 | 122574 | const char *pCons = 0; /* Text of the constraint */ |
| 122222 | 122575 | int nCons; /* Bytes of text to use from pCons[] */ |
| 122576 | + int rc; /* Result from error checking pExpr */ | |
| 122223 | 122577 | |
| 122224 | 122578 | /* Look up the table being altered. */ |
| 122225 | 122579 | assert( pSrc->nSrc==1 ); |
| 122226 | 122580 | pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 1); |
| 122227 | - if( !pTab ) return; | |
| 122581 | + if( !pTab ){ | |
| 122582 | + sqlite3ExprDelete(pParse->db, pExpr); | |
| 122583 | + return; | |
| 122584 | + } | |
| 122585 | + | |
| 122586 | + /* Verify that the new CHECK constraint does not contain any | |
| 122587 | + ** internal-use-only function. Forum post 2026-05-10T01:11:28Z | |
| 122588 | + */ | |
| 122589 | + rc = sqlite3ResolveSelfReference(pParse, pTab, NC_IsCheck, pExpr, 0); | |
| 122590 | + sqlite3ExprDelete(pParse->db, pExpr); | |
| 122591 | + if( rc ) return; | |
| 122228 | 122592 | |
| 122229 | 122593 | /* If this new constraint has a name, check that it is not a duplicate of |
| 122230 | 122594 | ** an existing constraint. It is an error if it is. */ |
| 122231 | 122595 | if( pName ){ |
| 122232 | 122596 | char *zName = sqlite3NameFromToken(pParse->db, pName); |
| @@ -122243,11 +122607,11 @@ | ||
| 122243 | 122607 | |
| 122244 | 122608 | /* Search for a constraint violation. Throw an exception if one is found. */ |
| 122245 | 122609 | sqlite3NestedParse(pParse, |
| 122246 | 122610 | "SELECT sqlite_fail('constraint failed', %d) " |
| 122247 | 122611 | "FROM %Q.%Q WHERE (%.*s) IS NOT TRUE", |
| 122248 | - SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, pExpr | |
| 122612 | + SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, zExpr | |
| 122249 | 122613 | ); |
| 122250 | 122614 | |
| 122251 | 122615 | /* Edit the SQL for the named table. */ |
| 122252 | 122616 | pCons = pFirst->z; |
| 122253 | 122617 | nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons); |
| @@ -124098,21 +124462,21 @@ | ||
| 124098 | 124462 | }else{ |
| 124099 | 124463 | nIdxCol = pIdx->nColumn; |
| 124100 | 124464 | } |
| 124101 | 124465 | pIdx->nSampleCol = nIdxCol; |
| 124102 | 124466 | pIdx->mxSample = nSample; |
| 124103 | - nByte = ROUND8(sizeof(IndexSample) * nSample); | |
| 124104 | - nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; | |
| 124105 | - nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ | |
| 124467 | + nByte = ROUND8(sizeof64(IndexSample) * nSample); | |
| 124468 | + nByte += sizeof64(tRowcnt) * nIdxCol * 3 * nSample; | |
| 124469 | + nByte += nIdxCol * sizeof64(tRowcnt); /* Space for Index.aAvgEq[] */ | |
| 124106 | 124470 | |
| 124107 | 124471 | pIdx->aSample = sqlite3DbMallocZero(db, nByte); |
| 124108 | 124472 | if( pIdx->aSample==0 ){ |
| 124109 | 124473 | sqlite3_finalize(pStmt); |
| 124110 | 124474 | return SQLITE_NOMEM_BKPT; |
| 124111 | 124475 | } |
| 124112 | 124476 | pPtr = (u8*)pIdx->aSample; |
| 124113 | - pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0])); | |
| 124477 | + pPtr += ROUND8(nSample*sizeof64(pIdx->aSample[0])); | |
| 124114 | 124478 | pSpace = (tRowcnt*)pPtr; |
| 124115 | 124479 | assert( EIGHT_BYTE_ALIGNMENT( pSpace ) ); |
| 124116 | 124480 | pIdx->aAvgEq = pSpace; pSpace += nIdxCol; |
| 124117 | 124481 | pIdx->pTable->tabFlags |= TF_HasStat4; |
| 124118 | 124482 | for(i=0; i<nSample; i++){ |
| @@ -125929,10 +126293,23 @@ | ||
| 125929 | 126293 | if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; |
| 125930 | 126294 | if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0; |
| 125931 | 126295 | return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; |
| 125932 | 126296 | } |
| 125933 | 126297 | |
| 126298 | +/* | |
| 126299 | +** Suppress false-positive warning message generated with -O3 in GCC | |
| 126300 | +** on the second call to sqlite3Strlen30() in the sqlite3ColumnSetColl() | |
| 126301 | +** function below. See the forum thread beginning on 2026-05-10T01:11:22Z. | |
| 126302 | +** | |
| 126303 | +** See also the "pop" pragma to undo this warning suppression immediately | |
| 126304 | +** after the function. | |
| 126305 | +*/ | |
| 126306 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 126307 | +# pragma GCC diagnostic push | |
| 126308 | +# pragma GCC diagnostic ignored "-Wstringop-overread" | |
| 126309 | +#endif | |
| 126310 | + | |
| 125934 | 126311 | /* |
| 125935 | 126312 | ** Set the collating sequence name for a column. |
| 125936 | 126313 | */ |
| 125937 | 126314 | SQLITE_PRIVATE void sqlite3ColumnSetColl( |
| 125938 | 126315 | sqlite3 *db, |
| @@ -125953,10 +126330,15 @@ | ||
| 125953 | 126330 | pCol->zCnName = zNew; |
| 125954 | 126331 | memcpy(pCol->zCnName + n, zColl, nColl); |
| 125955 | 126332 | pCol->colFlags |= COLFLAG_HASCOLL; |
| 125956 | 126333 | } |
| 125957 | 126334 | } |
| 126335 | + | |
| 126336 | +/* Undo the false-positive warning suppression above. */ | |
| 126337 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 126338 | +# pragma GCC diagnostic pop | |
| 126339 | +#endif | |
| 125958 | 126340 | |
| 125959 | 126341 | /* |
| 125960 | 126342 | ** Return the collating sequence name for a column |
| 125961 | 126343 | */ |
| 125962 | 126344 | SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){ |
| @@ -132946,13 +133328,22 @@ | ||
| 132946 | 133328 | x.nUsed = 0; |
| 132947 | 133329 | x.apArg = argv+1; |
| 132948 | 133330 | sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); |
| 132949 | 133331 | str.printfFlags = SQLITE_PRINTF_SQLFUNC; |
| 132950 | 133332 | sqlite3_str_appendf(&str, zFormat, &x); |
| 132951 | - n = str.nChar; | |
| 132952 | - sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, | |
| 132953 | - SQLITE_DYNAMIC); | |
| 133333 | + if( str.accError==SQLITE_OK ){ | |
| 133334 | + n = str.nChar; | |
| 133335 | + sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, | |
| 133336 | + SQLITE_DYNAMIC); | |
| 133337 | + }else{ | |
| 133338 | + if( str.accError==SQLITE_NOMEM ){ | |
| 133339 | + sqlite3_result_error_nomem(context); | |
| 133340 | + }else{ | |
| 133341 | + sqlite3_result_error_toobig(context); | |
| 133342 | + } | |
| 133343 | + sqlite3_str_reset(&str); | |
| 133344 | + } | |
| 132954 | 133345 | } |
| 132955 | 133346 | } |
| 132956 | 133347 | |
| 132957 | 133348 | /* |
| 132958 | 133349 | ** Implementation of the substr() function. |
| @@ -134120,11 +134511,11 @@ | ||
| 134120 | 134511 | int nStr; /* Size of zStr */ |
| 134121 | 134512 | int nPattern; /* Size of zPattern */ |
| 134122 | 134513 | int nRep; /* Size of zRep */ |
| 134123 | 134514 | i64 nOut; /* Maximum size of zOut */ |
| 134124 | 134515 | int loopLimit; /* Last zStr[] that might match zPattern[] */ |
| 134125 | - int i, j; /* Loop counters */ | |
| 134516 | + i64 i, j; /* Loop counters */ | |
| 134126 | 134517 | unsigned cntExpand; /* Number zOut expansions */ |
| 134127 | 134518 | sqlite3 *db = sqlite3_context_db_handle(context); |
| 134128 | 134519 | |
| 134129 | 134520 | assert( argc==3 ); |
| 134130 | 134521 | UNUSED_PARAMETER(argc); |
| @@ -134599,15 +134990,20 @@ | ||
| 134599 | 134990 | ** to initialize it */ |
| 134600 | 134991 | if( ALWAYS(p) && type!=SQLITE_NULL ){ |
| 134601 | 134992 | assert( p->cnt>0 ); |
| 134602 | 134993 | p->cnt--; |
| 134603 | 134994 | if( !p->approx ){ |
| 134604 | - if( sqlite3SubInt64(&p->iSum, sqlite3_value_int64(argv[0])) ){ | |
| 134605 | - p->ovrfl = 1; | |
| 134606 | - p->approx = 1; | |
| 134995 | + i64 x = p->iSum; | |
| 134996 | + if( sqlite3SubInt64(&x, sqlite3_value_int64(argv[0]))==0 ){ | |
| 134997 | + p->iSum = x; | |
| 134998 | + return; | |
| 134607 | 134999 | } |
| 134608 | - }else if( type==SQLITE_INTEGER ){ | |
| 135000 | + p->ovrfl = 1; | |
| 135001 | + p->approx = 1; | |
| 135002 | + kahanBabuskaNeumaierInit(p, p->iSum); | |
| 135003 | + } | |
| 135004 | + if( type==SQLITE_INTEGER ){ | |
| 134609 | 135005 | i64 iVal = sqlite3_value_int64(argv[0]); |
| 134610 | 135006 | if( iVal!=SMALLEST_INT64 ){ |
| 134611 | 135007 | kahanBabuskaNeumaierStepInt64(p, -iVal); |
| 134612 | 135008 | }else{ |
| 134613 | 135009 | kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64); |
| @@ -135569,57 +135965,95 @@ | ||
| 135569 | 135965 | ** from the standard library because: |
| 135570 | 135966 | ** |
| 135571 | 135967 | ** (1) To avoid a dependency on qsort() |
| 135572 | 135968 | ** (2) To avoid the function call to the comparison routine for each |
| 135573 | 135969 | ** comparison. |
| 135970 | +** | |
| 135971 | +** If parameter iReq is non-negative, then the caller will only access | |
| 135972 | +** elements a[iReq] and a[iReq+1] (if it exists) of the sorted array and | |
| 135973 | +** so it is not necessary to position any other elements. Or if iReq is | |
| 135974 | +** negative, then the final array must be fully sorted. | |
| 135574 | 135975 | */ |
| 135575 | -static void percentSort(double *a, unsigned int n){ | |
| 135976 | +static void percentSort( | |
| 135977 | + double *a, /* Array to sort */ | |
| 135978 | + unsigned int n, /* Number of elements in array a[] */ | |
| 135979 | + int iReq /* Element caller cares about (or -ve) */ | |
| 135980 | +){ | |
| 135576 | 135981 | int iLt; /* Entries before a[iLt] are less than rPivot */ |
| 135577 | 135982 | int iGt; /* Entries at or after a[iGt] are greater than rPivot */ |
| 135578 | 135983 | int i; /* Loop counter */ |
| 135579 | 135984 | double rPivot; /* The pivot value */ |
| 135580 | 135985 | |
| 135581 | 135986 | assert( n>=2 ); |
| 135582 | - if( a[0]>a[n-1] ){ | |
| 135583 | - SWAP_DOUBLE(a[0],a[n-1]) | |
| 135584 | - } | |
| 135585 | - if( n==2 ) return; | |
| 135586 | - iGt = n-1; | |
| 135587 | - i = n/2; | |
| 135588 | - if( a[0]>a[i] ){ | |
| 135589 | - SWAP_DOUBLE(a[0],a[i]) | |
| 135590 | - }else if( a[i]>a[iGt] ){ | |
| 135591 | - SWAP_DOUBLE(a[i],a[iGt]) | |
| 135592 | - } | |
| 135593 | - if( n==3 ) return; | |
| 135594 | - rPivot = a[i]; | |
| 135595 | - iLt = i = 1; | |
| 135596 | - do{ | |
| 135597 | - if( a[i]<rPivot ){ | |
| 135598 | - if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt]) | |
| 135599 | - iLt++; | |
| 135600 | - i++; | |
| 135601 | - }else if( a[i]>rPivot ){ | |
| 135602 | - do{ | |
| 135603 | - iGt--; | |
| 135604 | - }while( iGt>i && a[iGt]>rPivot ); | |
| 135605 | - SWAP_DOUBLE(a[i],a[iGt]) | |
| 135606 | - }else{ | |
| 135607 | - i++; | |
| 135608 | - } | |
| 135609 | - }while( i<iGt ); | |
| 135610 | - if( iLt>=2 ) percentSort(a, iLt); | |
| 135611 | - if( n-iGt>=2 ) percentSort(a+iGt, n-iGt); | |
| 135612 | - | |
| 135613 | -/* Uncomment for testing */ | |
| 135614 | -#if 0 | |
| 135615 | - for(i=0; i<n-1; i++){ | |
| 135616 | - assert( a[i]<=a[i+1] ); | |
| 135617 | - } | |
| 135618 | -#endif | |
| 135619 | -} | |
| 135620 | - | |
| 135987 | + do{ | |
| 135988 | + if( a[0]>a[n-1] ){ | |
| 135989 | + SWAP_DOUBLE(a[0],a[n-1]) | |
| 135990 | + } | |
| 135991 | + if( n==2 ) return; | |
| 135992 | + iGt = n-1; | |
| 135993 | + i = n/2; | |
| 135994 | + if( a[0]>a[i] ){ | |
| 135995 | + SWAP_DOUBLE(a[0],a[i]) | |
| 135996 | + }else if( a[i]>a[iGt] ){ | |
| 135997 | + SWAP_DOUBLE(a[i],a[iGt]) | |
| 135998 | + } | |
| 135999 | + if( n==3 ) return; | |
| 136000 | + rPivot = a[i]; | |
| 136001 | + iLt = i = 1; | |
| 136002 | + do{ | |
| 136003 | + if( a[i]<rPivot ){ | |
| 136004 | + if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt]) | |
| 136005 | + iLt++; | |
| 136006 | + i++; | |
| 136007 | + }else if( a[i]>rPivot ){ | |
| 136008 | + do{ | |
| 136009 | + iGt--; | |
| 136010 | + }while( iGt>i && a[iGt]>rPivot ); | |
| 136011 | + SWAP_DOUBLE(a[i],a[iGt]) | |
| 136012 | + }else{ | |
| 136013 | + i++; | |
| 136014 | + } | |
| 136015 | + }while( i<iGt ); | |
| 136016 | + | |
| 136017 | + assert( a[iLt]==rPivot ); | |
| 136018 | + assert( iGt>iLt ); | |
| 136019 | + | |
| 136020 | + if( iReq>=0 ){ | |
| 136021 | + /* In this case, the only elements that the caller requires sorted into | |
| 136022 | + ** the correct positions are elements a[iReq] and a[iReq+1]. At this | |
| 136023 | + ** point we know that element a[iLt] is in the correct position and | |
| 136024 | + ** all elements smaller than a[iLt] are in the left-hand partition. | |
| 136025 | + ** So if (iReq<iLt), then it is only necessary to sort the left | |
| 136026 | + ** partition. | |
| 136027 | + ** | |
| 136028 | + ** If (iReq>=iLt), then elements iReq and iReq+1 are either in the | |
| 136029 | + ** right partition or the equal partition (elements for which | |
| 136030 | + ** iLt<=iElem<iGt). Therefore it is always sufficient to sort only | |
| 136031 | + ** the right partition in this case. */ | |
| 136032 | + if( iReq<iLt ){ | |
| 136033 | + n = iLt; | |
| 136034 | + }else{ | |
| 136035 | + a += iGt; | |
| 136036 | + n -= iGt; | |
| 136037 | + iReq = MAX(0, iReq-iGt); | |
| 136038 | + } | |
| 136039 | + }else{ | |
| 136040 | + /* Recurse on the smaller partition only. The smaller partition | |
| 136041 | + ** will hold n/2 or fewer entries, which assures that the stack | |
| 136042 | + ** depth will not exceed O(log(n)), even for pathological cases. | |
| 136043 | + ** Loop without recursion for the larger partition. */ | |
| 136044 | + if( iLt>(int)(n/2) ){ | |
| 136045 | + if( n-iGt>=2 ) percentSort(a+iGt, n-iGt, -1); | |
| 136046 | + n = iLt; | |
| 136047 | + }else{ | |
| 136048 | + if( iLt>=2 ) percentSort(a, iLt, -1); | |
| 136049 | + a += iGt; | |
| 136050 | + n -= iGt; | |
| 136051 | + } | |
| 136052 | + } | |
| 136053 | + }while( n>=2 ); | |
| 136054 | +} | |
| 135621 | 136055 | |
| 135622 | 136056 | /* |
| 135623 | 136057 | ** The "inverse" function for percentile(Y,P) is called to remove a |
| 135624 | 136058 | ** row that was previously inserted by "step". |
| 135625 | 136059 | */ |
| @@ -135649,11 +136083,11 @@ | ||
| 135649 | 136083 | if( percentIsInfinity(y) ){ |
| 135650 | 136084 | return; |
| 135651 | 136085 | } |
| 135652 | 136086 | if( p->bSorted==0 ){ |
| 135653 | 136087 | assert( p->nUsed>1 ); |
| 135654 | - percentSort(p->a, p->nUsed); | |
| 136088 | + percentSort(p->a, p->nUsed, -1); | |
| 135655 | 136089 | p->bSorted = 1; |
| 135656 | 136090 | } |
| 135657 | 136091 | p->bKeepSorted = 1; |
| 135658 | 136092 | |
| 135659 | 136093 | /* Find and remove the row */ |
| @@ -135678,17 +136112,21 @@ | ||
| 135678 | 136112 | double ix, vx; |
| 135679 | 136113 | p = (Percentile*)sqlite3_aggregate_context(pCtx, 0); |
| 135680 | 136114 | if( p==0 ) return; |
| 135681 | 136115 | if( p->a==0 ) return; |
| 135682 | 136116 | if( p->nUsed ){ |
| 136117 | + ix = p->rPct*(p->nUsed-1); | |
| 136118 | + i1 = (unsigned)ix; | |
| 135683 | 136119 | if( p->bSorted==0 ){ |
| 136120 | + /* In cases where bIsFinal is non-zero, setting Percentile.bSorted | |
| 136121 | + ** after the percentSort() call here is not technically correct, as | |
| 136122 | + ** the array is not fully sorted. But in this case the object will be | |
| 136123 | + ** freed below anyway, so it doesn't matter. */ | |
| 135684 | 136124 | assert( p->nUsed>1 ); |
| 135685 | - percentSort(p->a, p->nUsed); | |
| 136125 | + percentSort(p->a, p->nUsed, (bIsFinal ? (int)i1 : -1)); | |
| 135686 | 136126 | p->bSorted = 1; |
| 135687 | 136127 | } |
| 135688 | - ix = p->rPct*(p->nUsed-1); | |
| 135689 | - i1 = (unsigned)ix; | |
| 135690 | 136128 | if( settings & 1 ){ |
| 135691 | 136129 | vx = p->a[i1]; |
| 135692 | 136130 | }else{ |
| 135693 | 136131 | i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; |
| 135694 | 136132 | v1 = p->a[i1]; |
| @@ -140569,10 +141007,48 @@ | ||
| 140569 | 141007 | } |
| 140570 | 141008 | |
| 140571 | 141009 | /* If no test above fails then the indices must be compatible */ |
| 140572 | 141010 | return 1; |
| 140573 | 141011 | } |
| 141012 | + | |
| 141013 | +/* | |
| 141014 | +** Examine an expression node and abort if it references the ROWID. | |
| 141015 | +** This is a Walker callback used by xferCompatibleCheck() | |
| 141016 | +*/ | |
| 141017 | +static int xferCheckRowid(Walker *pWalk, Expr *pExpr){ | |
| 141018 | + if( pExpr->op==TK_COLUMN && pExpr->iColumn<0 ){ | |
| 141019 | + pWalk->eCode = 1; | |
| 141020 | + return WRC_Abort; | |
| 141021 | + }else{ | |
| 141022 | + return WRC_Continue; | |
| 141023 | + } | |
| 141024 | +} | |
| 141025 | + | |
| 141026 | +/* | |
| 141027 | +** Analyze CHECK constraints on the source and destination tables and | |
| 141028 | +** return true if those CHECK constraints are compatible with the | |
| 141029 | +** xfer-optimization. | |
| 141030 | +** | |
| 141031 | +** * The pDest and pSrc tables must have identical CHECK constraints. | |
| 141032 | +** | |
| 141033 | +** * If the destination table, pDest, does not have an | |
| 141034 | +** INTEGER PRIMARY KEY column, then no CHECK constraint may | |
| 141035 | +** referenced the ROWID. (See forum post 2026-05-11T13:15:57Z) | |
| 141036 | +*/ | |
| 141037 | +static int xferCompatibleCheck(Table *pDest, Table *pSrc){ | |
| 141038 | + if( sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ | |
| 141039 | + return 0; | |
| 141040 | + } | |
| 141041 | + if( pDest->iPKey<0 ){ | |
| 141042 | + Walker w; | |
| 141043 | + memset(&w, 0, sizeof(w)); | |
| 141044 | + w.xExprCallback = xferCheckRowid; | |
| 141045 | + sqlite3WalkExprList(&w,pDest->pCheck); | |
| 141046 | + if( w.eCode ) return 0; | |
| 141047 | + } | |
| 141048 | + return 1; | |
| 141049 | +} | |
| 140574 | 141050 | |
| 140575 | 141051 | /* |
| 140576 | 141052 | ** Attempt the transfer optimization on INSERTs of the form |
| 140577 | 141053 | ** |
| 140578 | 141054 | ** INSERT INTO tab1 SELECT * FROM tab2; |
| @@ -140696,12 +141172,23 @@ | ||
| 140696 | 141172 | return 0; /* Number of columns must be the same in tab1 and tab2 */ |
| 140697 | 141173 | } |
| 140698 | 141174 | if( pDest->iPKey!=pSrc->iPKey ){ |
| 140699 | 141175 | return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ |
| 140700 | 141176 | } |
| 140701 | - if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){ | |
| 140702 | - return 0; /* Cannot feed from a non-strict into a strict table */ | |
| 141177 | + if( (pDest->tabFlags & TF_Strict)!=0 ){ | |
| 141178 | + if( (pSrc->tabFlags & TF_Strict)==0 ){ | |
| 141179 | + return 0; /* Cannot feed from a non-strict into a strict table */ | |
| 141180 | + } | |
| 141181 | + for(i=0; i<pDest->nCol; i++){ | |
| 141182 | + unsigned eDestType = pDest->aCol[i].eCType; | |
| 141183 | + unsigned eSrcType = pSrc->aCol[i].eCType; | |
| 141184 | + if( eDestType==COLTYPE_ANY ) continue; | |
| 141185 | + if( eDestType==eSrcType ) continue; | |
| 141186 | + if( eDestType==COLTYPE_INT && eSrcType==COLTYPE_INTEGER ) continue; | |
| 141187 | + if( eDestType==COLTYPE_INTEGER && eSrcType==COLTYPE_INT ) continue; | |
| 141188 | + return 0; /* Incompatible types in source and destination */ | |
| 141189 | + } | |
| 140703 | 141190 | } |
| 140704 | 141191 | for(i=0; i<pDest->nCol; i++){ |
| 140705 | 141192 | Column *pDestCol = &pDest->aCol[i]; |
| 140706 | 141193 | Column *pSrcCol = &pSrc->aCol[i]; |
| 140707 | 141194 | #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS |
| @@ -140791,11 +141278,11 @@ | ||
| 140791 | 141278 | } |
| 140792 | 141279 | } |
| 140793 | 141280 | #ifndef SQLITE_OMIT_CHECK |
| 140794 | 141281 | if( pDest->pCheck |
| 140795 | 141282 | && (db->mDbFlags & DBFLAG_Vacuum)==0 |
| 140796 | - && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) | |
| 141283 | + && !xferCompatibleCheck(pDest,pSrc) | |
| 140797 | 141284 | ){ |
| 140798 | 141285 | return 0; /* Tables have different CHECK constraints. Ticket #2252 */ |
| 140799 | 141286 | } |
| 140800 | 141287 | #endif |
| 140801 | 141288 | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| @@ -140812,10 +141299,22 @@ | ||
| 140812 | 141299 | } |
| 140813 | 141300 | #endif |
| 140814 | 141301 | if( (db->flags & SQLITE_CountRows)!=0 ){ |
| 140815 | 141302 | return 0; /* xfer opt does not play well with PRAGMA count_changes */ |
| 140816 | 141303 | } |
| 141304 | +#ifndef SQLITE_OMIT_AUTHORIZATION | |
| 141305 | + if( db->xAuth ){ | |
| 141306 | + int iDb = sqlite3SchemaToIndex(db, pSrc->pSchema); | |
| 141307 | + if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 0; | |
| 141308 | + for(i=0; i<pSrc->nCol; i++){ | |
| 141309 | + Column *pSrcCol = &pSrc->aCol[i]; | |
| 141310 | + if( sqlite3AuthReadCol(pParse, pSrc->zName, pSrcCol->zCnName, iDb) ){ | |
| 141311 | + return 0; | |
| 141312 | + } | |
| 141313 | + } | |
| 141314 | + } | |
| 141315 | +#endif | |
| 140817 | 141316 | |
| 140818 | 141317 | /* If we get this far, it means that the xfer optimization is at |
| 140819 | 141318 | ** least a possibility, though it might only work if the destination |
| 140820 | 141319 | ** table (tab1) is initially empty. |
| 140821 | 141320 | */ |
| @@ -146810,11 +147309,17 @@ | ||
| 146810 | 147309 | assert( iDb>=0 && iDb<db->nDb ); |
| 146811 | 147310 | assert( db->aDb[iDb].pSchema ); |
| 146812 | 147311 | assert( sqlite3_mutex_held(db->mutex) ); |
| 146813 | 147312 | assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); |
| 146814 | 147313 | |
| 146815 | - db->init.busy = 1; | |
| 147314 | + db->init.busy = 1 + ((mFlags & INITFLAG_AlterAdd)!=0); | |
| 147315 | + /* ^--- Any non-zero value for init.busy means that we are scanning | |
| 147316 | + ** the sqlite_schema table to build the internal schema representation, | |
| 147317 | + ** rather than running actual CREATE statements. init.busy==2 has the | |
| 147318 | + ** additional meaning that the scan is happening as part of | |
| 147319 | + ** ALTER TABLE ADD COLUMN, which is stricter in its enforcement of | |
| 147320 | + ** function name resolution. */ | |
| 146816 | 147321 | |
| 146817 | 147322 | /* Construct the in-memory representation schema tables (sqlite_schema or |
| 146818 | 147323 | ** sqlite_temp_schema) by invoking the parser directly. The appropriate |
| 146819 | 147324 | ** table name will be inserted automatically by the parser so we can just |
| 146820 | 147325 | ** use the abbreviation "x" here. The parser will also automatically tag |
| @@ -150131,10 +150636,17 @@ | ||
| 150131 | 150636 | SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){ |
| 150132 | 150637 | Table *pTab; |
| 150133 | 150638 | sqlite3 *db = pParse->db; |
| 150134 | 150639 | u64 savedFlags; |
| 150135 | 150640 | |
| 150641 | + pParse->nNestSel++; | |
| 150642 | +#if SQLITE_MAX_EXPR_DEPTH>0 | |
| 150643 | + if( pParse->nNestSel >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ | |
| 150644 | + sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); | |
| 150645 | + return 0; | |
| 150646 | + } | |
| 150647 | +#endif | |
| 150136 | 150648 | savedFlags = db->flags; |
| 150137 | 150649 | db->flags &= ~(u64)SQLITE_FullColNames; |
| 150138 | 150650 | db->flags |= SQLITE_ShortColNames; |
| 150139 | 150651 | sqlite3SelectPrep(pParse, pSelect, 0); |
| 150140 | 150652 | db->flags = savedFlags; |
| @@ -150152,10 +150664,12 @@ | ||
| 150152 | 150664 | pTab->iPKey = -1; |
| 150153 | 150665 | if( db->mallocFailed ){ |
| 150154 | 150666 | sqlite3DeleteTable(db, pTab); |
| 150155 | 150667 | return 0; |
| 150156 | 150668 | } |
| 150669 | + pParse->nNestSel--; | |
| 150670 | + assert( pParse->nNestSel>=0 ); | |
| 150157 | 150671 | return pTab; |
| 150158 | 150672 | } |
| 150159 | 150673 | |
| 150160 | 150674 | /* |
| 150161 | 150675 | ** Get a VDBE for the given parser context. Create a new one if necessary. |
| @@ -155122,12 +155636,15 @@ | ||
| 155122 | 155636 | ** Then, if CheckOnCtx.iJoin indicates that this expression is part of an |
| 155123 | 155637 | ** ON clause from that SrcList (i.e. if iJoin is non-zero), check that it |
| 155124 | 155638 | ** does not refer to a table to the right of CheckOnCtx.iJoin. */ |
| 155125 | 155639 | do { |
| 155126 | 155640 | SrcList *pSrc = pCtx->pSrc; |
| 155641 | + int nSrc = pSrc->nSrc; | |
| 155127 | 155642 | int iTab = pExpr->iTable; |
| 155128 | - if( iTab>=pSrc->a[0].iCursor && iTab<=pSrc->a[pSrc->nSrc-1].iCursor ){ | |
| 155643 | + int ii; | |
| 155644 | + for(ii=0; ii<nSrc && pSrc->a[ii].iCursor!=iTab; ii++){} | |
| 155645 | + if( ii<nSrc ){ | |
| 155129 | 155646 | if( pCtx->iJoin && iTab>pCtx->iJoin ){ |
| 155130 | 155647 | sqlite3ErrorMsg(pWalker->pParse, |
| 155131 | 155648 | "%s references tables to its right", |
| 155132 | 155649 | (pCtx->bFuncArg ? "table-function argument" : "ON clause") |
| 155133 | 155650 | ); |
| @@ -158092,22 +158609,36 @@ | ||
| 158092 | 158609 | Parse *pParse, /* Current parse context */ |
| 158093 | 158610 | Trigger *pTrigger, /* Trigger to code */ |
| 158094 | 158611 | Table *pTab, /* The table pTrigger is attached to */ |
| 158095 | 158612 | int orconf /* ON CONFLICT policy to code trigger program with */ |
| 158096 | 158613 | ){ |
| 158097 | - Parse *pTop = sqlite3ParseToplevel(pParse); | |
| 158614 | + Parse *pTop; /* Top level Parse object */ | |
| 158098 | 158615 | sqlite3 *db = pParse->db; /* Database handle */ |
| 158099 | 158616 | TriggerPrg *pPrg; /* Value to return */ |
| 158100 | 158617 | Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ |
| 158101 | 158618 | Vdbe *v; /* Temporary VM */ |
| 158102 | 158619 | NameContext sNC; /* Name context for sub-vdbe */ |
| 158103 | 158620 | SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ |
| 158104 | 158621 | int iEndTrigger = 0; /* Label to jump to if WHEN is false */ |
| 158105 | 158622 | Parse sSubParse; /* Parse context for sub-vdbe */ |
| 158623 | + int nDepth; /* Trigger depth */ | |
| 158106 | 158624 | |
| 158625 | + /* Ensure that triggers are not chained too deep. This test is linear | |
| 158626 | + ** in the chaining depth, but sensible code ought not be chaining | |
| 158627 | + ** triggers excessively, so that shouldn't be a problem. | |
| 158628 | + */ | |
| 158629 | + pTop = pParse; | |
| 158630 | + for(nDepth=0; pTop->pOuterParse; pTop = pTop->pOuterParse, nDepth++){} | |
| 158631 | + if( nDepth>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ | |
| 158632 | + sqlite3ErrorMsg(pParse, "triggers nested too deep"); | |
| 158633 | + return 0; | |
| 158634 | + } | |
| 158635 | + | |
| 158636 | + pTop = sqlite3ParseToplevel(pParse); | |
| 158107 | 158637 | assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); |
| 158108 | 158638 | assert( pTop->pVdbe ); |
| 158639 | + | |
| 158109 | 158640 | |
| 158110 | 158641 | /* Allocate the TriggerPrg and SubProgram objects. To ensure that they |
| 158111 | 158642 | ** are freed if an error occurs, link them into the Parse.pTriggerPrg |
| 158112 | 158643 | ** list of the top-level Parse object sooner rather than later. */ |
| 158113 | 158644 | pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); |
| @@ -160105,11 +160636,12 @@ | ||
| 160105 | 160636 | ** So we have to make a copy before passing it down into sqlite3Update() */ |
| 160106 | 160637 | pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0); |
| 160107 | 160638 | /* excluded.* columns of type REAL need to be converted to a hard real */ |
| 160108 | 160639 | for(i=0; i<pTab->nCol; i++){ |
| 160109 | 160640 | if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ |
| 160110 | - sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i); | |
| 160641 | + int iStorage = pTop->regData + sqlite3TableColumnToStorage(pTab, i); | |
| 160642 | + sqlite3VdbeAddOp1(v, OP_RealAffinity, iStorage); | |
| 160111 | 160643 | } |
| 160112 | 160644 | } |
| 160113 | 160645 | sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0), |
| 160114 | 160646 | sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert); |
| 160115 | 160647 | VdbeNoopComment((v, "End DO UPDATE of UPSERT")); |
| @@ -164903,11 +165435,11 @@ | ||
| 164903 | 165435 | |
| 164904 | 165436 | /* Set up a new SrcList in pOrTab containing the table being scanned |
| 164905 | 165437 | ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. |
| 164906 | 165438 | ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). |
| 164907 | 165439 | */ |
| 164908 | - if( pWInfo->nLevel>1 ){ | |
| 165440 | + if( pWInfo->nLevel>1 || pTabItem->fg.fromExists ){ | |
| 164909 | 165441 | int nNotReady; /* The number of notReady tables */ |
| 164910 | 165442 | SrcItem *origSrc; /* Original list of tables */ |
| 164911 | 165443 | nNotReady = pWInfo->nLevel - iLevel - 1; |
| 164912 | 165444 | pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1)); |
| 164913 | 165445 | if( pOrTab==0 ) return notReady; |
| @@ -164916,10 +165448,17 @@ | ||
| 164916 | 165448 | memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); |
| 164917 | 165449 | origSrc = pWInfo->pTabList->a; |
| 164918 | 165450 | for(k=1; k<=nNotReady; k++){ |
| 164919 | 165451 | memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); |
| 164920 | 165452 | } |
| 165453 | + | |
| 165454 | + /* Clear the fromExists flag on the OR-optimized table entry so that | |
| 165455 | + ** the calls to sqlite3WhereEnd() do not code early-exits after the | |
| 165456 | + ** first row is visited. The early exit applies to this table's | |
| 165457 | + ** overall loop - including the multiple OR branches and any WHERE | |
| 165458 | + ** conditions not passed to the sub-loops - not to the sub-loops. */ | |
| 165459 | + pOrTab->a[0].fg.fromExists = 0; | |
| 164921 | 165460 | }else{ |
| 164922 | 165461 | pOrTab = pWInfo->pTabList; |
| 164923 | 165462 | } |
| 164924 | 165463 | |
| 164925 | 165464 | /* Initialize the rowset register to contain NULL. An SQL NULL is |
| @@ -165159,11 +165698,11 @@ | ||
| 165159 | 165698 | ** indent everything in between the this point and the final OP_Return. |
| 165160 | 165699 | ** See tag-20220407a in vdbe.c and shell.c */ |
| 165161 | 165700 | assert( pLevel->op==OP_Return ); |
| 165162 | 165701 | pLevel->p2 = sqlite3VdbeCurrentAddr(v); |
| 165163 | 165702 | |
| 165164 | - if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); } | |
| 165703 | + if( pWInfo->pTabList!=pOrTab ){ sqlite3DbFreeNN(db, pOrTab); } | |
| 165165 | 165704 | if( !untestedTerms ) disableTerm(pLevel, pTerm); |
| 165166 | 165705 | }else |
| 165167 | 165706 | #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ |
| 165168 | 165707 | |
| 165169 | 165708 | { |
| @@ -165316,10 +165855,11 @@ | ||
| 165316 | 165855 | assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); |
| 165317 | 165856 | pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, |
| 165318 | 165857 | WO_EQ|WO_IN|WO_IS, 0); |
| 165319 | 165858 | if( pAlt==0 ) continue; |
| 165320 | 165859 | if( pAlt->wtFlags & (TERM_CODED) ) continue; |
| 165860 | + if( ExprHasProperty(pAlt->pExpr, EP_Collate) ) continue; | |
| 165321 | 165861 | if( (pAlt->eOperator & WO_IN) |
| 165322 | 165862 | && ExprUseXSelect(pAlt->pExpr) |
| 165323 | 165863 | && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) |
| 165324 | 165864 | ){ |
| 165325 | 165865 | continue; |
| @@ -166069,11 +166609,14 @@ | ||
| 166069 | 166609 | ** Mark term iChild as being a child of term iParent |
| 166070 | 166610 | */ |
| 166071 | 166611 | static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ |
| 166072 | 166612 | pWC->a[iChild].iParent = iParent; |
| 166073 | 166613 | pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; |
| 166614 | + assert( pWC->a[iParent].nChild < UMXV(pWC->a[0].nChild) ); | |
| 166074 | 166615 | pWC->a[iParent].nChild++; |
| 166616 | + testcase( pWC->a[iParent].nChild == UMXV(pWC->a[0].nChild) ); | |
| 166617 | + | |
| 166075 | 166618 | } |
| 166076 | 166619 | |
| 166077 | 166620 | /* |
| 166078 | 166621 | ** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not |
| 166079 | 166622 | ** a conjunction, then return just pTerm when N==0. If N is exceeds |
| @@ -166508,23 +167051,22 @@ | ||
| 166508 | 167051 | ** 1. The SQLITE_Transitive optimization must be enabled |
| 166509 | 167052 | ** 2. Must be either an == or an IS operator |
| 166510 | 167053 | ** 3. Not originating in the ON clause of an OUTER JOIN |
| 166511 | 167054 | ** 4. The operator is not IS or else the query does not contain RIGHT JOIN |
| 166512 | 167055 | ** 5. The affinities of A and B must be compatible |
| 166513 | -** 6a. Both operands use the same collating sequence OR | |
| 166514 | -** 6b. The overall collating sequence is BINARY | |
| 167056 | +** 6. Both operands use the same collating sequence, and they must not | |
| 167057 | +** use explicit COLLATE clauses. | |
| 166515 | 167058 | ** If this routine returns TRUE, that means that the RHS can be substituted |
| 166516 | 167059 | ** for the LHS anyplace else in the WHERE clause where the LHS column occurs. |
| 166517 | 167060 | ** This is an optimization. No harm comes from returning 0. But if 1 is |
| 166518 | 167061 | ** returned when it should not be, then incorrect answers might result. |
| 166519 | 167062 | */ |
| 166520 | 167063 | static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){ |
| 166521 | 167064 | char aff1, aff2; |
| 166522 | - CollSeq *pColl; | |
| 166523 | 167065 | if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; /* (1) */ |
| 166524 | 167066 | if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; /* (2) */ |
| 166525 | - if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* (3) */ | |
| 167067 | + if( ExprHasProperty(pExpr, EP_OuterON|EP_Collate) ) return 0; /* (3) */ | |
| 166526 | 167068 | assert( pSrc!=0 ); |
| 166527 | 167069 | if( pExpr->op==TK_IS |
| 166528 | 167070 | && pSrc->nSrc>=2 |
| 166529 | 167071 | && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 |
| 166530 | 167072 | ){ |
| @@ -166535,14 +167077,11 @@ | ||
| 166535 | 167077 | if( aff1!=aff2 |
| 166536 | 167078 | && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) |
| 166537 | 167079 | ){ |
| 166538 | 167080 | return 0; /* (5) */ |
| 166539 | 167081 | } |
| 166540 | - pColl = sqlite3ExprCompareCollSeq(pParse, pExpr); | |
| 166541 | - if( !sqlite3IsBinary(pColl) | |
| 166542 | - && !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight) | |
| 166543 | - ){ | |
| 167082 | + if( !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight) ){ | |
| 166544 | 167083 | return 0; /* (6) */ |
| 166545 | 167084 | } |
| 166546 | 167085 | return 1; |
| 166547 | 167086 | } |
| 166548 | 167087 | |
| @@ -166850,10 +167389,11 @@ | ||
| 166850 | 167389 | static const u8 ops[] = {TK_GE, TK_LE}; |
| 166851 | 167390 | assert( ExprUseXList(pExpr) ); |
| 166852 | 167391 | pList = pExpr->x.pList; |
| 166853 | 167392 | assert( pList!=0 ); |
| 166854 | 167393 | assert( pList->nExpr==2 ); |
| 167394 | + assert( pWC->a[idxTerm].nChild==0 ); | |
| 166855 | 167395 | for(i=0; i<2; i++){ |
| 166856 | 167396 | Expr *pNewExpr; |
| 166857 | 167397 | int idxNew; |
| 166858 | 167398 | pNewExpr = sqlite3PExpr(pParse, ops[i], |
| 166859 | 167399 | sqlite3ExprDup(db, pExpr->pLeft, 0), |
| @@ -166870,11 +167410,11 @@ | ||
| 166870 | 167410 | |
| 166871 | 167411 | #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) |
| 166872 | 167412 | /* Analyze a term that is composed of two or more subterms connected by |
| 166873 | 167413 | ** an OR operator. |
| 166874 | 167414 | */ |
| 166875 | - else if( pExpr->op==TK_OR ){ | |
| 167415 | + else if( pExpr->op==TK_OR && !ExprHasProperty(pExpr, EP_Collate) ){ | |
| 166876 | 167416 | assert( pWC->op==TK_AND ); |
| 166877 | 167417 | exprAnalyzeOrTerm(pSrc, pWC, idxTerm); |
| 166878 | 167418 | pTerm = &pWC->a[idxTerm]; |
| 166879 | 167419 | } |
| 166880 | 167420 | #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ |
| @@ -167060,12 +167600,15 @@ | ||
| 167060 | 167600 | && (pExpr->x.pSelect->pPrior==0 || (pExpr->x.pSelect->selFlags & SF_Values)) |
| 167061 | 167601 | #ifndef SQLITE_OMIT_WINDOWFUNC |
| 167062 | 167602 | && pExpr->x.pSelect->pWin==0 |
| 167063 | 167603 | #endif |
| 167064 | 167604 | && pWC->op==TK_AND |
| 167605 | + && pExpr->x.pSelect->pEList->nExpr <= UMXV(pTerm->nChild) | |
| 167606 | + /* ^-- See bug 2026-06-04T10:00:49Z */ | |
| 167065 | 167607 | ){ |
| 167066 | 167608 | int i; |
| 167609 | + assert( pTerm->nChild==0 ); | |
| 167067 | 167610 | for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){ |
| 167068 | 167611 | int idxNew; |
| 167069 | 167612 | idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE); |
| 167070 | 167613 | pWC->a[idxNew].u.x.iField = i+1; |
| 167071 | 167614 | exprAnalyze(pSrc, pWC, idxNew); |
| @@ -170589,13 +171132,14 @@ | ||
| 170589 | 171132 | pLoop->nOut--; |
| 170590 | 171133 | if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 |
| 170591 | 171134 | && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ |
| 170592 | 171135 | ){ |
| 170593 | 171136 | Expr *pRight = pOpExpr->pRight; |
| 171137 | + Parse *pParse = pWC->pWInfo->pParse; | |
| 170594 | 171138 | int k = 0; |
| 170595 | 171139 | testcase( pOpExpr->op==TK_IS ); |
| 170596 | - if( sqlite3ExprIsInteger(pRight, &k, 0) && k>=(-1) && k<=1 ){ | |
| 171140 | + if( sqlite3ExprIsInteger(pRight, &k, pParse) && k>=(-1) && k<=1 ){ | |
| 170597 | 171141 | k = 10; |
| 170598 | 171142 | }else{ |
| 170599 | 171143 | k = 20; |
| 170600 | 171144 | } |
| 170601 | 171145 | if( iReduce<k ){ |
| @@ -170688,11 +171232,12 @@ | ||
| 170688 | 171232 | testcase( pLhs->iColumn==XN_ROWID ); |
| 170689 | 171233 | aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs)); |
| 170690 | 171234 | idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); |
| 170691 | 171235 | if( aff!=idxaff ) break; |
| 170692 | 171236 | |
| 170693 | - pColl = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); | |
| 171237 | + if( ExprHasProperty(pTerm->pExpr, EP_Commuted) ) SWAP(Expr*, pRhs, pLhs); | |
| 171238 | + pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); | |
| 170694 | 171239 | if( pColl==0 ) break; |
| 170695 | 171240 | if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; |
| 170696 | 171241 | } |
| 170697 | 171242 | return i; |
| 170698 | 171243 | } |
| @@ -183162,13 +183707,15 @@ | ||
| 183162 | 183707 | case 196: /* expr ::= LP nexprlist COMMA expr RP */ |
| 183163 | 183708 | { |
| 183164 | 183709 | ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454); |
| 183165 | 183710 | yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); |
| 183166 | 183711 | if( yymsp[-4].minor.yy454 ){ |
| 183712 | + int i; | |
| 183167 | 183713 | yymsp[-4].minor.yy454->x.pList = pList; |
| 183168 | - if( ALWAYS(pList->nExpr) ){ | |
| 183169 | - yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate; | |
| 183714 | + for(i=0; i<pList->nExpr; i++){ | |
| 183715 | + assert( pList->a[i].pExpr!=0 ); | |
| 183716 | + yymsp[-4].minor.yy454->flags |= pList->a[i].pExpr->flags & EP_Propagate; | |
| 183170 | 183717 | } |
| 183171 | 183718 | }else{ |
| 183172 | 183719 | sqlite3ExprListDelete(pParse->db, pList); |
| 183173 | 183720 | } |
| 183174 | 183721 | } |
| @@ -183632,19 +184179,17 @@ | ||
| 183632 | 184179 | sqlite3AlterSetNotNull(pParse, yymsp[-7].minor.yy203, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0); |
| 183633 | 184180 | } |
| 183634 | 184181 | break; |
| 183635 | 184182 | case 300: /* cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ |
| 183636 | 184183 | { |
| 183637 | - sqlite3AlterAddConstraint(pParse, yymsp[-8].minor.yy203, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1)); | |
| 184184 | + sqlite3AlterAddConstraint(pParse, yymsp[-8].minor.yy203, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1), yymsp[-2].minor.yy454); | |
| 183638 | 184185 | } |
| 183639 | - yy_destructor(yypParser,219,&yymsp[-2].minor); | |
| 183640 | 184186 | break; |
| 183641 | 184187 | case 301: /* cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ |
| 183642 | 184188 | { |
| 183643 | - sqlite3AlterAddConstraint(pParse, yymsp[-6].minor.yy203, &yymsp[-4].minor.yy0, 0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1)); | |
| 184189 | + sqlite3AlterAddConstraint(pParse, yymsp[-6].minor.yy203, &yymsp[-4].minor.yy0, 0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1), yymsp[-2].minor.yy454); | |
| 183644 | 184190 | } |
| 183645 | - yy_destructor(yypParser,219,&yymsp[-2].minor); | |
| 183646 | 184191 | break; |
| 183647 | 184192 | case 302: /* cmd ::= create_vtab */ |
| 183648 | 184193 | {sqlite3VtabFinishParse(pParse,0);} |
| 183649 | 184194 | break; |
| 183650 | 184195 | case 303: /* cmd ::= create_vtab LP vtabarglist RP */ |
| @@ -186617,11 +187162,11 @@ | ||
| 186617 | 187162 | ** or disables the collection of memory allocation statistics. */ |
| 186618 | 187163 | sqlite3GlobalConfig.bMemstat = va_arg(ap, int); |
| 186619 | 187164 | break; |
| 186620 | 187165 | } |
| 186621 | 187166 | case SQLITE_CONFIG_SMALL_MALLOC: { |
| 186622 | - sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int); | |
| 187167 | + sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int)!=0; | |
| 186623 | 187168 | break; |
| 186624 | 187169 | } |
| 186625 | 187170 | case SQLITE_CONFIG_PAGECACHE: { |
| 186626 | 187171 | /* EVIDENCE-OF: R-18761-36601 There are three arguments to |
| 186627 | 187172 | ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem), |
| @@ -192926,10 +193471,16 @@ | ||
| 192926 | 193471 | #ifndef SQLITE_CORE |
| 192927 | 193472 | /* # include "sqlite3ext.h" */ |
| 192928 | 193473 | SQLITE_EXTENSION_INIT1 |
| 192929 | 193474 | #endif |
| 192930 | 193475 | |
| 193476 | + | |
| 193477 | +/* | |
| 193478 | +** Assume any b-tree layer with more levels than this is corrupt. | |
| 193479 | +*/ | |
| 193480 | +#define FTS3_MAX_BTREE_HEIGHT 48 | |
| 193481 | + | |
| 192931 | 193482 | typedef struct Fts3HashWrapper Fts3HashWrapper; |
| 192932 | 193483 | struct Fts3HashWrapper { |
| 192933 | 193484 | Fts3Hash hash; /* Hash table */ |
| 192934 | 193485 | int nRef; /* Number of pointers to this object */ |
| 192935 | 193486 | }; |
| @@ -194642,11 +195193,15 @@ | ||
| 194642 | 195193 | int iHeight; /* Height of this node in tree */ |
| 194643 | 195194 | |
| 194644 | 195195 | assert( piLeaf || piLeaf2 ); |
| 194645 | 195196 | |
| 194646 | 195197 | fts3GetVarint32(zNode, &iHeight); |
| 194647 | - rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); | |
| 195198 | + if( iHeight>FTS3_MAX_BTREE_HEIGHT ){ | |
| 195199 | + rc = FTS_CORRUPT_VTAB; | |
| 195200 | + }else{ | |
| 195201 | + rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); | |
| 195202 | + } | |
| 194648 | 195203 | assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); |
| 194649 | 195204 | |
| 194650 | 195205 | if( rc==SQLITE_OK && iHeight>1 ){ |
| 194651 | 195206 | char *zBlob = 0; /* Blob read from %_segments table */ |
| 194652 | 195207 | int nBlob = 0; /* Size of zBlob in bytes */ |
| @@ -194687,12 +195242,17 @@ | ||
| 194687 | 195242 | char **pp, /* IN/OUT: Output pointer */ |
| 194688 | 195243 | sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ |
| 194689 | 195244 | sqlite3_int64 iVal /* Write this value to the list */ |
| 194690 | 195245 | ){ |
| 194691 | 195246 | assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); |
| 194692 | - *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); | |
| 194693 | - *piPrev = iVal; | |
| 195247 | + if( iVal-(*piPrev)>=0 ){ | |
| 195248 | + /* Refuse to write a negative delta integer. This only happens with a | |
| 195249 | + ** corrupt db (see the assert above) and can cause buffer overwrites | |
| 195250 | + ** in some cases. */ | |
| 195251 | + *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); | |
| 195252 | + *piPrev = iVal; | |
| 195253 | + } | |
| 194694 | 195254 | } |
| 194695 | 195255 | |
| 194696 | 195256 | /* |
| 194697 | 195257 | ** When this function is called, *ppPoslist is assumed to point to the |
| 194698 | 195258 | ** start of a position-list. After it returns, *ppPoslist points to the |
| @@ -199171,11 +199731,11 @@ | ||
| 199171 | 199731 | break; |
| 199172 | 199732 | |
| 199173 | 199733 | /* State 3. The integer just read is a column number. */ |
| 199174 | 199734 | default: assert( eState==3 ); |
| 199175 | 199735 | iCol = (int)v; |
| 199176 | - if( iCol<1 ){ | |
| 199736 | + if( iCol<1 || iCol>(pFts3->nColumn+1) ){ | |
| 199177 | 199737 | rc = SQLITE_CORRUPT_VTAB; |
| 199178 | 199738 | break; |
| 199179 | 199739 | } |
| 199180 | 199740 | if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; |
| 199181 | 199741 | pCsr->aStat[iCol+1].nDoc++; |
| @@ -199861,10 +200421,11 @@ | ||
| 199861 | 200421 | /* If this is a "NEAR" keyword, check for an explicit nearness. */ |
| 199862 | 200422 | if( pKey->eType==FTSQUERY_NEAR ){ |
| 199863 | 200423 | assert( nKey==4 ); |
| 199864 | 200424 | if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ |
| 199865 | 200425 | nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear); |
| 200426 | + if( nNear>=1000000000 ) nNear = 1000000000; | |
| 199866 | 200427 | } |
| 199867 | 200428 | } |
| 199868 | 200429 | |
| 199869 | 200430 | /* At this point this is probably a keyword. But for that to be true, |
| 199870 | 200431 | ** the next byte must contain either whitespace, an open or close |
| @@ -206107,10 +206668,14 @@ | ||
| 206107 | 206668 | iMul = -1; |
| 206108 | 206669 | } |
| 206109 | 206670 | for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ |
| 206110 | 206671 | iVal = iVal*10 + (zText[i] - '0'); |
| 206111 | 206672 | } |
| 206673 | + | |
| 206674 | + /* This if() clause is just to avoid an integer overflow. The record is | |
| 206675 | + ** corrupt in this case. */ | |
| 206676 | + if( (i64)iVal==SMALLEST_INT64 ) iMul = 1; | |
| 206112 | 206677 | *pnByte = ((i64)iVal * (i64)iMul); |
| 206113 | 206678 | } |
| 206114 | 206679 | } |
| 206115 | 206680 | |
| 206116 | 206681 | |
| @@ -208969,14 +209534,13 @@ | ||
| 208969 | 209534 | */ |
| 208970 | 209535 | |
| 208971 | 209536 | /* |
| 208972 | 209537 | ** Allocate a two-slot MatchinfoBuffer object. |
| 208973 | 209538 | */ |
| 208974 | -static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ | |
| 209539 | +static MatchinfoBuffer *fts3MIBufferNew(i64 nElem, const char *zMatchinfo){ | |
| 208975 | 209540 | MatchinfoBuffer *pRet; |
| 208976 | - sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) | |
| 208977 | - + SZ_MATCHINFOBUFFER(1); | |
| 209541 | + sqlite3_int64 nByte = sizeof(u32) * (2*(i64)nElem+1) + SZ_MATCHINFOBUFFER(1); | |
| 208978 | 209542 | sqlite3_int64 nStr = strlen(zMatchinfo); |
| 208979 | 209543 | |
| 208980 | 209544 | pRet = sqlite3Fts3MallocZero(nByte + nStr+1); |
| 208981 | 209545 | if( pRet ){ |
| 208982 | 209546 | pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet; |
| @@ -209724,11 +210288,11 @@ | ||
| 209724 | 210288 | int nHit = fts3ColumnlistCount(&pIter); |
| 209725 | 210289 | if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ |
| 209726 | 210290 | if( p->flag==FTS3_MATCHINFO_LHITS ){ |
| 209727 | 210291 | p->aMatchinfo[iStart + iCol] = (u32)nHit; |
| 209728 | 210292 | }else if( nHit ){ |
| 209729 | - p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); | |
| 210293 | + p->aMatchinfo[iStart + iCol/32] |= (1U << (iCol&0x1F)); | |
| 209730 | 210294 | } |
| 209731 | 210295 | } |
| 209732 | 210296 | assert( *pIter==0x00 || *pIter==0x01 ); |
| 209733 | 210297 | if( *pIter!=0x01 ) break; |
| 209734 | 210298 | pIter++; |
| @@ -209843,12 +210407,12 @@ | ||
| 209843 | 210407 | } |
| 209844 | 210408 | sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); |
| 209845 | 210409 | return SQLITE_ERROR; |
| 209846 | 210410 | } |
| 209847 | 210411 | |
| 209848 | -static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ | |
| 209849 | - size_t nVal; /* Number of integers output by cArg */ | |
| 210412 | +static i64 fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ | |
| 210413 | + i64 nVal; /* Number of integers output by cArg */ | |
| 209850 | 210414 | |
| 209851 | 210415 | switch( cArg ){ |
| 209852 | 210416 | case FTS3_MATCHINFO_NDOC: |
| 209853 | 210417 | case FTS3_MATCHINFO_NPHRASE: |
| 209854 | 210418 | case FTS3_MATCHINFO_NCOL: |
| @@ -209860,20 +210424,20 @@ | ||
| 209860 | 210424 | case FTS3_MATCHINFO_LCS: |
| 209861 | 210425 | nVal = pInfo->nCol; |
| 209862 | 210426 | break; |
| 209863 | 210427 | |
| 209864 | 210428 | case FTS3_MATCHINFO_LHITS: |
| 209865 | - nVal = (size_t)pInfo->nCol * pInfo->nPhrase; | |
| 210429 | + nVal = (i64)pInfo->nCol * pInfo->nPhrase; | |
| 209866 | 210430 | break; |
| 209867 | 210431 | |
| 209868 | 210432 | case FTS3_MATCHINFO_LHITS_BM: |
| 209869 | - nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); | |
| 210433 | + nVal = (i64)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); | |
| 209870 | 210434 | break; |
| 209871 | 210435 | |
| 209872 | 210436 | default: |
| 209873 | 210437 | assert( cArg==FTS3_MATCHINFO_HITS ); |
| 209874 | - nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3; | |
| 210438 | + nVal = (i64)pInfo->nCol * pInfo->nPhrase * 3; | |
| 209875 | 210439 | break; |
| 209876 | 210440 | } |
| 209877 | 210441 | |
| 209878 | 210442 | return nVal; |
| 209879 | 210443 | } |
| @@ -210151,11 +210715,11 @@ | ||
| 210151 | 210715 | } |
| 210152 | 210716 | break; |
| 210153 | 210717 | |
| 210154 | 210718 | case FTS3_MATCHINFO_LHITS_BM: |
| 210155 | 210719 | case FTS3_MATCHINFO_LHITS: { |
| 210156 | - size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); | |
| 210720 | + i64 nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); | |
| 210157 | 210721 | memset(pInfo->aMatchinfo, 0, nZero); |
| 210158 | 210722 | rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); |
| 210159 | 210723 | break; |
| 210160 | 210724 | } |
| 210161 | 210725 | |
| @@ -210220,11 +210784,11 @@ | ||
| 210220 | 210784 | ** matchinfo function has been called for this query. In this case |
| 210221 | 210785 | ** allocate the array used to accumulate the matchinfo data and |
| 210222 | 210786 | ** initialize those elements that are constant for every row. |
| 210223 | 210787 | */ |
| 210224 | 210788 | if( pCsr->pMIBuffer==0 ){ |
| 210225 | - size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ | |
| 210789 | + i64 nMatchinfo = 0; /* Number of u32 elements in match-info */ | |
| 210226 | 210790 | int i; /* Used to iterate through zArg */ |
| 210227 | 210791 | |
| 210228 | 210792 | /* Determine the number of phrases in the query */ |
| 210229 | 210793 | pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr); |
| 210230 | 210794 | sInfo.nPhrase = pCsr->nPhrase; |
| @@ -212214,11 +212778,11 @@ | ||
| 212214 | 212778 | case SQLITE_NULL: { |
| 212215 | 212779 | jsonAppendRawNZ(p, "null", 4); |
| 212216 | 212780 | break; |
| 212217 | 212781 | } |
| 212218 | 212782 | case SQLITE_FLOAT: { |
| 212219 | - jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue)); | |
| 212783 | + jsonPrintf(100, p, "%!0.17g", sqlite3_value_double(pValue)); | |
| 212220 | 212784 | break; |
| 212221 | 212785 | } |
| 212222 | 212786 | case SQLITE_INTEGER: { |
| 212223 | 212787 | const char *z = (const char*)sqlite3_value_text(pValue); |
| 212224 | 212788 | u32 n = (u32)sqlite3_value_bytes(pValue); |
| @@ -213528,13 +214092,14 @@ | ||
| 213528 | 214092 | */ |
| 213529 | 214093 | static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ |
| 213530 | 214094 | u8 x; |
| 213531 | 214095 | u32 sz; |
| 213532 | 214096 | u32 n; |
| 213533 | - assert( i<=pParse->nBlob ); | |
| 213534 | - x = pParse->aBlob[i]>>4; | |
| 213535 | - if( x<=11 ){ | |
| 214097 | + if( i>=pParse->nBlob ){ | |
| 214098 | + *pSz = 0; | |
| 214099 | + return 0; | |
| 214100 | + }else if( (x = pParse->aBlob[i]>>4)<=11 ){ | |
| 213536 | 214101 | sz = x; |
| 213537 | 214102 | n = 1; |
| 213538 | 214103 | }else if( x==12 ){ |
| 213539 | 214104 | if( i+1>=pParse->nBlob ){ |
| 213540 | 214105 | *pSz = 0; |
| @@ -213744,11 +214309,11 @@ | ||
| 213744 | 214309 | break; |
| 213745 | 214310 | case '\n': |
| 213746 | 214311 | break; |
| 213747 | 214312 | case 0xe2: |
| 213748 | 214313 | /* '\' followed by either U+2028 or U+2029 is ignored as |
| 213749 | - ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29. | |
| 214314 | + ** whitespace. Note that in UTF8, U+2028 is 0xe2 0x80 0x29. | |
| 213750 | 214315 | ** U+2029 is the same except for the last byte */ |
| 213751 | 214316 | if( sz2<4 |
| 213752 | 214317 | || 0x80!=(u8)zIn[2] |
| 213753 | 214318 | || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3]) |
| 213754 | 214319 | ){ |
| @@ -216313,15 +216878,13 @@ | ||
| 216313 | 216878 | char c; |
| 216314 | 216879 | JsonString *pStr; |
| 216315 | 216880 | UNUSED_PARAMETER(argc); |
| 216316 | 216881 | UNUSED_PARAMETER(argv); |
| 216317 | 216882 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); |
| 216318 | -#ifdef NEVER | |
| 216319 | 216883 | /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will |
| 216320 | 216884 | ** always have been called to initialize it */ |
| 216321 | 216885 | if( NEVER(!pStr) ) return; |
| 216322 | -#endif | |
| 216323 | 216886 | z = pStr->zBuf; |
| 216324 | 216887 | for(i=1; i<pStr->nUsed && ((c = z[i])!=',' || inStr || nNest); i++){ |
| 216325 | 216888 | if( c=='"' ){ |
| 216326 | 216889 | inStr = !inStr; |
| 216327 | 216890 | }else if( c=='\\' ){ |
| @@ -216346,10 +216909,17 @@ | ||
| 216346 | 216909 | |
| 216347 | 216910 | /* |
| 216348 | 216911 | ** json_group_obj(NAME,VALUE) |
| 216349 | 216912 | ** |
| 216350 | 216913 | ** Return a JSON object composed of all names and values in the aggregate. |
| 216914 | +** | |
| 216915 | +** Rows for which NAME is NULL do not result in a new entry. However, we | |
| 216916 | +** do initially insert a "@" entry into the growing string for each null entry | |
| 216917 | +** and change the first character of the string to "@" to signal that the | |
| 216918 | +** string contains null entries. The "@" markers are needed in order to | |
| 216919 | +** correctly process xInverse() requests. The initial "@" is converted | |
| 216920 | +** back into "{" and the "@" null values are removed by jsonObjectCompute(). | |
| 216351 | 216921 | */ |
| 216352 | 216922 | static void jsonObjectStep( |
| 216353 | 216923 | sqlite3_context *ctx, |
| 216354 | 216924 | int argc, |
| 216355 | 216925 | sqlite3_value **argv |
| @@ -216363,49 +216933,97 @@ | ||
| 216363 | 216933 | z = (const char*)sqlite3_value_text(argv[0]); |
| 216364 | 216934 | n = sqlite3Strlen30(z); |
| 216365 | 216935 | if( pStr->zBuf==0 ){ |
| 216366 | 216936 | jsonStringInit(pStr, ctx); |
| 216367 | 216937 | jsonAppendChar(pStr, '{'); |
| 216368 | - }else if( pStr->nUsed>1 && z!=0 ){ | |
| 216938 | + }else if( pStr->nUsed>1 ){ | |
| 216369 | 216939 | jsonAppendChar(pStr, ','); |
| 216370 | 216940 | } |
| 216371 | 216941 | pStr->pCtx = ctx; |
| 216372 | 216942 | if( z!=0 ){ |
| 216373 | 216943 | jsonAppendString(pStr, z, n); |
| 216374 | 216944 | jsonAppendChar(pStr, ':'); |
| 216375 | 216945 | jsonAppendSqlValue(pStr, argv[1]); |
| 216946 | + }else{ | |
| 216947 | + pStr->zBuf[0] = '@'; | |
| 216948 | + jsonAppendRawNZ(pStr, "@", 1); | |
| 216376 | 216949 | } |
| 216377 | 216950 | } |
| 216378 | 216951 | } |
| 216379 | 216952 | static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ |
| 216380 | 216953 | JsonString *pStr; |
| 216381 | 216954 | int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 216382 | 216955 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); |
| 216383 | 216956 | if( pStr ){ |
| 216384 | - jsonAppendRawNZ(pStr, "}", 2); | |
| 216385 | - jsonStringTrimOneChar(pStr); | |
| 216957 | + JsonString *pOgStr = pStr; | |
| 216958 | + JsonString tmpStr; | |
| 216959 | + jsonAppendRawNZ(pOgStr, "}", 2); /* Ensure it is zero-terminated */ | |
| 216960 | + jsonStringTrimOneChar(pOgStr); /* Remove the zero terminator */ | |
| 216386 | 216961 | pStr->pCtx = ctx; |
| 216387 | 216962 | if( pStr->eErr ){ |
| 216388 | 216963 | jsonReturnString(pStr, 0, 0); |
| 216389 | 216964 | return; |
| 216390 | - }else if( flags & JSON_BLOB ){ | |
| 216965 | + } | |
| 216966 | + if( pStr->zBuf[0]!='{' ){ | |
| 216967 | + /* The string contains null entries that need to be removed */ | |
| 216968 | + u64 i, j; | |
| 216969 | + int inStr = 0; | |
| 216970 | + if( !isFinal ){ | |
| 216971 | + /* Work with a temporary copy of the string if this is not the | |
| 216972 | + ** final result */ | |
| 216973 | + jsonStringInit(&tmpStr, ctx); | |
| 216974 | + jsonAppendRawNZ(&tmpStr, pStr->zBuf, pStr->nUsed+1); | |
| 216975 | + pStr = &tmpStr; | |
| 216976 | + if( pStr->eErr ){ | |
| 216977 | + jsonReturnString(pStr, 0, 0); | |
| 216978 | + return; | |
| 216979 | + } | |
| 216980 | + jsonStringTrimOneChar(pStr); /* Remove zero terminator */ | |
| 216981 | + } | |
| 216982 | + /* Fix up the string by changing the initial "@" flag back to | |
| 216983 | + ** to "{" and removing all subsequence "@" entries, with their | |
| 216984 | + ** associated comma delimeters. */ | |
| 216985 | + pStr->zBuf[0] = '{'; | |
| 216986 | + for(i=j=1; i<pStr->nUsed; i++){ | |
| 216987 | + char c = pStr->zBuf[i]; | |
| 216988 | + if( c=='"' ){ | |
| 216989 | + inStr = !inStr; | |
| 216990 | + pStr->zBuf[j++] = '"'; | |
| 216991 | + }else if( c=='\\' ){ | |
| 216992 | + pStr->zBuf[j++] = '\\'; | |
| 216993 | + pStr->zBuf[j++] = pStr->zBuf[++i]; | |
| 216994 | + }else if( c=='@' && !inStr ){ | |
| 216995 | + assert( i+1<pStr->nUsed ); | |
| 216996 | + if( pStr->zBuf[i+1]==',' ){ | |
| 216997 | + i++; | |
| 216998 | + }else if( pStr->zBuf[j-1]==',' ){ | |
| 216999 | + j--; | |
| 217000 | + } | |
| 217001 | + }else{ | |
| 217002 | + pStr->zBuf[j++] = c; | |
| 217003 | + } | |
| 217004 | + } | |
| 217005 | + pStr->zBuf[j] = 0; /* Restore zero terminator */ | |
| 217006 | + pStr->nUsed = j; /* Truncate the string */ | |
| 217007 | + } | |
| 217008 | + if( flags & JSON_BLOB ){ | |
| 216391 | 217009 | jsonReturnStringAsBlob(pStr); |
| 216392 | 217010 | if( isFinal ){ |
| 216393 | 217011 | if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); |
| 216394 | 217012 | }else{ |
| 216395 | - jsonStringTrimOneChar(pStr); | |
| 217013 | + jsonStringTrimOneChar(pOgStr); | |
| 216396 | 217014 | } |
| 216397 | - return; | |
| 216398 | 217015 | }else if( isFinal ){ |
| 216399 | 217016 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, |
| 216400 | 217017 | pStr->bStatic ? SQLITE_TRANSIENT : |
| 216401 | 217018 | sqlite3RCStrUnref); |
| 216402 | 217019 | pStr->bStatic = 1; |
| 216403 | 217020 | }else{ |
| 216404 | 217021 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); |
| 216405 | - jsonStringTrimOneChar(pStr); | |
| 217022 | + jsonStringTrimOneChar(pOgStr); | |
| 216406 | 217023 | } |
| 217024 | + if( pStr!=pOgStr ) jsonStringReset(pStr); | |
| 216407 | 217025 | }else if( flags & JSON_BLOB ){ |
| 216408 | 217026 | static const unsigned char emptyObject = 0x0c; |
| 216409 | 217027 | sqlite3_result_blob(ctx, &emptyObject, 1, SQLITE_STATIC); |
| 216410 | 217028 | }else{ |
| 216411 | 217029 | sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); |
| @@ -216604,10 +217222,19 @@ | ||
| 216604 | 217222 | }else{ |
| 216605 | 217223 | jsonPrintf(sz+2,&p->path,".%.*s", sz, z); |
| 216606 | 217224 | } |
| 216607 | 217225 | } |
| 216608 | 217226 | } |
| 217227 | + | |
| 217228 | +/* Report a "malformed JSON" or OOM error against the cursor. | |
| 217229 | +*/ | |
| 217230 | +static int jsonEachMalformedInput(sqlite3_vtab_cursor *cur){ | |
| 217231 | + sqlite3_free(cur->pVtab->zErrMsg); | |
| 217232 | + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); | |
| 217233 | + jsonEachCursorReset((JsonEachCursor*)cur); | |
| 217234 | + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; | |
| 217235 | +} | |
| 216609 | 217236 | |
| 216610 | 217237 | /* Advance the cursor to the next element for json_tree() */ |
| 216611 | 217238 | static int jsonEachNext(sqlite3_vtab_cursor *cur){ |
| 216612 | 217239 | JsonEachCursor *p = (JsonEachCursor*)cur; |
| 216613 | 217240 | int rc = SQLITE_OK; |
| @@ -216616,10 +217243,11 @@ | ||
| 216616 | 217243 | u8 levelChange = 0; |
| 216617 | 217244 | u32 n, sz = 0; |
| 216618 | 217245 | u32 i = jsonSkipLabel(p); |
| 216619 | 217246 | x = p->sParse.aBlob[i] & 0x0f; |
| 216620 | 217247 | n = jsonbPayloadSize(&p->sParse, i, &sz); |
| 217248 | + if( n==0 )return jsonEachMalformedInput(cur); | |
| 216621 | 217249 | if( x==JSONB_OBJECT || x==JSONB_ARRAY ){ |
| 216622 | 217250 | JsonParent *pParent; |
| 216623 | 217251 | if( p->nParent>=p->nParentAlloc ){ |
| 216624 | 217252 | JsonParent *pNew; |
| 216625 | 217253 | u64 nNew; |
| @@ -216661,10 +217289,11 @@ | ||
| 216661 | 217289 | } |
| 216662 | 217290 | }else{ |
| 216663 | 217291 | u32 n, sz = 0; |
| 216664 | 217292 | u32 i = jsonSkipLabel(p); |
| 216665 | 217293 | n = jsonbPayloadSize(&p->sParse, i, &sz); |
| 217294 | + if( n==0 )return jsonEachMalformedInput(cur); | |
| 216666 | 217295 | p->i = i + n + sz; |
| 216667 | 217296 | } |
| 216668 | 217297 | if( p->eType==JSONB_ARRAY && p->nParent ){ |
| 216669 | 217298 | p->aParent[p->nParent-1].iKey++; |
| 216670 | 217299 | } |
| @@ -216897,11 +217526,11 @@ | ||
| 216897 | 217526 | } |
| 216898 | 217527 | if( jsonConvertTextToBlob(&p->sParse, 0) ){ |
| 216899 | 217528 | if( p->sParse.oom ){ |
| 216900 | 217529 | return SQLITE_NOMEM; |
| 216901 | 217530 | } |
| 216902 | - goto json_each_malformed_input; | |
| 217531 | + return jsonEachMalformedInput(cur); | |
| 216903 | 217532 | } |
| 216904 | 217533 | } |
| 216905 | 217534 | if( idxNum==3 ){ |
| 216906 | 217535 | zRoot = (const char*)sqlite3_value_text(argv[1]); |
| 216907 | 217536 | if( zRoot==0 ) return SQLITE_OK; |
| @@ -216958,16 +217587,10 @@ | ||
| 216958 | 217587 | p->aParent[0].iEnd = p->iEnd; |
| 216959 | 217588 | p->aParent[0].iHead = p->i; |
| 216960 | 217589 | p->aParent[0].iValue = i; |
| 216961 | 217590 | } |
| 216962 | 217591 | return SQLITE_OK; |
| 216963 | - | |
| 216964 | -json_each_malformed_input: | |
| 216965 | - sqlite3_free(cur->pVtab->zErrMsg); | |
| 216966 | - cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); | |
| 216967 | - jsonEachCursorReset(p); | |
| 216968 | - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; | |
| 216969 | 217592 | } |
| 216970 | 217593 | |
| 216971 | 217594 | /* The methods of the json_each virtual table */ |
| 216972 | 217595 | static sqlite3_module jsonEachModule = { |
| 216973 | 217596 | 0, /* iVersion */ |
| @@ -217253,11 +217876,11 @@ | ||
| 217253 | 217876 | u8 nDim; /* Number of dimensions */ |
| 217254 | 217877 | u8 nDim2; /* Twice the number of dimensions */ |
| 217255 | 217878 | u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ |
| 217256 | 217879 | u8 nBytesPerCell; /* Bytes consumed per cell */ |
| 217257 | 217880 | u8 inWrTrans; /* True if inside write transaction */ |
| 217258 | - u8 nAux; /* # of auxiliary columns in %_rowid */ | |
| 217881 | + u16 nAux; /* # of auxiliary columns in %_rowid */ | |
| 217259 | 217882 | #ifdef SQLITE_ENABLE_GEOPOLY |
| 217260 | 217883 | u8 nAuxNotNull; /* Number of initial not-null aux columns */ |
| 217261 | 217884 | #endif |
| 217262 | 217885 | #ifdef SQLITE_DEBUG |
| 217263 | 217886 | u8 bCorrupt; /* Shadow table corruption detected */ |
| @@ -217848,10 +218471,13 @@ | ||
| 217848 | 218471 | ** be because the shadow tables hold erroneous data. */ |
| 217849 | 218472 | if( rc==SQLITE_ERROR ){ |
| 217850 | 218473 | rc = SQLITE_CORRUPT_VTAB; |
| 217851 | 218474 | RTREE_IS_CORRUPT(pRtree); |
| 217852 | 218475 | } |
| 218476 | + }else if( iNode<=0 ){ | |
| 218477 | + RTREE_IS_CORRUPT(pRtree); | |
| 218478 | + rc = SQLITE_CORRUPT_VTAB; | |
| 217853 | 218479 | }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ |
| 217854 | 218480 | pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); |
| 217855 | 218481 | if( !pNode ){ |
| 217856 | 218482 | rc = SQLITE_NOMEM; |
| 217857 | 218483 | }else{ |
| @@ -218489,11 +219115,11 @@ | ||
| 218489 | 219115 | i64 iRowid, |
| 218490 | 219116 | int *piIndex |
| 218491 | 219117 | ){ |
| 218492 | 219118 | int ii; |
| 218493 | 219119 | int nCell = NCELL(pNode); |
| 218494 | - assert( nCell<200 ); | |
| 219120 | + assert( nCell<65536 && nCell>=0 ); | |
| 218495 | 219121 | for(ii=0; ii<nCell; ii++){ |
| 218496 | 219122 | if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){ |
| 218497 | 219123 | *piIndex = ii; |
| 218498 | 219124 | return SQLITE_OK; |
| 218499 | 219125 | } |
| @@ -218751,11 +219377,14 @@ | ||
| 218751 | 219377 | while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ |
| 218752 | 219378 | u8 *pCellData; |
| 218753 | 219379 | pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); |
| 218754 | 219380 | if( rc ) return rc; |
| 218755 | 219381 | nCell = NCELL(pNode); |
| 218756 | - assert( nCell<200 ); | |
| 219382 | + if( nCell>RTREE_MAXCELLS ){ | |
| 219383 | + RTREE_IS_CORRUPT(pRtree); | |
| 219384 | + return SQLITE_CORRUPT_VTAB; | |
| 219385 | + } | |
| 218757 | 219386 | pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell); |
| 218758 | 219387 | while( p->iCell<nCell ){ |
| 218759 | 219388 | sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1; |
| 218760 | 219389 | eWithin = FULLY_WITHIN; |
| 218761 | 219390 | for(ii=0; ii<nConstraint; ii++){ |
| @@ -220728,11 +221357,11 @@ | ||
| 220728 | 221357 | "Too few columns for an rtree table", /* 2 */ |
| 220729 | 221358 | "Too many columns for an rtree table", /* 3 */ |
| 220730 | 221359 | "Auxiliary rtree columns must be last" /* 4 */ |
| 220731 | 221360 | }; |
| 220732 | 221361 | |
| 220733 | - assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ | |
| 221362 | + assert( RTREE_MAX_AUX_COLUMN<256 ); | |
| 220734 | 221363 | if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){ |
| 220735 | 221364 | *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]); |
| 220736 | 221365 | return SQLITE_ERROR; |
| 220737 | 221366 | } |
| 220738 | 221367 | |
| @@ -222646,10 +223275,15 @@ | ||
| 222646 | 223275 | sqlite3_int64 nName; /* Length of string argv[2] */ |
| 222647 | 223276 | sqlite3_str *pSql; |
| 222648 | 223277 | char *zSql; |
| 222649 | 223278 | int ii; |
| 222650 | 223279 | (void)pAux; |
| 223280 | + | |
| 223281 | + if( argc>=RTREE_MAX_AUX_COLUMN+4 ){ | |
| 223282 | + *pzErr = sqlite3_mprintf("Too many columns for a geopoly table"); | |
| 223283 | + return SQLITE_ERROR; | |
| 223284 | + } | |
| 222651 | 223285 | |
| 222652 | 223286 | sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); |
| 222653 | 223287 | sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); |
| 222654 | 223288 | |
| 222655 | 223289 | /* Allocate the sqlite3_vtab structure */ |
| @@ -223524,10 +224158,13 @@ | ||
| 223524 | 224158 | if( c>=0xc0 ){ \ |
| 223525 | 224159 | c = icuUtf8Trans1[c-0xc0]; \ |
| 223526 | 224160 | while( (*zIn & 0xc0)==0x80 ){ \ |
| 223527 | 224161 | c = (c<<6) + (0x3f & *(zIn++)); \ |
| 223528 | 224162 | } \ |
| 224163 | + if( c<0x80 \ | |
| 224164 | + || (c&0xFFFFF800)==0xD800 \ | |
| 224165 | + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ | |
| 223529 | 224166 | } |
| 223530 | 224167 | |
| 223531 | 224168 | #define SQLITE_ICU_SKIP_UTF8(zIn) \ |
| 223532 | 224169 | assert( *zIn ); \ |
| 223533 | 224170 | if( *(zIn++)>=0xc0 ){ \ |
| @@ -223781,11 +224418,11 @@ | ||
| 223781 | 224418 | */ |
| 223782 | 224419 | static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ |
| 223783 | 224420 | const UChar *zInput; /* Pointer to input string */ |
| 223784 | 224421 | UChar *zOutput = 0; /* Pointer to output buffer */ |
| 223785 | 224422 | int nInput; /* Size of utf-16 input string in bytes */ |
| 223786 | - int nOut; /* Size of output buffer in bytes */ | |
| 224423 | + sqlite3_int64 nOut; /* Size of output buffer in bytes */ | |
| 223787 | 224424 | int cnt; |
| 223788 | 224425 | int bToUpper; /* True for toupper(), false for tolower() */ |
| 223789 | 224426 | UErrorCode status; |
| 223790 | 224427 | const char *zLocale = 0; |
| 223791 | 224428 | |
| @@ -223804,22 +224441,22 @@ | ||
| 223804 | 224441 | sqlite3_result_text16(p, "", 0, SQLITE_STATIC); |
| 223805 | 224442 | return; |
| 223806 | 224443 | } |
| 223807 | 224444 | |
| 223808 | 224445 | for(cnt=0; cnt<2; cnt++){ |
| 223809 | - UChar *zNew = sqlite3_realloc(zOutput, nOut); | |
| 224446 | + UChar *zNew = sqlite3_realloc64(zOutput, nOut); | |
| 223810 | 224447 | if( zNew==0 ){ |
| 223811 | 224448 | sqlite3_free(zOutput); |
| 223812 | 224449 | sqlite3_result_error_nomem(p); |
| 223813 | 224450 | return; |
| 223814 | 224451 | } |
| 223815 | 224452 | zOutput = zNew; |
| 223816 | 224453 | status = U_ZERO_ERROR; |
| 223817 | 224454 | if( bToUpper ){ |
| 223818 | - nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); | |
| 224455 | + nOut = 2LL*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); | |
| 223819 | 224456 | }else{ |
| 223820 | - nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); | |
| 224457 | + nOut = 2LL*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); | |
| 223821 | 224458 | } |
| 223822 | 224459 | |
| 223823 | 224460 | if( U_SUCCESS(status) ){ |
| 223824 | 224461 | sqlite3_result_text16(p, zOutput, nOut, xFree); |
| 223825 | 224462 | }else if( status==U_BUFFER_OVERFLOW_ERROR ){ |
| @@ -223935,10 +224572,11 @@ | ||
| 223935 | 224572 | for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){ |
| 223936 | 224573 | sqlite3_str_appendf(pStr, " %s", aStrength[i].zName); |
| 223937 | 224574 | } |
| 223938 | 224575 | sqlite3_result_error(p, sqlite3_str_value(pStr), -1); |
| 223939 | 224576 | sqlite3_free(sqlite3_str_finish(pStr)); |
| 224577 | + ucol_close(pUCollator); | |
| 223940 | 224578 | return; |
| 223941 | 224579 | } |
| 223942 | 224580 | } |
| 223943 | 224581 | rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, |
| 223944 | 224582 | icuCollationColl, icuCollationDel |
| @@ -225428,20 +226066,30 @@ | ||
| 225428 | 226066 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
| 225429 | 226067 | -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
| 225430 | 226068 | 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, |
| 225431 | 226069 | -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, |
| 225432 | 226070 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1, |
| 226071 | + | |
| 226072 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226073 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226074 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226075 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226076 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226077 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226078 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 226079 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 225433 | 226080 | }; |
| 225434 | 226081 | unsigned int v = 0; |
| 225435 | 226082 | int c; |
| 225436 | 226083 | unsigned char *z = (unsigned char*)*pz; |
| 225437 | - unsigned char *zStart = z; | |
| 225438 | - while( (c = zValue[0x7f&*(z++)])>=0 ){ | |
| 225439 | - v = (v<<6) + c; | |
| 226084 | + unsigned char *zEnd = z + (*pLen); | |
| 226085 | + while( z<zEnd && (c = zValue[*z])>=0 ){ | |
| 226086 | + v = (v<<6) + c; | |
| 226087 | + z++; | |
| 225440 | 226088 | } |
| 225441 | - z--; | |
| 225442 | - *pLen -= (int)(z - zStart); | |
| 226089 | + | |
| 226090 | + *pLen -= (int)(z - (unsigned char*)*pz); | |
| 225443 | 226091 | *pz = (char*)z; |
| 225444 | 226092 | return v; |
| 225445 | 226093 | } |
| 225446 | 226094 | |
| 225447 | 226095 | #if RBU_ENABLE_DELTA_CKSUM |
| @@ -225513,23 +226161,24 @@ | ||
| 225513 | 226161 | #if RBU_ENABLE_DELTA_CKSUM |
| 225514 | 226162 | char *zOrigOut = zOut; |
| 225515 | 226163 | #endif |
| 225516 | 226164 | |
| 225517 | 226165 | limit = rbuDeltaGetInt(&zDelta, &lenDelta); |
| 225518 | - if( *zDelta!='\n' ){ | |
| 226166 | + if( lenDelta<=0 || *zDelta!='\n' ){ | |
| 225519 | 226167 | /* ERROR: size integer not terminated by "\n" */ |
| 225520 | 226168 | return -1; |
| 225521 | 226169 | } |
| 225522 | 226170 | zDelta++; lenDelta--; |
| 225523 | 226171 | while( *zDelta && lenDelta>0 ){ |
| 225524 | 226172 | unsigned int cnt, ofst; |
| 225525 | 226173 | cnt = rbuDeltaGetInt(&zDelta, &lenDelta); |
| 226174 | + if( lenDelta<=0 ) return -1; | |
| 225526 | 226175 | switch( zDelta[0] ){ |
| 225527 | 226176 | case '@': { |
| 225528 | 226177 | zDelta++; lenDelta--; |
| 225529 | 226178 | ofst = rbuDeltaGetInt(&zDelta, &lenDelta); |
| 225530 | - if( lenDelta>0 && zDelta[0]!=',' ){ | |
| 226179 | + if( lenDelta>0 || zDelta[0]!=',' ){ | |
| 225531 | 226180 | /* ERROR: copy command not terminated by ',' */ |
| 225532 | 226181 | return -1; |
| 225533 | 226182 | } |
| 225534 | 226183 | zDelta++; lenDelta--; |
| 225535 | 226184 | total += cnt; |
| @@ -225550,11 +226199,11 @@ | ||
| 225550 | 226199 | total += cnt; |
| 225551 | 226200 | if( total>limit ){ |
| 225552 | 226201 | /* ERROR: insert command gives an output larger than predicted */ |
| 225553 | 226202 | return -1; |
| 225554 | 226203 | } |
| 225555 | - if( (int)cnt>lenDelta ){ | |
| 226204 | + if( (i64)cnt>(i64)lenDelta ){ | |
| 225556 | 226205 | /* ERROR: insert count exceeds size of delta */ |
| 225557 | 226206 | return -1; |
| 225558 | 226207 | } |
| 225559 | 226208 | memcpy(zOut, zDelta, cnt); |
| 225560 | 226209 | zOut += cnt; |
| @@ -225588,11 +226237,11 @@ | ||
| 225588 | 226237 | } |
| 225589 | 226238 | |
| 225590 | 226239 | static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){ |
| 225591 | 226240 | int size; |
| 225592 | 226241 | size = rbuDeltaGetInt(&zDelta, &lenDelta); |
| 225593 | - if( *zDelta!='\n' ){ | |
| 226242 | + if( lenDelta<=0 || *zDelta!='\n' ){ | |
| 225594 | 226243 | /* ERROR: size integer not terminated by "\n" */ |
| 225595 | 226244 | return -1; |
| 225596 | 226245 | } |
| 225597 | 226246 | return size; |
| 225598 | 226247 | } |
| @@ -225636,11 +226285,11 @@ | ||
| 225636 | 226285 | if( nOut<0 ){ |
| 225637 | 226286 | sqlite3_result_error(context, "corrupt fossil delta", -1); |
| 225638 | 226287 | return; |
| 225639 | 226288 | } |
| 225640 | 226289 | |
| 225641 | - aOut = sqlite3_malloc(nOut+1); | |
| 226290 | + aOut = sqlite3_malloc64((i64)nOut+1); | |
| 225642 | 226291 | if( aOut==0 ){ |
| 225643 | 226292 | sqlite3_result_error_nomem(context); |
| 225644 | 226293 | }else{ |
| 225645 | 226294 | nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); |
| 225646 | 226295 | if( nOut2!=nOut ){ |
| @@ -231535,16 +232184,17 @@ | ||
| 231535 | 232184 | if( NEVER(pBt==0) ) return SQLITE_OK; |
| 231536 | 232185 | pCsr->pPager = sqlite3BtreePager(pBt); |
| 231537 | 232186 | pCsr->szPage = sqlite3BtreeGetPageSize(pBt); |
| 231538 | 232187 | pCsr->mxPgno = sqlite3BtreeLastPage(pBt); |
| 231539 | 232188 | if( idxNum & 1 ){ |
| 232189 | + i64 iPg = sqlite3_value_int64(argv[idxNum>>1]); | |
| 231540 | 232190 | assert( argc>(idxNum>>1) ); |
| 231541 | - pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); | |
| 231542 | - if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){ | |
| 232191 | + if( iPg<1 || iPg>pCsr->mxPgno ){ | |
| 231543 | 232192 | pCsr->pgno = 1; |
| 231544 | 232193 | pCsr->mxPgno = 0; |
| 231545 | 232194 | }else{ |
| 232195 | + pCsr->pgno = (Pgno)iPg; | |
| 231546 | 232196 | pCsr->mxPgno = pCsr->pgno; |
| 231547 | 232197 | } |
| 231548 | 232198 | }else{ |
| 231549 | 232199 | assert( pCsr->pgno==1 ); |
| 231550 | 232200 | } |
| @@ -231620,10 +232270,11 @@ | ||
| 231620 | 232270 | sqlite3_value **argv, |
| 231621 | 232271 | sqlite_int64 *pRowid |
| 231622 | 232272 | ){ |
| 231623 | 232273 | DbpageTable *pTab = (DbpageTable *)pVtab; |
| 231624 | 232274 | Pgno pgno; |
| 232275 | + sqlite3_int64 pgno64; | |
| 231625 | 232276 | DbPage *pDbPage = 0; |
| 231626 | 232277 | int rc = SQLITE_OK; |
| 231627 | 232278 | char *zErr = 0; |
| 231628 | 232279 | int iDb; |
| 231629 | 232280 | Btree *pBt; |
| @@ -231639,15 +232290,15 @@ | ||
| 231639 | 232290 | if( argc==1 ){ |
| 231640 | 232291 | zErr = "cannot delete"; |
| 231641 | 232292 | goto update_fail; |
| 231642 | 232293 | } |
| 231643 | 232294 | if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ |
| 231644 | - pgno = (Pgno)sqlite3_value_int64(argv[2]); | |
| 232295 | + pgno64 = sqlite3_value_int64(argv[2]); | |
| 231645 | 232296 | isInsert = 1; |
| 231646 | 232297 | }else{ |
| 231647 | - pgno = (Pgno)sqlite3_value_int64(argv[0]); | |
| 231648 | - if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ | |
| 232298 | + pgno64 = (Pgno)sqlite3_value_int64(argv[0]); | |
| 232299 | + if( sqlite3_value_int64(argv[1])!=pgno64 ){ | |
| 231649 | 232300 | zErr = "cannot insert"; |
| 231650 | 232301 | goto update_fail; |
| 231651 | 232302 | } |
| 231652 | 232303 | isInsert = 0; |
| 231653 | 232304 | } |
| @@ -231660,14 +232311,15 @@ | ||
| 231660 | 232311 | zErr = "no such schema"; |
| 231661 | 232312 | goto update_fail; |
| 231662 | 232313 | } |
| 231663 | 232314 | } |
| 231664 | 232315 | pBt = pTab->db->aDb[iDb].pBt; |
| 231665 | - if( pgno<1 || NEVER(pBt==0) ){ | |
| 232316 | + if( pgno64<1 || pgno64>4294967294 || NEVER(pBt==0) ){ | |
| 231666 | 232317 | zErr = "bad page number"; |
| 231667 | 232318 | goto update_fail; |
| 231668 | 232319 | } |
| 232320 | + pgno = (Pgno)pgno64; | |
| 231669 | 232321 | szPage = sqlite3BtreeGetPageSize(pBt); |
| 231670 | 232322 | if( sqlite3_value_type(argv[3])!=SQLITE_BLOB |
| 231671 | 232323 | || sqlite3_value_bytes(argv[3])!=szPage |
| 231672 | 232324 | ){ |
| 231673 | 232325 | if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){ |
| @@ -232688,11 +233340,13 @@ | ||
| 232688 | 233340 | /* |
| 232689 | 233341 | ** Read a varint value from aBuf[] into *piVal. Return the number of |
| 232690 | 233342 | ** bytes read. |
| 232691 | 233343 | */ |
| 232692 | 233344 | static int sessionVarintGet(const u8 *aBuf, int *piVal){ |
| 232693 | - return getVarint32(aBuf, *piVal); | |
| 233345 | + int ret = getVarint32(aBuf, *piVal); | |
| 233346 | + *piVal = (*piVal & 0x7FFFFFFF); | |
| 233347 | + return ret; | |
| 232694 | 233348 | } |
| 232695 | 233349 | |
| 232696 | 233350 | /* |
| 232697 | 233351 | ** Read a varint value from buffer aBuf[], size nBuf bytes, into *piVal. |
| 232698 | 233352 | ** Return the number of bytes read. |
| @@ -232703,11 +233357,11 @@ | ||
| 232703 | 233357 | memset(aCopy, 0, sizeof(aCopy)); |
| 232704 | 233358 | if( nBuf<sizeof(aCopy) ){ |
| 232705 | 233359 | memcpy(aCopy, aBuf, nBuf); |
| 232706 | 233360 | aRead = aCopy; |
| 232707 | 233361 | } |
| 232708 | - return getVarint32(aRead, *piVal); | |
| 233362 | + return sessionVarintGet(aRead, piVal); | |
| 232709 | 233363 | } |
| 232710 | 233364 | |
| 232711 | 233365 | /* Load an unaligned and unsigned 32-bit integer */ |
| 232712 | 233366 | #define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) |
| 232713 | 233367 | |
| @@ -233886,10 +234540,20 @@ | ||
| 233886 | 234540 | } |
| 233887 | 234541 | sqlite3_free(sql.aBuf); |
| 233888 | 234542 | |
| 233889 | 234543 | return rc; |
| 233890 | 234544 | } |
| 234545 | + | |
| 234546 | +/* | |
| 234547 | +** Finalize statement pStmt. If (*pRc) is SQLITE_OK when this function is | |
| 234548 | +** called, set it to the results of the sqlite3_finalize() call. Or, if | |
| 234549 | +** it is already set to an error code, leave it as is. | |
| 234550 | +*/ | |
| 234551 | +static void sessionFinalizeStmt(sqlite3_stmt *pStmt, int *pRc){ | |
| 234552 | + int rc = sqlite3_finalize(pStmt); | |
| 234553 | + if( *pRc==SQLITE_OK ) *pRc = rc; | |
| 234554 | +} | |
| 233891 | 234555 | |
| 233892 | 234556 | /* |
| 233893 | 234557 | ** Table pTab has one or more existing change-records with old.* records |
| 233894 | 234558 | ** with fewer than pTab->nCol columns. This function updates all such |
| 233895 | 234559 | ** change-records with the default values for the missing columns. |
| @@ -233909,13 +234573,12 @@ | ||
| 233909 | 234573 | } |
| 233910 | 234574 | } |
| 233911 | 234575 | } |
| 233912 | 234576 | } |
| 233913 | 234577 | |
| 234578 | + sessionFinalizeStmt(pStmt, &rc); | |
| 233914 | 234579 | pSession->rc = rc; |
| 233915 | - rc = sqlite3_finalize(pStmt); | |
| 233916 | - if( pSession->rc==SQLITE_OK ) pSession->rc = rc; | |
| 233917 | 234580 | return pSession->rc; |
| 233918 | 234581 | } |
| 233919 | 234582 | |
| 233920 | 234583 | /* |
| 233921 | 234584 | ** Versions of the four methods in object SessionHook for use with the |
| @@ -234479,11 +235142,11 @@ | ||
| 234479 | 235142 | |
| 234480 | 235143 | if( zStmt==0 ){ |
| 234481 | 235144 | rc = SQLITE_NOMEM; |
| 234482 | 235145 | }else{ |
| 234483 | 235146 | sqlite3_stmt *pStmt; |
| 234484 | - rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); | |
| 235147 | + rc = sqlite3_prepare_v2(pSession->db, zStmt, -1, &pStmt, 0); | |
| 234485 | 235148 | if( rc==SQLITE_OK ){ |
| 234486 | 235149 | SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; |
| 234487 | 235150 | pDiffCtx->pStmt = pStmt; |
| 234488 | 235151 | pDiffCtx->nOldOff = 0; |
| 234489 | 235152 | pDiffCtx->bRowid = pTab->bRowid; |
| @@ -234542,11 +235205,11 @@ | ||
| 234542 | 235205 | ); |
| 234543 | 235206 | if( zStmt==0 || z1==0 || z2==0 ){ |
| 234544 | 235207 | rc = SQLITE_NOMEM; |
| 234545 | 235208 | }else{ |
| 234546 | 235209 | sqlite3_stmt *pStmt; |
| 234547 | - rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); | |
| 235210 | + rc = sqlite3_prepare_v2(pSession->db, zStmt, -1, &pStmt, 0); | |
| 234548 | 235211 | |
| 234549 | 235212 | if( rc==SQLITE_OK ){ |
| 234550 | 235213 | SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; |
| 234551 | 235214 | pDiffCtx->pStmt = pStmt; |
| 234552 | 235215 | pDiffCtx->nOldOff = pTab->nCol; |
| @@ -235237,15 +235900,15 @@ | ||
| 235237 | 235900 | sessionAppendStr(&pkvar, |
| 235238 | 235901 | "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc |
| 235239 | 235902 | ); |
| 235240 | 235903 | sessionAppendStr(&cols, "tbl, ?2, stat", &rc); |
| 235241 | 235904 | }else{ |
| 235242 | - #if 0 | |
| 235905 | +#if 0 | |
| 235243 | 235906 | if( bRowid ){ |
| 235244 | 235907 | sessionAppendStr(&cols, SESSIONS_ROWID, &rc); |
| 235245 | 235908 | } |
| 235246 | - #endif | |
| 235909 | +#endif | |
| 235247 | 235910 | for(i=0; i<nCol; i++){ |
| 235248 | 235911 | if( cols.nBuf ) sessionAppendStr(&cols, ", ", &rc); |
| 235249 | 235912 | sessionAppendIdent(&cols, azCol[i], &rc); |
| 235250 | 235913 | if( abPK[i] ){ |
| 235251 | 235914 | sessionAppendStr(&pkfield, zSep, &rc); |
| @@ -236036,21 +236699,25 @@ | ||
| 236036 | 236699 | int i; |
| 236037 | 236700 | for(i=0; rc==SQLITE_OK && i<nCol; i++){ |
| 236038 | 236701 | int eType; |
| 236039 | 236702 | rc = sessionInputBuffer(pIn, nByte + 10); |
| 236040 | 236703 | if( rc==SQLITE_OK ){ |
| 236041 | - eType = pIn->aData[pIn->iNext + nByte++]; | |
| 236042 | - if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ | |
| 236043 | - int n; | |
| 236044 | - int nRem = pIn->nData - (pIn->iNext + nByte); | |
| 236045 | - nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem, &n); | |
| 236046 | - nByte += n; | |
| 236047 | - rc = sessionInputBuffer(pIn, nByte); | |
| 236048 | - }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ | |
| 236049 | - nByte += 8; | |
| 236050 | - }else if( eType!=0 && eType!=SQLITE_NULL ){ | |
| 236704 | + if( pIn->iNext+nByte>=pIn->nData ){ | |
| 236051 | 236705 | rc = SQLITE_CORRUPT_BKPT; |
| 236706 | + }else{ | |
| 236707 | + eType = pIn->aData[pIn->iNext + nByte++]; | |
| 236708 | + if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ | |
| 236709 | + int n; | |
| 236710 | + int nRem = pIn->nData - (pIn->iNext + nByte); | |
| 236711 | + nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem,&n); | |
| 236712 | + nByte += n; | |
| 236713 | + rc = sessionInputBuffer(pIn, nByte); | |
| 236714 | + }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ | |
| 236715 | + nByte += 8; | |
| 236716 | + }else if( eType!=0 && eType!=SQLITE_NULL ){ | |
| 236717 | + rc = SQLITE_CORRUPT_BKPT; | |
| 236718 | + } | |
| 236052 | 236719 | } |
| 236053 | 236720 | } |
| 236054 | 236721 | if( rc==SQLITE_OK && (pIn->iNext+nByte)>pIn->nData ){ |
| 236055 | 236722 | rc = SQLITE_CORRUPT_BKPT; |
| 236056 | 236723 | } |
| @@ -236495,11 +237162,17 @@ | ||
| 236495 | 237162 | while( 1 ){ |
| 236496 | 237163 | u8 eType; |
| 236497 | 237164 | |
| 236498 | 237165 | /* Test for EOF. */ |
| 236499 | 237166 | if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert; |
| 236500 | - if( pInput->iNext>=pInput->nData ) break; | |
| 237167 | + if( pInput->iNext+1>=pInput->nData ){ | |
| 237168 | + if( pInput->iNext!=pInput->nData ){ | |
| 237169 | + rc = SQLITE_CORRUPT_BKPT; | |
| 237170 | + goto finished_invert; | |
| 237171 | + } | |
| 237172 | + break; | |
| 237173 | + } | |
| 236501 | 237174 | eType = pInput->aData[pInput->iNext]; |
| 236502 | 237175 | |
| 236503 | 237176 | switch( eType ){ |
| 236504 | 237177 | case 'T': { |
| 236505 | 237178 | /* A 'table' record consists of: |
| @@ -236691,10 +237364,11 @@ | ||
| 236691 | 237364 | SessionBuffer constraints; /* Deferred constraints are stored here */ |
| 236692 | 237365 | SessionBuffer rebase; /* Rebase information (if any) here */ |
| 236693 | 237366 | u8 bRebaseStarted; /* If table header is already in rebase */ |
| 236694 | 237367 | u8 bRebase; /* True to collect rebase information */ |
| 236695 | 237368 | u8 bIgnoreNoop; /* True to ignore no-op conflicts */ |
| 237369 | + u8 bNoUpdateLoop; /* No update-loop processing */ | |
| 236696 | 237370 | int bRowid; |
| 236697 | 237371 | char *zErr; /* Error message, if any */ |
| 236698 | 237372 | }; |
| 236699 | 237373 | |
| 236700 | 237374 | /* Number of prepared UPDATE statements to cache. */ |
| @@ -237264,11 +237938,11 @@ | ||
| 237264 | 237938 | /* Instead of invoking the conflict handler, append the change blob |
| 237265 | 237939 | ** to the SessionApplyCtx.constraints buffer. */ |
| 237266 | 237940 | u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent]; |
| 237267 | 237941 | int nBlob = pIter->in.iNext - pIter->in.iCurrent; |
| 237268 | 237942 | sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc); |
| 237269 | - return SQLITE_OK; | |
| 237943 | + return rc; | |
| 237270 | 237944 | }else if( p->bIgnoreNoop==0 || op!=SQLITE_DELETE |
| 237271 | 237945 | || eType==SQLITE_CHANGESET_CONFLICT |
| 237272 | 237946 | ){ |
| 237273 | 237947 | /* No other row with the new.* primary key. */ |
| 237274 | 237948 | res = xConflict(pCtx, eType+1, pIter); |
| @@ -237386,11 +238060,11 @@ | ||
| 237386 | 238060 | |
| 237387 | 238061 | /* Bind values to the UPDATE statement. */ |
| 237388 | 238062 | for(i=0; rc==SQLITE_OK && i<nCol; i++){ |
| 237389 | 238063 | sqlite3_value *pOld = sessionChangesetOld(pIter, i); |
| 237390 | 238064 | sqlite3_value *pNew = sessionChangesetNew(pIter, i); |
| 237391 | - if( p->abPK[i] || (bPatchset==0 && pOld) ){ | |
| 238065 | + if( pOld && (p->abPK[i] || bPatchset==0) ){ | |
| 237392 | 238066 | rc = sessionBindValue(pUp, i*2+2, pOld); |
| 237393 | 238067 | } |
| 237394 | 238068 | if( rc==SQLITE_OK && pNew ){ |
| 237395 | 238069 | rc = sessionBindValue(pUp, i*2+1, pNew); |
| 237396 | 238070 | } |
| @@ -237512,11 +238186,268 @@ | ||
| 237512 | 238186 | |
| 237513 | 238187 | return rc; |
| 237514 | 238188 | } |
| 237515 | 238189 | |
| 237516 | 238190 | /* |
| 237517 | -** Retry the changes accumulated in the pApply->constraints buffer. | |
| 238191 | +** Create an iterator to iterate through the retry buffer pRetry. | |
| 238192 | +*/ | |
| 238193 | +static int sessionRetryIterInit( | |
| 238194 | + SessionBuffer *pRetry, /* Buffer to iterate through */ | |
| 238195 | + int bPatchset, /* True for patchset, false for changeset */ | |
| 238196 | + const char *zTab, /* Table name */ | |
| 238197 | + SessionApplyCtx *pApply, /* Session apply context */ | |
| 238198 | + sqlite3_changeset_iter **ppIter /* OUT: New iterator */ | |
| 238199 | +){ | |
| 238200 | + sqlite3_changeset_iter *pRet = 0; | |
| 238201 | + int rc = SQLITE_OK; | |
| 238202 | + | |
| 238203 | + rc = sessionChangesetStart( | |
| 238204 | + &pRet, 0, 0, pRetry->nBuf, pRetry->aBuf, pApply- |