SQLite

Check-in [b10346818b]
Login

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

Overview
Comment:Beginning to clean up the trigger code. Still lots of work to do. (CVS 566)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b10346818b25940c6dc85e94de8e36d20954161c
User & Date: drh 2002-05-15 12:45:43.000
Context
2002-05-15
14:17
Fix for ticket #41: Better handling of CREATE TRIGGER in the sqlite_complete() function. (CVS 567) (check-in: f45c4b767a user: drh tags: trunk)
12:45
Beginning to clean up the trigger code. Still lots of work to do. (CVS 566) (check-in: b10346818b user: drh tags: trunk)
11:44
Remove all tabs from the beginning of source code lines. Replace tabs with the appropriate number of spaces. (CVS 565) (check-in: 690f9a1631 user: drh tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to Makefile.template.
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128







-
+







#
TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src

# Object files for the SQLite library.
#
LIBOBJ = btree.o build.o delete.o expr.o func.o hash.o insert.o \
         main.o os.o pager.o parse.o printf.o random.o select.o table.o \
         tokenize.o update.o util.o vdbe.o where.o tclsqlite.o
         tokenize.o trigger.o update.o util.o vdbe.o where.o tclsqlite.o

# All of the source code files.
#
SRC = \
  $(TOP)/src/btree.c \
  $(TOP)/src/btree.h \
  $(TOP)/src/build.c \
142
143
144
145
146
147
148

149
150
151
152
153
154
155
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156







+







  $(TOP)/src/select.c \
  $(TOP)/src/shell.c \
  $(TOP)/src/sqlite.h.in \
  $(TOP)/src/sqliteInt.h \
  $(TOP)/src/table.c \
  $(TOP)/src/tclsqlite.c \
  $(TOP)/src/tokenize.c \
  $(TOP)/src/trigger.c \
  $(TOP)/src/update.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/vdbe.h \
  $(TOP)/src/where.c

# Source code to the test files.
240
241
242
243
244
245
246



247
248
249
250
251
252
253
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257







+
+
+







sqlite.h:	$(TOP)/src/sqlite.h.in 
	sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \
            -e s/--ENCODING--/$(ENCODING)/ \
                 $(TOP)/src/sqlite.h.in >sqlite.h

tokenize.o:	$(TOP)/src/tokenize.c $(HDR)
	$(TCCX) -c $(TOP)/src/tokenize.c

trigger.o:	$(TOP)/src/trigger.c $(HDR)
	$(TCCX) -c $(TOP)/src/trigger.c

util.o:	$(TOP)/src/util.c $(HDR)
	$(TCCX) -c $(TOP)/src/util.c

vdbe.o:	$(TOP)/src/vdbe.c $(HDR)
	$(TCCX) -c $(TOP)/src/vdbe.c

Changes to src/build.c.
21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35







-
+







**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.89 2002/05/15 11:44:14 drh Exp $
** $Id: build.c,v 1.90 2002/05/15 12:45:43 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
352
353
354
355
356
357
358

359
360
361
362
363
364
365







-







  /* Any triggers that were dropped - put 'em back in place */
  for(pElem = sqliteHashFirst(&db->trigDrop); pElem; 
      pElem = sqliteHashNext(pElem)) {
    Trigger * pTrigger = sqliteHashData(pElem);
    Table * tab = sqliteFindTable(db, pTrigger->table);
    sqliteHashInsert(&db->trigHash, pTrigger->name, 
        strlen(pTrigger->name) + 1, pTrigger);

    pTrigger->pNext = tab->pTrigger;
    tab->pTrigger = pTrigger;
  }

  sqliteHashClear(&db->trigDrop);
  db->flags &= ~SQLITE_InternChanges;
}
649
650
651
652
653
654
655
656

657
658
659
660
661
662
663
648
649
650
651
652
653
654

655
656
657
658
659
660
661
662







-
+







