blob: ca114254188cc9a77bc54533a659d2be81d2c228 [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**
drh4794b982000-06-06 13:54:14 +000027** $Id: update.c,v 1.4 2000/06/06 13:54:16 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
55 ** put in an IdList structure because some of the subroutines will
56 ** 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 pChanges->a[i].idx = j;
108 aXRef[j] = i;
109 break;
110 }
111 }
112 if( j>=pTab->nCol ){
113 sqliteSetString(&pParse->zErrMsg, "no such field: ",
114 pChanges->a[i].zName, 0);
115 pParse->nErr++;
116 goto update_cleanup;
117 }
118 }
119
120 /* Allocate memory for the array apIdx[] and fill it pointers to every
121 ** index that needs to be updated. Indices only need updating if their
122 ** key includes one of the fields named in pChanges.
123 */
124 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
125 for(i=0; i<pIdx->nField; i++){
126 if( aXRef[pIdx->aiField[i]]>=0 ) break;
127 }
128 if( i<pIdx->nField ) nIdx++;
129 }
130 apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
131 if( apIdx==0 ) goto update_cleanup;
132 for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
133 for(i=0; i<pIdx->nField; i++){
134 if( aXRef[pIdx->aiField[i]]>=0 ) break;
135 }
136 if( i<pIdx->nField ) apIdx[nIdx++] = pIdx;
137 }
138
139 /* Begin generating code.
140 */
141 v = pParse->pVdbe;
142 if( v==0 ){
143 v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
144 }
145 if( v==0 ) goto update_cleanup;
146
147 /* Begin the database scan
148 */
149 sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
150 pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
151 if( pWInfo==0 ) goto update_cleanup;
152
153 /* Remember the index of every item to be updated.
154 */
155 sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
156
157 /* End the database scan loop.
158 */
159 sqliteWhereEnd(pWInfo);
160
161 /* Rewind the list of records that need to be updated and
162 ** open every index that needs updating.
163 */
164 sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000165 base = pParse->nTab;
166 sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
drhcce7d172000-05-31 15:34:51 +0000167 for(i=0; i<nIdx; i++){
drh4794b982000-06-06 13:54:14 +0000168 sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
drhcce7d172000-05-31 15:34:51 +0000169 }
170
171 /* Loop over every record that needs updating. We have to load
172 ** the old data for each record to be updated because some fields
173 ** might not change and we will need to copy the old value, therefore.
174 ** Also, the old data is needed to delete the old index entires.
175 */
176 end = sqliteVdbeMakeLabel(v);
177 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
178 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000179 sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000180
181 /* Delete the old indices for the current record.
182 */
183 for(i=0; i<nIdx; i++){
184 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
185 pIdx = apIdx[i];
186 for(j=0; j<pIdx->nField; j++){
drh4794b982000-06-06 13:54:14 +0000187 sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0);
drhcce7d172000-05-31 15:34:51 +0000188 }
189 sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000190 sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000191 }
192
193 /* Compute a completely new data for this record.
194 */
195 for(i=0; i<pTab->nCol; i++){
196 j = aXRef[i];
197 if( j<0 ){
drh4794b982000-06-06 13:54:14 +0000198 sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000199 }else{
200 sqliteExprCode(pParse, pChanges->a[j].pExpr);
201 }
202 }
203
204 /* Insert new index entries that correspond to the new data
205 */
206 for(i=0; i<nIdx; i++){
207 sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
208 pIdx = apIdx[i];
209 for(j=0; j<pIdx->nField; j++){
210 sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
211 }
212 sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000213 sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000214 }
215
216 /* Write the new data back into the database.
217 */
218 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000219 sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000220
221 /* Repeat the above with the next record to be updated, until
222 ** all record selected by the WHERE clause have been updated.
223 */
224 sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
225 sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
226
227update_cleanup:
228 sqliteFree(apIdx);
229 sqliteFree(aXRef);
230 sqliteIdListDelete(pTabList);
231 sqliteExprListDelete(pChanges);
232 sqliteExprDelete(pWhere);
233 return;
234}