/ Check-in [19f93e13]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Fix a crash caused by adding a trigger to a shared-schema and then deleting it using a different connection. (CVS 2873)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 19f93e135f1ff4f987d14afe74b955e119904017
User & Date: danielk1977 2006-01-06 15:03:48
Context
2006-01-06
16:17
A first attempt at adding native support for WinCE. (CVS 2874) check-in: 43440567 user: drh tags: trunk
15:03
Fix a crash caused by adding a trigger to a shared-schema and then deleting it using a different connection. (CVS 2873) check-in: 19f93e13 user: danielk1977 tags: trunk
14:46
Fix an alignment problem in the sqlite3OsRandomSeed(). Ticket #1584. (CVS 2872) check-in: 373b56f0 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.451 2006/01/06 12:03:19 drh Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.452 2006/01/06 15:03:48 danielk1977 Exp $
    15     15   */
    16     16   #ifndef _SQLITEINT_H_
    17     17   #define _SQLITEINT_H_
    18     18   
    19     19   /*
    20     20   ** Extra interface definitions for those who need them
    21     21   */
................................................................................
  1293   1293    *
  1294   1294    * The "step_list" member points to the first element of a linked list
  1295   1295    * containing the SQL statements specified as the trigger program.
  1296   1296    */
  1297   1297   struct Trigger {
  1298   1298     char *name;             /* The name of the trigger                        */
  1299   1299     char *table;            /* The table or view to which the trigger applies */
  1300         -//u8 iDb;                 /* Database containing this trigger               */
  1301         -  u8 iTabDb;              /* Database containing Trigger.table              */
  1302   1300     u8 op;                  /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
  1303   1301     u8 tr_tm;               /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
  1304   1302     Expr *pWhen;            /* The WHEN clause of the expresion (may be NULL) */
  1305   1303     IdList *pColumns;       /* If this is an UPDATE OF <column-list> trigger,
  1306   1304                                the <column-list> is stored here */
  1307   1305     int foreach;            /* One of TK_ROW or TK_STATEMENT */
  1308   1306     Token nameToken;        /* Token containing zName. Use during parsing only */
  1309         -  DbSchema *pSchema;
         1307  +  DbSchema *pSchema;      /* Schema containing the trigger */
         1308  +  DbSchema *pTabSchema;   /* Schema containing the table */
  1310   1309     TriggerStep *step_list; /* Link list of trigger program steps             */
  1311   1310     Trigger *pNext;         /* Next trigger associated with the table */
  1312   1311   };
  1313   1312   
  1314   1313   /*
  1315   1314   ** A trigger is either a BEFORE or an AFTER trigger.  The following constants
  1316   1315   ** determine which. 

Changes to src/trigger.c.

   160    160     /* Build the Trigger object */
   161    161     pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
   162    162     if( pTrigger==0 ) goto trigger_cleanup;
   163    163     pTrigger->name = zName;
   164    164     zName = 0;
   165    165     pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
   166    166     pTrigger->pSchema = db->aDb[iDb].pSchema;
   167         -  pTrigger->iTabDb = iTabDb;
          167  +  pTrigger->pTabSchema = pTab->pSchema;
   168    168     pTrigger->op = op;
   169    169     pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
   170    170     pTrigger->pWhen = sqlite3ExprDup(pWhen);
   171    171     pTrigger->pColumns = sqlite3IdListDup(pColumns);
   172    172     pTrigger->foreach = foreach;
   173    173     sqlite3TokenCopy(&pTrigger->nameToken,pName);
   174    174     assert( pParse->pNewTrigger==0 );
................................................................................
   245    245       sqlite3ChangeCookie(db, v, iDb);
   246    246       sqlite3VdbeAddOp(v, OP_Close, 0, 0);
   247    247       sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, 
   248    248          sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
   249    249     }
   250    250   
   251    251     if( db->init.busy ){
          252  +    int n;
   252    253       Table *pTab;
   253    254       Trigger *pDel;
   254    255       pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, 
   255    256                        pTrig->name, strlen(pTrig->name)+1, pTrig);
   256    257       if( pDel ){
   257    258         assert( sqlite3Tsd()->mallocFailed && pDel==pTrig );
   258    259         goto triggerfinish_cleanup;
   259    260       }
   260         -    pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
          261  +    n = strlen(pTrig->table) + 1;
          262  +    pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
   261    263       assert( pTab!=0 );
   262    264       pTrig->pNext = pTab->pTrigger;
   263    265       pTab->pTrigger = pTrig;
   264    266       pTrig = 0;
   265    267     }
   266    268   
   267    269   triggerfinish_cleanup:
