SQLite

Check-in [19f93e135f]
Login

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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 19f93e135f1ff4f987d14afe74b955e119904017
User & Date: danielk1977 2006-01-06 15:03:48.000
Context
2006-01-06
16:17
A first attempt at adding native support for WinCE. (CVS 2874) (check-in: 4344056787 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: 19f93e135f user: danielk1977 tags: trunk)
14:46
Fix an alignment problem in the sqlite3OsRandomSeed(). Ticket #1584. (CVS 2872) (check-in: 373b56f004 user: drh tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21













-
+







/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.451 2006/01/06 12:03:19 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.452 2006/01/06 15:03:48 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309


1310
1311
1312
1313
1314
1315
1316
1293
1294
1295
1296
1297
1298
1299


1300
1301
1302
1303
1304
1305
1306

1307
1308
1309
1310
1311
1312
1313
1314
1315







-
-







-
+
+







 *
 * The "step_list" member points to the first element of a linked list
 * containing the SQL statements specified as the trigger program.
 */
struct Trigger {
  char *name;             /* The name of the trigger                        */
  char *table;            /* The table or view to which the trigger applies */
//u8 iDb;                 /* Database containing this trigger               */
  u8 iTabDb;              /* Database containing Trigger.table              */
  u8 op;                  /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
  u8 tr_tm;               /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
  Expr *pWhen;            /* The WHEN clause of the expresion (may be NULL) */
  IdList *pColumns;       /* If this is an UPDATE OF <column-list> trigger,
                             the <column-list> is stored here */
  int foreach;            /* One of TK_ROW or TK_STATEMENT */
  Token nameToken;        /* Token containing zName. Use during parsing only */
  DbSchema *pSchema;
  DbSchema *pSchema;      /* Schema containing the trigger */
  DbSchema *pTabSchema;   /* Schema containing the table */
  TriggerStep *step_list; /* Link list of trigger program steps             */
  Trigger *pNext;         /* Next trigger associated with the table */
};

/*
** A trigger is either a BEFORE or an AFTER trigger.  The following constants
** determine which. 
Changes to src/trigger.c.
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
160
161
162
163
164
165
166

167
168
169
170
171
172
173
174







-
+







  /* Build the Trigger object */
  pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
  if( pTrigger==0 ) goto trigger_cleanup;
  pTrigger->name = zName;
  zName = 0;
  pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
  pTrigger->pSchema = db->aDb[iDb].pSchema;
  pTrigger->iTabDb = iTabDb;
  pTrigger->pTabSchema = pTab->pSchema;
  pTrigger->op = op;
  pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
  pTrigger->pWhen = sqlite3ExprDup(pWhen);
  pTrigger->pColumns = sqlite3IdListDup(pColumns);
  pTrigger->foreach = foreach;
  sqlite3TokenCopy(&pTrigger->nameToken,pName);
  assert( pParse->pNewTrigger==0 );
245
246
247
248
249
250
251

252
253
254
255
256
257
258
259
260


261
262
263
264
265
266
267
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







+








-
+
+







    sqlite3ChangeCookie(db, v, iDb);
    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
    sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, 
       sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
  }

  if( db->init.busy ){
    int n;
    Table *pTab;
    Trigger *pDel;
    pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, 
                     pTrig->name, strlen(pTrig->name)+1, pTrig);
    if( pDel ){
      assert( sqlite3Tsd()->mallocFailed && pDel==pTrig );
      goto triggerfinish_cleanup;
    }
    pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
    n = strlen(pTrig->table) + 1;
    pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
    assert( pTab!=0 );
    pTrig->pNext = pTab->pTrigger;
    pTab->pTrigger = pTrig;
    pTrig = 0;
  }

triggerfinish_cleanup:
463
464
465
466
467
468
469
470


471
472
473
474
475
476
477
465
466
467
468
469
470
471

472
473
474
475
476
477
478
479
480







-
+
+







}

/*
** Return a pointer to the Table structure for the table that a trigger
** is set on.
*/
static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
  return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
  int n = strlen(pTrigger->table) + 1;
  return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
}


/*
** Drop a trigger given a pointer to that trigger.  If nested is false,
** then also generate code to remove the trigger from the SQLITE_MASTER
** table.
Changes to test/shared.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
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













-
+



















-

+
+







# 2005 December 30
#
# 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 regression tests for SQLite library.  The
# focus of this file is testing the SELECT statement.
#
# $Id: shared.test,v 1.4 2006/01/06 13:00:30 danielk1977 Exp $
# $Id: shared.test,v 1.5 2006/01/06 15:03:48 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
db close

ifcapable !shared_cache {
  finish_test
  return
}
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

# Test organization:
#
# shared-1.*: Simple test to verify basic sanity of table level locking when
#             two connections share a pager cache.
# shared-2.*: Test that a read transaction can co-exist with a 
#             write-transaction, including a simple test to ensure the 
#             external locking protocol is still working.
# shared-3.*: Simple test of read-uncommitted mode.
#
# shared-4.*: Check that the schema is locked and unlocked correctly.
# shared-5.*: Test that creating/dropping schema items works when databases
#             are attached in different orders to different handles.
#

do_test shared-1.1 {
  # Open a second database on the file test.db. It should use the same pager
  # cache and schema as the original connection. Verify that only 1 file is 
  # opened.
  sqlite3 db2 test.db
355
356
357
358
359
360
361
362

363
364
365













































366
367
368
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








+



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



} {1 {(6) database schema is locked: test}}
do_test shared-4.4.5 {
  set rc [catch {
    set ::STMT1 [sqlite3_prepare $::DB2 "SELECT * FROM ghi" -1 DUMMY]
  } msg]
  list $rc $msg
} {1 {(6) database schema is locked: test}}


catch {db2 close}
catch {db close}

#--------------------------------------------------------------------------
# Tests shared-5.* 
#
foreach db [list test.db test1.db test2.db test3.db] {
  file delete -force $db ${db}-journal
}
do_test shared-5.1.1 {
  sqlite3 db1 test.db
  sqlite3 db2 test.db
  execsql {
    ATTACH 'test1.db' AS test1;
    ATTACH 'test2.db' AS test2;
    ATTACH 'test3.db' AS test3;
  } db1
  execsql {
    ATTACH 'test3.db' AS test3;
    ATTACH 'test2.db' AS test2;
    ATTACH 'test1.db' AS test1;
  } db2
} {}
do_test shared-5.1.2 {
  execsql {
    CREATE TABLE test1.t1(a, b);
    CREATE INDEX test1.i1 ON t1(a, b);
    CREATE VIEW test1.v1 AS SELECT * FROM t1;
    CREATE TRIGGER test1.trig1 AFTER INSERT ON t1 BEGIN
      INSERT INTO t1 VALUES(new.a, new.b);
    END;
  } db1
  execsql {
    DROP INDEX i1;
    DROP VIEW v1;
    DROP TRIGGER trig1;
    DROP TABLE t1;
  } db2
} {}
do_test shared-5.1.2 {
  execsql {
    SELECT * FROM sqlite_master UNION ALL SELECT * FROM test1.sqlite_master
  } db1
} {}

catch {db1 close}
catch {db2 close}

finish_test
sqlite3_enable_shared_cache $::enable_shared_cache