blob: 15c7bbf754545f8cbca5adf5628052baafb2f547 [file] [log] [blame]
drhcce7d172000-05-31 15:34:51 +00001/*
2** Copyright (c) 1999, 2000 D. Richard Hipp
3**
4** This program is free software; you can redistribute it and/or
5** modify it under the terms of the GNU General Public
6** License as published by the Free Software Foundation; either
7** version 2 of the License, or (at your option) any later version.
8**
9** This program is distributed in the hope that it will be useful,
10** but WITHOUT ANY WARRANTY; without even the implied warranty of
11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12** General Public License for more details.
13**
14** You should have received a copy of the GNU General Public
15** License along with this library; if not, write to the
16** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17** Boston, MA 02111-1307, USA.
18**
19** Author contact information:
20** drh@hwaci.com
21** http://www.hwaci.com/drh/
22**
23*************************************************************************
24** This file contains C code routines that are called by the parser
25** to handle UPDATE statements.
26**
drh1ccde152000-06-17 13:12:39 +000027** $Id: update.c,v 1.6 2000/06/17 13:12:40 drh Exp $
drhcce7d172000-05-31 15:34:51 +000028*/
29#include "sqliteInt.h"
30
31/*
32** Process an UPDATE statement.
33*/
34void sqliteUpdate(
35 Parse *pParse, /* The parser context */
36 Token *pTableName, /* The table in which we should change things */
37 ExprList *pChanges, /* Things to be changed */
38 Expr *pWhere /* The WHERE clause. May be null */
39){
40 int i, j; /* Loop counters */
41 Table *pTab; /* The table to be updated */
42 IdList *pTabList = 0; /* List containing only pTab */
43 int end, addr; /* A couple of addresses in the generated code */
44 WhereInfo *pWInfo; /* Information about the WHERE clause */
45 Vdbe *v; /* The virtual database engine */
46 Index *pIdx; /* For looping over indices */
47 int nIdx; /* Number of indices that need updating */
drh4794b982000-06-06 13:54:14 +000048 int base; /* Index of first available table cursor */
drhcce7d172000-05-31 15:34:51 +000049 Index **apIdx = 0; /* An array of indices that need updating too */
50 int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
51 ** an expression for the i-th field of the table.
52 ** aXRef[i]==-1 if the i-th field is not changed. */
53
54 /* Locate the table which we want to update. This table has to be
drh1ccde152000-06-17 13:12:39 +000055 ** put in an IdList structure because some of the subroutines we
drhcce7d172000-05-31 15:34:51 +000056 ** will be calling are designed to work with multiple tables and expect
57 ** an IdList* parameter instead of just a Table* parameger.
58 */
59 pTabList = sqliteIdListAppend(0, pTableName);
60 for(i=0; i<pTabList->nId; i++){
61 pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
62 if( pTabList->a[i].pTab==0 ){
63 sqliteSetString(&pParse->zErrMsg, "no such table: ",
64 pTabList->a[i].zName, 0);
65 pParse->nErr++;
66 goto update_cleanup;
67 }
68 if( pTabList->a[i].pTab->readOnly ){
69 sqliteSetString(&pParse->zErrMsg, "table ", pTabList->a[i].zName,
70 " may not be modified", 0);
71 pParse->nErr++;
72 goto update_cleanup;
73 }
74 }
75 pTab = pTabList->a[0].pTab;
76 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
77 if( aXRef==0 ) goto update_cleanup;
78 for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
79
80 /* Resolve the field names in all the expressions in both the
81 ** WHERE clause and in the new values. Also find the field index
82 ** for each field to be updated in the pChanges array.
83 */
84 if( pWhere ){
drh4794b982000-06-06 13:54:14 +000085 sqliteExprResolveInSelect(pParse, pWhere);
86 }
87 for(i=0; i<pChanges->nExpr; i++){
88 sqliteExprResolveInSelect(pParse, pChanges->a[i].pExpr);
89 }
90 if( pWhere ){
drhcce7d172000-05-31 15:34:51 +000091 if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
92 goto update_cleanup;
93 }
94 if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
95 goto update_cleanup;
96 }
97 }
98 for(i=0; i<pChanges->nExpr; i++){
99 if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
100 goto update_cleanup;
101 }
102 if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
103 goto update_cleanup;
104 }
105 for(j=0; j<pTab->nCol; j++){
drh7020f652000-06-03 18:06:52 +0000106 if( strcmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
drhcce7d172000-05-31 15:34:51 +0000107 aXRef[j] = i;
108 break;
109 }
110 }
111 if( j>=pTab->nCol ){
112 sqliteSetString(&pParse->zErrMsg, "no such field: ",
113 pChanges->a[i].zName, 0);
114 pParse->nErr++;
115 goto update_cleanup;
116 }
117 }
118
119 /* Allocate memory for the array apIdx[] and fill it pointers to every
120 ** index that needs to be updated. Indices only need updating if their
121 ** key includes one of the fields named in pChanges.
122 */
123 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
124 for(i=0; i<pIdx->nField; i++){
125 if( aXRef[pIdx->aiField[i]]>=0 ) break;
126 }
127 if( i<pIdx->nField ) nIdx++;
128 }
129 apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
130 if( apIdx==0 ) goto update_cleanup;
131 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
132 for(i=0; i<pIdx->nField; i++){
133 if( aXRef[pIdx->aiField[i]]>=0 ) break;
134 }
135 if( i<pIdx->nField ) apIdx[nIdx++] = pIdx;
136 }
137
138 /* Begin generating code.
139 */
drhd8bc7082000-06-07 23:51:50 +0000140 v = sqliteGetVdbe(pParse);
drhcce7d172000-05-31 15:34:51 +0000141 if( v==0 ) goto update_cleanup;
142
143 /* Begin the database scan
144 */
145 sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
146 pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
147 if( pWInfo==0 ) goto update_cleanup;
148
149 /* Remember the index of every item to be updated.
150 */
151 sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
152
153 /* End the database scan loop.
154 */
155 sqliteWhereEnd(pWInfo);
156
157 /* Rewind the list of records that need to be updated and
158 ** open every index that needs updating.
159 */
160 sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000161 base = pParse->nTab;
162 sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
drhcce7d172000-05-31 15:34:51 +0000163 for(i=0; i<nIdx; i++){
drh4794b982000-06-06 13:54:14 +0000164 sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
drhcce7d172000-05-31 15:34:51 +0000165 }
166
167 /* Loop over every record that needs updating. We have to load
168 ** the old data for each record to be updated because some fields
drh1ccde152000-06-17 13:12:39 +0000169 ** might not change and we will need to copy the old value.
drhcce7d172000-05-31 15:34:51 +0000170 ** Also, the old data is needed to delete the old index entires.
171 */
172 end = sqliteVdbeMakeLabel(v);
173 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
174 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000175 sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000176
177 /* Delete the old indices for the current record.
178 */
179 for(i=0; i<nIdx; i++){
180 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
181 pIdx = apIdx[i];
182 for(j=0; j<pIdx->nField; j++){
drh4794b982000-06-06 13:54:14 +0000183 sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0);
drhcce7d172000-05-31 15:34:51 +0000184 }
185 sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000186 sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000187 }
188
189 /* Compute a completely new data for this record.
190 */
191 for(i=0; i<pTab->nCol; i++){
192 j = aXRef[i];
193 if( j<0 ){
drh4794b982000-06-06 13:54:14 +0000194 sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000195 }else{
196 sqliteExprCode(pParse, pChanges->a[j].pExpr);
197 }
198 }
199
200 /* Insert new index entries that correspond to the new data
201 */
202 for(i=0; i<nIdx; i++){
203 sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
204 pIdx = apIdx[i];
205 for(j=0; j<pIdx->nField; j++){
206 sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
207 }
208 sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000209 sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000210 }
211
212 /* Write the new data back into the database.
213 */
214 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000215 sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000216
217 /* Repeat the above with the next record to be updated, until
218 ** all record selected by the WHERE clause have been updated.
219 */
220 sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
221 sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
222
223update_cleanup:
224 sqliteFree(apIdx);
225 sqliteFree(aXRef);
226 sqliteIdListDelete(pTabList);
227 sqliteExprListDelete(pChanges);
228 sqliteExprDelete(pWhere);
229 return;
230}