Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a bug introduced by the fts3 refactoring (segfault when creating a table with zero module args). Also a fix to handle an OOM error. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
eada284bc10cafcab9beb3473bb0c70b |
User & Date: | dan 2009-11-28 12:40:32.000 |
Context
2009-11-28
| ||
13:46 | Initialize a variable (unnecessarily) to avoid a compiler warning. (check-in: db65fd5913 user: drh tags: trunk) | |
12:40 | Fix a bug introduced by the fts3 refactoring (segfault when creating a table with zero module args). Also a fix to handle an OOM error. (check-in: eada284bc1 user: dan tags: trunk) | |
2009-11-27
| ||
18:31 | Change the test numbers in e_fkey.test so that they are in order. (check-in: ca73be44cc user: dan tags: trunk) | |
Changes
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
630 631 632 633 634 635 636 | ** methods of the FTS3 virtual table. ** ** The argv[] array contains the following: ** ** argv[0] -> module name ** argv[1] -> database name ** argv[2] -> table name | | | | | 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 | ** methods of the FTS3 virtual table. ** ** The argv[] array contains the following: ** ** argv[0] -> module name ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> "column name" and other module argument fields. */ int fts3InitVtab( int isCreate, /* True for xCreate, false for xConnect */ sqlite3 *db, /* The SQLite database connection */ void *pAux, /* Hash table containing tokenizers */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ Fts3Hash *pHash = (Fts3Hash *)pAux; Fts3Table *p; /* Pointer to allocated vtab */ int rc; /* Return code */ int i; /* Iterator variable */ int nByte; /* Size of allocation used for *p */ int iCol; int nString = 0; int nCol = 0; char *zCsr; int nDb; int nName; |
︙ | ︙ | |||
676 677 678 679 680 681 682 683 684 685 686 687 688 689 | if( zTokenizer==0 ){ rc = sqlite3Fts3InitTokenizer(pHash, 0, &pTokenizer, 0, pzErr); if( rc!=SQLITE_OK ){ return rc; } assert( pTokenizer ); } /* Allocate and populate the Fts3Table structure. */ nByte = sizeof(Fts3Table) + /* Fts3Table */ nCol * sizeof(char *) + /* azColumn */ nName + /* zName */ nDb + /* zDb */ nString; /* Space for azColumn strings */ | > > > > | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | if( zTokenizer==0 ){ rc = sqlite3Fts3InitTokenizer(pHash, 0, &pTokenizer, 0, pzErr); if( rc!=SQLITE_OK ){ return rc; } assert( pTokenizer ); } if( nCol==0 ){ nCol = 1; } /* Allocate and populate the Fts3Table structure. */ nByte = sizeof(Fts3Table) + /* Fts3Table */ nCol * sizeof(char *) + /* azColumn */ nName + /* zName */ nDb + /* zDb */ nString; /* Space for azColumn strings */ |
︙ | ︙ | |||
722 723 724 725 726 727 728 729 730 731 732 733 734 735 | zCsr[n] = '\0'; sqlite3Fts3Dequote(zCsr); p->azColumn[iCol++] = zCsr; zCsr += n+1; assert( zCsr <= &((char *)p)[nByte] ); } } /* If this is an xCreate call, create the underlying tables in the ** database. TODO: For xConnect(), it could verify that said tables exist. */ if( isCreate ){ rc = fts3CreateTables(p); if( rc!=SQLITE_OK ) goto fts3_init_out; | > > > > | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | zCsr[n] = '\0'; sqlite3Fts3Dequote(zCsr); p->azColumn[iCol++] = zCsr; zCsr += n+1; assert( zCsr <= &((char *)p)[nByte] ); } } if( iCol==0 ){ assert( nCol==1 ); p->azColumn[0] = "content"; } /* If this is an xCreate call, create the underlying tables in the ** database. TODO: For xConnect(), it could verify that said tables exist. */ if( isCreate ){ rc = fts3CreateTables(p); if( rc!=SQLITE_OK ) goto fts3_init_out; |
︙ | ︙ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | } p->iLastCol = iCol; p->iLastPos = 0; } if( iCol>=0 ){ assert( iPos>p->iLastPos || (iPos==0 && p->iLastPos==0) ); rc = fts3PendingListAppendVarint(&p, 2+iPos-p->iLastPos); p->iLastPos = iPos; } pendinglistappend_out: *pRc = rc; if( p!=*pp ){ *pp = p; return 1; } | > > | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | } p->iLastCol = iCol; p->iLastPos = 0; } if( iCol>=0 ){ assert( iPos>p->iLastPos || (iPos==0 && p->iLastPos==0) ); rc = fts3PendingListAppendVarint(&p, 2+iPos-p->iLastPos); if( rc==SQLITE_OK ){ p->iLastPos = iPos; } } pendinglistappend_out: *pRc = rc; if( p!=*pp ){ *pp = p; return 1; } |
︙ | ︙ |
Added test/e_fts3.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 | # 2009 November 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 implements tests to verify the "testable statements" in the # fts3.in document. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !fts3 { finish_test return } source $testdir/fts3_common.tcl set DO_MALLOC_TEST 0 # Procs used to make the tests in this file easier to read. # proc ddl_test {tn ddl} { uplevel [list do_write_test e_fts3-$tn sqlite_master $ddl] } proc write_test {tn tbl sql} { uplevel [list do_write_test e_fts3-$tn $tbl $sql] } proc read_test {tn sql result} { uplevel [list do_select_test e_fts3-$tn $sql $result] } #----------------------------------------------------------------- # Test the example CREATE VIRTUAL TABLE statements in section 1.1 # of fts3.in. # ddl_test 1.1.1 {CREATE VIRTUAL TABLE data USING fts3()} read_test 1.1.2 {PRAGMA table_info(data)} {0 content {} 0 {} 0} ddl_test 1.2.1 { CREATE VIRTUAL TABLE pages USING fts3(title, keywords, body) } read_test 1.2.2 { PRAGMA table_info(pages) } {0 title {} 0 {} 0 1 keywords {} 0 {} 0 2 body {} 0 {} 0} ddl_test 1.3.1 { CREATE VIRTUAL TABLE mail USING fts3( subject VARCHAR(256) NOT NULL, body TEXT CHECK(length(body)<10240) ) } read_test 1.3.2 { PRAGMA table_info(mail) } {0 subject {} 0 {} 0 1 body {} 0 {} 0} # A very large string. Used to test if the constraint on column "body" of # table "mail" is enforced (it should not be - FTS3 tables do not support # constraints). set largetext [string repeat "the quick brown fox " 5000] write_test 1.3.3 mail_content { INSERT INTO mail VALUES(NULL, $largetext) } read_test 1.3.4 { SELECT subject IS NULL, length(body) FROM mail } [list 1 100000] finish_test |
Changes to test/fts3_common.tcl.
︙ | ︙ | |||
282 283 284 285 286 287 288 | foreach {t d} [fts3_readleaf $block] { lappend a($t) $d } } } } } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | foreach {t d} [fts3_readleaf $block] { lappend a($t) $d } } } } } ########################################################################## #------------------------------------------------------------------------- # This proc is used to test a single SELECT statement. Parameter $name is # passed a name for the test case (i.e. "fts3_malloc-1.4.1") and parameter # $sql is passed the text of the SELECT statement. Parameter $result is # set to the expected output if the SELECT statement is successfully # executed using [db eval]. # # Example: # # do_select_test testcase-1.1 "SELECT 1+1, 1+2" {1 2} # # If global variable DO_MALLOC_TEST is set to a non-zero value, or if # it is not defined at all, then OOM testing is performed on the SELECT # statement. Each OOM test case is said to pass if either (a) executing # the SELECT statement succeeds and the results match those specified # by parameter $result, or (b) TCL throws an "out of memory" error. # # If DO_MALLOC_TEST is defined and set to zero, then the SELECT statement # is executed just once. In this case the test case passes if the results # match the expected results passed via parameter $result. # proc do_select_test {name sql result} { doPassiveTest $name $sql [list 0 $result] } proc do_error_test {name sql error} { doPassiveTest $name $sql [list 1 $error] } proc doPassiveTest {name sql catchres} { if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 } if {$::DO_MALLOC_TEST} { set answers [list {1 {out of memory}} $catchres] set modes [list 100000 transient 1 persistent] } else { set answers [list $catchres] set modes [list 0 nofail] } set str [join $answers " OR "] foreach {nRepeat zName} $modes { for {set iFail 1} 1 {incr iFail} { if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat} set res [catchsql $sql] if {[lsearch $answers $res]>=0} { set res $str } do_test $name.$zName.$iFail [list set {} $res] $str set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] if {$nFail==0} break } } } #------------------------------------------------------------------------- # Test a single write to the database. In this case a "write" is a # DELETE, UPDATE or INSERT statement. # # If OOM testing is performed, there are several acceptable outcomes: # # 1) The write succeeds. No error is returned. # # 2) An "out of memory" exception is thrown and: # # a) The statement has no effect, OR # b) The current transaction is rolled back, OR # c) The statement succeeds. This can only happen if the connection # is in auto-commit mode (after the statement is executed, so this # includes COMMIT statements). # # If the write operation eventually succeeds, zero is returned. If a # transaction is rolled back, non-zero is returned. # # Parameter $name is the name to use for the test case (or test cases). # The second parameter, $tbl, should be the name of the database table # being modified. Parameter $sql contains the SQL statement to test. # proc do_write_test {name tbl sql} { if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 } # Figure out an statement to get a checksum for table $tbl. db eval "SELECT * FROM $tbl" V break set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl" # Calculate the initial table checksum. set cksum1 [db one $cksumsql] if {$::DO_MALLOC_TEST } { set answers [list {1 {out of memory}} {0 {}}] set modes [list 100000 transient 1 persistent] } else { set answers [list {0 {}}] set modes [list 0 nofail] } set str [join $answers " OR "] foreach {nRepeat zName} $modes { for {set iFail 1} 1 {incr iFail} { if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat} set res [uplevel [list catchsql $sql]] set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] if {$nFail==0} { do_test $name.$zName.$iFail [list set {} $res] {0 {}} return } else { if {[lsearch $answers $res]>=0} { set res $str } do_test $name.$zName.$iFail [list set {} $res] $str set cksum2 [db one $cksumsql] if {$cksum1 != $cksum2} return } } } } |
Changes to test/tester.tcl.
︙ | ︙ | |||
408 409 410 411 412 413 414 | uplevel [list $db eval $sql] } # Execute SQL and catch exceptions. # proc catchsql {sql {db db}} { # puts "SQL = $sql" | | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | uplevel [list $db eval $sql] } # Execute SQL and catch exceptions. # proc catchsql {sql {db db}} { # puts "SQL = $sql" set r [catch [list uplevel [list $db eval $sql]] msg] lappend r $msg return $r } # Do an VDBE code dump on the SQL given # proc explain {sql {db db}} { |
︙ | ︙ |