/ Check-in [81be7290]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix crash in delete when existing row has null fields. Previous code assumed that the row had values in all columns, sigh. Fixes bug http://www.sqlite.org/cvstrac/tktview?tn=2289 . (CVS 3833)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 81be7290a4db7b74a533aaf95c7389eb4bde6a88
User & Date: shess 2007-04-09 20:45:41
Context
2007-04-10
13:51
Be careful not to use the result of sqlite3_value_blob() after changing the representation of an object. Ticket #2290. (CVS 3834) check-in: e14374e4 user: drh tags: trunk
2007-04-09
20:45
Fix crash in delete when existing row has null fields. Previous code assumed that the row had values in all columns, sigh. Fixes bug http://www.sqlite.org/cvstrac/tktview?tn=2289 . (CVS 3833) check-in: 81be7290 user: shess tags: trunk
20:30
Fix stack buffer overrun problem in the test harness. (CVS 3832) check-in: cad9faf3 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts1/fts1.c.

  1269   1269     return sql_single_step_statement(v, CONTENT_UPDATE_STMT, &s);
  1270   1270   }
  1271   1271   
  1272   1272   static void freeStringArray(int nString, const char **pString){
  1273   1273     int i;
  1274   1274   
  1275   1275     for (i=0 ; i < nString ; ++i) {
  1276         -    free((void *) pString[i]);
         1276  +    if( pString[i]!=NULL ) free((void *) pString[i]);
  1277   1277     }
  1278   1278     free((void *) pString);
  1279   1279   }
  1280   1280   
  1281   1281   /* select * from %_content where rowid = [iRow]
  1282   1282    * The caller must delete the returned array and all strings in it.
         1283  + * null fields will be NULL in the returned array.
  1283   1284    *
  1284   1285    * TODO: Perhaps we should return pointer/length strings here for consistency
  1285   1286    * with other code which uses pointer/length. */
  1286   1287   static int content_select(fulltext_vtab *v, sqlite_int64 iRow,
  1287   1288                             const char ***pValues){
  1288   1289     sqlite3_stmt *s;
  1289   1290     const char **values;
................................................................................
  1299   1300     if( rc!=SQLITE_OK ) return rc;
  1300   1301   
  1301   1302     rc = sql_step_statement(v, CONTENT_SELECT_STMT, &s);
  1302   1303     if( rc!=SQLITE_ROW ) return rc;
  1303   1304   
  1304   1305     values = (const char **) malloc(v->nColumn * sizeof(const char *));
  1305   1306     for(i=0; i<v->nColumn; ++i){
  1306         -    values[i] = string_dup((char*)sqlite3_column_text(s, i));
         1307  +    if( sqlite3_column_type(s, i)==SQLITE_NULL ){
         1308  +      values[i] = NULL;
         1309  +    }else{
         1310  +      values[i] = string_dup((char*)sqlite3_column_text(s, i));
         1311  +    }
  1307   1312     }
  1308   1313   
  1309   1314     /* We expect only one row.  We must execute another sqlite3_step()
  1310   1315      * to complete the iteration; otherwise the table will remain locked. */
  1311   1316     rc = sqlite3_step(s);
  1312   1317     if( rc==SQLITE_DONE ){
  1313   1318       *pValues = values;

Changes to ext/fts2/fts2.c.

  1920   1920     return sql_single_step_statement(v, CONTENT_UPDATE_STMT, &s);
  1921   1921   }
  1922   1922   
  1923   1923   static void freeStringArray(int nString, const char **pString){
  1924   1924     int i;
  1925   1925   
  1926   1926     for (i=0 ; i < nString ; ++i) {
  1927         -    free((void *) pString[i]);
         1927  +    if( pString[i]!=NULL ) free((void *) pString[i]);
  1928   1928     }
  1929   1929     free((void *) pString);
  1930   1930   }
  1931   1931   
  1932   1932   /* select * from %_content where rowid = [iRow]
  1933   1933    * The caller must delete the returned array and all strings in it.
         1934  + * null fields will be NULL in the returned array.
  1934   1935    *
  1935   1936    * TODO: Perhaps we should return pointer/length strings here for consistency
  1936   1937    * with other code which uses pointer/length. */
  1937   1938   static int content_select(fulltext_vtab *v, sqlite_int64 iRow,
  1938   1939                             const char ***pValues){
  1939   1940     sqlite3_stmt *s;
  1940   1941     const char **values;
................................................................................
  1950   1951     if( rc!=SQLITE_OK ) return rc;
  1951   1952   
  1952   1953     rc = sql_step_statement(v, CONTENT_SELECT_STMT, &s);
  1953   1954     if( rc!=SQLITE_ROW ) return rc;
  1954   1955   
  1955   1956     values = (const char **) malloc(v->nColumn * sizeof(const char *));
  1956   1957     for(i=0; i<v->nColumn; ++i){
  1957         -    values[i] = string_dup((char*)sqlite3_column_text(s, i));
         1958  +    if( sqlite3_column_type(s, i)==SQLITE_NULL ){
         1959  +      values[i] = NULL;
         1960  +    }else{
         1961  +      values[i] = string_dup((char*)sqlite3_column_text(s, i));
         1962  +    }
  1958   1963     }
  1959   1964   
  1960   1965     /* We expect only one row.  We must execute another sqlite3_step()
  1961   1966      * to complete the iteration; otherwise the table will remain locked. */
  1962   1967     rc = sqlite3_step(s);
  1963   1968     if( rc==SQLITE_DONE ){
  1964   1969       *pValues = values;

Added test/fts1l.test.

            1  +# 2007 April 9
            2  +#
            3  +# The author disclaims copyright to this source code.
            4  +#
            5  +#*************************************************************************
            6  +# This file implements regression tests for SQLite library.  fts1
            7  +# DELETE handling assumed all fields were non-null.  This was not
            8  +# the intention at all.
            9  +#
           10  +# $Id: fts1l.test,v 1.1 2007/04/09 20:45:42 shess Exp $
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +
           16  +# If SQLITE_ENABLE_FTS1 is defined, omit this file.
           17  +ifcapable !fts1 {
           18  +  finish_test
           19  +  return
           20  +}
           21  +
           22  +db eval {
           23  +  CREATE VIRTUAL TABLE t1 USING fts1(col_a, col_b);
           24  +
           25  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(1, 'testing', 'testing');
           26  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(2, 'only a', null);
           27  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(3, null, 'only b');
           28  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(4, null, null);
           29  +}
           30  +
           31  +do_test fts1m-1.0 {
           32  +  execsql {
           33  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           34  +  }
           35  +} {2 2 4}
           36  +
           37  +do_test fts1m-1.1 {
           38  +  execsql {
           39  +    DELETE FROM t1 WHERE rowid = 1;
           40  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           41  +  }
           42  +} {1 1 3}
           43  +
           44  +do_test fts1m-1.2 {
           45  +  execsql {
           46  +    DELETE FROM t1 WHERE rowid = 2;
           47  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           48  +  }
           49  +} {0 1 2}
           50  +
           51  +do_test fts1m-1.3 {
           52  +  execsql {
           53  +    DELETE FROM t1 WHERE rowid = 3;
           54  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           55  +  }
           56  +} {0 0 1}
           57  +
           58  +do_test fts1m-1.4 {
           59  +  execsql {
           60  +    DELETE FROM t1 WHERE rowid = 4;
           61  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           62  +  }
           63  +} {0 0 0}
           64  +
           65  +finish_test

Added test/fts2m.test.

            1  +# 2007 April 9
            2  +#
            3  +# The author disclaims copyright to this source code.
            4  +#
            5  +#*************************************************************************
            6  +# This file implements regression tests for SQLite library.  fts2
            7  +# DELETE handling assumed all fields were non-null.  This was not
            8  +# the intention at all.
            9  +#
           10  +# $Id: fts2m.test,v 1.1 2007/04/09 20:45:42 shess Exp $
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +
           16  +# If SQLITE_ENABLE_FTS2 is defined, omit this file.
           17  +ifcapable !fts2 {
           18  +  finish_test
           19  +  return
           20  +}
           21  +
           22  +db eval {
           23  +  CREATE VIRTUAL TABLE t1 USING fts2(col_a, col_b);
           24  +
           25  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(1, 'testing', 'testing');
           26  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(2, 'only a', null);
           27  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(3, null, 'only b');
           28  +  INSERT INTO t1(rowid, col_a, col_b) VALUES(4, null, null);
           29  +}
           30  +
           31  +do_test fts2m-1.0 {
           32  +  execsql {
           33  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           34  +  }
           35  +} {2 2 4}
           36  +
           37  +do_test fts2m-1.1 {
           38  +  execsql {
           39  +    DELETE FROM t1 WHERE rowid = 1;
           40  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           41  +  }
           42  +} {1 1 3}
           43  +
           44  +do_test fts2m-1.2 {
           45  +  execsql {
           46  +    DELETE FROM t1 WHERE rowid = 2;
           47  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           48  +  }
           49  +} {0 1 2}
           50  +
           51  +do_test fts2m-1.3 {
           52  +  execsql {
           53  +    DELETE FROM t1 WHERE rowid = 3;
           54  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           55  +  }
           56  +} {0 0 1}
           57  +
           58  +do_test fts2m-1.4 {
           59  +  execsql {
           60  +    DELETE FROM t1 WHERE rowid = 4;
           61  +    SELECT COUNT(col_a), COUNT(col_b), COUNT(*) FROM t1;
           62  +  }
           63  +} {0 0 0}
           64  +
           65  +finish_test