**
** This plan is not completely bullet-proof.  It is possible for
** the schema to change multiple times and for the cookie to be
** set back to prior value.  But schema changes are infrequent
** and the probability of hitting the same cookie value is only
** 1 chance in 2^32.  So we're safe enough.
*/
void changeCookie(sqlite *db){
void sqliteChangeCookie(sqlite *db){
  if( db->next_cookie==db->schema_cookie ){
    db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
    db->flags |= SQLITE_InternChanges;
  }
}

/*
848
849
850
851
852
853
854
855

856
857
858
859
860
861
862
847
848
849
850
851
852
853

854
855
856
857
858
859
860
861







-
+







      }else{
        assert( pEnd!=0 );
        n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
        sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
      }
      sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
      sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
      changeCookie(db);
      sqliteChangeCookie(db);
      sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
      sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
      sqliteVdbeAddOp(v, OP_Close, 0, 0);
    }
    if( pSelect ){
      int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite;
      sqliteVdbeAddOp(v, op, 1, 0);
1091
1092
1093
1094
1095
1096
1097
1098

1099
1100
1101
1102
1103
1104
1105
1106
1107

1108
1109
1110
1111
1112
1113
1114
1090
1091
1092
1093
1094
1095
1096

1097
1098
1099
1100
1101
1102
1103
1104
1105

1106
1107
1108
1109
1110
1111
1112
1113







-
+








-
+







      { OP_Integer,    0, 0,        0}, /* 9 */
      { OP_SetCookie,  0, 0,        0},
      { OP_Close,      0, 0,        0},
    };
    Index *pIdx;
    sqliteBeginWriteOperation(pParse);
    /* Drop all triggers associated with the table being dropped */
    while (pTable->pTrigger) {
    while( pTable->pTrigger ){
      Token tt;
      tt.z = pTable->pTrigger->name;
      tt.n = strlen(pTable->pTrigger->name);
      sqliteDropTrigger(pParse, &tt, 1);
    }
    if( !pTable->isTemp ){
      base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
      sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
      changeCookie(db);
      sqliteChangeCookie(db);
      sqliteVdbeChangeP1(v, base+9, db->next_cookie);
    }
    if( !isView ){
      sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp);
      for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
        sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp);
      }
1405
1406
1407
1408
1409
1410
1411
1412

1413
1414
1415
1416
1417
1418
1419
1404
1405
1406
1407
1408
1409
1410

1411
1412
1413
1414
1415
1416
1417
1418







-
+







      sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
      sqliteVdbeResolveLabel(v, lbl2);
      sqliteVdbeAddOp(v, OP_Close, 2, 0);
      sqliteVdbeAddOp(v, OP_Close, 1, 0);
    }
    if( pTable!=0 ){
      if( !isTemp ){
        changeCookie(db);
        sqliteChangeCookie(db);
        sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
        sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
        sqliteVdbeAddOp(v, OP_Close, 0, 0);
      }
      sqliteEndWriteOperation(pParse);
    }
  }
1468
1469
1470
1471
1472
1473
1474
1475

1476
1477
1478
1479
1480
1481
1482
1467
1468
1469
1470
1471
1472
1473

1474
1475
1476
1477
1478
1479
1480
1481







-
+







    int base;
    Table *pTab = pIndex->pTable;

    sqliteBeginWriteOperation(pParse);
    if( !pTab->isTemp ){
      base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
      sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC);
      changeCookie(db);
      sqliteChangeCookie(db);
      sqliteVdbeChangeP1(v, base+10, db->next_cookie);
    }
    sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
    sqliteEndWriteOperation(pParse);
  }

  /* Move the index onto the pending DROP queue.  Or, if the index was
1707
1708
1709
1710
1711
1712
1713
1714

1715
1716
1717
1718
1719
1720
1721

1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741

1742
1743
1744
1745
1746
1747
1748
1706
1707
1708
1709
1710
1711
1712

1713
1714
1715
1716
1717
1718
1719

1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739

1740
1741
1742
1743
1744
1745
1746
1747







-
+






-
+



















-
+







  db->onError = OE_Default;
}

/*
** Generate VDBE code that prepares for doing an operation that
** might change the database.  The operation will be atomic in the
** sense that it will either do its changes completely or not at
** all.  So there is not need to set a checkpoint is a transaction
** all.  So there is no need to set a checkpoint is a transaction
** is already in effect.
*/
void sqliteBeginWriteOperation(Parse *pParse){
  Vdbe *v;
  v = sqliteGetVdbe(pParse);
  if( v==0 ) return;
  if (pParse->trigStack) return; /* if this is in a trigger */
  if( pParse->trigStack ) return; /* if this is in a trigger */
  if( (pParse->db->flags & SQLITE_InTrans)==0  ){
    sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
    sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
    pParse->schemaVerified = 1;
  }
}

