Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge changes from trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | apple-osx |
Files: | files | file ages | folders |
SHA1: |
0f707d1532d6c8277cf0f70821a83e0a |
User & Date: | drh 2016-06-15 10:21:06.192 |
Context
2016-07-25
| ||
17:31 | Merge 3.14 alpha changes from trunk. (check-in: e98cefb17d user: drh tags: apple-osx) | |
2016-06-15
| ||
10:21 | Merge changes from trunk. (check-in: 0f707d1532 user: drh tags: apple-osx) | |
2016-06-13
| ||
19:58 | Fix RBU so that it builds with -DSQLITE_ENABLE_8_3_NAMES. Fix "PRAGMA compile_options" for SQLITE_ENABLE_8_3_NAMES such that it reports the numeric setting: "1" or "2". (check-in: 0230ca17ba user: drh tags: trunk) | |
2016-05-23
| ||
02:57 | Merge changes from trunk. (check-in: 815cc2bb48 user: drh tags: apple-osx) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 427 428 429 | $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/misc/ieee754.c \ | > | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/misc/ieee754.c \ |
︙ | ︙ | |||
548 549 550 551 552 553 554 | # executables needed for testing # TESTPROGS = \ testfixture$(TEXE) \ sqlite3$(TEXE) \ sqlite3_analyzer$(TEXE) \ | | > | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | # executables needed for testing # TESTPROGS = \ testfixture$(TEXE) \ sqlite3$(TEXE) \ sqlite3_analyzer$(TEXE) \ sqldiff$(TEXE) \ dbhash$(TEXE) # Databases containing fuzzer test cases # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ |
︙ | ︙ | |||
598 599 600 601 602 603 604 605 606 607 608 609 610 611 | $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \ $(TOP)/src/shell.c sqlite3.c \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.o $(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \ $(TOP)/ext/misc/scrub.c sqlite3.o $(TLIBS) srcck1$(BEXE): $(TOP)/tool/srcck1.c $(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c | > > > | 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \ $(TOP)/src/shell.c sqlite3.c \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.o $(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \ $(TOP)/ext/misc/scrub.c sqlite3.o $(TLIBS) srcck1$(BEXE): $(TOP)/tool/srcck1.c $(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c |
︙ | ︙ | |||
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 | rm -f sqlite-*-output.vsix rm -f mptester mptester.exe rm -f rbu rbu.exe rm -f srcck1 srcck1.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sqldiff sqldiff.exe rm -f fts5.* fts5parse.* distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section | > | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | rm -f sqlite-*-output.vsix rm -f mptester mptester.exe rm -f rbu rbu.exe rm -f srcck1 srcck1.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sqldiff sqldiff.exe rm -f dbhash dbhash.exe rm -f fts5.* fts5parse.* distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 | $(TOP)\ext\session\test_session.c # Statically linked extensions. # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\fts5\fts5_test_tok.c \ $(TOP)\ext\misc\ieee754.c \ | > | 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 | $(TOP)\ext\session\test_session.c # Statically linked extensions. # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ $(TOP)\ext\misc\csv.c \ $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\fts5\fts5_test_tok.c \ $(TOP)\ext\misc\ieee754.c \ |
︙ | ︙ | |||
1373 1374 1375 1376 1377 1378 1379 | # executables needed for testing # TESTPROGS = \ testfixture.exe \ $(SQLITE3EXE) \ sqlite3_analyzer.exe \ | | > | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | # executables needed for testing # TESTPROGS = \ testfixture.exe \ $(SQLITE3EXE) \ sqlite3_analyzer.exe \ sqldiff.exe \ dbhash.exe # Databases containing fuzzer test cases # FUZZDATA = \ $(TOP)\test\fuzzdata1.db \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db \ |
︙ | ︙ | |||
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 | $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \ /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) # <<mark>> sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) srcck1.exe: $(TOP)\tool\srcck1.c $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c sourcetest: srcck1.exe sqlite3.c | > > > | 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 | $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \ /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) # <<mark>> sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) srcck1.exe: $(TOP)\tool\srcck1.c $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c sourcetest: srcck1.exe sqlite3.c |
︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 | del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL del /Q sqlite3.c sqlite3-*.c 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL | | | 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 | del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL del /Q sqlite3.c sqlite3-*.c 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL del /Q fts5.* fts5parse.* 2>NUL # <</mark>> |
Changes to autoconf/configure.ac.
︙ | ︙ | |||
26 27 28 29 30 31 32 | # Check for library functions that SQLite can optionally use. AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) AC_FUNC_STRERROR_R AC_CONFIG_FILES([Makefile sqlite3.pc]) AC_SUBST(BUILD_CFLAGS) | | > > > > > > > > > > > > | < < < | | < < | > | | | < < | > | < > | < | > > | | > | | | | | | > | > > | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # Check for library functions that SQLite can optionally use. AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) AC_FUNC_STRERROR_R AC_CONFIG_FILES([Makefile sqlite3.pc]) AC_SUBST(BUILD_CFLAGS) #------------------------------------------------------------------------- # Two options to enable readline compatible libraries: # # --enable-editline # --enable-readline # # Both are enabled by default. If, after command line processing both are # still enabled, the script searches for editline first and automatically # disables readline if it is found. So, to use readline explicitly, the # user must pass "--disable-editline". To disable command line editing # support altogether, "--disable-editline --disable-readline". # # When searching for either library, check for headers before libraries # as some distros supply packages that contain libraries but not header # files, which come as a separate development package. # AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])]) AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])]) AS_IF([ test x"$enable_editline" != xno ],[ AC_CHECK_HEADERS([editline/readline.h],[ sLIBS=$LIBS LIBS="" AC_SEARCH_LIBS([readline],[edit],[ AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline) READLINE_LIBS=$LIBS enable_readline=no ]) AS_UNSET(ac_cv_search_readline) LIBS=$sLIBS ]) ]) AS_IF([ test x"$enable_readline" != xno ],[ AC_CHECK_HEADERS([readline/readline.h],[ sLIBS=$LIBS LIBS="" AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], []) AC_SEARCH_LIBS(readline,[readline edit], [ AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper) READLINE_LIBS=$LIBS ]) LIBS=$sLIBS ]) ]) AC_SUBST(READLINE_LIBS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-threadsafe # AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING( |
︙ | ︙ |
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
682 683 684 685 686 687 688 | typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); int sqlite3Fts5ExprPopulatePoslists( Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int ); void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); | < | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); int sqlite3Fts5ExprPopulatePoslists( Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int ); void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); /******************************************* ** The fts5_expr.c API above this point is used by the other hand-written |
︙ | ︙ |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
2613 2614 2615 2616 2617 2618 2619 | return 1; } void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ fts5ExprCheckPoslists(pExpr->pRoot, iRowid); } | < < < < < < < < < < < | 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 | return 1; } void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ fts5ExprCheckPoslists(pExpr->pRoot, iRowid); } /* ** This function is only called for detail=columns tables. */ int sqlite3Fts5ExprPhraseCollist( Fts5Expr *pExpr, int iPhrase, const u8 **ppCollist, |
︙ | ︙ |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 | assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); | < | 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 | assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); }else if( pMatch ){ const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); if( zExpr==0 ) zExpr = ""; rc = fts5CursorParseRank(pConfig, pCsr, pRank); if( rc==SQLITE_OK ){ if( zExpr[0]=='*' ){ |
︙ | ︙ |
Changes to ext/fts5/test/fts5rank.test.
︙ | ︙ | |||
87 88 89 90 91 92 93 | } {1 3 2} do_test 2.7 { execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db } {1 3 2} | > > | > | > > | > > > > > > > > > > > > > > > > > > > > > > > > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | } {1 3 2} do_test 2.7 { execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db } {1 3 2} #-------------------------------------------------------------------------- # At one point there was a problem with queries such as: # # ... MATCH 'x OR y' ORDER BY rank; # # if there were zero occurrences of token 'y' in the dataset. The # following tests verify that that problem has been addressed. # foreach_detail_mode $::testprefix { do_execsql_test 3.0 { CREATE VIRTUAL TABLE y1 USING fts5(z, detail=%DETAIL%); INSERT INTO y1 VALUES('test xyz'); INSERT INTO y1 VALUES('test test xyz test'); INSERT INTO y1 VALUES('test test xyz'); } do_execsql_test 3.1 { SELECT rowid FROM y1('test OR tset'); } {1 2 3} do_execsql_test 3.2 { SELECT rowid FROM y1('test OR tset') ORDER BY bm25(y1) } {2 3 1} do_execsql_test 3.3 { SELECT rowid FROM y1('test OR tset') ORDER BY +rank } {2 3 1} do_execsql_test 3.4 { SELECT rowid FROM y1('test OR tset') ORDER BY rank } {2 3 1} } finish_test |
Added ext/misc/csv.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | /* ** 2016-05-28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains the implementation of an SQLite virtual table for ** reading CSV files. ** ** Usage: ** ** .load ./csv ** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME); ** SELECT * FROM csv; ** ** The columns are named "c1", "c2", "c3", ... by default. But the ** application can define its own CREATE TABLE statement as an additional ** parameter. For example: ** ** CREATE VIRTUAL TABLE temp.csv2 USING csv( ** filename = "../http.log", ** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)" ** ); ** ** Instead of specifying a file, the text of the CSV can be loaded using ** the data= parameter. ** ** If the columns=N parameter is supplied, then the CSV file is assumed to have ** N columns. If the columns parameter is omitted, the CSV file is opened ** as soon as the virtual table is constructed and the first row of the CSV ** is read in order to count the tables. ** ** Some extra debugging features (used for testing virtual tables) are available ** if this module is compiled with -DSQLITE_TEST. */ #include <sqlite3ext.h> SQLITE_EXTENSION_INIT1 #include <string.h> #include <stdlib.h> #include <assert.h> #include <stdarg.h> #include <ctype.h> #include <stdio.h> /* ** A macro to hint to the compiler that a function should not be ** inlined. */ #if defined(__GNUC__) # define CSV_NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) && _MSC_VER>=1310 # define CSV_NOINLINE __declspec(noinline) #else # define CSV_NOINLINE #endif /* Max size of the error message in a CsvReader */ #define CSV_MXERR 200 /* Size of the CsvReader input buffer */ #define CSV_INBUFSZ 1024 /* A context object used when read a CSV file. */ typedef struct CsvReader CsvReader; struct CsvReader { FILE *in; /* Read the CSV text from this input stream */ char *z; /* Accumulated text for a field */ int n; /* Number of bytes in z */ int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ char cTerm; /* Character that terminated the most recent field */ size_t iIn; /* Next unread character in the input buffer */ size_t nIn; /* Number of characters in the input buffer */ char *zIn; /* The input buffer */ char zErr[CSV_MXERR]; /* Error message */ }; /* Initialize a CsvReader object */ static void csv_reader_init(CsvReader *p){ p->in = 0; p->z = 0; p->n = 0; p->nAlloc = 0; p->nLine = 0; p->nIn = 0; p->zIn = 0; p->zErr[0] = 0; } /* Close and reset a CsvReader object */ static void csv_reader_reset(CsvReader *p){ if( p->in ){ fclose(p->in); sqlite3_free(p->zIn); } sqlite3_free(p->z); csv_reader_init(p); } /* Report an error on a CsvReader */ static void csv_errmsg(CsvReader *p, const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); sqlite3_vsnprintf(CSV_MXERR, p->zErr, zFormat, ap); va_end(ap); } /* Open the file associated with a CsvReader ** Return the number of errors. */ static int csv_reader_open( CsvReader *p, /* The reader to open */ const char *zFilename, /* Read from this filename */ const char *zData /* ... or use this data */ ){ if( zFilename ){ p->zIn = sqlite3_malloc( CSV_INBUFSZ ); if( p->zIn==0 ){ csv_errmsg(p, "out of memory"); return 1; } p->in = fopen(zFilename, "rb"); if( p->in==0 ){ csv_reader_reset(p); csv_errmsg(p, "cannot open '%s' for reading", zFilename); return 1; } }else{ assert( p->in==0 ); p->zIn = (char*)zData; p->nIn = strlen(zData); } return 0; } /* The input buffer has overflowed. Refill the input buffer, then ** return the next character */ static CSV_NOINLINE int csv_getc_refill(CsvReader *p){ size_t got; assert( p->iIn>=p->nIn ); /* Only called on an empty input buffer */ assert( p->in!=0 ); /* Only called if reading froma file */ got = fread(p->zIn, 1, CSV_INBUFSZ, p->in); if( got==0 ) return EOF; p->nIn = got; p->iIn = 1; return p->zIn[0]; } /* Return the next character of input. Return EOF at end of input. */ static int csv_getc(CsvReader *p){ if( p->iIn >= p->nIn ){ if( p->in!=0 ) return csv_getc_refill(p); return EOF; } return p->zIn[p->iIn++]; } /* Increase the size of p->z and append character c to the end. ** Return 0 on success and non-zero if there is an OOM error */ static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){ char *zNew; int nNew = p->nAlloc*2 + 100; zNew = sqlite3_realloc64(p->z, nNew); if( zNew ){ p->z = zNew; p->nAlloc = nNew; p->z[p->n++] = c; return 0; }else{ csv_errmsg(p, "out of memory"); return 1; } } /* Append a single character to the CsvReader.z[] array. ** Return 0 on success and non-zero if there is an OOM error */ static int csv_append(CsvReader *p, char c){ if( p->n>=p->nAlloc-1 ) return csv_resize_and_append(p, c); p->z[p->n++] = c; return 0; } /* Read a single field of CSV text. Compatible with rfc4180 and extended ** with the option of having a separator other than ",". ** ** + Input comes from p->in. ** + Store results in p->z of length p->n. Space to hold p->z comes ** from sqlite3_malloc64(). ** + Keep track of the line number in p->nLine. ** + Store the character that terminates the field in p->cTerm. Store ** EOF on end-of-file. ** ** Return "" at EOF. Return 0 on an OOM error. */ static char *csv_read_one_field(CsvReader *p){ int c; p->n = 0; c = csv_getc(p); if( c==EOF ){ p->cTerm = EOF; return ""; } if( c=='"' ){ int pc, ppc; int startLine = p->nLine; pc = ppc = 0; while( 1 ){ c = csv_getc(p); if( c<='"' || pc=='"' ){ if( c=='\n' ) p->nLine++; if( c=='"' ){ if( pc=='"' ){ pc = 0; continue; } } if( (c==',' && pc=='"') || (c=='\n' && pc=='"') || (c=='\n' && pc=='\r' && ppc=='"') || (c==EOF && pc=='"') ){ do{ p->n--; }while( p->z[p->n]!='"' ); p->cTerm = c; break; } if( pc=='"' && c!='\r' ){ csv_errmsg(p, "line %d: unescaped %c character", p->nLine, '"'); break; } if( c==EOF ){ csv_errmsg(p, "line %d: unterminated %c-quoted field\n", startLine, '"'); p->cTerm = c; break; } } if( csv_append(p, (char)c) ) return 0; ppc = pc; pc = c; } }else{ while( c>',' || (c!=EOF && c!=',' && c!='\n') ){ if( csv_append(p, (char)c) ) return 0; c = csv_getc(p); } if( c=='\n' ){ p->nLine++; if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } p->cTerm = c; } if( p->z ) p->z[p->n] = 0; return p->z; } /* Forward references to the various virtual table methods implemented ** in this file. */ static int csvtabCreate(sqlite3*, void*, int, const char*const*, sqlite3_vtab**,char**); static int csvtabConnect(sqlite3*, void*, int, const char*const*, sqlite3_vtab**,char**); static int csvtabBestIndex(sqlite3_vtab*,sqlite3_index_info*); static int csvtabDisconnect(sqlite3_vtab*); static int csvtabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**); static int csvtabClose(sqlite3_vtab_cursor*); static int csvtabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); static int csvtabNext(sqlite3_vtab_cursor*); static int csvtabEof(sqlite3_vtab_cursor*); static int csvtabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int); static int csvtabRowid(sqlite3_vtab_cursor*,sqlite3_int64*); /* An instance of the CSV virtual table */ typedef struct CsvTable { sqlite3_vtab base; /* Base class. Must be first */ char *zFilename; /* Name of the CSV file */ char *zData; /* Raw CSV data in lieu of zFilename */ long iStart; /* Offset to start of data in zFilename */ int nCol; /* Number of columns in the CSV file */ unsigned int tstFlags; /* Bit values used for testing */ } CsvTable; /* Allowed values for tstFlags */ #define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/ /* A cursor for the CSV virtual table */ typedef struct CsvCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ CsvReader rdr; /* The CsvReader object */ char **azVal; /* Value of the current row */ int *aLen; /* Length of each entry */ sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */ } CsvCursor; /* Transfer error message text from a reader into a CsvTable */ static void csv_xfer_error(CsvTable *pTab, CsvReader *pRdr){ sqlite3_free(pTab->base.zErrMsg); pTab->base.zErrMsg = sqlite3_mprintf("%s", pRdr->zErr); } /* ** This method is the destructor fo a CsvTable object. */ static int csvtabDisconnect(sqlite3_vtab *pVtab){ CsvTable *p = (CsvTable*)pVtab; sqlite3_free(p->zFilename); sqlite3_free(p->zData); sqlite3_free(p); return SQLITE_OK; } /* Skip leading whitespace. Return a pointer to the first non-whitespace ** character, or to the zero terminator if the string has only whitespace */ static const char *csv_skip_whitespace(const char *z){ while( isspace((unsigned char)z[0]) ) z++; return z; } /* Remove trailing whitespace from the end of string z[] */ static void csv_trim_whitespace(char *z){ size_t n = strlen(z); while( n>0 && isspace((unsigned char)z[n]) ) n--; z[n] = 0; } /* Dequote the string */ static void csv_dequote(char *z){ int i, j; char cQuote = z[0]; size_t n; if( cQuote!='\'' && cQuote!='"' ) return; n = strlen(z); if( n<2 || z[n-1]!=z[0] ) return; for(i=1, j=0; i<n-1; i++){ if( z[i]==cQuote && z[i+1]==cQuote ) i++; z[j++] = z[i]; } z[j] = 0; } /* Check to see if the string is of the form: "TAG = VALUE" with optional ** whitespace before and around tokens. If it is, return a pointer to the ** first character of VALUE. If it is not, return NULL. */ static const char *csv_parameter(const char *zTag, int nTag, const char *z){ z = csv_skip_whitespace(z); if( strncmp(zTag, z, nTag)!=0 ) return 0; z = csv_skip_whitespace(z+nTag); if( z[0]!='=' ) return 0; return csv_skip_whitespace(z+1); } /* Decode a parameter that requires a dequoted string. ** ** Return 1 if the parameter is seen, or 0 if not. 1 is returned ** even if there is an error. If an error occurs, then an error message ** is left in p->zErr. If there are no errors, p->zErr[0]==0. */ static int csv_string_parameter( CsvReader *p, /* Leave the error message here, if there is one */ const char *zParam, /* Parameter we are checking for */ const char *zArg, /* Raw text of the virtual table argment */ char **pzVal /* Write the dequoted string value here */ ){ const char *zValue; zValue = csv_parameter(zParam,strlen(zParam),zArg); if( zValue==0 ) return 0; p->zErr[0] = 0; if( *pzVal ){ csv_errmsg(p, "more than one '%s' parameter", zParam); return 1; } *pzVal = sqlite3_mprintf("%s", zValue); if( *pzVal==0 ){ csv_errmsg(p, "out of memory"); return 1; } csv_trim_whitespace(*pzVal); csv_dequote(*pzVal); return 1; } /* Return 0 if the argument is false and 1 if it is true. Return -1 if ** we cannot really tell. */ static int csv_boolean(const char *z){ if( sqlite3_stricmp("yes",z)==0 || sqlite3_stricmp("on",z)==0 || sqlite3_stricmp("true",z)==0 || (z[0]=='1' && z[0]==0) ){ return 1; } if( sqlite3_stricmp("no",z)==0 || sqlite3_stricmp("off",z)==0 || sqlite3_stricmp("false",z)==0 || (z[0]=='0' && z[1]==0) ){ return 0; } return -1; } /* ** Parameters: ** filename=FILENAME Name of file containing CSV content ** data=TEXT Direct CSV content. ** schema=SCHEMA Alternative CSV schema. ** header=YES|NO First row of CSV defines the names of ** columns if "yes". Default "no". ** columns=N Assume the CSV file contains N columns. ** ** Only available if compiled with SQLITE_TEST: ** ** testflags=N Bitmask of test flags. Optional ** ** If schema= is omitted, then the columns are named "c0", "c1", "c2", ** and so forth. If columns=N is omitted, then the file is opened and ** the number of columns in the first row is counted to determine the ** column count. If header=YES, then the first row is skipped. */ static int csvtabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ CsvTable *pNew = 0; /* The CsvTable object to construct */ int bHeader = -1; /* header= flags. -1 means not seen yet */ int rc = SQLITE_OK; /* Result code from this routine */ int i, j; /* Loop counters */ #ifdef SQLITE_TEST int tstFlags = 0; /* Value for testflags=N parameter */ #endif int nCol = -99; /* Value of the columns= parameter */ CsvReader sRdr; /* A CSV file reader used to store an error ** message and/or to count the number of columns */ static const char *azParam[] = { "filename", "data", "schema", }; char *azPValue[3]; /* Parameter values */ # define CSV_FILENAME (azPValue[0]) # define CSV_DATA (azPValue[1]) # define CSV_SCHEMA (azPValue[2]) assert( sizeof(azPValue)==sizeof(azParam) ); memset(&sRdr, 0, sizeof(sRdr)); memset(azPValue, 0, sizeof(azPValue)); for(i=3; i<argc; i++){ const char *z = argv[i]; const char *zValue; for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){ if( csv_string_parameter(&sRdr, azParam[j], z, &azPValue[j]) ) break; } if( j<sizeof(azParam)/sizeof(azParam[0]) ){ if( sRdr.zErr[0] ) goto csvtab_connect_error; }else if( (zValue = csv_parameter("header",6,z))!=0 ){ int x; if( bHeader>=0 ){ csv_errmsg(&sRdr, "more than one 'header' parameter"); goto csvtab_connect_error; } x = csv_boolean(zValue); if( x==1 ){ bHeader = 1; }else if( x==0 ){ bHeader = 0; }else{ csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue); goto csvtab_connect_error; } }else #ifdef SQLITE_TEST if( (zValue = csv_parameter("testflags",9,z))!=0 ){ tstFlags = (unsigned int)atoi(zValue); }else #endif if( (zValue = csv_parameter("columns",7,z))!=0 ){ if( nCol>0 ){ csv_errmsg(&sRdr, "more than one 'columns' parameter"); goto csvtab_connect_error; } nCol = atoi(zValue); if( nCol<=0 ){ csv_errmsg(&sRdr, "must have at least one column"); goto csvtab_connect_error; } }else { csv_errmsg(&sRdr, "unrecognized parameter '%s'", z); goto csvtab_connect_error; } } if( (CSV_FILENAME==0)==(CSV_DATA==0) ){ csv_errmsg(&sRdr, "must either filename= or data= but not both"); goto csvtab_connect_error; } if( nCol<=0 && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA) ){ goto csvtab_connect_error; } pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) goto csvtab_connect_oom; memset(pNew, 0, sizeof(*pNew)); if( nCol>0 ){ pNew->nCol = nCol; }else{ do{ const char *z = csv_read_one_field(&sRdr); if( z==0 ) goto csvtab_connect_oom; pNew->nCol++; }while( sRdr.cTerm==',' ); } pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0; pNew->zData = CSV_DATA; CSV_DATA = 0; #ifdef SQLITE_TEST pNew->tstFlags = tstFlags; #endif pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0; csv_reader_reset(&sRdr); if( CSV_SCHEMA==0 ){ char *zSep = ""; CSV_SCHEMA = sqlite3_mprintf("CREATE TABLE x("); if( CSV_SCHEMA==0 ) goto csvtab_connect_oom; for(i=0; i<pNew->nCol; i++){ CSV_SCHEMA = sqlite3_mprintf("%z%sc%d TEXT",CSV_SCHEMA, zSep, i); zSep = ","; } CSV_SCHEMA = sqlite3_mprintf("%z);", CSV_SCHEMA); } rc = sqlite3_declare_vtab(db, CSV_SCHEMA); if( rc ) goto csvtab_connect_error; for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ sqlite3_free(azPValue[i]); } return SQLITE_OK; csvtab_connect_oom: rc = SQLITE_NOMEM; csv_errmsg(&sRdr, "out of memory"); csvtab_connect_error: if( pNew ) csvtabDisconnect(&pNew->base); for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ sqlite3_free(azPValue[i]); } if( sRdr.zErr[0] ){ sqlite3_free(*pzErr); *pzErr = sqlite3_mprintf("%s", sRdr.zErr); } csv_reader_reset(&sRdr); if( rc==SQLITE_OK ) rc = SQLITE_ERROR; return rc; } /* ** Reset the current row content held by a CsvCursor. */ static void csvtabCursorRowReset(CsvCursor *pCur){ CsvTable *pTab = (CsvTable*)pCur->base.pVtab; int i; for(i=0; i<pTab->nCol; i++){ sqlite3_free(pCur->azVal[i]); pCur->azVal[i] = 0; pCur->aLen[i] = 0; } } /* ** The xConnect and xCreate methods do the same thing, but they must be ** different so that the virtual table is not an eponymous virtual table. */ static int csvtabCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return csvtabConnect(db, pAux, argc, argv, ppVtab, pzErr); } /* ** Destructor for a CsvCursor. */ static int csvtabClose(sqlite3_vtab_cursor *cur){ CsvCursor *pCur = (CsvCursor*)cur; csvtabCursorRowReset(pCur); csv_reader_reset(&pCur->rdr); sqlite3_free(cur); return SQLITE_OK; } /* ** Constructor for a new CsvTable cursor object. */ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ CsvTable *pTab = (CsvTable*)p; CsvCursor *pCur; size_t nByte; nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol; pCur = sqlite3_malloc( nByte ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, nByte); pCur->azVal = (char**)&pCur[1]; pCur->aLen = (int*)&pCur->azVal[pTab->nCol]; *ppCursor = &pCur->base; if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){ csv_xfer_error(pTab, &pCur->rdr); return SQLITE_ERROR; } return SQLITE_OK; } /* ** Advance a CsvCursor to its next row of input. ** Set the EOF marker if we reach the end of input. */ static int csvtabNext(sqlite3_vtab_cursor *cur){ CsvCursor *pCur = (CsvCursor*)cur; CsvTable *pTab = (CsvTable*)cur->pVtab; int i = 0; char *z; do{ z = csv_read_one_field(&pCur->rdr); if( z==0 ){ csv_xfer_error(pTab, &pCur->rdr); break; } if( i<pTab->nCol ){ if( pCur->aLen[i] < pCur->rdr.n+1 ){ char *zNew = sqlite3_realloc(pCur->azVal[i], pCur->rdr.n+1); if( zNew==0 ){ csv_errmsg(&pCur->rdr, "out of memory"); csv_xfer_error(pTab, &pCur->rdr); break; } pCur->azVal[i] = zNew; pCur->aLen[i] = pCur->rdr.n+1; } memcpy(pCur->azVal[i], z, pCur->rdr.n+1); i++; } }while( pCur->rdr.cTerm==',' ); while( i<pTab->nCol ){ sqlite3_free(pCur->azVal[i]); pCur->azVal[i] = 0; pCur->aLen[i] = 0; i++; } if( z==0 || pCur->rdr.cTerm==EOF ){ pCur->iRowid = -1; }else{ pCur->iRowid++; } return SQLITE_OK; } /* ** Return values of columns for the row at which the CsvCursor ** is currently pointing. */ static int csvtabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ CsvCursor *pCur = (CsvCursor*)cur; CsvTable *pTab = (CsvTable*)cur->pVtab; if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){ sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC); } return SQLITE_OK; } /* ** Return the rowid for the current row. */ static int csvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ CsvCursor *pCur = (CsvCursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int csvtabEof(sqlite3_vtab_cursor *cur){ CsvCursor *pCur = (CsvCursor*)cur; return pCur->iRowid<0; } /* ** Only a full table scan is supported. So xFilter simply rewinds to ** the beginning. */ static int csvtabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ CsvCursor *pCur = (CsvCursor*)pVtabCursor; CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab; pCur->iRowid = 0; if( pCur->rdr.in==0 ){ assert( pCur->rdr.zIn==pTab->zData ); assert( pTab->iStart<=pCur->rdr.nIn ); pCur->rdr.iIn = pTab->iStart; }else{ fseek(pCur->rdr.in, pTab->iStart, SEEK_SET); pCur->rdr.iIn = 0; pCur->rdr.nIn = 0; } return csvtabNext(pVtabCursor); } /* ** Only a forward full table scan is supported. xBestIndex is mostly ** a no-op. If CSVTEST_FIDX is set, then the presence of equality ** constraints lowers the estimated cost, which is fiction, but is useful ** for testing certain kinds of virtual table behavior. */ static int csvtabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ pIdxInfo->estimatedCost = 1000000; #ifdef SQLITE_TEST if( (((CsvTable*)tab)->tstFlags & CSVTEST_FIDX)!=0 ){ /* The usual (and sensible) case is to always do a full table scan. ** The code in this branch only runs when testflags=1. This code ** generates an artifical and unrealistic plan which is useful ** for testing virtual table logic but is not helpful to real applications. ** ** Any ==, LIKE, or GLOB constraint is marked as usable by the virtual ** table (even though it is not) and the cost of running the virtual table ** is reduced from 1 million to just 10. The constraints are *not* marked ** as omittable, however, so the query planner should still generate a ** plan that gives a correct answer, even if they plan is not optimal. */ int i; int nConst = 0; for(i=0; i<pIdxInfo->nConstraint; i++){ unsigned char op; if( pIdxInfo->aConstraint[i].usable==0 ) continue; op = pIdxInfo->aConstraint[i].op; if( op==SQLITE_INDEX_CONSTRAINT_EQ || op==SQLITE_INDEX_CONSTRAINT_LIKE || op==SQLITE_INDEX_CONSTRAINT_GLOB ){ pIdxInfo->estimatedCost = 10; pIdxInfo->aConstraintUsage[nConst].argvIndex = nConst+1; nConst++; } } } #endif return SQLITE_OK; } static sqlite3_module CsvModule = { 0, /* iVersion */ csvtabCreate, /* xCreate */ csvtabConnect, /* xConnect */ csvtabBestIndex, /* xBestIndex */ csvtabDisconnect, /* xDisconnect */ csvtabDisconnect, /* xDestroy */ csvtabOpen, /* xOpen - open a cursor */ csvtabClose, /* xClose - close a cursor */ csvtabFilter, /* xFilter - configure scan constraints */ csvtabNext, /* xNext - advance a cursor */ csvtabEof, /* xEof - check for end of scan */ csvtabColumn, /* xColumn - read data */ csvtabRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #ifdef SQLITE_TEST /* ** For virtual table testing, make a version of the CSV virtual table ** available that has an xUpdate function. But the xUpdate always returns ** SQLITE_READONLY since the CSV file is not really writable. */ static int csvtabUpdate(sqlite3_vtab *p,int n,sqlite3_value**v,sqlite3_int64*x){ return SQLITE_READONLY; } static sqlite3_module CsvModuleFauxWrite = { 0, /* iVersion */ csvtabCreate, /* xCreate */ csvtabConnect, /* xConnect */ csvtabBestIndex, /* xBestIndex */ csvtabDisconnect, /* xDisconnect */ csvtabDisconnect, /* xDestroy */ csvtabOpen, /* xOpen - open a cursor */ csvtabClose, /* xClose - close a cursor */ csvtabFilter, /* xFilter - configure scan constraints */ csvtabNext, /* xNext - advance a cursor */ csvtabEof, /* xEof - check for end of scan */ csvtabColumn, /* xColumn - read data */ csvtabRowid, /* xRowid - read data */ csvtabUpdate, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_TEST */ #ifdef _WIN32 __declspec(dllexport) #endif /* ** This routine is called when the extension is loaded. The new ** CSV virtual table module is registered with the calling database ** connection. */ int sqlite3_csv_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_module(db, "csv", &CsvModule, 0); #ifdef SQLITE_TEST if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0); } #endif return rc; } |
Added ext/misc/vfsstat.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | /* ** 2016-05-27 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains the implementation of an SQLite vfs shim that ** tracks I/O. Access to the accumulated status counts is provided using ** an eponymous virtual table. */ #include <sqlite3ext.h> SQLITE_EXTENSION_INIT1 /* ** This module contains code for a wrapper VFS that cause stats for ** most VFS calls to be recorded. ** ** To use this module, first compile it as a loadable extension. See ** https://www.sqlite.org/loadext.html#build for compilations instructions. ** ** After compliing, load this extension, then open database connections to be ** measured. Query usages status using the vfsstat virtual table: ** ** SELECT * FROM vfsstat; ** ** Reset counters using UPDATE statements against vfsstat: ** ** UPDATE vfsstat SET count=0; ** ** EXAMPLE SCRIPT: ** ** .load ./vfsstat ** .open test.db ** DROP TABLE IF EXISTS t1; ** CREATE TABLE t1(x,y); ** INSERT INTO t1 VALUES(123, randomblob(5000)); ** CREATE INDEX t1x ON t1(x); ** DROP TABLE t1; ** VACUUM; ** SELECT * FROM vfsstat WHERE count>0; ** ** LIMITATIONS: ** ** This module increments counters without using mutex protection. So if ** two or more threads try to use this module at the same time, race conditions ** may occur which mess up the counts. This is harmless, other than giving ** incorrect statistics. */ #include <string.h> #include <stdlib.h> #include <assert.h> /* ** File types */ #define VFSSTAT_MAIN 0 /* Main database file */ #define VFSSTAT_JOURNAL 1 /* Rollback journal */ #define VFSSTAT_WAL 2 /* Write-ahead log file */ #define VFSSTAT_MASTERJRNL 3 /* Master journal */ #define VFSSTAT_SUBJRNL 4 /* Subjournal */ #define VFSSTAT_TEMPDB 5 /* TEMP database */ #define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */ #define VFSSTAT_TRANSIENT 7 /* Transient database */ #define VFSSTAT_ANY 8 /* Unspecified file type */ #define VFSSTAT_nFile 9 /* This many file types */ /* Names of the file types. These are allowed values for the ** first column of the vfsstat virtual table. */ static const char *azFile[] = { "database", "journal", "wal", "master-journal", "sub-journal", "temp-database", "temp-journal", "transient-db", "*" }; /* ** Stat types */ #define VFSSTAT_BYTESIN 0 /* Bytes read in */ #define VFSSTAT_BYTESOUT 1 /* Bytes written out */ #define VFSSTAT_READ 2 /* Read requests */ #define VFSSTAT_WRITE 3 /* Write requests */ #define VFSSTAT_SYNC 4 /* Syncs */ #define VFSSTAT_OPEN 5 /* File opens */ #define VFSSTAT_LOCK 6 /* Lock requests */ #define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */ #define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */ #define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */ #define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */ #define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */ #define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */ #define VFSSTAT_nStat 7 /* This many stat types */ /* Names for the second column of the vfsstat virtual table for all ** cases except when the first column is "*" or VFSSTAT_ANY. */ static const char *azStat[] = { "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock", }; static const char *azStatAny[] = { "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp", "not-used" }; /* Total number of counters */ #define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile) /* ** Performance stats are collected in an instance of the following ** global array. */ static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT]; /* ** Access to a specific counter */ #define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)]) /* ** Forward declaration of objects used by this utility */ typedef struct VStatVfs VStatVfs; typedef struct VStatFile VStatFile; /* An instance of the VFS */ struct VStatVfs { sqlite3_vfs base; /* VFS methods */ sqlite3_vfs *pVfs; /* Parent VFS */ }; /* An open file */ struct VStatFile { sqlite3_file base; /* IO methods */ sqlite3_file *pReal; /* Underlying file handle */ unsigned char eFiletype; /* What type of file is this */ }; #define REALVFS(p) (((VStatVfs*)(p))->pVfs) /* ** Methods for VStatFile */ static int vstatClose(sqlite3_file*); static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int vstatTruncate(sqlite3_file*, sqlite3_int64 size); static int vstatSync(sqlite3_file*, int flags); static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int vstatLock(sqlite3_file*, int); static int vstatUnlock(sqlite3_file*, int); static int vstatCheckReservedLock(sqlite3_file*, int *pResOut); static int vstatFileControl(sqlite3_file*, int op, void *pArg); static int vstatSectorSize(sqlite3_file*); static int vstatDeviceCharacteristics(sqlite3_file*); static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); static int vstatShmLock(sqlite3_file*, int offset, int n, int flags); static void vstatShmBarrier(sqlite3_file*); static int vstatShmUnmap(sqlite3_file*, int deleteFlag); static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* ** Methods for VStatVfs */ static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir); static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *); static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename); static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg); static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); static void vstatDlClose(sqlite3_vfs*, void*); static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut); static int vstatSleep(sqlite3_vfs*, int microseconds); static int vstatCurrentTime(sqlite3_vfs*, double*); static int vstatGetLastError(sqlite3_vfs*, int, char *); static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static VStatVfs vstat_vfs = { { 2, /* iVersion */ 0, /* szOsFile (set by register_vstat()) */ 1024, /* mxPathname */ 0, /* pNext */ "vfslog", /* zName */ 0, /* pAppData */ vstatOpen, /* xOpen */ vstatDelete, /* xDelete */ vstatAccess, /* xAccess */ vstatFullPathname, /* xFullPathname */ vstatDlOpen, /* xDlOpen */ vstatDlError, /* xDlError */ vstatDlSym, /* xDlSym */ vstatDlClose, /* xDlClose */ vstatRandomness, /* xRandomness */ vstatSleep, /* xSleep */ vstatCurrentTime, /* xCurrentTime */ vstatGetLastError, /* xGetLastError */ vstatCurrentTimeInt64 /* xCurrentTimeInt64 */ }, 0 }; static const sqlite3_io_methods vstat_io_methods = { 3, /* iVersion */ vstatClose, /* xClose */ vstatRead, /* xRead */ vstatWrite, /* xWrite */ vstatTruncate, /* xTruncate */ vstatSync, /* xSync */ vstatFileSize, /* xFileSize */ vstatLock, /* xLock */ vstatUnlock, /* xUnlock */ vstatCheckReservedLock, /* xCheckReservedLock */ vstatFileControl, /* xFileControl */ vstatSectorSize, /* xSectorSize */ vstatDeviceCharacteristics, /* xDeviceCharacteristics */ vstatShmMap, /* xShmMap */ vstatShmLock, /* xShmLock */ vstatShmBarrier, /* xShmBarrier */ vstatShmUnmap, /* xShmUnmap */ vstatFetch, /* xFetch */ vstatUnfetch /* xUnfetch */ }; /* ** Close an vstat-file. */ static int vstatClose(sqlite3_file *pFile){ VStatFile *p = (VStatFile *)pFile; int rc = SQLITE_OK; if( p->pReal->pMethods ){ rc = p->pReal->pMethods->xClose(p->pReal); } return rc; } /* ** Read data from an vstat-file. */ static int vstatRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); STATCNT(p->eFiletype,VFSSTAT_READ)++; if( rc==SQLITE_OK ){ STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt; } return rc; } /* ** Write data to an vstat-file. */ static int vstatWrite( sqlite3_file *pFile, const void *z, int iAmt, sqlite_int64 iOfst ){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst); STATCNT(p->eFiletype,VFSSTAT_WRITE)++; if( rc==SQLITE_OK ){ STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt; } return rc; } /* ** Truncate an vstat-file. */ static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xTruncate(p->pReal, size); return rc; } /* ** Sync an vstat-file. */ static int vstatSync(sqlite3_file *pFile, int flags){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xSync(p->pReal, flags); STATCNT(p->eFiletype,VFSSTAT_SYNC)++; return rc; } /* ** Return the current file-size of an vstat-file. */ static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); return rc; } /* ** Lock an vstat-file. */ static int vstatLock(sqlite3_file *pFile, int eLock){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xLock(p->pReal, eLock); STATCNT(p->eFiletype,VFSSTAT_LOCK)++; return rc; } /* ** Unlock an vstat-file. */ static int vstatUnlock(sqlite3_file *pFile, int eLock){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); STATCNT(p->eFiletype,VFSSTAT_LOCK)++; return rc; } /* ** Check if another file-handle holds a RESERVED lock on an vstat-file. */ static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); STATCNT(p->eFiletype,VFSSTAT_LOCK)++; return rc; } /* ** File control method. For custom operations on an vstat-file. */ static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){ VStatFile *p = (VStatFile *)pFile; int rc; rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg); if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){ *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg); } return rc; } /* ** Return the sector-size in bytes for an vstat-file. */ static int vstatSectorSize(sqlite3_file *pFile){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xSectorSize(p->pReal); return rc; } /* ** Return the device characteristic flags supported by an vstat-file. */ static int vstatDeviceCharacteristics(sqlite3_file *pFile){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); return rc; } /* Create a shared memory file mapping */ static int vstatShmMap( sqlite3_file *pFile, int iPg, int pgsz, int bExtend, void volatile **pp ){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp); } /* Perform locking on a shared-memory segment */ static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags); } /* Memory barrier operation on shared memory */ static void vstatShmBarrier(sqlite3_file *pFile){ VStatFile *p = (VStatFile *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } /* Unmap a shared memory segment */ static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag); } /* Fetch a page of a memory-mapped file */ static int vstatFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp); } /* Release a memory-mapped page */ static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage); } /* ** Open an vstat file handle. */ static int vstatOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ int rc; VStatFile *p = (VStatFile*)pFile; p->pReal = (sqlite3_file*)&p[1]; rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags); if( flags & SQLITE_OPEN_MAIN_DB ){ p->eFiletype = VFSSTAT_MAIN; }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){ p->eFiletype = VFSSTAT_JOURNAL; }else if( flags & SQLITE_OPEN_WAL ){ p->eFiletype = VFSSTAT_WAL; }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){ p->eFiletype = VFSSTAT_MASTERJRNL; }else if( flags & SQLITE_OPEN_SUBJOURNAL ){ p->eFiletype = VFSSTAT_SUBJRNL; }else if( flags & SQLITE_OPEN_TEMP_DB ){ p->eFiletype = VFSSTAT_TEMPDB; }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){ p->eFiletype = VFSSTAT_TEMPJRNL; }else{ p->eFiletype = VFSSTAT_TRANSIENT; } STATCNT(p->eFiletype,VFSSTAT_OPEN)++; pFile->pMethods = rc ? 0 : &vstat_io_methods; return rc; } /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before ** returning. */ static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int rc; rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync); STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++; return rc; } /* ** Test for access permissions. Return true if the requested permission ** is available, or false otherwise. */ static int vstatAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ int rc; rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut); STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++; return rc; } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (INST_MAX_PATHNAME+1) bytes. */ static int vstatFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++; return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut); } /* ** Open the dynamic library located at zPath and return a handle. */ static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){ return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath); } /* ** Populate the buffer zErrMsg (size nByte bytes) with a human readable ** utf-8 string describing the most recent error encountered associated ** with dynamic libraries. */ static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg); } /* ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. */ static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym); } /* ** Close the dynamic library handle pHandle. */ static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){ REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle); } /* ** Populate the buffer pointed to by zBufOut with nByte bytes of ** random data. */ static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++; return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut); } /* ** Sleep for nMicro microseconds. Return the number of microseconds ** actually slept. */ static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){ STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++; return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro); } /* ** Return the current time as a Julian Day number in *pTimeOut. */ static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++; return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut); } static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b); } static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++; return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p); } /* ** A virtual table for accessing the stats collected by this VFS shim */ static int vstattabConnect(sqlite3*, void*, int, const char*const*, sqlite3_vtab**,char**); static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*); static int vstattabDisconnect(sqlite3_vtab*); static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**); static int vstattabClose(sqlite3_vtab_cursor*); static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); static int vstattabNext(sqlite3_vtab_cursor*); static int vstattabEof(sqlite3_vtab_cursor*); static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int); static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*); static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); /* A cursor for the vfsstat virtual table */ typedef struct VfsStatCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ int i; /* Pointing to this aVfsCnt[] value */ } VfsStatCursor; static int vstattabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define VSTAT_COLUMN_FILE 0 #define VSTAT_COLUMN_STAT 1 #define VSTAT_COLUMN_COUNT 2 rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } return rc; } /* ** This method is the destructor for vstat table object. */ static int vstattabDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new vstat table cursor object. */ static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ VfsStatCursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a VfsStatCursor. */ static int vstattabClose(sqlite3_vtab_cursor *cur){ sqlite3_free(cur); return SQLITE_OK; } /* ** Advance a VfsStatCursor to its next row of output. */ static int vstattabNext(sqlite3_vtab_cursor *cur){ ((VfsStatCursor*)cur)->i++; return SQLITE_OK; } /* ** Return values of columns for the row at which the VfsStatCursor ** is currently pointing. */ static int vstattabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ VfsStatCursor *pCur = (VfsStatCursor*)cur; switch( i ){ case VSTAT_COLUMN_FILE: { sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC); break; } case VSTAT_COLUMN_STAT: { const char **az; az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat; sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC); break; } case VSTAT_COLUMN_COUNT: { sqlite3_result_int64(ctx, aVfsCnt[pCur->i]); break; } } return SQLITE_OK; } /* ** Return the rowid for the current row. */ static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ VfsStatCursor *pCur = (VfsStatCursor*)cur; *pRowid = pCur->i; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int vstattabEof(sqlite3_vtab_cursor *cur){ VfsStatCursor *pCur = (VfsStatCursor*)cur; return pCur->i >= VFSSTAT_MXCNT; } /* ** Only a full table scan is supported. So xFilter simply rewinds to ** the beginning. */ static int vstattabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor; pCur->i = 0; return SQLITE_OK; } /* ** Only a forwards full table scan is supported. xBestIndex is a no-op. */ static int vstattabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ return SQLITE_OK; } /* ** Any VSTAT_COLUMN_COUNT can be changed to a positive integer. ** No deletions or insertions are allowed. No changes to other ** columns are allowed. */ static int vstattabUpdate( sqlite3_vtab *tab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid ){ sqlite3_int64 iRowid, x; if( argc==1 ) return SQLITE_ERROR; if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR; iRowid = sqlite3_value_int64(argv[0]); if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR; if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR; if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){ return SQLITE_ERROR; } x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]); if( x<0 ) return SQLITE_ERROR; aVfsCnt[iRowid] = x; return SQLITE_OK; } static sqlite3_module VfsStatModule = { 0, /* iVersion */ 0, /* xCreate */ vstattabConnect, /* xConnect */ vstattabBestIndex, /* xBestIndex */ vstattabDisconnect, /* xDisconnect */ 0, /* xDestroy */ vstattabOpen, /* xOpen - open a cursor */ vstattabClose, /* xClose - close a cursor */ vstattabFilter, /* xFilter - configure scan constraints */ vstattabNext, /* xNext - advance a cursor */ vstattabEof, /* xEof - check for end of scan */ vstattabColumn, /* xColumn - read data */ vstattabRowid, /* xRowid - read data */ vstattabUpdate, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** This routine is an sqlite3_auto_extension() callback, invoked to register ** the vfsstat virtual table for all new database connections. */ static int vstatRegister( sqlite3 *db, const char **pzErrMsg, const struct sqlite3_api_routines *pThunk ){ return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0); } #ifdef _WIN32 __declspec(dllexport) #endif /* ** This routine is called when the extension is loaded. ** ** Register the new VFS. Make arrangement to register the virtual table ** for each new database connection. */ int sqlite3_vfsstat_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); vstat_vfs.pVfs = sqlite3_vfs_find(0); vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile; rc = sqlite3_vfs_register(&vstat_vfs.base, 1); if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))vstatRegister); } if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } |
Changes to ext/rbu/rbu_common.tcl.
︙ | ︙ | |||
31 32 33 34 35 36 37 38 | sqlite3rbu rbu $target $rbu set rc [rbu step] rbu close if {$rc != "SQLITE_OK"} break } set rc } | > > > > > > > > > > > > > > > > > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | sqlite3rbu rbu $target $rbu set rc [rbu step] rbu close if {$rc != "SQLITE_OK"} break } set rc } proc do_rbu_vacuum_test {tn step} { uplevel [list do_test $tn.1 { if {$step==0} { sqlite3rbu_vacuum rbu test.db state.db } while 1 { if {$step==1} { sqlite3rbu_vacuum rbu test.db state.db } set rc [rbu step] if {$rc!="SQLITE_OK"} break if {$step==1} { rbu close } } rbu close } {SQLITE_DONE}] uplevel [list do_execsql_test $tn.2 { PRAGMA integrity_check } ok] } |
Changes to ext/rbu/rbuvacuum.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuvacuum | < < < < < < < < < < < < < < < < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuvacuum foreach step {0 1} { set ::testprefix rbuvacuum-step=$step reset_db # Simplest possible vacuum. do_execsql_test 1.0 { |
︙ | ︙ | |||
399 400 401 402 403 404 405 | sqlite3_create_collation_v2 $db1 length length_cmp noop sqlite3_create_collation_v2 $db2 length length_cmp noop while {[rbu step]=="SQLITE_OK"} {} list [catch { rbu close } msg] $msg } {0 SQLITE_DONE} | < | 382 383 384 385 386 387 388 389 390 391 392 | sqlite3_create_collation_v2 $db1 length length_cmp noop sqlite3_create_collation_v2 $db2 length length_cmp noop while {[rbu step]=="SQLITE_OK"} {} list [catch { rbu close } msg] $msg } {0 SQLITE_DONE} catch { db close } finish_test |
Added ext/rbu/rbuvacuum2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | # 2016 June 1 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] foreach step {0 1} { set ::testprefix rbuvacuum2-$step #------------------------------------------------------------------------- # Test that a database that contains fts3 tables can be vacuumed. # ifcapable fts3 { reset_db do_execsql_test 1.1 { CREATE VIRTUAL TABLE t1 USING fts3(z, y); INSERT INTO t1 VALUES('fix this issue', 'at some point'); } do_rbu_vacuum_test 1.2 $step do_execsql_test 1.3 { SELECT * FROM t1; } {{fix this issue} {at some point}} do_execsql_test 1.4 { SELECT rowid FROM t1 WHERE t1 MATCH 'fix'; } {1} do_execsql_test 1.5 { INSERT INTO t1 VALUES('a b c', 'd e f'); INSERT INTO t1 VALUES('l h i', 'd e f'); DELETE FROM t1 WHERE docid = 2; INSERT INTO t1 VALUES('a b c', 'x y z'); } do_rbu_vacuum_test 1.6 $step do_execsql_test 1.7 { INSERT INTO t1(t1) VALUES('integrity-check'); SELECT * FROM t1; } { {fix this issue} {at some point} {l h i} {d e f} {a b c} {x y z} } } #------------------------------------------------------------------------- # Test that a database that contains fts5 tables can be vacuumed. # ifcapable fts5 { reset_db do_execsql_test 2.1 { CREATE VIRTUAL TABLE t1 USING fts5(z, y); INSERT INTO t1 VALUES('fix this issue', 'at some point'); } do_rbu_vacuum_test 2.2 $step do_execsql_test 2.3 { SELECT * FROM t1; } {{fix this issue} {at some point}} do_execsql_test 2.4 { SELECT rowid FROM t1 ('fix'); } {1} do_execsql_test 2.5 { INSERT INTO t1 VALUES('a b c', 'd e f'); INSERT INTO t1 VALUES('l h i', 'd e f'); DELETE FROM t1 WHERE rowid = 2; INSERT INTO t1 VALUES('a b c', 'x y z'); } do_rbu_vacuum_test 2.6 $step do_execsql_test 2.7 { INSERT INTO t1(t1) VALUES('integrity-check'); SELECT * FROM t1; } { {fix this issue} {at some point} {l h i} {d e f} {a b c} {x y z} } } #------------------------------------------------------------------------- # Test that a database that contains an rtree table can be vacuumed. # ifcapable rtree { reset_db do_execsql_test 3.1 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); INSERT INTO rt VALUES(1, 45, 55); INSERT INTO rt VALUES(2, 50, 60); INSERT INTO rt VALUES(3, 55, 65); } do_rbu_vacuum_test 3.2 $step do_execsql_test 3.3 { SELECT * FROM rt; } {1 45.0 55.0 2 50.0 60.0 3 55.0 65.0} do_execsql_test 3.4.1 { SELECT rowid FROM rt WHERE x2>51 AND x1 < 51 } {1 2} do_execsql_test 3.4.2 { SELECT rowid FROM rt WHERE x2>59 AND x1 < 59 } {2 3} do_rbu_vacuum_test 3.5 $step do_execsql_test 3.6.1 { SELECT rowid FROM rt WHERE x2>51 AND x1 < 51 } {1 2} do_execsql_test 3.6.2 { SELECT rowid FROM rt WHERE x2>59 AND x1 < 59 } {2 3} } ifcapable trigger { reset_db do_execsql_test 4.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END; } do_execsql_test 4.2 { SELECT * FROM sqlite_master; } { table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } do_rbu_vacuum_test 4.3 $step do_execsql_test 4.4 { SELECT * FROM sqlite_master; } { table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } } } finish_test |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
917 918 919 920 921 922 923 | ** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); | | > > < > | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | ** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " "FROM sqlite_master " "WHERE type IN ('table', 'view') AND target IS NOT NULL " " %s " "ORDER BY name" , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " " FROM main.sqlite_master " " WHERE type='index' AND tbl_name = ?" ); |
︙ | ︙ | |||
2501 2502 2503 2504 2505 2506 2507 | static void rbuFileSuffix3(const char *zBase, char *z){ #ifdef SQLITE_ENABLE_8_3_NAMES #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) #endif { int i, sz; | | | | 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 | static void rbuFileSuffix3(const char *zBase, char *z){ #ifdef SQLITE_ENABLE_8_3_NAMES #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) #endif { int i, sz; sz = (int)strlen(z)&0xffffff; for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } #endif } /* ** Return the current wal-index header checksum for the target database ** as a 64-bit integer. |
︙ | ︙ |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 | if( f<d ){ f = (float)(d*(d<0 ? RNDTOWARDS : RNDAWAY)); } return f; } #endif /* !defined(SQLITE_RTREE_INT_ONLY) */ /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 | if( f<d ){ f = (float)(d*(d<0 ? RNDTOWARDS : RNDAWAY)); } return f; } #endif /* !defined(SQLITE_RTREE_INT_ONLY) */ /* ** A constraint has failed while inserting a row into an rtree table. ** Assuming no OOM error occurs, this function sets the error message ** (at pRtree->base.zErrMsg) to an appropriate value and returns ** SQLITE_CONSTRAINT. ** ** Parameter iCol is the index of the leftmost column involved in the ** constraint failure. If it is 0, then the constraint that failed is ** the unique constraint on the id column. Otherwise, it is the rtree ** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. ** ** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. */ static int rtreeConstraintError(Rtree *pRtree, int iCol){ sqlite3_stmt *pStmt = 0; char *zSql; int rc; assert( iCol==0 || iCol%2 ); zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); if( zSql ){ rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); if( rc==SQLITE_OK ){ if( iCol==0 ){ const char *zCol = sqlite3_column_name(pStmt, 0); pRtree->base.zErrMsg = sqlite3_mprintf( "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol ); }else{ const char *zCol1 = sqlite3_column_name(pStmt, iCol); const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); pRtree->base.zErrMsg = sqlite3_mprintf( "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 ); } } sqlite3_finalize(pStmt); return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); } /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, |
︙ | ︙ | |||
2847 2848 2849 2850 2851 2852 2853 | #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<nData-4; ii+=2){ cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]); cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ | | | | | 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 | #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<nData-4; ii+=2){ cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]); cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } }else #endif { for(ii=0; ii<nData-4; ii+=2){ cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]); cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]); if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } } /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ cell.iRowid = sqlite3_value_int64(azData[2]); if( sqlite3_value_type(azData[0])==SQLITE_NULL || sqlite3_value_int64(azData[0])!=cell.iRowid ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); rc = sqlite3_reset(pRtree->pReadRowid); if( SQLITE_ROW==steprc ){ if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ rc = rtreeConstraintError(pRtree, 0); goto constraint; } } } bHaveRowid = 1; } } |
︙ | ︙ | |||
2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 | static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); | > > > > > | 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 | static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; if( sqlite3_table_column_metadata(db,pRtree->zDb,"sqlite_stat1", 0,0,0,0,0,0)==SQLITE_ERROR ){ pRtree->nRowEst = RTREE_DEFAULT_ROWEST; return SQLITE_OK; } zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
190 191 192 193 194 195 196 | do_test rtree-2.1.3 { execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { SELECT ii FROM t1 ORDER BY ii } } {1 2 3} do_test rtree-2.2.1 { catchsql { INSERT INTO t1 VALUES(2, 1, 3, 2, 4) } | | | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | do_test rtree-2.1.3 { execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { SELECT ii FROM t1 ORDER BY ii } } {1 2 3} do_test rtree-2.2.1 { catchsql { INSERT INTO t1 VALUES(2, 1, 3, 2, 4) } } {1 {UNIQUE constraint failed: t1.ii}} do_test rtree-2.2.2 { catchsql { INSERT INTO t1 VALUES(4, 1, 3, 4, 2) } } {1 {rtree constraint failed: t1.(y1<=y2)}} do_test rtree-2.2.3 { catchsql { INSERT INTO t1 VALUES(4, 3, 1, 2, 4) } } {1 {rtree constraint failed: t1.(x1<=x2)}} do_test rtree-2.2.4 { execsql { SELECT ii FROM t1 ORDER BY ii } } {1 2 3} do_test rtree-2.X { execsql { DROP TABLE t1 } } {} |
︙ | ︙ | |||
232 233 234 235 236 237 238 | SELECT * FROM t1; } } {5 1 3 2 4 6 2 6 4 8} # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)): do_test rtree-3.2.1 { catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) } | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | SELECT * FROM t1; } } {5 1 3 2 4 6 2 6 4 8} # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)): do_test rtree-3.2.1 { catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) } } {1 {rtree constraint failed: t1.(y1<=y2)}} do_test rtree-3.2.2 { catchsql { INSERT INTO t1 VALUES(8, 2, 6, 3, 3) } } {0 {}} #---------------------------------------------------------------------------- # Test cases rtree-5.* test DELETE operations. # |
︙ | ︙ | |||
486 487 488 489 490 491 492 | ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} REPLACE 1 0 {1 4 5 6 7 2 2 3 4 5 5 3 4 5 6} } 4 "INSERT %CONF% INTO t1 VALUES(2, 7, 6, 7, 7)" { | | | | | | > > | 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} REPLACE 1 0 {1 4 5 6 7 2 2 3 4 5 5 3 4 5 6} } 4 "INSERT %CONF% INTO t1 VALUES(2, 7, 6, 7, 7)" { ROLLBACK 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} ABORT 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} FAIL 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} REPLACE 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} } } { foreach {mode uses error data} $testdata { db_restore_and_reopen set sql [string map [list %CONF% "OR $mode"] $sql_template] set testname "12.$tn.[string tolower $mode]" execsql { BEGIN; INSERT INTO t1 VALUES(4, 4, 5, 6, 7); } set res(0) {0 {}} set res(1) {1 {UNIQUE constraint failed: t1.idx}} set res(2) {1 {rtree constraint failed: t1.(x1<=x2)}} do_catchsql_test $testname.1 $sql $res($error) do_test $testname.2 [list sql_uses_stmt db $sql] $uses do_execsql_test $testname.3 { SELECT * FROM t1 ORDER BY idx } $data do_test $testname.4 { rtree_check db t1 } 0 db close } |
︙ | ︙ |
Changes to ext/rtree/rtree3.test.
︙ | ︙ | |||
43 44 45 46 47 48 49 | # # rtree3-6: Test OOM while deleting all rows of a table, one at a time. # # rtree3-7: OOM during an ALTER TABLE RENAME TABLE command. # # rtree3-8: Test OOM while registering the r-tree module with sqlite. # | > | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # # rtree3-6: Test OOM while deleting all rows of a table, one at a time. # # rtree3-7: OOM during an ALTER TABLE RENAME TABLE command. # # rtree3-8: Test OOM while registering the r-tree module with sqlite. # # rtree3-11: OOM following a constraint failure # do_faultsim_test rtree3-1 -faults oom* -prep { faultsim_delete_and_reopen } -body { execsql { BEGIN TRANSACTION; CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2); INSERT INTO rt VALUES(NULL, 3, 5, 7, 9); |
︙ | ︙ | |||
230 231 232 233 234 235 236 237 | execsql { SELECT * FROM rt } } -body { execsql { SELECT ii FROM rt WHERE ii MATCH cube(4.5, 5.5, 6.5, 1, 1, 1) } } -test { faultsim_test_result {0 2} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | execsql { SELECT * FROM rt } } -body { execsql { SELECT ii FROM rt WHERE ii MATCH cube(4.5, 5.5, 6.5, 1, 1, 1) } } -test { faultsim_test_result {0 2} } do_test rtree3-11.prep { faultsim_delete_and_reopen execsql { CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2); INSERT INTO rt VALUES(1, 2, 3, 4, 5); } faultsim_save_and_close } {} do_faultsim_test rtree3-10.1 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM rt } } -body { execsql { INSERT INTO rt VALUES(1, 2, 3, 4, 5) } } -test { faultsim_test_result {1 {UNIQUE constraint failed: rt.ii}} \ {1 {constraint failed}} } do_faultsim_test rtree3-10.2 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM rt } } -body { execsql { INSERT INTO rt VALUES(2, 2, 3, 5, 4) } } -test { faultsim_test_result {1 {rtree constraint failed: rt.(y1<=y2)}} \ {1 {constraint failed}} } finish_test |
Changes to ext/rtree/rtreeC.test.
︙ | ︙ | |||
344 345 346 347 348 349 350 | WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 1 {SCAN TABLE xdir} 0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 2 4 } | < < < < | 344 345 346 347 348 349 350 351 352 | WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 1 {SCAN TABLE xdir} 0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 2 4 } finish_test |
Added ext/rtree/rtreeG.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | # 2016-05-32 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file contains tests for the r-tree module. # # Verify that no invalid SQL is run during initialization if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl ifcapable !rtree { finish_test ; return } db close sqlite3_shutdown test_sqlite3_log [list lappend ::log] set ::log [list] sqlite3 db test.db set ::log {} do_execsql_test rtreeG-1.1 { CREATE VIRTUAL TABLE t1 USING rtree(id,x0,x1,y0,y1); } {} do_test rtreeG-1.1log { set ::log } {} do_execsql_test rtreeG-1.2 { INSERT INTO t1 VALUES(1,10,15,5,23),(2,20,21,5,23),(3,10,15,20,30); SELECT id from t1 WHERE x0>8 AND x1<16 AND y0>2 AND y1<25; } {1} do_test rtreeG-1.2log { set ::log } {} db close sqlite3 db test.db do_execsql_test rtreeG-1.3 { SELECT id from t1 WHERE x0>8 AND x1<16 AND y0>2 AND y1<25; } {1} do_test rtreeG-1.3log { set ::log } {} do_execsql_test rtreeG-1.4 { DROP TABLE t1; } {} do_test rtreeG-1.4log { set ::log } {} db close sqlite3_shutdown test_sqlite3_log sqlite3_initialize sqlite3 db test.db finish_test |
Changes to main.mk.
︙ | ︙ | |||
324 325 326 327 328 329 330 331 332 333 334 335 336 337 | $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ | > | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ |
︙ | ︙ | |||
434 435 436 437 438 439 440 | # executables needed for testing # TESTPROGS = \ testfixture$(EXE) \ sqlite3$(EXE) \ sqlite3_analyzer$(EXE) \ | | > | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | # executables needed for testing # TESTPROGS = \ testfixture$(EXE) \ sqlite3$(EXE) \ sqlite3_analyzer$(EXE) \ sqldiff$(EXE) \ dbhash$(EXE) # Databases containing fuzzer test cases # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ |
︙ | ︙ | |||
470 471 472 473 474 475 476 477 478 479 480 481 482 483 | sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \ $(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o $(TCC) -I. -DSCRUB_STANDALONE -o scrub$(EXE) $(TOP)/ext/misc/scrub.c sqlite3.o $(THREADLIB) srcck1$(EXE): $(TOP)/tool/srcck1.c $(BCC) -o srcck1$(EXE) $(TOP)/tool/srcck1.c | > > > > | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \ $(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) dbhash$(EXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h $(TCCX) -o dbhash$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) $(THREADLIB) scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o $(TCC) -I. -DSCRUB_STANDALONE -o scrub$(EXE) $(TOP)/ext/misc/scrub.c sqlite3.o $(THREADLIB) srcck1$(EXE): $(TOP)/tool/srcck1.c $(BCC) -o srcck1$(EXE) $(TOP)/tool/srcck1.c |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
452 453 454 455 456 457 458 459 460 461 462 463 464 465 | ** ** Verify that the cursor holds the mutex on its BtShared */ #ifdef SQLITE_DEBUG static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } static int cursorOwnsBtShared(BtCursor *p){ assert( cursorHoldsMutex(p) ); return (p->pBtree->db==p->pBt->db); } #endif /* | > > > > > > > > > | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | ** ** Verify that the cursor holds the mutex on its BtShared */ #ifdef SQLITE_DEBUG static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } /* Verify that the cursor and the BtShared agree about what is the current ** database connetion. This is important in shared-cache mode. If the database ** connection pointers get out-of-sync, it is possible for routines like ** btreeInitPage() to reference an stale connection pointer that references a ** a connection that has already closed. This routine is used inside assert() ** statements only and for the purpose of double-checking that the btree code ** does keep the database connection pointers up-to-date. */ static int cursorOwnsBtShared(BtCursor *p){ assert( cursorHoldsMutex(p) ); return (p->pBtree->db==p->pBt->db); } #endif /* |
︙ | ︙ | |||
611 612 613 614 615 616 617 | ** If the cursor is open on an intkey table, then the integer key ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is ** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ | | > > | < | < | < < | | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 | ** If the cursor is open on an intkey table, then the integer key ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is ** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ int rc = SQLITE_OK; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); if( pCur->curIntKey ){ /* Only the rowid is required for a table btree */ pCur->nKey = sqlite3BtreeIntegerKey(pCur); }else{ /* For an index btree, save the complete key content */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); pKey = sqlite3Malloc( pCur->nKey ); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ sqlite3_free(pKey); } |
︙ | ︙ | |||
4264 4265 4266 4267 4268 4269 4270 | */ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ /* | | > | | < < < < < < < | > | < | | > < < < < | | < < < | < | 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 | */ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ /* ** Return the value of the integer key or "rowid" for a table btree. ** This routine is only valid for a cursor that is pointing into a ** ordinary table btree. If the cursor points to an index btree or ** is invalid, the result of this routine is undefined. */ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->curIntKey ); getCellInfo(pCur); return pCur->info.nKey; } /* ** Return the number of bytes of payload for the entry that pCur is ** currently pointing to. For table btrees, this will be the amount ** of data. For index btrees, this will be the size of the key. ** ** The caller must guarantee that the cursor is pointing to a non-NULL ** valid entry. In other words, the calling procedure must guarantee ** that the cursor has Cursor.eState==CURSOR_VALID. */ u32 sqlite3BtreePayloadSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); return pCur->info.nPayload; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum ** pointer-map data instead of reading the content of page ovfl to do so. |
︙ | ︙ | |||
4745 4746 4747 4748 4749 4750 4751 | ** including calls from other threads against the same cache. ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ | | < < < | 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 | ** including calls from other threads against the same cache. ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ return fetchPayload(pCur, pAmt); } /* ** Move the cursor down to a new child page. The newPgno argument is the ** page number of the child page to move to. |
︙ | ︙ | |||
5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 | int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ | > > | < | 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 | int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pIdxKey==0 && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){ *pRes = -1; |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
280 281 282 283 284 285 286 | int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int bias, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); int sqlite3BtreeEof(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int *pRes); | | | < | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int bias, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); int sqlite3BtreeEof(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int *pRes); i64 sqlite3BtreeIntegerKey(BtCursor*); int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); u32 sqlite3BtreePayloadSize(BtCursor*); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); struct Pager *sqlite3BtreePager(Btree*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); void sqlite3BtreeIncrblobCursor(BtCursor *); |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
334 335 336 337 338 339 340 | ** ** The difference between this routine and sqlite3FindTable() is that this ** routine leaves an error message in pParse->zErrMsg where ** sqlite3FindTable() does not. */ Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ | | | > | | | | | | > | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | ** ** The difference between this routine and sqlite3FindTable() is that this ** routine leaves an error message in pParse->zErrMsg where ** sqlite3FindTable() does not. */ Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */ const char *zName, /* Name of the table we are looking for */ const char *zDbase /* Name of the database. Might be NULL */ ){ Table *p; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ return pMod->pEpoTab; } } #endif if( (flags & LOCATE_NOERR)==0 ){ if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } } return p; } /* ** Locate the table identified by *p. ** ** This is a wrapper around sqlite3LocateTable(). The difference between ** sqlite3LocateTable() and this function is that this function restricts ** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be ** non-NULL if it is part of a view or trigger program definition. See ** sqlite3FixSrcList() for details. */ Table *sqlite3LocateTableItem( Parse *pParse, u32 flags, struct SrcList_item *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); zDb = pParse->db->aDb[iDb].zName; }else{ zDb = p->zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. |
︙ | ︙ | |||
601 602 603 604 605 606 607 | ** lookaside, this number should not change. */ TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ? db->lookaside.nOut : 0 ); /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; | | > | | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | ** lookaside, this number should not change. */ TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ? db->lookaside.nOut : 0 ); /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); } |
︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 | int autoInc, /* True if the AUTOINCREMENT keyword is present */ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; Column *pCol = 0; int iCol = -1, i; int nTerm; | | | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | int autoInc, /* True if the AUTOINCREMENT keyword is present */ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; Column *pCol = 0; int iCol = -1, i; int nTerm; if( pTab==0 ) goto primary_key_exit; if( pTab->tabFlags & TF_HasPrimaryKey ){ sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } pTab->tabFlags |= TF_HasPrimaryKey; if( pList==0 ){ |
︙ | ︙ | |||
1330 1331 1332 1333 1334 1335 1336 | if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ | < | | < < < | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 | if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pParse->db, pList); return; } |
︙ | ︙ | |||
1652 1653 1654 1655 1656 1657 1658 | /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** | > | | | < > > > > > > > > > > > > > > > > | 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 | /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. ** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is ** no rowid btree for a WITHOUT ROWID. Instead, the canonical ** data storage is a covering index btree. ** (3) Bypass the creation of the sqlite_master table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. ** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus ** columns are part of KeyInfo.nXField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. ** ** For virtual tables, only (1) is performed. */ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; Index *pPk; int nPk; int i, j; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) */ if( !db->init.imposterTable ){ for(i=0; i<pTab->nCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ pTab->aCol[i].notNull = OE_Abort; } } } /* The remaining transformations only apply to b-tree tables, not to ** virtual tables */ if( IN_DECLARE_VTAB ) return; /* Convert the OP_CreateTable opcode that would normally create the ** root-page for the table into an OP_CreateIndex opcode. The index ** created will become the PRIMARY KEY index. */ if( pParse->addrCrTab ){ assert( v ); |
︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 | Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); | | < | > > | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 | Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( db->mallocFailed ) return; pPk = sqlite3PrimaryKeyIndex(pTab); pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master ** table entry. This is only required if currently generating VDBE ** code for a CREATE TABLE (not when parsing one as part of reading |
︙ | ︙ | |||
1727 1728 1729 1730 1731 1732 1733 | pPk->nColumn--; }else{ pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } | < < | < < | < < < | | < | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 | pPk->nColumn--; }else{ pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } assert( pPk!=0 ); pPk->isCovering = 1; if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nKeyCol; /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
︙ | ︙ | |||
2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); goto exit_drop_table; } | > | 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); goto exit_drop_table; } |
︙ | ︙ | |||
2864 2865 2866 2867 2868 2869 2870 | ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is ** currently being constructed by a CREATE TABLE statement. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. | < < < < | | > < | > > > | 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 | ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is ** currently being constructed by a CREATE TABLE statement. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. */ void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins this statement */ Expr *pPIWhere, /* WHERE clause for partial indices */ int sortOrder, /* Sort order of primary key when pList==NULL */ int ifNotExist, /* Omit error if index already exists */ u8 idxType /* The index type */ ){ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ int nName; /* Number of characters in zName */ int i, j; DbFixer sFix; /* For assigning database names to pTable */ int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ sqlite3 *db = pParse->db; Db *pDb; /* The specific table containing the indexed database */ int iDb; /* Index of the database that is being written */ Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ if( db->mallocFailed || pParse->nErr>0 ){ goto exit_create_index; } if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } /* |
︙ | ︙ | |||
3088 3089 3090 3091 3092 3093 3094 | assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; | | | 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 | assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; pIndex->idxType = idxType; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); pIndex->pPartIdxWhere = pPIWhere; pPIWhere = 0; } |
︙ | ︙ | |||
3268 3269 3270 3271 3272 3273 3274 | sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } | | > | 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 | sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } } /* Link the new Index structure to its table and to the other ** in-memory database structures. */ assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; assert( !IN_DECLARE_VTAB ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ sqlite3OomFault(db); goto exit_create_index; |
︙ | ︙ | |||
3386 3387 3388 3389 3390 3391 3392 | Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } | < < | 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 | Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ) freeIndex(db, pIndex); sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** ** aiRowEst[0] is supposed to contain the number of elements in the index. |
︙ | ︙ | |||
3426 3427 3428 3429 3430 3431 3432 | /* 10, 9, 8, 7, 6 */ LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Set the first entry (number of rows in the index) to the estimated | | | > | | 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 | /* 10, 9, 8, 7, 6 */ LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Set the first entry (number of rows in the index) to the estimated ** number of rows in the table, or half the number of rows in the table ** for a partial index. But do not let the estimate drop below 10. */ a[0] = pIdx->pTable->nRowLogEst; if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ a[i] = 23; assert( 23==sqlite3LogEst(5) ); } |
︙ | ︙ | |||
4311 4312 4313 4314 4315 4316 4317 | sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif /* ** Return a KeyInfo structure that is appropriate for the given Index. ** | < < < < | 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 | sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif /* ** Return a KeyInfo structure that is appropriate for the given Index. ** ** The caller should invoke sqlite3KeyInfoUnref() on the returned object ** when it has finished using it. */ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; int nKey = pIdx->nKeyCol; |
︙ | ︙ |
Changes to src/ctime.c.
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #endif #if SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #if SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #if SQLITE_DEBUG "DEBUG", #endif #if SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #if SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #if SQLITE_ENABLE_8_3_NAMES | > > > > > > > | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #endif #if SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #if SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if defined(__clang__) && defined(__clang_version__) "COMPILER=clang-" __clang_version__, #elif defined(_MSC_VER) "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif #if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #if SQLITE_DEBUG "DEBUG", #endif #if SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #if SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #if SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #if SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #if SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif |
︙ | ︙ |
Changes to src/dbstat.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | ** the overflow pages associated with a cell will appear earlier in the ** sort-order than its child page: ** ** '/1c2/000/' // Left-most child of 451st child of root */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ | | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** the overflow pages associated with a cell will appear earlier in the ** sort-order than its child page: ** ** '/1c2/000/' // Left-most child of 451st child of root */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ " name TEXT, /* Name of table or index */" \ " path TEXT, /* Path to page from root */" \ " pageno INTEGER, /* Page number */" \ " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \ " ncell INTEGER, /* Cells on page (0 for overflow) */" \ " payload INTEGER, /* Bytes of payload on this page */" \ " unused INTEGER, /* Bytes of unused space on this page */" \ " mx_payload INTEGER, /* Largest payload size of all cells */" \ " pgoffset INTEGER, /* Offset of page in file */" \ " pgsize INTEGER, /* Size of the page */" \ " schema TEXT HIDDEN /* Database schema being analyzed */" \ |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
2218 2219 2220 2221 2222 2223 2224 | sqlite3VdbeJumpHere(v, addr1); } } if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree */ | < | | 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 | sqlite3VdbeJumpHere(v, addr1); } } if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree */ sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); }else{ /* In this case, the RHS is an index b-tree. */ sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); /* If the set membership test fails, then the result of the |
︙ | ︙ | |||
2532 2533 2534 2535 2536 2537 2538 | int regOut /* Extract the value into this register */ ){ if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; | | | 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 | int regOut /* Extract the value into this register */ ){ if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; if( !HasRowid(pTab) && !IsVirtual(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 | ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ | > | | 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 | ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ assert( db==0 || IsVirtual(pTab) || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
736 737 738 739 740 741 742 | return 0; } continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; | | | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | return 0; } continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ continue; } if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; return 0; } return *zString==0; } |
︙ | ︙ |
Changes to src/loadext.c.
︙ | ︙ | |||
442 443 444 445 446 447 448 449 450 451 452 453 454 455 | int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = 300 + sqlite3Strlen30(zFile); int ii; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" #elif defined(__APPLE__) "dylib" | > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = 300 + sqlite3Strlen30(zFile); int ii; int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" #elif defined(__APPLE__) "dylib" |
︙ | ︙ | |||
544 545 546 547 548 549 550 | } } sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; } sqlite3_free(zAltEntry); | | > > | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 | } } sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; } sqlite3_free(zAltEntry); rc = xInit(db, &zErrmsg, &sqlite3Apis); if( rc ){ if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK; if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } sqlite3_free(zErrmsg); sqlite3OsDlClose(pVfs, handle); return SQLITE_ERROR; } |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 | */ static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* | > > > > > > > > > > > > | 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 | */ static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) DWORD nByte; void *zConverted; char *zOut; #endif /* If this path name begins with "/X:", where "X" is any alphabetic ** character, discard the initial "/" from the pathname. */ if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ zRelative++; } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* |
︙ | ︙ | |||
5352 5353 5354 5355 5356 5357 5358 | }else{ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); } return SQLITE_OK; #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) | < < < < < < < < < < < | 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 | }else{ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); } return SQLITE_OK; #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
296 297 298 299 300 301 302 | // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} | | > | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);} ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} // The optional AUTOINCREMENT keyword |
︙ | ︙ | |||
345 346 347 348 349 350 351 | conslist ::= tcons. tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). | | > | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | conslist ::= tcons. tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E.pExpr);} tcons ::= FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); sqlite3DeferForeignKey(pParse, D); } |
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 | ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U, | | | 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 | ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U, &S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF); } %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} uniqueflag(A) ::= . {A = OE_None;} |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 | ** name: Column name ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | ** name: Column name ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ static const char *azCol[] = { "cid", "name", "type", "notnull", "dflt_value", "pk" }; int i, k; int nHidden = 0; Column *pCol; |
︙ | ︙ | |||
1330 1331 1332 1333 1334 1335 1336 | if( pParent && pIdx==0 ){ int iKey = pFK->aCol[0].iFrom; assert( iKey>=0 && iKey<pTab->nCol ); if( iKey!=pTab->iPKey ){ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); sqlite3ColumnDefault(v, pTab, iKey, regRow); sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); | < < | | 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 | if( pParent && pIdx==0 ){ int iKey = pFK->aCol[0].iFrom; assert( iKey>=0 && iKey<pTab->nCol ); if( iKey!=pTab->iPKey ){ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); sqlite3ColumnDefault(v, pTab, iKey, regRow); sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); } sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); }else{ for(j=0; j<pFK->nCol; j++){ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 | /* ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1); | | | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | /* ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1); KeyInfo *p = sqlite3DbMallocRaw(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortOrder = (u8*)&p->aColl[N+X]; p->nField = (u16)N; p->nXField = (u16)X; p->enc = ENC(db); p->db = db; p->nRef = 1; |
︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 | /* ** Deallocate a KeyInfo object */ void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; | | | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 | /* ** Deallocate a KeyInfo object */ void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ) sqlite3DbFree(p->db, p); } } /* ** Make a new pointer to a KeyInfo object */ KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
502 503 504 505 506 507 508 509 510 511 512 513 514 515 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3613 3614 3615 3616 3617 3618 3619 | void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); | | | | 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 | void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); |
︙ | ︙ | |||
3667 3668 3669 3670 3671 3672 3673 | #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); | > > | | | 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 | #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*, int); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 | ** $db onecolumn $sql ** ** The onecolumn method is the equivalent of: ** lindex [$db eval $sql] 0 */ case DB_EXISTS: case DB_ONECOLUMN: { DbEvalContext sEval; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL"); return TCL_ERROR; } dbEvalInit(&sEval, pDb, objv[2], 0); rc = dbEvalStep(&sEval); if( choice==DB_ONECOLUMN ){ if( rc==TCL_OK ){ | > | | > | 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 | ** $db onecolumn $sql ** ** The onecolumn method is the equivalent of: ** lindex [$db eval $sql] 0 */ case DB_EXISTS: case DB_ONECOLUMN: { Tcl_Obj *pResult = 0; DbEvalContext sEval; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL"); return TCL_ERROR; } dbEvalInit(&sEval, pDb, objv[2], 0); rc = dbEvalStep(&sEval); if( choice==DB_ONECOLUMN ){ if( rc==TCL_OK ){ pResult = dbEvalColumnValue(&sEval, 0); }else if( rc==TCL_BREAK ){ Tcl_ResetResult(interp); } }else if( rc==TCL_BREAK || rc==TCL_OK ){ pResult = Tcl_NewBooleanObj(rc==TCL_OK); } dbEvalFinalize(&sEval); if( pResult ) Tcl_SetObjResult(interp, pResult); if( rc==TCL_BREAK ){ rc = TCL_OK; } break; } |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 | void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, | > > | 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 | void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, { "csv", sqlite3_csv_init }, { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, |
︙ | ︙ |
Changes to src/test3.c.
︙ | ︙ | |||
381 382 383 384 385 386 387 | static int btree_payload_size( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; | | < < < < < < < < | < | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | static int btree_payload_size( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; u32 n; char zBuf[50]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); n = sqlite3BtreePayloadSize(pCur); sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } /* ** usage: varint_test START MULTIPLIER COUNT INCREMENT ** |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
211 212 213 214 215 216 217 | sqlite3_randomness(sizeof(int), &iFinal); iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite; for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--; pFinal = pWrite; } #ifdef TRACE_CRASHTEST | > | > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | sqlite3_randomness(sizeof(int), &iFinal); iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite; for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--; pFinal = pWrite; } #ifdef TRACE_CRASHTEST if( pFile ){ printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a")); } #endif ppPtr = &g.pWriteList; for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){ sqlite3_file *pRealFile = pWrite->pFile->pRealFile; /* (eAction==1) -> write block out normally, |
︙ | ︙ | |||
794 795 796 797 798 799 800 801 802 803 804 805 806 807 | } if( setSectorsize ){ *piSectorSize = iSectorSize; } return TCL_OK; } /* ** tclcmd: sqlite_crash_enable ENABLE ** ** Parameter ENABLE must be a boolean value. If true, then the "crash" ** vfs is added to the system. If false, it is removed. */ | > > > > > > > > > > > > > > > > > > > > > | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 | } if( setSectorsize ){ *piSectorSize = iSectorSize; } return TCL_OK; } /* ** tclcmd: sqlite3_crash_now ** ** Simulate a crash immediately. This function does not return ** (writeListSync() calls exit(-1)). */ static int crashNowCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } writeListSync(0, 1); assert( 0 ); return TCL_OK; } /* ** tclcmd: sqlite_crash_enable ENABLE ** ** Parameter ENABLE must be a boolean value. If true, then the "crash" ** vfs is added to the system. If false, it is removed. */ |
︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | /* ** This procedure registers the TCL procedures defined in this file. */ int Sqlitetest6_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_DISKIO Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0); #endif return TCL_OK; } #endif /* SQLITE_TEST */ | > | 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | /* ** This procedure registers the TCL procedures defined in this file. */ int Sqlitetest6_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_DISKIO Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0); #endif return TCL_OK; } #endif /* SQLITE_TEST */ |
Changes to src/treeview.c.
︙ | ︙ | |||
441 442 443 444 445 446 447 448 449 450 451 452 453 454 | case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } if( zBinOp ){ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); | > > > > > > | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif case TK_MATCH: { sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pRight, 0); break; } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } if( zBinOp ){ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
2377 2378 2379 2380 2381 2382 2383 | ** ** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { | < | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 | ** ** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ Mem *pDest; /* Where to write the extracted value */ |
︙ | ︙ | |||
2430 2431 2432 2433 2434 2435 2436 | }else{ sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); | < | < < < < < < < | < < < < | < | 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 | }else{ sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail); assert( avail<=65536 ); /* Maximum page size is 64KiB */ if( pC->payloadSize <= (u32)avail ){ pC->szRow = pC->payloadSize; }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; }else{ pC->szRow = avail; |
︙ | ︙ | |||
4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 | }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; } break; } /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an ** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > | 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 | }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; } break; } /* Opcode: SeekRowid P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). If register P3 does not contain an integer or if P1 does not ** contain a record with rowid P3 then jump immediately to P2. ** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain ** a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_NotExists opcode performs the same operation, but with OP_NotExists ** the P3 register must be guaranteed to contain an integer value. With this ** opcode, register P3 might not contain an integer. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an ** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_SeekRowid opcode performs the same operation but also allows the ** P3 register to contain a non-integer value, in which case the jump is ** always taken. This opcode requires that P3 always contain an integer. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & MEM_Int)==0 ){ applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; } /* Fall through into OP_NotExists */ case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG pC->seekOp = 0; #endif |
︙ | ︙ | |||
4163 4164 4165 4166 4167 4168 4169 | if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); | | < | 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 | if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); v = sqlite3BtreeIntegerKey(pC->uc.pCursor); if( v>=MAX_ROWID ){ pC->useRandomRowid = 1; }else{ v++; /* IMP: R-29538-34987 */ } } } |
︙ | ︙ | |||
4247 4248 4249 4250 4251 4252 4253 | ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of | | > | > | 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 | ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of ** the last seek operation (OP_NotExists or OP_SeekRowid) was a success, ** then this ** operation will not attempt to find the appropriate row before doing ** the insert but will instead overwrite the row that the cursor is ** currently pointing to. Presumably, the prior OP_NotExists or ** OP_SeekRowid opcode ** has already positioned the cursor correctly. This is an optimization ** that boosts performance by avoiding redundant seeks. ** ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an ** UPDATE operation. Otherwise (if the flag is clear) then this opcode ** is part of an INSERT operation. The difference is only important to ** the update hook. |
︙ | ︙ | |||
4419 4420 4421 4422 4423 4424 4425 | assert( pC->deferredMoveto==0 ); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ | | < | | 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 | assert( pC->deferredMoveto==0 ); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); assert( pC->movetoTarget==iKey ); } #endif /* If the update-hook or pre-update-hook will be invoked, set zDb to ** the name of the db to pass as to it. Also set local pTab to a copy ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); assert( pOp->p4.pTab!=0 ); zDb = db->aDb[pC->iDb].zName; pTab = pOp->p4.pTab; if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ zDb = 0; /* Not needed. Silence a compiler warning. */ pTab = 0; /* Not needed. Silence a compiler warning. */ } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK |
︙ | ︙ | |||
4590 4591 4592 4593 4594 4595 4596 | ** of a real table, not a pseudo-table. */ case OP_RowKey: case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; | < | > | < < | < < < < < < < < | | < | 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 | ** of a real table, not a pseudo-table. */ case OP_RowKey: case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( isSorter(pC)==0 ); assert( pC->isTable || pOp->opcode!=OP_RowData ); assert( pC->isTable==0 || pOp->opcode==OP_RowData ); assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); #if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ goto no_mem; } pOut->n = n; MemSetTypeFlag(pOut, MEM_Blob); |
︙ | ︙ | |||
4699 4700 4701 4702 4703 4704 4705 | assert( pC->uc.pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; if( pC->nullRow ){ pOut->flags = MEM_Null; break; } | | < | 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 | assert( pC->uc.pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; if( pC->nullRow ){ pOut->flags = MEM_Null; break; } v = sqlite3BtreeIntegerKey(pC->uc.pCursor); } pOut->u.i = v; break; } /* Opcode: NullRow P1 * * * * ** |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
1689 1690 1691 1692 1693 1694 1695 | } /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; | | < | 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 | } /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreeData(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); if( !p->pUnpacked ) rc = SQLITE_NOMEM; } |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
4311 4312 4313 4314 4315 4316 4317 | /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); | | < | 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 | /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; |
︙ | ︙ | |||
4389 4390 4391 4392 4393 4394 4395 | int rc; BtCursor *pCur; Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); | | < | 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 | int rc; BtCursor *pCur; Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); |
︙ | ︙ |
Changes to src/vdbeblob.c.
︙ | ︙ | |||
411 412 413 414 415 416 417 | ** SQLITE_UPDATE where the PK columns do not change is handled in the ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | ** SQLITE_UPDATE where the PK columns do not change is handled in the ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); sqlite3VdbePreUpdateHook( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 ); } #endif rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
987 988 989 990 991 992 993 | assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); | < | < < < | 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 | assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); if( offset+amt<=available ){ pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
750 751 752 753 754 755 756 | if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) && pParse->pNewTable && !db->mallocFailed && !pParse->pNewTable->pSelect && (pParse->pNewTable->tabFlags & TF_Virtual)==0 ){ if( !pTab->aCol ){ | > > | | > | | > > > > > > > > > > > | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) && pParse->pNewTable && !db->mallocFailed && !pParse->pNewTable->pSelect && (pParse->pNewTable->tabFlags & TF_Virtual)==0 ){ if( !pTab->aCol ){ Table *pNew = pParse->pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); pNew->nCol = 0; pNew->aCol = 0; assert( pTab->pIndex==0 ); if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){ rc = SQLITE_ERROR; } pIdx = pNew->pIndex; if( pIdx ){ assert( pIdx->pNext==0 ); pTab->pIndex = pIdx; pNew->pIndex = 0; pIdx->pTable = pTab; } } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } |
︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ sqlite3OomFault(pToplevel->db); } } /* | | < < | > > > > > < < | 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ sqlite3OomFault(pToplevel->db); } } /* ** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if the eponymous virtual table instance exists ** when this routine returns, and return zero if it does not exist. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE ** statement in order to come into existance. Eponymous virtual table ** instances always exist. They cannot be DROP-ed. ** ** Any virtual table module for which xConnect and xCreate are the same ** method can have an eponymous virtual table instance. */ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ const sqlite3_module *pModule = pMod->pModule; Table *pTab; char *zErr = 0; int rc; sqlite3 *db = pParse->db; if( pMod->pEpoTab ) return 1; if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 0; pTab->zName = sqlite3DbStrDup(db, pMod->zName); if( pTab->zName==0 ){ sqlite3DbFree(db, pTab); return 0; } pMod->pEpoTab = pTab; pTab->nRef = 1; pTab->pSchema = db->aDb[0].pSchema; pTab->tabFlags |= TF_Virtual; pTab->nModuleArg = 0; pTab->iPKey = -1; addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(db, pTab, 0); |
︙ | ︙ | |||
1136 1137 1138 1139 1140 1141 1142 | /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ | > | > | | | 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 | /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ /* Mark the table as Ephemeral prior to deleting it, so that the ** sqlite3DeleteTable() routine will know that it is not stored in ** the schema. */ pTab->tabFlags |= TF_Ephemeral; sqlite3DeleteTable(db, pTab); pMod->pEpoTab = 0; } } /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 | ** needed and only the sync is done. If padding is needed, then the ** final frame is repeated (with its commit mark) until the next sector ** boundary is crossed. Only the part of the WAL prior to the last ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) { #if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED) free(w.aFrameBuf); #endif return rc; } iOffset += szFrame; nExtra++; } | > > > > > | | 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 | ** needed and only the sync is done. If padding is needed, then the ** final frame is repeated (with its commit mark) until the next sector ** boundary is crossed. Only the part of the WAL prior to the last ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; bSync = (w.iSyncPoint==iOffset); testcase( bSync ); while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) { #if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED) free(w.aFrameBuf); #endif return rc; } iOffset += szFrame; nExtra++; } } if( bSync ){ assert( rc==SQLITE_OK ); rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK); } } #if defined(SQLITE_WRITE_WALFRAME_PREBUFFERED) free(w.aFrameBuf); #endif |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 | ** Print the content of a WhereTerm object */ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; memcpy(zType, "...", 4); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; sqlite3DebugPrintf( | > > > > > > > > > > | | > > > > > > > > > > > > | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 | ** Print the content of a WhereTerm object */ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; char zLeft[50]; memcpy(zType, "...", 4); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; if( pTerm->eOperator & WO_SINGLE ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", pTerm->leftCursor, pTerm->u.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } sqlite3DebugPrintf( "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x\n", iTerm, pTerm, zType, zLeft, pTerm->truthProb, pTerm->eOperator, pTerm->wtFlags); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } #endif #ifdef WHERETRACE_ENABLED /* ** Show the complete content of a WhereClause */ void sqlite3WhereClausePrint(WhereClause *pWC){ int i; for(i=0; i<pWC->nTerm; i++){ whereTermPrint(&pWC->a[i], i); } } #endif #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes */ |
︙ | ︙ | |||
2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 | m = pSrc->colUsed & ~columnsInIndex(pProbe); pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ if( b || !HasRowid(pTab) || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRow<pTab->szTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) | > | 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 | m = pSrc->colUsed & ~columnsInIndex(pProbe); pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ if( b || !HasRowid(pTab) || pProbe->pPartIdxWhere!=0 || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRow<pTab->szTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) |
︙ | ︙ | |||
3120 3121 3122 3123 3124 3125 3126 | continue; } sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ | | < < | 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 | continue; } sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ sqlite3WhereClausePrint(sSubBuild.pWC); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif |
︙ | ︙ | |||
4306 4307 4308 4309 4310 4311 4312 | sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ | < | < < | 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 | sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ sqlite3WhereClausePrint(sWLB.pWC); } #endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; |
︙ | ︙ |
Changes to src/whereInt.h.
︙ | ︙ | |||
433 434 435 436 437 438 439 440 441 442 443 444 445 446 | /* ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ | > > > | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | /* ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED void sqlite3WhereClausePrint(WhereClause *pWC); #endif WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
967 968 969 970 971 972 973 | assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; | < | | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 | assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
564 565 566 567 568 569 570 | sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); | | > > | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); if( allowedOp(pAndTerm->pExpr->op) || pAndTerm->eOperator==WO_MATCH ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } } indexable &= b; } }else if( pOrTerm->wtFlags & TERM_COPIED ){ |
︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_MATCH auxiliary term to the constraint set if the ** current expression is of the form: column MATCH expr. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ | | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_MATCH auxiliary term to the constraint set if the ** current expression is of the form: column MATCH expr. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){ int idxNew; Expr *pRight, *pLeft; WhereTerm *pNewTerm; Bitmask prereqColumn, prereqExpr; pRight = pExpr->x.pList->a[0].pExpr; pLeft = pExpr->x.pList->a[1].pExpr; |
︙ | ︙ |
Added test/bestindex3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | # 2016 May 29 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix bestindex3 ifcapable !vtab { finish_test return } #------------------------------------------------------------------------- # Virtual table callback for a virtual table named $tbl. # # The table created is: # # "CREATE TABLE t1 (a, b, c)" # # This virtual table supports both LIKE and = operators on all columns. # proc vtab_cmd {bOmit method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { foreach {clist orderby mask} $args {} set ret [list] set use use if {$bOmit} {set use omit} for {set i 0} {$i < [llength $clist]} {incr i} { array unset C array set C [lindex $clist $i] if {$C(usable) && ($C(op)=="like" || $C(op)=="eq")} { lappend ret $use $i lappend ret idxstr lappend ret "[lindex {a b c} $C(column)] [string toupper $C(op)] ?" break } } if {$ret==""} { lappend ret cost 1000000 rows 1000000 } else { lappend ret cost 100 rows 10 } return $ret } xFilter { foreach {idxnum idxstr param} $args {} set where "" if {$bOmit && $idxstr != ""} { set where " WHERE [string map [list ? '$param' EQ =] $idxstr]" } return [list sql "SELECT rowid, * FROM ttt$where"] } } return "" } register_tcl_module db do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} } do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} } do_eqp_test 1.3 { SELECT * FROM t1 WHERE a = 'abc' OR b = 'def'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?} } do_eqp_test 1.4 { SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?} } do_execsql_test 1.5 { CREATE TABLE ttt(a, b, c); INSERT INTO ttt VALUES(1, 'two', 'three'); INSERT INTO ttt VALUES(2, 'one', 'two'); INSERT INTO ttt VALUES(3, 'three', 'one'); INSERT INTO ttt VALUES(4, 'y', 'one'); INSERT INTO ttt VALUES(5, 'x', 'two'); INSERT INTO ttt VALUES(6, 'y', 'three'); } foreach omit {0 1} { do_execsql_test 1.6.$omit.0 " DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING tcl('vtab_cmd $omit'); " do_execsql_test 1.6.$omit.1 { SELECT rowid FROM t1 WHERE c LIKE 'o%' } {3 4} do_execsql_test 1.6.$omit.2 { SELECT rowid FROM t1 WHERE c LIKE 'o%' OR b='y' } {3 4 6} do_execsql_test 1.6.$omit.3 { SELECT rowid FROM t1 WHERE c = 'three' OR c LIKE 'o%' } {1 6 3 4} } #------------------------------------------------------------------------- # Test the same pattern works with ordinary tables. # do_execsql_test 2.1 { CREATE TABLE t2(x TEXT COLLATE nocase, y TEXT); CREATE INDEX t2x ON t2(x COLLATE nocase); CREATE INDEX t2y ON t2(y); } do_eqp_test 2.2 { SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def' } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)} 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)} } #------------------------------------------------------------------------- # Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE # statement is currently ignored. # proc vvv_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a PRIMARY KEY, b, c)" } } } proc yyy_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b))" } } } do_execsql_test 3.1 { CREATE VIRTUAL TABLE t3 USING tcl('vvv_command') } do_execsql_test 3.2 { CREATE VIRTUAL TABLE t4 USING tcl('yyy_command') } finish_test |
Added test/csv01.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # 2016-06-02 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for CSV virtual table. set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix closure01 ifcapable !vtab||!cte { finish_test ; return } load_static_extension db csv do_execsql_test 1.0 { CREATE VIRTUAL TABLE temp.t1 USING csv( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4 ); SELECT * FROM t1 WHERE c1=10; } {9 10 11 12} do_execsql_test 1.1 { SELECT * FROM t1 WHERE c1='10'; } {9 10 11 12} do_execsql_test 1.2 { SELECT rowid FROM t1; } {1 2 3 4} do_execsql_test 2.0 { DROP TABLE t1; CREATE VIRTUAL TABLE temp.t2 USING csv( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4, schema='CREATE TABLE t2(a INT, b TEXT, c REAL, d BLOB)' ); SELECT * FROM t2 WHERE a=9; } {9 10 11 12} do_execsql_test 2.1 { SELECT * FROM t2 WHERE b=10; } {9 10 11 12} do_execsql_test 2.2 { SELECT * FROM t2 WHERE c=11; } {9 10 11 12} do_execsql_test 2.3 { SELECT * FROM t2 WHERE d=12; } {} do_execsql_test 2.4 { SELECT * FROM t2 WHERE d='12'; } {9 10 11 12} do_execsql_test 2.5 { SELECT * FROM t2 WHERE a='9'; } {9 10 11 12} do_execsql_test 3.0 { DROP TABLE t2; CREATE VIRTUAL TABLE temp.t3 USING csv( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4, schema= 'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID', testflags=1 ); SELECT a FROM t3 WHERE b=6 OR c=7 OR d=12 ORDER BY +a; } {5 9} do_execsql_test 3.1 { SELECT a FROM t3 WHERE +b=6 OR c=7 OR d=12 ORDER BY +a; } {5 9} # The rowid column is not visible on a WITHOUT ROWID virtual table do_catchsql_test 3.2 { SELECT rowid, a FROM t3; } {1 {no such column: rowid}} do_catchsql_test 4.0 { DROP TABLE t3; CREATE VIRTUAL TABLE temp.t4 USING csv_wr( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4, schema= 'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID', testflags=1 ); } {1 {vtable constructor failed: t4}} finish_test |
Changes to test/ctime.test.
︙ | ︙ | |||
198 199 200 201 202 203 204 | set N [ expr {$tc-1} ] set ans1 [ catchsql { SELECT sqlite_compileoption_get($N); } ] set ans2 [ catchsql { SELECT sqlite_compileoption_used($opt); } ] | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | set N [ expr {$tc-1} ] set ans1 [ catchsql { SELECT sqlite_compileoption_get($N); } ] set ans2 [ catchsql { SELECT sqlite_compileoption_used($opt); } ] list [ lindex $ans1 0 ] [ expr { [lindex [lindex $ans1 1] 0]==$opt } ] \ [ expr { $ans2 } ] } {0 1 {0 1}} incr tc 1 } # test 1 past array bounds do_test ctime-2.5.$tc { set N [ expr {$tc-1} ] |
︙ | ︙ |
Changes to test/index6.test.
︙ | ︙ | |||
371 372 373 374 375 376 377 378 379 | do_execsql_test index6-10.3 { SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {9 5} do_execsql_test index6-10.3eqp { EXPLAIN QUERY PLAN SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {~/USING INDEX t10x/} finish_test | > > > > > > > > > > > | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | do_execsql_test index6-10.3 { SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {9 5} do_execsql_test index6-10.3eqp { EXPLAIN QUERY PLAN SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {~/USING INDEX t10x/} # A partial index will be used for a full table scan, where possible do_execsql_test index6-11.1 { CREATE TABLE t11(a,b,c); CREATE INDEX t11x ON t11(a) WHERE b<>99; EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99; } {/USING INDEX t11x/} do_execsql_test index6-11.2 { EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99 AND c<>98; } {/USING INDEX t11x/} finish_test |
Changes to test/misc5.test.
︙ | ︙ | |||
566 567 568 569 570 571 572 573 574 575 576 577 578 579 | LIMIT (SELECT lmt FROM logs_base) ; } } {1 {no such table: logs_base}} } # Overflow the lemon parser stack by providing an overly complex # expression. Make sure that the overflow is detected and reported. # do_test misc5-7.1 { execsql {CREATE TABLE t1(x)} set sql "INSERT INTO t1 VALUES(" set tail "" for {set i 0} {$i<200} {incr i} { append sql "(1+" | > > | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | LIMIT (SELECT lmt FROM logs_base) ; } } {1 {no such table: logs_base}} } # Overflow the lemon parser stack by providing an overly complex # expression. Make sure that the overflow is detected and reported. # # This test fails when building with -DYYSTACKDEPTH=0 # do_test misc5-7.1 { execsql {CREATE TABLE t1(x)} set sql "INSERT INTO t1 VALUES(" set tail "" for {set i 0} {$i<200} {incr i} { append sql "(1+" |
︙ | ︙ |
Changes to test/speedtest1.c.
︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | break; } } } fclose(in); } #endif int main(int argc, char **argv){ int doAutovac = 0; /* True for --autovacuum */ int cacheSize = 0; /* Desired cache size. 0 means default */ int doExclusive = 0; /* True for --exclusive */ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ int doIncrvac = 0; /* True for --incrvacuum */ | > > > > | 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 | break; } } } fclose(in); } #endif #if SQLITE_VERSION_NUMBER<3006018 # define sqlite3_sourceid(X) "(before 3.6.18)" #endif int main(int argc, char **argv){ int doAutovac = 0; /* True for --autovacuum */ int cacheSize = 0; /* Desired cache size. 0 means default */ int doExclusive = 0; /* True for --exclusive */ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ int doIncrvac = 0; /* True for --incrvacuum */ |
︙ | ︙ |
Changes to test/stat.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | set ::asc 1 proc a_string {n} { string range [string repeat [incr ::asc]. $n] 1 $n } db func a_string a_string register_dbstat_vtab db do_execsql_test stat-0.0 { PRAGMA auto_vacuum = OFF; CREATE VIRTUAL TABLE temp.stat USING dbstat; SELECT * FROM stat; } {} if {[wal_is_capable]} { do_execsql_test stat-0.1 { | > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | set ::asc 1 proc a_string {n} { string range [string repeat [incr ::asc]. $n] 1 $n } db func a_string a_string register_dbstat_vtab db do_execsql_test stat-0.0 { PRAGMA table_info(dbstat); } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} do_execsql_test stat-0.1 { PRAGMA auto_vacuum = OFF; CREATE VIRTUAL TABLE temp.stat USING dbstat; SELECT * FROM stat; } {} if {[wal_is_capable]} { do_execsql_test stat-0.1 { |
︙ | ︙ |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
630 631 632 633 634 635 636 637 638 639 640 | do_execsql_test tcl-14.1 { CREATE TABLE t6(x); INSERT INTO t6 VALUES(1); } do_test tcl-14.2 { db one {SELECT x FROM t6 WHERE xCall()!='value'} } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | do_execsql_test tcl-14.1 { CREATE TABLE t6(x); INSERT INTO t6 VALUES(1); } do_test tcl-14.2 { db one {SELECT x FROM t6 WHERE xCall()!='value'} } {} # Verify that the "exists" and "onecolumn" methods work when # a "profile" is registered. # catch {db close} sqlite3 db :memory: proc noop-profile {args} { return } do_test tcl-15.0 { db eval {CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),(2),(3);} db onecolumn {SELECT a FROM t1 WHERE a>2} } {3} do_test tcl-15.1 { db exists {SELECT a FROM t1 WHERE a>2} } {1} do_test tcl-15.2 { db exists {SELECT a FROM t1 WHERE a>3} } {0} db profile noop-profile do_test tcl-15.3 { db onecolumn {SELECT a FROM t1 WHERE a>2} } {3} do_test tcl-15.4 { db exists {SELECT a FROM t1 WHERE a>2} } {1} do_test tcl-15.5 { db exists {SELECT a FROM t1 WHERE a>3} } {0} finish_test |
Added test/walcrash4.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | # 2010 May 25 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/wal_common.tcl ifcapable !wal {finish_test ; return } set testprefix walcrash4 #------------------------------------------------------------------------- # At one point, if "PRAGMA synchronous=full" is set and the platform # does not support POWERSAFE_OVERWRITE, and the last frame written to # the wal file in a transaction is aligned with a sector boundary, the # xSync() call was omitted. # # The following test verifies that this has been fixed. # do_execsql_test 1.0 { PRAGMA autovacuum = 0; PRAGMA page_size = 1024; PRAGMA journal_mode = wal; PRAGMA main.synchronous = full; } {wal} faultsim_save_and_close # The error message is different on unix and windows # if {$::tcl_platform(platform)=="windows"} { set msg "child killed: unknown signal" } else { set msg "child process exited abnormally" } for {set nExtra 0} {$nExtra < 10} {incr nExtra} { for {set i 0} {$i < 10} {incr i} { do_test 1.nExtra=$nExtra.i=$i.1 { faultsim_restore_and_reopen set fd [open crash.tcl w] puts $fd [subst -nocommands { sqlite3_crash_enable 1 sqlite3_test_control_pending_byte $::sqlite_pending_byte sqlite3 db test.db -vfs crash db eval { PRAGMA main.synchronous=FULL; BEGIN; CREATE TABLE t1(x UNIQUE); } for {set e 2} {[set e] < ($nExtra+2)} {incr e} { db eval "CREATE TABLE t[set e] (x)" } db eval { INSERT INTO t1 VALUES( randomblob(170000) ); COMMIT; } sqlite3_crash_now }] close $fd set r [catch { exec [info nameofexec] crash.tcl >@stdout } msg] list $r $msg } "1 {$msg}" do_execsql_test 1.nExtra=$nExtra.i=$i.2 { SELECT count(*) FROM t1; PRAGMA integrity_check; } {1 ok} } } finish_test |
Added tool/dbhash.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | /* ** 2016-06-07 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This is a utility program that computes an SHA1 hash on the content ** of an SQLite database. ** ** The hash is computed over just the content of the database. Free ** space inside of the database file, and alternative on-disk representations ** of the same content (ex: UTF8 vs UTF16) do not affect the hash. So, ** for example, the database file page size, encoding, and auto_vacuum setting ** can all be changed without changing the hash. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <ctype.h> #include <string.h> #include <assert.h> #include "sqlite3.h" /* Context for the SHA1 hash */ typedef struct SHA1Context SHA1Context; struct SHA1Context { unsigned int state[5]; unsigned int count[2]; unsigned char buffer[64]; }; /* ** All global variables are gathered into the "g" singleton. */ struct GlobalVars { const char *zArgv0; /* Name of program */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ SHA1Context cx; /* SHA1 hash context */ } g; /* ** Debugging flags */ #define DEBUG_FULLTRACE 0x00000001 /* Trace hash to stderr */ /****************************************************************************** ** The Hash Engine ** ** Modify these routines (and appropriate state fields in global variable 'g') ** in order to compute a different (better?) hash of the database. */ /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #endif #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 * * Rl0() for little-endian and Rb0() for big-endian. Endianness is * determined at run-time. */ #define Rl0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2); #define Rb0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R1(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R2(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2); #define R3(v,w,x,y,z,i) \ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); #define R4(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); /* * Hash a single 512-bit block. This is the core of the algorithm. */ #define a qq[0] #define b qq[1] #define c qq[2] #define d qq[3] #define e qq[4] void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){ unsigned int qq[5]; /* a, b, c, d, e; */ static int one = 1; unsigned int block[16]; memcpy(block, buffer, 64); memcpy(qq,state,5*sizeof(unsigned int)); /* Copy g.cx.state[] to working vars */ /* a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; */ /* 4 rounds of 20 operations each. Loop unrolled. */ if( 1 == *(unsigned char*)&one ){ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3); Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7); Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11); Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15); }else{ Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3); Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7); Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11); Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15); } R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } /* Initialize the SHA1 hash */ static void hash_init(void){ /* SHA1 initialization constants */ g.cx.state[0] = 0x67452301; g.cx.state[1] = 0xEFCDAB89; g.cx.state[2] = 0x98BADCFE; g.cx.state[3] = 0x10325476; g.cx.state[4] = 0xC3D2E1F0; g.cx.count[0] = g.cx.count[1] = 0; } /* Add new content to the SHA1 hash */ static void hash_step(const unsigned char *data, unsigned int len){ unsigned int i, j; j = g.cx.count[0]; if( (g.cx.count[0] += len << 3) < j ){ g.cx.count[1] += (len>>29)+1; } j = (j >> 3) & 63; if( (j + len) > 63 ){ (void)memcpy(&g.cx.buffer[j], data, (i = 64-j)); SHA1Transform(g.cx.state, g.cx.buffer); for(; i + 63 < len; i += 64){ SHA1Transform(g.cx.state, &data[i]); } j = 0; }else{ i = 0; } (void)memcpy(&g.cx.buffer[j], &data[i], len - i); } /* Add padding and compute and output the message digest. */ static void hash_finish(const char *zName){ unsigned int i; unsigned char finalcount[8]; unsigned char digest[20]; static const char zEncode[] = "0123456789abcdef"; char zOut[41]; for (i = 0; i < 8; i++){ finalcount[i] = (unsigned char)((g.cx.count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } hash_step((const unsigned char *)"\200", 1); while ((g.cx.count[0] & 504) != 448){ hash_step((const unsigned char *)"\0", 1); } hash_step(finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++){ digest[i] = (unsigned char)((g.cx.state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } for(i=0; i<20; i++){ zOut[i*2] = zEncode[(digest[i]>>4)&0xf]; zOut[i*2+1] = zEncode[digest[i] & 0xf]; } zOut[i*2]= 0; printf("%s %s\n", zOut, zName); } /* End of the hashing logic *******************************************************************************/ /* ** Print an error resulting from faulting command-line arguments and ** abort the program. */ static void cmdlineError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s: ", g.zArgv0); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0); exit(1); } /* ** Print an error message for an error that occurs at runtime, then ** abort the program. */ static void runtimeError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s: ", g.zArgv0); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } /* ** Prepare a new SQL statement. Print an error and abort if anything ** goes wrong. */ static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){ char *zSql; int rc; sqlite3_stmt *pStmt; zSql = sqlite3_vmprintf(zFormat, ap); if( zSql==0 ) runtimeError("out of memory"); rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); if( rc ){ runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db), zSql); } sqlite3_free(zSql); return pStmt; } static sqlite3_stmt *db_prepare(const char *zFormat, ...){ va_list ap; sqlite3_stmt *pStmt; va_start(ap, zFormat); pStmt = db_vprepare(zFormat, ap); va_end(ap); return pStmt; } /* ** Compute the hash for all rows of the query formed from the printf-style ** zFormat and its argument. */ static void hash_one_query(const char *zFormat, ...){ va_list ap; sqlite3_stmt *pStmt; /* The query defined by zFormat and "..." */ int nCol; /* Number of columns in the result set */ int i; /* Loop counter */ /* Prepare the query defined by zFormat and "..." */ va_start(ap, zFormat); pStmt = db_vprepare(zFormat, ap); va_end(ap); nCol = sqlite3_column_count(pStmt); /* Compute a hash over the result of the query */ while( SQLITE_ROW==sqlite3_step(pStmt) ){ for(i=0; i<nCol; i++){ switch( sqlite3_column_type(pStmt,i) ){ case SQLITE_NULL: { hash_step((const unsigned char*)"0",1); if( g.fDebug & DEBUG_FULLTRACE ) fprintf(stderr, "NULL\n"); break; } case SQLITE_INTEGER: { sqlite3_uint64 u; int j; unsigned char x[8]; sqlite3_int64 v = sqlite3_column_int64(pStmt,i); memcpy(&u, &v, 8); for(j=7; j>=0; j--){ x[j] = u & 0xff; u >>= 8; } hash_step((const unsigned char*)"1",1); hash_step(x,8); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "INT %s\n", sqlite3_column_text(pStmt,i)); } break; } case SQLITE_FLOAT: { sqlite3_uint64 u; int j; unsigned char x[8]; double r = sqlite3_column_double(pStmt,i); memcpy(&u, &r, 8); for(j=7; j>=0; j--){ x[j] = u & 0xff; u >>= 8; } hash_step((const unsigned char*)"2",1); hash_step(x,8); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "FLOAT %s\n", sqlite3_column_text(pStmt,i)); } break; } case SQLITE_TEXT: { int n = sqlite3_column_bytes(pStmt, i); const unsigned char *z = sqlite3_column_text(pStmt, i); hash_step((const unsigned char*)"3", 1); hash_step(z, n); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "TEXT '%s'\n", sqlite3_column_text(pStmt,i)); } break; } case SQLITE_BLOB: { int n = sqlite3_column_bytes(pStmt, i); const unsigned char *z = sqlite3_column_blob(pStmt, i); hash_step((const unsigned char*)"4", 1); hash_step(z, n); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "BLOB (%d bytes)\n", n); } break; } } } } sqlite3_finalize(pStmt); } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] FILE ...\n", g.zArgv0); printf( "Compute a SHA1 hash on the content of database FILE. System tables such as\n" "sqlite_stat1, sqlite_stat4, and sqlite_sequence are omitted from the hash.\n" "Options:\n" " --debug N Set debugging flags to N (experts only)\n" " --like PATTERN Only hash tables whose name is LIKE the pattern\n" " --schema-only Only hash the schema - omit table content\n" " --without-schema Only hash table content - omit the schema\n" ); } int main(int argc, char **argv){ const char *zDb = 0; /* Name of the database currently being hashed */ int i; /* Loop counter */ int rc; /* Subroutine return code */ char *zErrMsg; /* Error message when opening database */ sqlite3_stmt *pStmt; /* An SQLite query */ const char *zLike = 0; /* LIKE pattern of tables to hash */ int omitSchema = 0; /* True to compute hash on content only */ int omitContent = 0; /* True to compute hash on schema only */ int nFile = 0; /* Number of input filenames seen */ g.zArgv0 = argv[0]; sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); for(i=1; i<argc; i++){ const char *z = argv[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"debug")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); g.fDebug = strtol(argv[++i], 0, 0); }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"like")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); if( zLike!=0 ) cmdlineError("only one --like allowed"); zLike = argv[++i]; }else if( strcmp(z,"schema-only")==0 ){ omitContent = 1; }else if( strcmp(z,"without-schema")==0 ){ omitSchema = 1; }else { cmdlineError("unknown option: %s", argv[i]); } }else{ nFile++; if( nFile<i ) argv[nFile] = argv[i]; } } if( nFile==0 ){ cmdlineError("no input files specified - nothing to do"); } if( omitSchema && omitContent ){ cmdlineError("only one of --without-schema and --omit-schema allowed"); } if( zLike==0 ) zLike = "%"; for(i=1; i<=nFile; i++){ static const int openFlags = SQLITE_OPEN_READWRITE | /* Read/write so hot journals can recover */ SQLITE_OPEN_URI ; zDb = argv[i]; rc = sqlite3_open_v2(zDb, &g.db, openFlags, 0); if( rc ){ fprintf(stderr, "cannot open database file '%s'\n", zDb); continue; } rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg); if( rc || zErrMsg ){ sqlite3_close(g.db); g.db = 0; fprintf(stderr, "'%s' is not a valid SQLite database\n", zDb); continue; } /* Start the hash */ hash_init(); /* Hash table content */ if( !omitContent ){ pStmt = db_prepare( "SELECT name FROM sqlite_master\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " AND name NOT LIKE 'sqlite_%%'\n" " AND name LIKE '%q'\n" " ORDER BY name COLLATE nocase;\n", zLike ); while( SQLITE_ROW==sqlite3_step(pStmt) ){ /* We want rows of the table to be hashed in PRIMARY KEY order. ** Technically, an ORDER BY clause is required to guarantee that ** order. However, though not guaranteed by the documentation, every ** historical version of SQLite has always output rows in PRIMARY KEY ** order when there is no WHERE or GROUP BY clause, so the ORDER BY ** can be safely omitted. */ hash_one_query("SELECT * FROM \"%w\"", sqlite3_column_text(pStmt,0)); } sqlite3_finalize(pStmt); } /* Hash the database schema */ if( !omitSchema ){ hash_one_query( "SELECT type, name, tbl_name, sql FROM sqlite_master\n" " WHERE tbl_name LIKE '%q'\n" " ORDER BY name COLLATE nocase;\n", zLike ); } /* Finish and output the hash and close the database connection. */ hash_finish(zDb); sqlite3_close(g.db); } return 0; } |
Changes to tool/lemon.c.
︙ | ︙ | |||
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ int iRule; /* Rule number as used in the generated tables */ Boolean canReduce; /* True if this rule is ever reduced */ struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; /* A configuration is a production rule of the grammar together with ** a mark (dot) showing how much of that rule has been processed so far. ** Configurations also contain a follow-set which is a list of terminal | > > > | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ int noCode; /* True if this rule has no associated C code */ int codeEmitted; /* True if the code has been emitted already */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ int iRule; /* Rule number as used in the generated tables */ Boolean canReduce; /* True if this rule is ever reduced */ Boolean doesReduce; /* Reduce actions occur after optimization */ struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; /* A configuration is a production rule of the grammar together with ** a mark (dot) showing how much of that rule has been processed so far. ** Configurations also contain a follow-set which is a list of terminal |
︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | struct action { struct symbol *sp; /* The look-ahead symbol */ enum e_action type; union { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ } x; struct action *next; /* Next action for this state */ struct action *collide; /* Next action with the same hash */ }; /* Each state of the generated parser's finite state machine ** is encoded as an instance of the following structure. */ struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ int statenum; /* Sequential number for this state */ | > | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | struct action { struct symbol *sp; /* The look-ahead symbol */ enum e_action type; union { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ } x; struct symbol *spOpt; /* SHIFTREDUCE optimization to this symbol */ struct action *next; /* Next action for this state */ struct action *collide; /* Next action with the same hash */ }; /* Each state of the generated parser's finite state machine ** is encoded as an instance of the following structure. */ struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ int statenum; /* Sequential number for this state */ struct action *ap; /* List of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ int iDfltReduce; /* Default action is to REDUCE by this rule */ struct rule *pDfltReduce;/* The default REDUCE rule. */ int autoReduce; /* True if this is an auto-reduce state */ }; #define NO_OFFSET (-2147483647) |
︙ | ︙ | |||
526 527 528 529 530 531 532 533 534 535 536 537 538 539 | ){ struct action *newaction; newaction = Action_new(); newaction->next = *app; *app = newaction; newaction->type = type; newaction->sp = sp; if( type==SHIFT ){ newaction->x.stp = (struct state *)arg; }else{ newaction->x.rp = (struct rule *)arg; } } /********************** New code to implement the "acttab" module ***********/ | > | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | ){ struct action *newaction; newaction = Action_new(); newaction->next = *app; *app = newaction; newaction->type = type; newaction->sp = sp; newaction->spOpt = 0; if( type==SHIFT ){ newaction->x.stp = (struct state *)arg; }else{ newaction->x.rp = (struct rule *)arg; } } /********************** New code to implement the "acttab" module ***********/ |
︙ | ︙ | |||
1495 1496 1497 1498 1499 1500 1501 | user_templatename = (char *) malloc( lemonStrlen(z)+1 ); if( user_templatename==0 ){ memory_error(); } lemon_strcpy(user_templatename, z); } | | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 | user_templatename = (char *) malloc( lemonStrlen(z)+1 ); if( user_templatename==0 ){ memory_error(); } lemon_strcpy(user_templatename, z); } /* Merge together to lists of rules ordered by rule.iRule */ static struct rule *Rule_merge(struct rule *pA, struct rule *pB){ struct rule *pFirst = 0; struct rule **ppPrev = &pFirst; while( pA && pB ){ if( pA->iRule<pB->iRule ){ *ppPrev = pA; ppPrev = &pA->next; |
︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 | for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); lem.nsymbol = i - 1; for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++); lem.nterminal = i; | | > > > | 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); lem.nsymbol = i - 1; for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++); lem.nterminal = i; /* Assign sequential rule numbers. Start with 0. Put rules that have no ** reduce action C-code associated with them last, so that the switch() ** statement that selects reduction actions will have a smaller jump table. */ for(i=0, rp=lem.rule; rp; rp=rp->next){ rp->iRule = rp->code ? i++ : -1; } for(rp=lem.rule; rp; rp=rp->next){ if( rp->iRule<0 ) rp->iRule = i++; } lem.startRule = lem.rule; |
︙ | ︙ | |||
2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 | ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first \ to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Token \"%s\" should be either \"%%\" or a nonterminal name.", x); | > | 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 | ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first \ to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; psp->prevrule->noCode = 0; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Token \"%s\" should be either \"%%\" or a nonterminal name.", x); |
︙ | ︙ | |||
2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 | rp->rhs[i] = psp->rhs[i]; rp->rhsalias[i] = psp->alias[i]; } rp->lhs = psp->lhs; rp->lhsalias = psp->lhsalias; rp->nrhs = psp->nrhs; rp->code = 0; rp->precsym = 0; rp->index = psp->gp->nrule++; rp->nextlhs = rp->lhs->rule; rp->lhs->rule = rp; rp->next = 0; if( psp->firstrule==0 ){ psp->firstrule = psp->lastrule = rp; | > | 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 | rp->rhs[i] = psp->rhs[i]; rp->rhsalias[i] = psp->alias[i]; } rp->lhs = psp->lhs; rp->lhsalias = psp->lhsalias; rp->nrhs = psp->nrhs; rp->code = 0; rp->noCode = 1; rp->precsym = 0; rp->index = psp->gp->nrule++; rp->nextlhs = rp->lhs->rule; rp->lhs->rule = rp; rp->next = 0; if( psp->firstrule==0 ){ psp->firstrule = psp->lastrule = rp; |
︙ | ︙ | |||
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 | result = 0; } break; case NOT_USED: result = 0; break; } return result; } /* Generate the "*.out" log file */ void ReportOutput(struct lemon *lemp) { int i; | > > > | 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 | result = 0; } break; case NOT_USED: result = 0; break; } if( result && ap->spOpt ){ fprintf(fp," /* because %s==%s */", ap->sp->name, ap->spOpt->name); } return result; } /* Generate the "*.out" log file */ void ReportOutput(struct lemon *lemp) { int i; |
︙ | ︙ | |||
3523 3524 3525 3526 3527 3528 3529 | } } z[used] = 0; return z; } /* | | | < | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 | } } z[used] = 0; return z; } /* ** Write and transform the rp->code string so that symbols are expanded. ** Populate the rp->codePrefix and rp->codeSuffix strings, as appropriate. ** ** Return 1 if the expanded code requires that "yylhsminor" local variable ** to be defined. */ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ char *cp, *xp; int i; |
︙ | ︙ | |||
3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 | for(i=0; i<rp->nrhs; i++) used[i] = 0; lhsused = 0; if( rp->code==0 ){ static char newlinestr[2] = { '\n', '\0' }; rp->code = newlinestr; rp->line = rp->ruleline; } if( rp->nrhs==0 ){ /* If there are no RHS symbols, then writing directly to the LHS is ok */ lhsdirect = 1; }else if( rp->rhsalias[0]==0 ){ /* The left-most RHS symbol has no value. LHS direct is ok. But ** we have to call the distructor on the RHS symbol first. */ lhsdirect = 1; if( has_destructor(rp->rhs[0],lemp) ){ append_str(0,0,0,0); append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[0]->index,1-rp->nrhs); rp->codePrefix = Strsafe(append_str(0,0,0,0)); } }else if( rp->lhsalias==0 ){ /* There is no LHS value symbol. */ lhsdirect = 1; }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){ /* The LHS symbol and the left-most RHS symbol are the same, so ** direct writing is allowed */ | > > > > | 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 | for(i=0; i<rp->nrhs; i++) used[i] = 0; lhsused = 0; if( rp->code==0 ){ static char newlinestr[2] = { '\n', '\0' }; rp->code = newlinestr; rp->line = rp->ruleline; rp->noCode = 1; }else{ rp->noCode = 0; } if( rp->nrhs==0 ){ /* If there are no RHS symbols, then writing directly to the LHS is ok */ lhsdirect = 1; }else if( rp->rhsalias[0]==0 ){ /* The left-most RHS symbol has no value. LHS direct is ok. But ** we have to call the distructor on the RHS symbol first. */ lhsdirect = 1; if( has_destructor(rp->rhs[0],lemp) ){ append_str(0,0,0,0); append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[0]->index,1-rp->nrhs); rp->codePrefix = Strsafe(append_str(0,0,0,0)); rp->noCode = 0; } }else if( rp->lhsalias==0 ){ /* There is no LHS value symbol. */ lhsdirect = 1; }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){ /* The LHS symbol and the left-most RHS symbol are the same, so ** direct writing is allowed */ |
︙ | ︙ | |||
3711 3712 3713 3714 3715 3716 3717 | append_str(" yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum); append_str(zLhs, 0, 0, 0); append_str(";\n", 0, 0, 0); } /* Suffix code generation complete */ cp = append_str(0,0,0,0); | | > > > | 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 | append_str(" yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum); append_str(zLhs, 0, 0, 0); append_str(";\n", 0, 0, 0); } /* Suffix code generation complete */ cp = append_str(0,0,0,0); if( cp && cp[0] ){ rp->codeSuffix = Strsafe(cp); rp->noCode = 0; } return rc; } /* ** Generate code which executes when the rule "rp" is reduced. Write ** the code to "out". Make sure lineno stays up-to-date. |
︙ | ︙ | |||
4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 | printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n", i, stp->statenum, ax[i].isTkn ? "Token" : "Var ", ax[i].nAction, pActtab->nAction, nn); } #endif } free(ax); /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; | > > > > > > > > > > > > > | 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 | printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n", i, stp->statenum, ax[i].isTkn ? "Token" : "Var ", ax[i].nAction, pActtab->nAction, nn); } #endif } free(ax); /* Mark rules that are actually used for reduce actions after all ** optimizations have been applied */ for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE; for(i=0; i<lemp->nxstate; i++){ struct action *ap; for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){ ap->x.rp->doesReduce = i; } } } /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; |
︙ | ︙ | |||
4392 4393 4394 4395 4396 4397 4398 | } if( i ){ fprintf(out," YYMINORTYPE yylhsminor;\n"); lineno++; } /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ struct rule *rp2; /* Other rules with the same action */ | < | | < < < | | | | < | < > | > > > > | 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 | } if( i ){ fprintf(out," YYMINORTYPE yylhsminor;\n"); lineno++; } /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ struct rule *rp2; /* Other rules with the same action */ if( rp->codeEmitted ) continue; if( rp->noCode ){ /* No C code actions, so this will be part of the "default:" rule */ continue; } fprintf(out," case %d: /* ", rp->iRule); writeRuleText(out, rp); fprintf(out, " */\n"); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ if( rp2->code==rp->code && rp2->codePrefix==rp->codePrefix && rp2->codeSuffix==rp->codeSuffix ){ fprintf(out," case %d: /* ", rp2->iRule); writeRuleText(out, rp2); fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++; rp2->codeEmitted = 1; } } emit_code(out,rp,lemp,&lineno); fprintf(out," break;\n"); lineno++; rp->codeEmitted = 1; } /* Finally, output the default: rule. We choose as the default: all ** empty actions. */ fprintf(out," default:\n"); lineno++; for(rp=lemp->rule; rp; rp=rp->next){ if( rp->codeEmitted ) continue; assert( rp->noCode ); fprintf(out," /* (%d) ", rp->iRule); writeRuleText(out, rp); if( rp->doesReduce ){ fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++; }else{ fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n", rp->iRule); lineno++; } } fprintf(out," break;\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes if a parse fails */ tplt_print(out,lemp,lemp->failure,&lineno); tplt_xfer(lemp->name,in,out,&lineno); |
︙ | ︙ | |||
4498 4499 4500 4501 4502 4503 4504 | ** In this version, we take the most frequent REDUCE action and make ** it the default. Except, there is no default if the wildcard token ** is a possible look-ahead. */ void CompressTables(struct lemon *lemp) { struct state *stp; | | | 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 | ** In this version, we take the most frequent REDUCE action and make ** it the default. Except, there is no default if the wildcard token ** is a possible look-ahead. */ void CompressTables(struct lemon *lemp) { struct state *stp; struct action *ap, *ap2, *nextap; struct rule *rp, *rp2, *rbest; int nbest, n; int i; int usesWildcard; for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; |
︙ | ︙ | |||
4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 | pNextState = ap->x.stp; if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ ap->type = SHIFTREDUCE; ap->x.rp = pNextState->pDfltReduce; } } } } /* ** Compare two states for sorting purposes. The smaller state is the ** one with the most non-terminal actions. If they have the same number ** of non-terminal actions, then the smaller is the one with the most | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 | pNextState = ap->x.stp; if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ ap->type = SHIFTREDUCE; ap->x.rp = pNextState->pDfltReduce; } } } /* If a SHIFTREDUCE action specifies a rule that has a single RHS term ** (meaning that the SHIFTREDUCE will land back in the state where it ** started) and if there is no C-code associated with the reduce action, ** then we can go ahead and convert the action to be the same as the ** action for the RHS of the rule. */ for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; for(ap=stp->ap; ap; ap=nextap){ nextap = ap->next; if( ap->type!=SHIFTREDUCE ) continue; rp = ap->x.rp; if( rp->noCode==0 ) continue; if( rp->nrhs!=1 ) continue; #if 1 /* Only apply this optimization to non-terminals. It would be OK to ** apply it to terminal symbols too, but that makes the parser tables ** larger. */ if( ap->sp->index<lemp->nterminal ) continue; #endif /* If we reach this point, it means the optimization can be applied */ nextap = ap; for(ap2=stp->ap; ap2 && (ap2==ap || ap2->sp!=rp->lhs); ap2=ap2->next){} assert( ap2!=0 ); ap->spOpt = ap2->sp; ap->type = ap2->type; ap->x = ap2->x; } } } /* ** Compare two states for sorting purposes. The smaller state is the ** one with the most non-terminal actions. If they have the same number ** of non-terminal actions, then the smaller is the one with the most |
︙ | ︙ |
Changes to tool/lempar.c.
︙ | ︙ | |||
199 200 201 202 203 204 205 | ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { | | | > | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { yyStackEntry *yytos; /* Pointer to top element of the stack */ #ifdef YYTRACKMAXSTACKDEPTH int yyhwm; /* High-water mark of the stack */ #endif #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ #endif ParseARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG |
︙ | ︙ | |||
267 268 269 270 271 272 273 | %% }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* | | > | > > > > > > | > | | | > > | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | %% }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. Return the number ** of errors. Return 0 on success. */ static int yyGrowStack(yyParser *p){ int newSize; int idx; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; if( p->yystack==&p->yystk0 ){ pNew = malloc(newSize*sizeof(pNew[0])); if( pNew ) pNew[0] = p->yystk0; }else{ pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } if( pNew ){ p->yystack = pNew; p->yytos = &p->yystack[idx]; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", yyTracePrompt, p->yystksz, newSize); } #endif p->yystksz = newSize; } return pNew==0; } #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to ParseAlloc() below. This can be changed by ** putting an appropriate #define in the %include section of the input ** grammar. |
︙ | ︙ | |||
313 314 315 316 317 318 319 | ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ | < | > | > > > > > > > > > | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ #ifdef YYTRACKMAXSTACKDEPTH pParser->yyhwm = 0; #endif #if YYSTACKDEPTH<=0 pParser->yytos = NULL; pParser->yystack = NULL; pParser->yystksz = 0; if( yyGrowStack(pParser) ){ pParser->yystack = &pParser->yystk0; pParser->yystksz = 1; } #endif #ifndef YYNOERRORRECOVERY pParser->yyerrcnt = -1; #endif pParser->yytos = pParser->yystack; pParser->yystack[0].stateno = 0; pParser->yystack[0].major = 0; } return pParser; } /* The following function deletes the "minor type" or semantic value ** associated with a symbol. The symbol can be either a terminal ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is |
︙ | ︙ | |||
365 366 367 368 369 370 371 | ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; | | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; assert( pParser->yytos!=0 ); yytos = pParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif |
︙ | ︙ | |||
393 394 395 396 397 398 399 | void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; #ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif | | | | | | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; #ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif (*freeProc)((void*)pParser); } /* ** Return the peak depth of the stack for a parser. */ #ifdef YYTRACKMAXSTACKDEPTH int ParseStackPeak(void *p){ yyParser *pParser = (yyParser*)p; return pParser->yyhwm; } #endif /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. */ static unsigned int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yytos->stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); do{ i = yy_shift_ofst[stateno]; if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); |
︙ | ︙ | |||
512 513 514 515 516 517 518 | } /* ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser){ ParseARG_FETCH; | | | | | | | | > | | | < > > > | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | } /* ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser){ ParseARG_FETCH; yypParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); } #endif while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ %% /******** End %stack_overflow code ********************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } /* ** Print tracing information for a SHIFT action */ #ifndef NDEBUG static void yyTraceShift(yyParser *yypParser, int yyNewState){ if( yyTraceFILE ){ if( yyNewState<YYNSTATE ){ fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n", yyTracePrompt,yyTokenName[yypParser->yytos->major], yyNewState); }else{ fprintf(yyTraceFILE,"%sShift '%s'\n", yyTracePrompt,yyTokenName[yypParser->yytos->major]); } } } #else # define yyTraceShift(X,Y) #endif /* ** Perform a shift action. */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ ParseTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yytos++; #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ yyStackOverflow(yypParser); return; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } } #endif if( yyNewState > YY_MAX_SHIFT ){ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } yytos = yypParser->yytos; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState); } /* The following table contains information about every rule that |
︙ | ︙ | |||
609 610 611 612 613 614 615 | unsigned int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; | | | | > | | | < > | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | unsigned int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; yymsp = yypParser->yytos; #ifndef NDEBUG if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, yyRuleName[yyruleno], yymsp[-yysize].stateno); } #endif /* NDEBUG */ /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ if( yyRuleInfo[yyruleno].nrhs==0 ){ #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ yyStackOverflow(yypParser); return; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } yymsp = yypParser->yytos; } #endif } switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: |
︙ | ︙ | |||
661 662 663 664 665 666 667 | /********** End reduce actions ************************************************/ }; assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact <= YY_MAX_SHIFTREDUCE ){ | | | > > | | | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | /********** End reduce actions ************************************************/ }; assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact <= YY_MAX_SHIFTREDUCE ){ if( yyact>YY_MAX_SHIFT ){ yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } yymsp -= yysize-1; yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact); }else{ assert( yyact == YY_ACCEPT_ACTION ); yypParser->yytos -= yysize; yy_accept(yypParser); } } /* ** The following code executes when the parse fails */ #ifndef YYNOERRORRECOVERY static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ %% /************ End %parse_failure code *****************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } |
︙ | ︙ | |||
725 726 727 728 729 730 731 | ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif | | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 | ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif assert( yypParser->yytos==yypParser->yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ %% /*********** End %parse_accept code *******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } |
︙ | ︙ | |||
771 772 773 774 775 776 777 | #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser; /* The parser */ /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; | | < < < < < < < < < < < < < < < < < < < < | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser; /* The parser */ /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif ParseARG_STORE; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); } #endif do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif yymajor = YYNOCODE; }else if( yyact <= YY_MAX_REDUCE ){ yy_reduce(yypParser,yyact-YY_MIN_REDUCE); |
︙ | ︙ | |||
847 848 849 850 851 852 853 | ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } | | < | | | | | | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } yymx = yypParser->yytos->major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ while( yypParser->yytos >= &yypParser->yystack && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yytos->stateno, YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); } } |
︙ | ︙ | |||
910 911 912 913 914 915 916 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } yymajor = YYNOCODE; #endif } | | | > | | < > > | 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } yymajor = YYNOCODE; #endif } }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); #ifndef NDEBUG if( yyTraceFILE ){ yyStackEntry *i; char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); cDiv = ' '; } fprintf(yyTraceFILE,"]\n"); } #endif return; } |
Added tool/libvers.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* ** Compile this program against an SQLite library of unknown version ** and then run this program, and it will print out the SQLite version ** information. */ #include <stdio.h> extern const char *sqlite3_libversion(void); extern const char *sqlite3_sourceid(void); int main(int argc, char **argv){ printf("SQLite version %s\n", sqlite3_libversion()); printf("SQLite source %s\n", sqlite3_sourceid()); return 0; } |