blob: 2b5c444d61cdaba372a96ff7df57defcbbac1072 [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**
drhd8bc7082000-06-07 23:51:50 +000027** $Id: update.c,v 1.5 2000/06/07 23:51:51 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 ){
drhd8bc7082000-06-07 23:51:50 +0000107 /* pChanges->a[i].idx = j; */
drhcce7d172000-05-31 15:34:51 +0000108 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 */
drhd8bc7082000-06-07 23:51:50 +0000141 v = sqliteGetVdbe(pParse);
drhcce7d172000-05-31 15:34:51 +0000142 if( v==0 ) goto update_cleanup;
143
144 /* Begin the database scan
145 */
146 sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
147 pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
148 if( pWInfo==0 ) goto update_cleanup;
149
150 /* Remember the index of every item to be updated.
151 */
152 sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
153
154 /* End the database scan loop.
155 */
156 sqliteWhereEnd(pWInfo);
157
158 /* Rewind the list of records that need to be updated and
159 ** open every index that needs updating.
160 */
161 sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000162 base = pParse->nTab;
163 sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
drhcce7d172000-05-31 15:34:51 +0000164 for(i=0; i<nIdx; i++){
drh4794b982000-06-06 13:54:14 +0000165 sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
drhcce7d172000-05-31 15:34:51 +0000166 }
167
168 /* Loop over every record that needs updating. We have to load
169 ** the old data for each record to be updated because some fields
170 ** might not change and we will need to copy the old value, therefore.
171 ** Also, the old data is needed to delete the old index entires.
172 */
173 end = sqliteVdbeMakeLabel(v);
174 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
175 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000176 sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000177
178 /* Delete the old indices for the current record.
179 */
180 for(i=0; i<nIdx; i++){
181 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
182 pIdx = apIdx[i];
183 for(j=0; j<pIdx->nField; j++){
drh4794b982000-06-06 13:54:14 +0000184 sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0);
drhcce7d172000-05-31 15:34:51 +0000185 }
186 sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000187 sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000188 }
189
190 /* Compute a completely new data for this record.
191 */
192 for(i=0; i<pTab->nCol; i++){
193 j = aXRef[i];
194 if( j<0 ){
drh4794b982000-06-06 13:54:14 +0000195 sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000196 }else{
197 sqliteExprCode(pParse, pChanges->a[j].pExpr);
198 }
199 }
200
201 /* Insert new index entries that correspond to the new data
202 */
203 for(i=0; i<nIdx; i++){
204 sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
205 pIdx = apIdx[i];
206 for(j=0; j<pIdx->nField; j++){
207 sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0);
208 }
209 sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000210 sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000211 }
212
213 /* Write the new data back into the database.
214 */
215 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
drh4794b982000-06-06 13:54:14 +0000216 sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000217
218 /* Repeat the above with the next record to be updated, until
219 ** all record selected by the WHERE clause have been updated.
220 */
221 sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
222 sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
223
224update_cleanup:
225 sqliteFree(apIdx);
226 sqliteFree(aXRef);
227 sqliteIdListDelete(pTabList);
228 sqliteExprListDelete(pChanges);
229 sqliteExprDelete(pWhere);
230 return;
231}