/ Check-in [ba1afc04]
Login

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

Overview
Comment:Alternative fix for ticket #3810. This is a replacement for check-in (6956). (CVS 6960)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ba1afc040171810d0c996708d7b9cb11abcd99d8
User & Date: drh 2009-08-06 17:43:31
Context
2009-08-06
18:36
Mark the rtreeUpdate function as static. (CVS 6961) check-in: b6bdfdc6 user: danielk1977 tags: trunk
17:43
Alternative fix for ticket #3810. This is a replacement for check-in (6956). (CVS 6960) check-in: ba1afc04 user: drh tags: trunk
17:40
Change a hyperlink label on shared cache mode documentation. No changes to code. (CVS 6959) check-in: 3d08ca0e user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/prepare.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains the implementation of the sqlite3_prepare()
    13     13   ** interface, and routines that contribute to loading the database schema
    14     14   ** from disk.
    15     15   **
    16         -** $Id: prepare.c,v 1.130 2009/08/01 16:27:00 drh Exp $
           16  +** $Id: prepare.c,v 1.131 2009/08/06 17:43:31 drh Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   
    20     20   /*
    21     21   ** Fill the InitData structure with an error message that indicates
    22     22   ** that the database is corrupt.
    23     23   */
    24     24   static void corruptSchema(
    25     25     InitData *pData,     /* Initialization context */
    26     26     const char *zObj,    /* Object being parsed at the point of error */
    27     27     const char *zExtra   /* Error information */
    28     28   ){
    29     29     sqlite3 *db = pData->db;
    30         -  if( pData->iDb==1 && zObj && zExtra ){
    31         -    *pData->pzErrMsg = sqlite3MPrintf(db, "in %s: %s", zObj, zExtra);
    32         -    pData->rc = SQLITE_ERROR;
    33         -    return;
    34         -  }
    35     30     if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
    36     31       if( zObj==0 ) zObj = "?";
    37     32       sqlite3SetString(pData->pzErrMsg, db,
    38     33         "malformed database schema (%s)", zObj);
    39     34       if( zExtra ){
    40     35         *pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg, 
    41     36                                    "%s - %s", *pData->pzErrMsg, zExtra);
................................................................................
    81     76       ** structures that describe the table, index, or view.
    82     77       */
    83     78       char *zErr;
    84     79       int rc;
    85     80       assert( db->init.busy );
    86     81       db->init.iDb = iDb;
    87     82       db->init.newTnum = atoi(argv[1]);
           83  +    db->init.orphanTrigger = 0;
    88     84       rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
    89     85       db->init.iDb = 0;
    90     86       assert( rc!=SQLITE_OK || zErr==0 );
    91     87       if( SQLITE_OK!=rc ){
    92         -      pData->rc = rc;
    93         -      if( rc==SQLITE_NOMEM ){
    94         -        db->mallocFailed = 1;
    95         -      }else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
    96         -        corruptSchema(pData, argv[0], zErr);
           88  +      if( db->init.orphanTrigger ){
           89  +        assert( iDb==1 );
           90  +      }else{
           91  +        pData->rc = rc;
           92  +        if( rc==SQLITE_NOMEM ){
           93  +          db->mallocFailed = 1;
           94  +        }else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
           95  +          corruptSchema(pData, argv[0], zErr);
           96  +        }
    97     97         }
    98     98         sqlite3DbFree(db, zErr);
    99     99       }
   100    100     }else if( argv[0]==0 ){
   101    101       corruptSchema(pData, 0, 0);
   102    102     }else{
   103    103       /* If the SQL column is blank it means this is an index that

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.896 2009/07/28 16:44:26 danielk1977 Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.897 2009/08/06 17:43:31 drh Exp $
    15     15   */
    16     16   #ifndef _SQLITEINT_H_
    17     17   #define _SQLITEINT_H_
    18     18   
    19     19   /*
    20     20   ** Include the configuration header output by 'configure' if we're using the
    21     21   ** autoconf-based build
................................................................................
   796    796     int nTotalChange;             /* Value returned by sqlite3_total_changes() */
   797    797     sqlite3_mutex *mutex;         /* Connection mutex */
   798    798     int aLimit[SQLITE_N_LIMIT];   /* Limits */
   799    799     struct sqlite3InitInfo {      /* Information used during initialization */
   800    800       int iDb;                    /* When back is being initialized */
   801    801       int newTnum;                /* Rootpage of table being initialized */
   802    802       u8 busy;                    /* TRUE if currently initializing */
          803  +    u8 orphanTrigger;           /* Last statement is orphaned TEMP trigger */
   803    804     } init;
   804    805     int nExtension;               /* Number of loaded extensions */
   805    806     void **aExtension;            /* Array of shared library handles */
   806    807     struct Vdbe *pVdbe;           /* List of active virtual machines */
   807    808     int activeVdbeCnt;            /* Number of VDBEs currently executing */
   808    809     int writeVdbeCnt;             /* Number of active VDBEs that are writing */
   809    810     void (*xTrace)(void*,const char*);        /* Trace function */

Changes to src/trigger.c.

     6      6   **    May you do good and not evil.
     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   **
    12     12   **
    13         -** $Id: trigger.c,v 1.141 2009/05/28 01:00:55 drh Exp $
           13  +** $Id: trigger.c,v 1.142 2009/08/06 17:43:31 drh Exp $
    14     14   */
    15     15   #include "sqliteInt.h"
    16     16   
    17     17   #ifndef SQLITE_OMIT_TRIGGER
    18     18   /*
    19     19   ** Delete a linked list of TriggerStep structures.
    20     20   */
................................................................................
    82     82     int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
    83     83     IdList *pColumns,   /* column list if this is an UPDATE OF trigger */
    84     84     SrcList *pTableName,/* The name of the table/view the trigger applies to */
    85     85     Expr *pWhen,        /* WHEN clause */
    86     86     int isTemp,         /* True if the TEMPORARY keyword is present */
    87     87     int noErr           /* Suppress errors if the trigger already exists */
    88     88   ){
    89         -  Trigger *pTrigger = 0;
    90         -  Table *pTab;
           89  +  Trigger *pTrigger = 0;  /* The new trigger */
           90  +  Table *pTab;            /* Table that the trigger fires off of */
    91     91     char *zName = 0;        /* Name of the trigger */
    92         -  sqlite3 *db = pParse->db;
           92  +  sqlite3 *db = pParse->db;  /* The database connection */
    93     93     int iDb;                /* The database to store the trigger in */
    94     94     Token *pName;           /* The unqualified db name */
    95         -  DbFixer sFix;
    96         -  int iTabDb;
           95  +  DbFixer sFix;           /* State vector for the DB fixer */
           96  +  int iTabDb;             /* Index of the database holding pTab */
    97     97   
    98     98     assert( pName1!=0 );   /* pName1->z might be NULL, but not pName1 itself */
    99     99     assert( pName2!=0 );
   100    100     assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE );
   101    101     assert( op>0 && op<0xff );
   102    102     if( isTemp ){
   103    103       /* If TEMP was specified, then the trigger name may not be qualified. */
................................................................................
   134    134     if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && 
   135    135         sqlite3FixSrcList(&sFix, pTableName) ){
   136    136       goto trigger_cleanup;
   137    137     }
   138    138     pTab = sqlite3SrcListLookup(pParse, pTableName);
   139    139     if( !pTab ){
   140    140       /* The table does not exist. */
          141  +    if( db->init.iDb==1 ){
          142  +      /* Ticket #3810.
          143  +      ** Normally, whenever a table is dropped, all associated triggers are
          144  +      ** dropped too.  But if a TEMP trigger is created on a non-TEMP table
          145  +      ** and the table is dropped by a different database connection, the
          146  +      ** trigger is not visible to the database connection that does the
          147  +      ** drop so the trigger cannot be dropped.  This results in an
          148  +      ** "orphaned trigger" - a trigger whose associated table is missing.
          149  +      */
          150  +      db->init.orphanTrigger = 1;
          151  +    }
   141    152       goto trigger_cleanup;
   142    153     }
   143    154     if( IsVirtual(pTab) ){
   144    155       sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
   145    156       goto trigger_cleanup;
   146    157     }
   147    158   

