blob: 62c024118816b1189dfbb66a540bf340d1d8cf2a [file] [log] [blame]
drhcce7d172000-05-31 15:34:51 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drhcce7d172000-05-31 15:34:51 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drhcce7d172000-05-31 15:34:51 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
drhcce7d172000-05-31 15:34:51 +000010**
11*************************************************************************
12** This file contains C code routines that are called by the parser
13** to handle UPDATE statements.
14**
drhb19a2bc2001-09-16 00:13:26 +000015** $Id: update.c,v 1.14 2001/09/16 00:13:27 drh Exp $
drhcce7d172000-05-31 15:34:51 +000016*/
17#include "sqliteInt.h"
18
19/*
20** Process an UPDATE statement.
21*/
22void sqliteUpdate(
23 Parse *pParse, /* The parser context */
24 Token *pTableName, /* The table in which we should change things */
25 ExprList *pChanges, /* Things to be changed */
26 Expr *pWhere /* The WHERE clause. May be null */
27){
28 int i, j; /* Loop counters */
29 Table *pTab; /* The table to be updated */
30 IdList *pTabList = 0; /* List containing only pTab */
31 int end, addr; /* A couple of addresses in the generated code */
32 WhereInfo *pWInfo; /* Information about the WHERE clause */
33 Vdbe *v; /* The virtual database engine */
34 Index *pIdx; /* For looping over indices */
35 int nIdx; /* Number of indices that need updating */
drh4794b982000-06-06 13:54:14 +000036 int base; /* Index of first available table cursor */
drhcce7d172000-05-31 15:34:51 +000037 Index **apIdx = 0; /* An array of indices that need updating too */
38 int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
drh967e8b72000-06-21 13:59:10 +000039 ** an expression for the i-th column of the table.
40 ** aXRef[i]==-1 if the i-th column is not changed. */
drhcce7d172000-05-31 15:34:51 +000041
drhdaffd0e2001-04-11 14:28:42 +000042 if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
43
drhcce7d172000-05-31 15:34:51 +000044 /* Locate the table which we want to update. This table has to be
drh1ccde152000-06-17 13:12:39 +000045 ** put in an IdList structure because some of the subroutines we
drhcce7d172000-05-31 15:34:51 +000046 ** will be calling are designed to work with multiple tables and expect
47 ** an IdList* parameter instead of just a Table* parameger.
48 */
49 pTabList = sqliteIdListAppend(0, pTableName);
drhdaffd0e2001-04-11 14:28:42 +000050 if( pTabList==0 ) goto update_cleanup;
drhcce7d172000-05-31 15:34:51 +000051 for(i=0; i<pTabList->nId; i++){
52 pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
53 if( pTabList->a[i].pTab==0 ){
54 sqliteSetString(&pParse->zErrMsg, "no such table: ",
55 pTabList->a[i].zName, 0);
56 pParse->nErr++;
57 goto update_cleanup;
58 }
59 if( pTabList->a[i].pTab->readOnly ){
60 sqliteSetString(&pParse->zErrMsg, "table ", pTabList->a[i].zName,
61 " may not be modified", 0);
62 pParse->nErr++;
63 goto update_cleanup;
64 }
65 }
66 pTab = pTabList->a[0].pTab;
67 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
68 if( aXRef==0 ) goto update_cleanup;
69 for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
70
drh967e8b72000-06-21 13:59:10 +000071 /* Resolve the column names in all the expressions in both the
72 ** WHERE clause and in the new values. Also find the column index
73 ** for each column to be updated in the pChanges array.
drhcce7d172000-05-31 15:34:51 +000074 */
75 if( pWhere ){
drh4794b982000-06-06 13:54:14 +000076 sqliteExprResolveInSelect(pParse, pWhere);
77 }
78 for(i=0; i<pChanges->nExpr; i++){
79 sqliteExprResolveInSelect(pParse, pChanges->a[i].pExpr);
80 }
81 if( pWhere ){
drhcce7d172000-05-31 15:34:51 +000082 if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
83 goto update_cleanup;
84 }
85 if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
86 goto update_cleanup;
87 }
88 }
89 for(i=0; i<pChanges->nExpr; i++){
90 if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
91 goto update_cleanup;
92 }
93 if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
94 goto update_cleanup;
95 }
96 for(j=0; j<pTab->nCol; j++){
drh6206d502000-06-19 19:09:08 +000097 if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
drhcce7d172000-05-31 15:34:51 +000098 aXRef[j] = i;
99 break;
100 }
101 }
102 if( j>=pTab->nCol ){
drh967e8b72000-06-21 13:59:10 +0000103 sqliteSetString(&pParse->zErrMsg, "no such column: ",
drhcce7d172000-05-31 15:34:51 +0000104 pChanges->a[i].zName, 0);
105 pParse->nErr++;
106 goto update_cleanup;
107 }
108 }
109
110 /* Allocate memory for the array apIdx[] and fill it pointers to every
111 ** index that needs to be updated. Indices only need updating if their
drh967e8b72000-06-21 13:59:10 +0000112 ** key includes one of the columns named in pChanges.
drhcce7d172000-05-31 15:34:51 +0000113 */
114 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
drh967e8b72000-06-21 13:59:10 +0000115 for(i=0; i<pIdx->nColumn; i++){
116 if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
drhcce7d172000-05-31 15:34:51 +0000117 }
drh967e8b72000-06-21 13:59:10 +0000118 if( i<pIdx->nColumn ) nIdx++;
drhcce7d172000-05-31 15:34:51 +0000119 }
drhb0729502001-03-14 12:35:57 +0000120 if( nIdx>0 ){
121 apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
122 if( apIdx==0 ) goto update_cleanup;
123 }
drhcce7d172000-05-31 15:34:51 +0000124 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
drh967e8b72000-06-21 13:59:10 +0000125 for(i=0; i<pIdx->nColumn; i++){
126 if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
drhcce7d172000-05-31 15:34:51 +0000127 }
drh967e8b72000-06-21 13:59:10 +0000128 if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx;
drhcce7d172000-05-31 15:34:51 +0000129 }
130
131 /* Begin generating code.
132 */
drhd8bc7082000-06-07 23:51:50 +0000133 v = sqliteGetVdbe(pParse);
drhcce7d172000-05-31 15:34:51 +0000134 if( v==0 ) goto update_cleanup;
drh5e00f6c2001-09-13 13:46:56 +0000135 if( (pParse->db->flags & SQLITE_InTrans)==0 ){
136 sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
drh50e5dad2001-09-15 00:57:28 +0000137 sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
drh5e00f6c2001-09-13 13:46:56 +0000138 }
drhcce7d172000-05-31 15:34:51 +0000139
140 /* Begin the database scan
141 */
142 sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
143 pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
144 if( pWInfo==0 ) goto update_cleanup;
145
146 /* Remember the index of every item to be updated.
147 */
148 sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
149
150 /* End the database scan loop.
151 */
152 sqliteWhereEnd(pWInfo);
153
154 /* Rewind the list of records that need to be updated and
155 ** open every index that needs updating.
156 */
157 sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000158 base = pParse->nTab;
drh5e00f6c2001-09-13 13:46:56 +0000159 sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000160 for(i=0; i<nIdx; i++){
drh5e00f6c2001-09-13 13:46:56 +0000161 sqliteVdbeAddOp(v, OP_Open, base+i+1, apIdx[i]->tnum, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000162 }
163
164 /* Loop over every record that needs updating. We have to load
drh967e8b72000-06-21 13:59:10 +0000165 ** the old data for each record to be updated because some columns
drh1ccde152000-06-17 13:12:39 +0000166 ** might not change and we will need to copy the old value.
drhcce7d172000-05-31 15:34:51 +0000167 ** Also, the old data is needed to delete the old index entires.
168 */
169 end = sqliteVdbeMakeLabel(v);
170 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
171 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
drh5e00f6c2001-09-13 13:46:56 +0000172 sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000173
174 /* Delete the old indices for the current record.
175 */
176 for(i=0; i<nIdx; i++){
177 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
178 pIdx = apIdx[i];
drh967e8b72000-06-21 13:59:10 +0000179 for(j=0; j<pIdx->nColumn; j++){
drh5e00f6c2001-09-13 13:46:56 +0000180 sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j], 0, 0);
drhcce7d172000-05-31 15:34:51 +0000181 }
drh5e00f6c2001-09-13 13:46:56 +0000182 sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000183 sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000184 }
185
186 /* Compute a completely new data for this record.
187 */
188 for(i=0; i<pTab->nCol; i++){
189 j = aXRef[i];
190 if( j<0 ){
drh5e00f6c2001-09-13 13:46:56 +0000191 sqliteVdbeAddOp(v, OP_Column, base, i, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000192 }else{
193 sqliteExprCode(pParse, pChanges->a[j].pExpr);
194 }
195 }
196
197 /* Insert new index entries that correspond to the new data
198 */
199 for(i=0; i<nIdx; i++){
200 sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
201 pIdx = apIdx[i];
drh967e8b72000-06-21 13:59:10 +0000202 for(j=0; j<pIdx->nColumn; j++){
203 sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000204 }
drh5e00f6c2001-09-13 13:46:56 +0000205 sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000206 sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000207 }
208
209 /* Write the new data back into the database.
210 */
211 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000212 sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000213
214 /* Repeat the above with the next record to be updated, until
215 ** all record selected by the WHERE clause have been updated.
216 */
217 sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
218 sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
drh5e00f6c2001-09-13 13:46:56 +0000219 if( (pParse->db->flags & SQLITE_InTrans)==0 ){
220 sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
221 }
drhcce7d172000-05-31 15:34:51 +0000222
223update_cleanup:
224 sqliteFree(apIdx);
225 sqliteFree(aXRef);
226 sqliteIdListDelete(pTabList);
227 sqliteExprListDelete(pChanges);
228 sqliteExprDelete(pWhere);
229 return;
230}