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