xref: /sqlite-3.40.0/src/update.c (revision 7c68d60b)
1 /*
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 **   [email protected]
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 **
27 ** $Id: update.c,v 1.8 2000/06/21 13:59:12 drh Exp $
28 */
29 #include "sqliteInt.h"
30 
31 /*
32 ** Process an UPDATE statement.
33 */
34 void 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 */
48   int base;              /* Index of first available table cursor */
49   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 column of the table.
52                          ** aXRef[i]==-1 if the i-th column 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 we
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 column names in all the expressions in both the
81   ** WHERE clause and in the new values.  Also find the column index
82   ** for each column to be updated in the pChanges array.
83   */
84   if( pWhere ){
85     sqliteExprResolveInSelect(pParse, pWhere);
86   }
87   for(i=0; i<pChanges->nExpr; i++){
88     sqliteExprResolveInSelect(pParse, pChanges->a[i].pExpr);
89   }
90   if( pWhere ){
91     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++){
106       if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
107         aXRef[j] = i;
108         break;
109       }
110     }
111     if( j>=pTab->nCol ){
112       sqliteSetString(&pParse->zErrMsg, "no such column: ",
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 columns named in pChanges.
122   */
123   for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
124     for(i=0; i<pIdx->nColumn; i++){
125       if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
126     }
127     if( i<pIdx->nColumn ) 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->nColumn; i++){
133       if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
134     }
135     if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx;
136   }
137 
138   /* Begin generating code.
139   */
140   v = sqliteGetVdbe(pParse);
141   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);
161   base = pParse->nTab;
162   sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
163   for(i=0; i<nIdx; i++){
164     sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
165   }
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 columns
169   ** might not change and we will need to copy the old value.
170   ** 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);
175   sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
176 
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->nColumn; j++){
183       sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
184     }
185     sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
186     sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
187   }
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 ){
194       sqliteVdbeAddOp(v, OP_Field, base, i, 0, 0);
195     }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->nColumn; j++){
206       sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0, 0, 0);
207     }
208     sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
209     sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
210   }
211 
212   /* Write the new data back into the database.
213   */
214   sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
215   sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0);
216 
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 
223 update_cleanup:
224   sqliteFree(apIdx);
225   sqliteFree(aXRef);
226   sqliteIdListDelete(pTabList);
227   sqliteExprListDelete(pChanges);
228   sqliteExprDelete(pWhere);
229   return;
230 }
231