Changes to test/tkt3810.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   #
    12     12   # Tests to make sure #3810 is fixed.
    13     13   #
    14         -# $Id: tkt3810.test,v 1.3 2009/08/01 18:22:30 drh Exp $
           14  +# $Id: tkt3810.test,v 1.4 2009/08/06 17:43:31 drh Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   
    19     19   # Create a table using the first database connection.
    20     20   #
    21     21   do_test tkt3810-1.1 {
    22     22     execsql {
    23     23       CREATE TABLE t1(x);
    24     24       INSERT INTO t1 VALUES(123);
    25     25       SELECT * FROM t1;
           26  +    CREATE TABLE t2(y);
           27  +    CREATE TABLE t3(z);
    26     28     }
    27     29   } 123
    28     30   
    29     31   # Create a second connection to the same database.  Make sure the
    30     32   # schema of the database has been parsed by the second connection.
    31     33   #
    32     34   do_test tkt3810-2 {
................................................................................
    40     42   # but the first connection does not yet know this.  Then try to create a TEMP
    41     43   # trigger in the first connection that references the table that was dropped.
    42     44   #
    43     45   do_test tkt3810-3 {
    44     46     execsql {DROP TABLE t1} db2
    45     47     execsql {
    46     48        CREATE TEMP TRIGGER r1 AFTER INSERT ON t1 BEGIN
    47         -       INSERT INTO t1 VALUES(2345);
           49  +       INSERT INTO t2 VALUES(new.rowid);
    48     50        END;
    49     51     }
    50     52     catchsql {
    51         -    SELECT * FROM t1;
           53  +    SELECT * FROM t3;
           54  +  }
           55  +} {0 {}}
           56  +
           57  +# Trigger still exists in the sqlite_temp_master table, but now it is
           58  +# an orphan.
           59  +#
           60  +do_test tkt3810-4 {
           61  +  execsql {SELECT name FROM sqlite_temp_master ORDER BY name}
           62  +} {r1}
           63  +
           64  +# Because it is an orphan, it cannot be dropped.
           65  +#
           66  +do_test tkt3810-5 {
           67  +  catchsql {DROP TRIGGER r1}
           68  +} {1 {no such trigger: r1}}
           69  +
           70  +# Create a table t1 then drop the table in order to drop the orphaned
           71  +# trigger.
           72  +#
           73  +do_test tkt3810-6 {
           74  +  execsql {CREATE TABLE t1(x)} db2
           75  +  execsql {DROP TABLE t1}
           76  +  execsql {
           77  +    SELECT name FROM sqlite_temp_master;
    52     78     }
    53         -} {1 {in r1: no such table: t1}}
           79  +} {}
    54     80   
    55     81   db2 close
    56     82   
    57     83   finish_test