/*
** Generate VDBE code that prepares for doing an operation that
** might change the database.  The operation might not be atomic in
** the sense that an error may be discovered and the operation might
** abort after some changes have been made.  If we are in the middle 
** of a transaction, then this sets a checkpoint.  If we are not in
** a transaction, then start a transaction.
*/
void sqliteBeginMultiWriteOperation(Parse *pParse){
  Vdbe *v;
  v = sqliteGetVdbe(pParse);
  if( v==0 ) return;
  if (pParse->trigStack) return; /* if this is in a trigger */
  if( pParse->trigStack ) return; /* if this is in a trigger */
  if( (pParse->db->flags & SQLITE_InTrans)==0 ){
    sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
    sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
    pParse->schemaVerified = 1;
  }else{
    sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
  }
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.108 2002/05/15 08:30:14 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.109 2002/05/15 12:45:43 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
554
555
556
557
558
559
560
561
562

563
564
565
566
567
568
569
570
571






572
573
574
575
576
577

578
579
580
581


582
583
584
585
586
587
588
589
590
591
592
593
594
595








596
597

598
599
600


601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
554
555
556
557
558
559
560


561
562
563
564






565
566
567
568
569
570
571
572
573
574
575

576
577
578


579
580
581
582
583
584
585
586








587
588
589
590
591
592
593
594
595

596



597
598
599
600
601






602
603






604
605
606
607
608
609
610







-
-
+



-
-
-
-
-
-
+
+
+
+
+
+





-
+


-
-
+
+






-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
+
-
-
-
+
+



-
-
-
-
-
-


-
-
-
-
-
-







  int nSet;            /* Number of sets used so far */
  int nAgg;            /* Number of aggregate expressions */
  AggExpr *aAgg;       /* An array of aggregate expressions */
  int useAgg;          /* If true, extract field values from the aggregator
                       ** while generating expressions.  Normally false */
  int schemaVerified;  /* True if an OP_VerifySchema has been coded someplace
                       ** other than after an OP_Transaction */

  TriggerStack * trigStack;
  TriggerStack *trigStack;
};

struct TriggerStack {
  Trigger * pTrigger;
  Table *   pTab;         /* Table that triggers are currently being coded as */
  int       newIdx;       /* Index of "new" temp table */
  int       oldIdx;       /* Index of "old" temp table */
  int       orconf;       /* Current orconf policy */
  struct TriggerStack * pNext;
  Trigger *pTrigger;
  Table *pTab;         /* Table that triggers are currently being coded as */
  int newIdx;          /* Index of "new" temp table */
  int oldIdx;          /* Index of "old" temp table */
  int orconf;          /* Current orconf policy */
  TriggerStack *pNext;
};
struct TriggerStep {
  int op;               /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
  int orconf;

  Select * pSelect;     /* Valid for SELECT and sometimes 
  Select *pSelect;     /* Valid for SELECT and sometimes 
			   INSERT steps (when pExprList == 0) */
  Token target;         /* Valid for DELETE, UPDATE, INSERT steps */
  Expr * pWhere;        /* Valid for DELETE, UPDATE steps */
  ExprList * pExprList; /* Valid for UPDATE statements and sometimes 
  Expr *pWhere;        /* Valid for DELETE, UPDATE steps */
  ExprList *pExprList; /* Valid for UPDATE statements and sometimes 
			   INSERT steps (when pSelect == 0)         */
  IdList *pIdList;      /* Valid for INSERT statements only */

  TriggerStep * pNext;  /* Next in the link-list */
};
struct Trigger {
  char * name;             /* The name of the trigger                        */
  char * table;            /* The table or view to which the trigger applies */
  int    op;               /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
  int    tr_tm;            /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD         */
  Expr * pWhen;            /* The WHEN clause of the expresion (may be NULL) */
  IdList * pColumns;       /* If this is an UPDATE OF <column-list> trigger,
			      the column names are stored in this list       */
  int foreach;             /* One of TK_ROW or TK_STATEMENT */
  char *name;             /* The name of the trigger                        */
  char *table;            /* The table or view to which the trigger applies */
  int op;                 /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
  int tr_tm;              /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD         */
  Expr *pWhen;            /* The WHEN clause of the expresion (may be NULL) */
  IdList *pColumns;       /* If this is an UPDATE OF <column-list> trigger,
                             the column names are stored in this list       */
  int foreach;            /* One of TK_ROW or TK_STATEMENT */

  TriggerStep * step_list; /* Link list of trigger program steps             */
  TriggerStep *step_list; /* Link list of trigger program steps             */

  char * strings;  /* pointer to the allocation of Token strings */
  Trigger * pNext; /* Next trigger associated with the table */
  char *strings;          /* pointer to allocation of Token strings */
  Trigger *pNext;         /* Next trigger associated with the table */
  int isCommit;
};

