annotate sqlite/update.c @ 1621:fae6e0cfcc77 trunk

[svn] - Reapply r2161
author nhjm449
date Tue, 05 Sep 2006 19:57:18 -0700
parents b6b61becdf4e
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1434
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
1 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
2 ** 2001 September 15
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
3 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
4 ** The author disclaims copyright to this source code. In place of
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
5 ** a legal notice, here is a blessing:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
6 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
7 ** May you do good and not evil.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
8 ** May you find forgiveness for yourself and forgive others.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
9 ** May you share freely, never taking more than you give.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
10 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
11 *************************************************************************
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
12 ** This file contains C code routines that are called by the parser
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
13 ** to handle UPDATE statements.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
14 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
15 ** $Id: update.c,v 1.123 2006/02/24 02:53:50 drh Exp $
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
16 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
17 #include "sqliteInt.h"
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
18
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
19 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
20 ** The most recently coded instruction was an OP_Column to retrieve the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
21 ** i-th column of table pTab. This routine sets the P3 parameter of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
22 ** OP_Column to the default value, if any.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
23 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
24 ** The default value of a column is specified by a DEFAULT clause in the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
25 ** column definition. This was either supplied by the user when the table
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
26 ** was created, or added later to the table definition by an ALTER TABLE
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
27 ** command. If the latter, then the row-records in the table btree on disk
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
28 ** may not contain a value for the column and the default value, taken
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
29 ** from the P3 parameter of the OP_Column instruction, is returned instead.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
30 ** If the former, then all row-records are guaranteed to include a value
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
31 ** for the column and the P3 value is not required.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
32 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
33 ** Column definitions created by an ALTER TABLE command may only have
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
34 ** literal default values specified: a number, null or a string. (If a more
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
35 ** complicated default expression value was provided, it is evaluated
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
36 ** when the ALTER TABLE is executed and one of the literal values written
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
37 ** into the sqlite_master table.)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
38 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
39 ** Therefore, the P3 parameter is only required if the default value for
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
40 ** the column is a literal number, string or null. The sqlite3ValueFromExpr()
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
41 ** function is capable of transforming these types of expressions into
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
42 ** sqlite3_value objects.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
43 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
44 void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
45 if( pTab && !pTab->pSelect ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
46 sqlite3_value *pValue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
47 u8 enc = ENC(sqlite3VdbeDb(v));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
48 Column *pCol = &pTab->aCol[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
49 sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
50 if( pValue ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
51 sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
52 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
53 VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
54 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
55 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
56 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
57
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
58 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
59 ** Process an UPDATE statement.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
60 **
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
61 ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
62 ** \_______/ \________/ \______/ \________________/
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
63 * onError pTabList pChanges pWhere
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
64 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
65 void sqlite3Update(
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
66 Parse *pParse, /* The parser context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
67 SrcList *pTabList, /* The table in which we should change things */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
68 ExprList *pChanges, /* Things to be changed */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
69 Expr *pWhere, /* The WHERE clause. May be null */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
70 int onError /* How to handle constraint errors */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
71 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
72 int i, j; /* Loop counters */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
73 Table *pTab; /* The table to be updated */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
74 int addr = 0; /* VDBE instruction address of the start of the loop */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
75 WhereInfo *pWInfo; /* Information about the WHERE clause */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
76 Vdbe *v; /* The virtual database engine */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
77 Index *pIdx; /* For looping over indices */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
78 int nIdx; /* Number of indices that need updating */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
79 int nIdxTotal; /* Total number of indices */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
80 int iCur; /* VDBE Cursor number of pTab */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
81 sqlite3 *db; /* The database structure */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
82 Index **apIdx = 0; /* An array of indices that need updating too */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
83 char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
84 int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
85 ** an expression for the i-th column of the table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
86 ** aXRef[i]==-1 if the i-th column is not changed. */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
87 int chngRowid; /* True if the record number is being changed */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
88 Expr *pRowidExpr = 0; /* Expression defining the new record number */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
89 int openAll = 0; /* True if all indices need to be opened */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
90 AuthContext sContext; /* The authorization context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
91 NameContext sNC; /* The name-context to resolve expressions in */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
92 int iDb; /* Database containing the table being updated */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
93
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
94 #ifndef SQLITE_OMIT_TRIGGER
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
95 int isView; /* Trying to update a view */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
96 int triggers_exist = 0; /* True if any row triggers exist */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
97 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
98
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
99 int newIdx = -1; /* index of trigger "new" temp table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
100 int oldIdx = -1; /* index of trigger "old" temp table */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
101
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
102 sContext.pParse = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
103 if( pParse->nErr || sqlite3MallocFailed() ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
104 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
105 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
106 db = pParse->db;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
107 assert( pTabList->nSrc==1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
108
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
109 /* Locate the table which we want to update.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
110 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
111 pTab = sqlite3SrcListLookup(pParse, pTabList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
112 if( pTab==0 ) goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
113 iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
114
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
115 /* Figure out if we have any triggers and if the table being
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
116 ** updated is a view
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
117 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
118 #ifndef SQLITE_OMIT_TRIGGER
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
119 triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
120 isView = pTab->pSelect!=0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
121 #else
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
122 # define triggers_exist 0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
123 # define isView 0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
124 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
125 #ifdef SQLITE_OMIT_VIEW
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
126 # undef isView
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
127 # define isView 0
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
128 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
129
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
130 if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
131 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
132 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
133 if( isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
134 if( sqlite3ViewGetColumnNames(pParse, pTab) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
135 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
136 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
137 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
138 aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
139 if( aXRef==0 ) goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
140 for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
141
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
142 /* If there are FOR EACH ROW triggers, allocate cursors for the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
143 ** special OLD and NEW tables
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
144 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
145 if( triggers_exist ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
146 newIdx = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
147 oldIdx = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
148 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
149
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
150 /* Allocate a cursors for the main database table and for all indices.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
151 ** The index cursors might not be used, but if they are used they
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
152 ** need to occur right after the database cursor. So go ahead and
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
153 ** allocate enough space, just in case.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
154 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
155 pTabList->a[0].iCursor = iCur = pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
156 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
157 pParse->nTab++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
158 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
159
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
160 /* Initialize the name-context */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
161 memset(&sNC, 0, sizeof(sNC));
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
162 sNC.pParse = pParse;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
163 sNC.pSrcList = pTabList;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
164
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
165 /* Resolve the column names in all the expressions of the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
166 ** of the UPDATE statement. Also find the column index
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
167 ** for each column to be updated in the pChanges array. For each
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
168 ** column to be updated, make sure we have authorization to change
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
169 ** that column.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
170 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
171 chngRowid = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
172 for(i=0; i<pChanges->nExpr; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
173 if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
174 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
175 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
176 for(j=0; j<pTab->nCol; j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
177 if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
178 if( j==pTab->iPKey ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
179 chngRowid = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
180 pRowidExpr = pChanges->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
181 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
182 aXRef[j] = i;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
183 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
184 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
185 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
186 if( j>=pTab->nCol ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
187 if( sqlite3IsRowid(pChanges->a[i].zName) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
188 chngRowid = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
189 pRowidExpr = pChanges->a[i].pExpr;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
190 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
191 sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
192 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
193 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
194 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
195 #ifndef SQLITE_OMIT_AUTHORIZATION
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
196 {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
197 int rc;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
198 rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
199 pTab->aCol[j].zName, db->aDb[iDb].zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
200 if( rc==SQLITE_DENY ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
201 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
202 }else if( rc==SQLITE_IGNORE ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
203 aXRef[j] = -1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
204 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
205 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
206 #endif
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
207 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
208
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
209 /* Allocate memory for the array apIdx[] and fill it with pointers to every
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
210 ** index that needs to be updated. Indices only need updating if their
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
211 ** key includes one of the columns named in pChanges or if the record
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
212 ** number of the original table entry is changing.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
213 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
214 for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
215 if( chngRowid ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
216 i = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
217 }else {
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
218 for(i=0; i<pIdx->nColumn; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
219 if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
220 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
221 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
222 if( i<pIdx->nColumn ) nIdx++;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
223 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
224 if( nIdxTotal>0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
225 apIdx = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
226 if( apIdx==0 ) goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
227 aIdxUsed = (char*)&apIdx[nIdx];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
228 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
229 for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
230 if( chngRowid ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
231 i = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
232 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
233 for(i=0; i<pIdx->nColumn; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
234 if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
235 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
236 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
237 if( i<pIdx->nColumn ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
238 apIdx[nIdx++] = pIdx;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
239 aIdxUsed[j] = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
240 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
241 aIdxUsed[j] = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
242 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
243 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
244
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
245 /* Resolve the column names in all the expressions in the
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
246 ** WHERE clause.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
247 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
248 if( sqlite3ExprResolveNames(&sNC, pWhere) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
249 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
250 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
251
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
252 /* Start the view context
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
253 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
254 if( isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
255 sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
256 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
257
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
258 /* Begin generating code.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
259 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
260 v = sqlite3GetVdbe(pParse);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
261 if( v==0 ) goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
262 if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
263 sqlite3BeginWriteOperation(pParse, 1, iDb);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
264
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
265 /* If we are trying to update a view, realize that view into
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
266 ** a ephemeral table.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
267 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
268 if( isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
269 Select *pView;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
270 pView = sqlite3SelectDup(pTab->pSelect);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
271 sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
272 sqlite3SelectDelete(pView);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
273 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
274
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
275 /* Begin the database scan
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
276 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
277 pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
278 if( pWInfo==0 ) goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
279
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
280 /* Remember the index of every item to be updated.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
281 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
282 sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
283 sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
284
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
285 /* End the database scan loop.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
286 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
287 sqlite3WhereEnd(pWInfo);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
288
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
289 /* Initialize the count of updated rows
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
290 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
291 if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
292 sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
293 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
294
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
295 if( triggers_exist ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
296 /* Create pseudo-tables for NEW and OLD
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
297 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
298 sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
299 sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
300 sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
301 sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
302
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
303 /* The top of the update loop for when there are triggers.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
304 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
305 addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
306
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
307 if( !isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
308 sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
309 sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
310 /* Open a cursor and make it point to the record that is
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
311 ** being updated.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
312 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
313 sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
314 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
315 sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
316
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
317 /* Generate the OLD table
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
318 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
319 sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
320 sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
321 sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
322
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
323 /* Generate the NEW table
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
324 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
325 if( chngRowid ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
326 sqlite3ExprCodeAndCache(pParse, pRowidExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
327 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
328 sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
329 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
330 for(i=0; i<pTab->nCol; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
331 if( i==pTab->iPKey ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
332 sqlite3VdbeAddOp(v, OP_Null, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
333 continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
334 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
335 j = aXRef[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
336 if( j<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
337 sqlite3VdbeAddOp(v, OP_Column, iCur, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
338 sqlite3ColumnDefault(v, pTab, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
339 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
340 sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
341 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
342 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
343 sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
344 if( !isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
345 sqlite3TableAffinityStr(v, pTab);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
346 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
347 if( pParse->nErr ) goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
348 sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
349 if( !isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
350 sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
351 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
352
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
353 /* Fire the BEFORE and INSTEAD OF triggers
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
354 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
355 if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
356 newIdx, oldIdx, onError, addr) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
357 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
358 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
359 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
360
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
361 if( !isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
362 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
363 ** Open every index that needs updating. Note that if any
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
364 ** index could potentially invoke a REPLACE conflict resolution
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
365 ** action, then we need to open all indices because we might need
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
366 ** to be deleting some records.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
367 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
368 sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
369 if( onError==OE_Replace ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
370 openAll = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
371 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
372 openAll = 0;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
373 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
374 if( pIdx->onError==OE_Replace ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
375 openAll = 1;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
376 break;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
377 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
378 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
379 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
380 for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
381 if( openAll || aIdxUsed[i] ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
382 KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
383 sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
384 sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
385 (char*)pKey, P3_KEYINFO_HANDOFF);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
386 assert( pParse->nTab>iCur+i+1 );
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
387 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
388 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
389
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
390 /* Loop over every record that needs updating. We have to load
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
391 ** the old data for each record to be updated because some columns
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
392 ** might not change and we will need to copy the old value.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
393 ** Also, the old data is needed to delete the old index entires.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
394 ** So make the cursor point at the old record.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
395 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
396 if( !triggers_exist ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
397 addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
398 sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
399 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
400 sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
401
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
402 /* If the record number will change, push the record number as it
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
403 ** will be after the update. (The old record number is currently
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
404 ** on top of the stack.)
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
405 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
406 if( chngRowid ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
407 sqlite3ExprCode(pParse, pRowidExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
408 sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
409 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
410
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
411 /* Compute new data for this record.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
412 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
413 for(i=0; i<pTab->nCol; i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
414 if( i==pTab->iPKey ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
415 sqlite3VdbeAddOp(v, OP_Null, 0, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
416 continue;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
417 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
418 j = aXRef[i];
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
419 if( j<0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
420 sqlite3VdbeAddOp(v, OP_Column, iCur, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
421 sqlite3ColumnDefault(v, pTab, i);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
422 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
423 sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
424 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
425 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
426
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
427 /* Do constraint checks
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
428 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
429 sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
430 onError, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
431
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
432 /* Delete the old indices for the current record.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
433 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
434 sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
435
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
436 /* If changing the record number, delete the old record.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
437 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
438 if( chngRowid ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
439 sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
440 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
441
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
442 /* Create the new index entries and the new record.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
443 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
444 sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
445 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
446
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
447 /* Increment the row counter
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
448 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
449 if( db->flags & SQLITE_CountRows && !pParse->trigStack){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
450 sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
451 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
452
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
453 /* If there are triggers, close all the cursors after each iteration
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
454 ** through the loop. The fire the after triggers.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
455 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
456 if( triggers_exist ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
457 if( !isView ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
458 for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
459 if( openAll || aIdxUsed[i] )
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
460 sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
461 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
462 sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
463 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
464 if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
465 newIdx, oldIdx, onError, addr) ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
466 goto update_cleanup;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
467 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
468 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
469
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
470 /* Repeat the above with the next record to be updated, until
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
471 ** all record selected by the WHERE clause have been updated.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
472 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
473 sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
474 sqlite3VdbeJumpHere(v, addr);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
475
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
476 /* Close all tables if there were no FOR EACH ROW triggers */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
477 if( !triggers_exist ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
478 for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
479 if( openAll || aIdxUsed[i] ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
480 sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
481 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
482 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
483 sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
484 }else{
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
485 sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
486 sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
487 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
488
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
489 /*
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
490 ** Return the number of rows that were changed. If this routine is
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
491 ** generating code because of a call to sqlite3NestedParse(), do not
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
492 ** invoke the callback function.
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
493 */
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
494 if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
495 sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
496 sqlite3VdbeSetNumCols(v, 1);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
497 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
498 }
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
499
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
500 update_cleanup:
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
501 sqlite3AuthContextPop(&sContext);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
502 sqliteFree(apIdx);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
503 sqliteFree(aXRef);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
504 sqlite3SrcListDelete(pTabList);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
505 sqlite3ExprListDelete(pChanges);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
506 sqlite3ExprDelete(pWhere);
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
507 return;
b6b61becdf4e [svn] - add sqlite/ directory
nenolod
parents:
diff changeset
508 }