................................................................................
   463    465   }
   464    466   
   465    467   /*
   466    468   ** Return a pointer to the Table structure for the table that a trigger
   467    469   ** is set on.
   468    470   */
   469    471   static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
   470         -  return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
          472  +  int n = strlen(pTrigger->table) + 1;
          473  +  return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
   471    474   }
   472    475   
   473    476   
   474    477   /*
   475    478   ** Drop a trigger given a pointer to that trigger.  If nested is false,
   476    479   ** then also generate code to remove the trigger from the SQLITE_MASTER
   477    480   ** table.

Changes to test/shared.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing the SELECT statement.
    13     13   #
    14         -# $Id: shared.test,v 1.4 2006/01/06 13:00:30 danielk1977 Exp $
           14  +# $Id: shared.test,v 1.5 2006/01/06 15:03:48 danielk1977 Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   db close
    19     19   
    20     20   ifcapable !shared_cache {
    21     21     finish_test
................................................................................
    27     27   #
    28     28   # shared-1.*: Simple test to verify basic sanity of table level locking when
    29     29   #             two connections share a pager cache.
    30     30   # shared-2.*: Test that a read transaction can co-exist with a 
    31     31   #             write-transaction, including a simple test to ensure the 
    32     32   #             external locking protocol is still working.
    33     33   # shared-3.*: Simple test of read-uncommitted mode.
    34         -#
    35     34   # shared-4.*: Check that the schema is locked and unlocked correctly.
           35  +# shared-5.*: Test that creating/dropping schema items works when databases
           36  +#             are attached in different orders to different handles.
    36     37   #
    37     38   
    38     39   do_test shared-1.1 {
    39     40     # Open a second database on the file test.db. It should use the same pager
    40     41     # cache and schema as the original connection. Verify that only 1 file is 
    41     42     # opened.
    42     43     sqlite3 db2 test.db
................................................................................
   355    356   } {1 {(6) database schema is locked: test}}
   356    357   do_test shared-4.4.5 {
   357    358     set rc [catch {
   358    359       set ::STMT1 [sqlite3_prepare $::DB2 "SELECT * FROM ghi" -1 DUMMY]
   359    360     } msg]
   360    361     list $rc $msg
   361    362   } {1 {(6) database schema is locked: test}}
          363  +
   362    364   
   363    365   catch {db2 close}
   364    366   catch {db close}
          367  +
          368  +#--------------------------------------------------------------------------
          369  +# Tests shared-5.* 
          370  +#
          371  +foreach db [list test.db test1.db test2.db test3.db] {
          372  +  file delete -force $db ${db}-journal
          373  +}
          374  +do_test shared-5.1.1 {
          375  +  sqlite3 db1 test.db
          376  +  sqlite3 db2 test.db
          377  +  execsql {
          378  +    ATTACH 'test1.db' AS test1;
          379  +    ATTACH 'test2.db' AS test2;
          380  +    ATTACH 'test3.db' AS test3;
          381  +  } db1
          382  +  execsql {
          383  +    ATTACH 'test3.db' AS test3;
          384  +    ATTACH 'test2.db' AS test2;
          385  +    ATTACH 'test1.db' AS test1;
          386  +  } db2
          387  +} {}
          388  +do_test shared-5.1.2 {
          389  +  execsql {
          390  +    CREATE TABLE test1.t1(a, b);
          391  +    CREATE INDEX test1.i1 ON t1(a, b);
          392  +    CREATE VIEW test1.v1 AS SELECT * FROM t1;
          393  +    CREATE TRIGGER test1.trig1 AFTER INSERT ON t1 BEGIN
          394  +      INSERT INTO t1 VALUES(new.a, new.b);
          395  +    END;
          396  +  } db1
          397  +  execsql {
          398  +    DROP INDEX i1;
          399  +    DROP VIEW v1;
          400  +    DROP TRIGGER trig1;
          401  +    DROP TABLE t1;
          402  +  } db2
          403  +} {}
          404  +do_test shared-5.1.2 {
          405  +  execsql {
          406  +    SELECT * FROM sqlite_master UNION ALL SELECT * FROM test1.sqlite_master
          407  +  } db1
          408  +} {}
          409  +
          410  +catch {db1 close}
          411  +catch {db2 close}
   365    412   
   366    413   finish_test
   367    414   sqlite3_enable_shared_cache $::enable_shared_cache
   368    415