TriggerStep * sqliteTriggerSelectStep(Select *);
TriggerStep * sqliteTriggerInsertStep(Token *, IdList *, ExprList *, 
    Select *, int);
TriggerStep * sqliteTriggerUpdateStep(Token *, ExprList *, Expr *, int);
TriggerStep * sqliteTriggerDeleteStep(Token *, Expr *);

extern int always_code_trigger_setup;

void sqliteCreateTrigger(Parse * ,Token *, int, int, IdList *, Token *, int, Expr *, TriggerStep *, char const *,int);
void sqliteDropTrigger(Parse *, Token *, int);
int sqliteTriggersExist( Parse * , Trigger * , int , int , int, ExprList * );
int sqliteCodeRowTrigger( Parse * pParse, int op, ExprList *, int tr_tm,   Table * tbl, int newTable, int oldTable, int onError);

void sqliteViewTriggers(Parse *, Table *, Expr *, int, ExprList *);

/*
** Internal function prototypes
*/
int sqliteStrICmp(const char *, const char *);
int sqliteStrNICmp(const char *, const char *, int);
int sqliteHashNoCase(const char *, int);
722
723
724
725
726
727
728
729
730











708
709
710
711
712
713
714


715
716
717
718
719
720
721
722
723
724
725







-
-
+
+
+
+
+
+
+
+
+
+
+
IdList *sqliteIdListDup(IdList*);
Select *sqliteSelectDup(Select*);
FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
void sqliteRegisterBuildinFunctions(sqlite*);
int sqliteSafetyOn(sqlite*);
int sqliteSafetyOff(sqlite*);
int sqliteSafetyCheck(sqlite*);

void changeCookie(sqlite *);
void sqliteChangeCookie(sqlite *);
void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*, 
                         int, Expr*, TriggerStep*, char const*,int);
void sqliteDropTrigger(Parse*, Token*, int);
int sqliteTriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
int sqliteCodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
TriggerStep *sqliteTriggerSelectStep(Select*);
TriggerStep *sqliteTriggerInsertStep(Token*, IdList*, ExprList*, Select*, int);
TriggerStep *sqliteTriggerUpdateStep(Token*, ExprList*, Expr*, int);
TriggerStep *sqliteTriggerDeleteStep(Token*, Expr*);
Changes to src/trigger.c.
98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112







-
+







    sqliteVdbeAddOp(pParse->pVdbe,        OP_Integer,    0, 0);
    sqliteVdbeAddOp(pParse->pVdbe,        OP_String,    0, 0);
    sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->strings,     0);
    sqliteVdbeAddOp(pParse->pVdbe,        OP_MakeRecord, 5, 0);
    sqliteVdbeAddOp(pParse->pVdbe,        OP_PutIntKey, 0, 1);

    /* Change the cookie, since the schema is changed */
    changeCookie(pParse->db);
    sqliteChangeCookie(pParse->db);
    sqliteVdbeAddOp(pParse->pVdbe, OP_Integer, pParse->db->next_cookie, 0);
    sqliteVdbeAddOp(pParse->pVdbe, OP_SetCookie, 0, 0);

    sqliteVdbeAddOp(pParse->pVdbe,        OP_Close,     0, 0);

    sqliteEndWriteOperation(pParse);
  }
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
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







-
+

-
+



-
-
-
-
+
+
+

-
-
+

+







      { OP_Delete,     0, 0,        0},
      { OP_Next,       0, ADDR(4),  0}, /* 8 */
      { OP_Integer,    0, 0,        0}, /* 9 */
      { OP_SetCookie,  0, 0,        0},
      { OP_Close,      0, 0,        0},
    };

    if (!nested) 
    if( !nested ){
      sqliteBeginWriteOperation(pParse);

    }
    base = sqliteVdbeAddOpList(pParse->pVdbe, 
        ArraySize(dropTrigger), dropTrigger);
    sqliteVdbeChangeP3(pParse->pVdbe, base+2, tmp_name, 0);

    if (!nested)
      changeCookie(pParse->db);

    if( !nested ){
      sqliteChangeCookie(pParse->db);
    }
    sqliteVdbeChangeP1(pParse->pVdbe, base+9, pParse->db->next_cookie);

    if (!nested)
    if( !nested ){
      sqliteEndWriteOperation(pParse);
    }
  }

  sqliteFree(tmp_name);
}

static int checkColumnOverLap(IdList * ii, ExprList * ee)
{