Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Progress toward registerification of the constraint checking logic for INSERT and UPDATE. (CVS 4693) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b9bf509e39f5ac38c2149d2a648f68e5 |
User & Date: | drh 2008-01-08 02:57:56.000 |
Context
2008-01-08
| ||
15:18 | Add additional randomness to crash tests. (CVS 4694) (check-in: 3ccce1f58b user: drh tags: trunk) | |
02:57 | Progress toward registerification of the constraint checking logic for INSERT and UPDATE. (CVS 4693) (check-in: b9bf509e39 user: drh tags: trunk) | |
2008-01-07
| ||
19:20 | Registerify the AUTOINCREMENT processing and the OP_IsNull and OP_NotNull operators. (CVS 4692) (check-in: aa48867cfa user: drh tags: trunk) | |
Changes
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** ** $Id: delete.c,v 1.153 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
488 489 490 491 492 493 494 | ** 3. The "iCur" cursor must be pointing to the row that is to be ** deleted. */ void sqlite3GenerateRowIndexDelete( Vdbe *v, /* Generate code into this VDBE */ Table *pTab, /* Table containing the row to be deleted */ int iCur, /* Cursor number for the table */ | | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | ** 3. The "iCur" cursor must be pointing to the row that is to be ** deleted. */ void sqlite3GenerateRowIndexDelete( Vdbe *v, /* Generate code into this VDBE */ Table *pTab, /* Table containing the row to be deleted */ int iCur, /* Cursor number for the table */ int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ ){ int i; Index *pIdx; for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue; sqlite3GenerateIndexKey(v, pIdx, iCur); sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i); } } /* ** Generate code that will assemble an index key and put it on the top |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.337 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
1940 1941 1942 1943 1944 1945 1946 | ** the make process cause these values to align. Assert()s in the code ** below verify that the numbers are aligned correctly. */ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; int op; int inReg = 0; | < < < | 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 | ** the make process cause these values to align. Assert()s in the code ** below verify that the numbers are aligned correctly. */ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; int op; int inReg = 0; int origTarget = target; assert( v!=0 || pParse->db->mallocFailed ); if( v==0 ) return 0; if( target<0 ){ target = ++pParse->nMem; } if( pExpr==0 ){ op = TK_NULL; }else{ op = pExpr->op; } |
︙ | ︙ | |||
1975 1976 1977 1978 1979 1980 1981 | break; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ | | < | | 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | break; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ assert( pParse->ckBase>0 ); inReg = pExpr->iColumn + pParse->ckBase; }else{ sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target); inReg = target; } break; } |
︙ | ︙ | |||
2048 2049 2050 2051 2052 2053 2054 | to_op = aff - SQLITE_AFF_TEXT + OP_ToText; assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); sqlite3VdbeAddOp1(v, to_op, target); | < < | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 | to_op = aff - SQLITE_AFF_TEXT + OP_ToText; assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); sqlite3VdbeAddOp1(v, to_op, target); inReg = target; break; } #endif /* SQLITE_OMIT_CAST */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { assert( TK_LT==OP_Lt ); assert( TK_LE==OP_Le ); assert( TK_GT==OP_Gt ); assert( TK_GE==OP_Ge ); assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3ExprCode(pParse, pExpr->pRight, 0); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); break; } case TK_AND: case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: |
︙ | ︙ | |||
2095 2096 2097 2098 2099 2100 2101 | assert( TK_REM==OP_Remainder ); assert( TK_BITAND==OP_BitAnd ); assert( TK_BITOR==OP_BitOr ); assert( TK_SLASH==OP_Divide ); assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); | | | < < < | 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 | assert( TK_REM==OP_Remainder ); assert( TK_BITAND==OP_BitAnd ); assert( TK_BITOR==OP_BitOr ); assert( TK_SLASH==OP_Divide ); assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1); r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1); sqlite3VdbeAddOp3(v, op, r2, r1, target); inReg = target; break; } case TK_UMINUS: { Expr *pLeft = pExpr->pLeft; assert( pLeft ); if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ |
︙ | ︙ | |||
2125 2126 2127 2128 2129 2130 2131 | } case TK_BITNOT: case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3VdbeAddOp0(v, op); | < < | 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | } case TK_BITNOT: case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3VdbeAddOp0(v, op); break; } case TK_ISNULL: case TK_NOTNULL: { int addr; assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); sqlite3ExprCode(pParse, pExpr->pLeft, 0); addr = sqlite3VdbeAddOp0(v, op); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, addr); inReg = target; break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; if( pInfo==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", |
︙ | ︙ | |||
2203 2204 2205 2206 2207 2208 2209 | } if( pDef->needCollSeq ){ if( !pColl ) pColl = pParse->db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp4(v, OP_Function, constMask, nExpr, 0, (char*)pDef, P4_FUNCDEF); | < < < | 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 | } if( pDef->needCollSeq ){ if( !pColl ) pColl = pParse->db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp4(v, OP_Function, constMask, nExpr, 0, (char*)pDef, P4_FUNCDEF); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { if( pExpr->iColumn==0 ){ sqlite3CodeSubselect(pParse, pExpr); } inReg = pExpr->iColumn; /* sqlite3VdbeAddOp1(v, OP_SCopy, pExpr->iColumn); VdbeComment((v, "load subquery result")); */ break; } case TK_IN: { int j1, j2, j3, j4, j5; char affinity; int eType; eType = sqlite3FindInIndex(pParse, pExpr, 0); /* Figure out the affinity to use to create a key from the results ** of the expression. affinityStr stores a static string suitable for ** P4 of OP_MakeRecord. */ affinity = comparisonAffinity(pExpr); sqlite3VdbeAddOp1(v, OP_Integer, 1); /* Code the <expr> from "<expr> IN (...)". The temporary table ** pExpr->iTable contains the values that make up the (...) set. */ sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3VdbeAddOp0(v, OP_SCopy); j1 = sqlite3VdbeAddOp0(v, OP_NotNull); |
︙ | ︙ | |||
2278 2279 2280 2281 2282 2283 2284 | sqlite3ExprCode(pParse, pRight, 0); codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0); sqlite3VdbeAddOp0(v, OP_And); break; } case TK_UPLUS: { inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget); | < | 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 | sqlite3ExprCode(pParse, pRight, 0); codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0); sqlite3VdbeAddOp0(v, OP_And); break; } case TK_UPLUS: { inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget); break; } case TK_CASE: { int expr_end_label; int jumpInst; int nExpr; int i; |
︙ | ︙ | |||
2345 2346 2347 2348 2349 2350 2351 | (char*)pExpr->token.z, pExpr->token.n); } else { assert( pExpr->iColumn == OE_Ignore ); sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump); VdbeComment((v, "raise(IGNORE)")); } | < < < < < < | 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 | (char*)pExpr->token.z, pExpr->token.n); } else { assert( pExpr->iColumn == OE_Ignore ); sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump); VdbeComment((v, "raise(IGNORE)")); } break; } #endif } if( inReg!=target ){ if( origTarget!=-1 ){ sqlite3VdbeAddOp2(v, (inReg>0 ? OP_SCopy : OP_Move), inReg, target); }else{ target = inReg; } } return target; } #ifndef SQLITE_OMIT_TRIGGER /* ** Generate code that evalutes the given expression and leaves the result |
︙ | ︙ | |||
2439 2440 2441 2442 2443 2444 2445 | ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in ** the make process cause these values to align. Assert()s in the code ** below verify that the numbers are aligned correctly. */ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; | < | 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 | ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in ** the make process cause these values to align. Assert()s in the code ** below verify that the numbers are aligned correctly. */ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; if( v==0 || pExpr==0 ) return; op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 | } default: { sqlite3ExprCode(pParse, pExpr, 0); sqlite3VdbeAddOp2(v, OP_If, jumpIfNull, dest); break; } } | < < | 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 | } default: { sqlite3ExprCode(pParse, pExpr, 0); sqlite3VdbeAddOp2(v, OP_If, jumpIfNull, dest); break; } } } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is false but execution ** continues straight thru if the expression is true. ** ** If the expression evaluates to NULL (neither true nor false) then ** jump if jumpIfNull is true or fall through if jumpIfNull is false. */ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; if( v==0 || pExpr==0 ) return; /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op ** --------- ---------- ** TK_ISNULL OP_NotNull |
︙ | ︙ | |||
2625 2626 2627 2628 2629 2630 2631 | } default: { sqlite3ExprCode(pParse, pExpr, 0); sqlite3VdbeAddOp2(v, OP_IfNot, jumpIfNull, dest); break; } } | < | 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 | } default: { sqlite3ExprCode(pParse, pExpr, 0); sqlite3VdbeAddOp2(v, OP_IfNot, jumpIfNull, dest); break; } } } /* ** Do a deep comparison of two expression trees. Return TRUE (non-zero) ** if they are identical and return FALSE if they differ in any way. ** ** Sometimes this routine will return FALSE even if the two expressions |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.216 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" /* ** Set P4 of the most recently inserted opcode to a column affinity ** string for index pIdx. A column affinity string has one character ** for each column in the table, according to the affinity of the column: |
︙ | ︙ | |||
369 370 371 372 373 374 375 376 377 378 379 380 381 382 | int regFromSelect; /* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ int regRecord; /* Holds the assemblied row record */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ #endif | > | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | int regFromSelect; /* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ int regRecord; /* Holds the assemblied row record */ int *aRegIdx = 0; /* One register allocated to each index */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ #endif |
︙ | ︙ | |||
627 628 629 630 631 632 633 634 | if( db->flags & SQLITE_CountRows ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } /* If this is not a view, open the table and and all indices */ if( !isView ){ base = pParse->nTab; | > > > | > > > > > > > | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | if( db->flags & SQLITE_CountRows ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } /* If this is not a view, open the table and and all indices */ if( !isView ){ int nIdx; int i; base = pParse->nTab; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1)); if( aRegIdx==0 ){ goto insert_cleanup; } for(i=0; i<nIdx; i++){ aRegIdx[i] = ++pParse->nMem; } } /* If the data source is a temporary table, then we have to create ** a loop because there might be multiple rows of data. If the data ** source is a subroutine call from the SELECT statement, then we need ** to launch the SELECT statement processing. */ |
︙ | ︙ | |||
826 827 828 829 830 831 832 | pParse->pVirtualLock = pTab; sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, (const char*)pTab->pVtab, P4_VTAB); }else #endif { sqlite3RegToStack(pParse, regIns, pTab->nCol+1); | | | | 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 | pParse->pVirtualLock = pTab; sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, (const char*)pTab->pVtab, P4_VTAB); }else #endif { sqlite3RegToStack(pParse, regIns, pTab->nCol+1); sqlite3GenerateConstraintChecks(pParse, pTab, base, aRegIdx, keyColumn>=0, 0, onError, endOfLoop); sqlite3CompleteInsertion(pParse, pTab, base, aRegIdx,0,0, (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, appendFlag); } } /* Update the count of rows that are inserted */ |
︙ | ︙ | |||
891 892 893 894 895 896 897 898 899 900 901 902 903 904 | } insert_cleanup: sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pList); sqlite3SelectDelete(pSelect); sqlite3IdListDelete(pColumn); } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** When this routine is called, the stack contains (from bottom to top) ** the following values: | > | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | } insert_cleanup: sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pList); sqlite3SelectDelete(pSelect); sqlite3IdListDelete(pColumn); sqlite3_free(aRegIdx); } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** When this routine is called, the stack contains (from bottom to top) ** the following values: |
︙ | ︙ | |||
915 916 917 918 919 920 921 | ** ** N. The data in the last column of the entry after the update. ** ** The old rowid shown as entry (1) above is omitted unless both isUpdate ** and rowidChng are 1. isUpdate is true for UPDATEs and false for ** INSERTs and rowidChng is true if the record number is being changed. ** | | | > | < | | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 | ** ** N. The data in the last column of the entry after the update. ** ** The old rowid shown as entry (1) above is omitted unless both isUpdate ** and rowidChng are 1. isUpdate is true for UPDATEs and false for ** INSERTs and rowidChng is true if the record number is being changed. ** ** The code generated by this routine store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** attached to the table. ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, ** then the appropriate action is performed. There are five possible ** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. ** ** Constraint type Action What Happens |
︙ | ︙ | |||
964 965 966 967 968 969 970 | ** is used. Or if pParse->onError==OE_Default then the onError value ** for the constraint is used. ** ** The calling routine must open a read/write cursor for pTab with ** cursor number "base". All indices of pTab must also have open ** read/write cursors with cursor number base+i for the i-th cursor. ** Except, if there is no possibility of a REPLACE action then | | | | < < > > > > > > > > > | < > | < | < < | 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | ** is used. Or if pParse->onError==OE_Default then the onError value ** for the constraint is used. ** ** The calling routine must open a read/write cursor for pTab with ** cursor number "base". All indices of pTab must also have open ** read/write cursors with cursor number base+i for the i-th cursor. ** Except, if there is no possibility of a REPLACE action then ** cursors do not need to be open for indices where aRegIdx[i]==0. ** ** If the isUpdate flag is true, it means that the "base" cursor is ** initially pointing to an entry that is being updated. The isUpdate ** flag causes extra code to be generated so that the "base" cursor ** is still pointing at the same entry after the routine returns. ** Without the isUpdate flag, the "base" cursor might be moved. */ void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int rowidChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest /* Jump to this label on an OE_Ignore resolution */ ){ int i; Vdbe *v; int nCol; int onError; int j1, j2, j3; /* Address of jump instructions */ int iCur; Index *pIdx; int seenReplace = 0; int hasTwoRowids = (isUpdate && rowidChng); int regRowid, regData; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; /* Copy rowids and data into registers */ regRowid = sqlite3StackToReg(pParse, nCol+1+hasTwoRowids); sqlite3RegToStack(pParse, regRowid, nCol+1+hasTwoRowids); if( hasTwoRowids ) regRowid++; regData = regRowid+1; /* Test all NOT NULL constraints. */ for(i=0; i<nCol; i++){ if( i==pTab->iPKey ){ continue; } onError = pTab->aCol[i].notNull; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ onError = OE_Abort; } j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i); assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { char *zMsg = 0; sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError); sqlite3SetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName, " may not be NULL", (char*)0); sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); break; } case OE_Ignore: { sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); sqlite3VdbeAddOp2(v, OP_Copy, 0, regData+i); sqlite3VdbeAddOp1(v, OP_Push, nCol-i); break; } } sqlite3VdbeJumpHere(v, j1); } /* Test all CHECK constraints */ #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){ int allOk = sqlite3VdbeMakeLabel(v); pParse->ckBase = regData; sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; if( onError==OE_Ignore ){ sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); }else{ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError); } |
︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ | | | | < | | | | | < | < | | | | | > | | 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); j2 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0); } j3 = sqlite3VdbeAddOp3(v, OP_NotExists, base, 0, regRowid); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, "PRIMARY KEY must be unique", P4_STATIC); break; } case OE_Replace: { sqlite3GenerateRowIndexDelete(v, pTab, base, 0); if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } } sqlite3VdbeJumpHere(v, j3); if( isUpdate ){ sqlite3VdbeJumpHere(v, j2); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); for(i=0; i<pIdx->nColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); }else{ sqlite3VdbeAddOp1(v, OP_SCopy, regData+idx); } } j2 = sqlite3VdbeAddOp3(v, OP_MakeIdxRec, pIdx->nColumn, 0, aRegIdx[iCur]); sqlite3IndexAffinityStr(v, pIdx); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */ if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( seenReplace ){ if( onError==OE_Ignore ) onError = OE_Replace; else if( onError==OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); j3 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ case OE_Rollback: case OE_Abort: |
︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 | sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], pIdx->nColumn>1 ? " are not unique" : " is not unique"); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErrMsg,0); break; } case OE_Ignore: { assert( seenReplace==0 ); | | | > > | < | | | | 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], pIdx->nColumn>1 ? " are not unique" : " is not unique"); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErrMsg,0); break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Pop, nCol+3+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { int iRowid = sqlite3StackToReg(pParse, 1); sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0); if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } } sqlite3VdbeJumpHere(v, j3); sqlite3VdbeAddOp1(v, OP_Pop, 1); #if NULL_DISTINCT_FOR_UNIQUE sqlite3VdbeJumpHere(v, j2); #endif } } /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. ** The stack must contain keys for all active indices followed by data ** and the rowid for the new entry. This routine creates the new ** entries in all indices and in the main table. ** ** The arguments to this routine should be the same as the first six ** arguments to sqlite3GenerateConstraintChecks. */ void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int rowidChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int newIdx, /* Index of NEW table for triggers. -1 if none */ int appendBias /* True if this is likely to be an append */ ){ int i; Vdbe *v; int nIdx; Index *pIdx; int pik_flags; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ if( aRegIdx[i]==0 ) continue; sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, aRegIdx[i]); } sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ sqlite3VdbeAddOp1(v, OP_Copy, -1); sqlite3VdbeAddOp1(v, OP_Copy, -1); |
︙ | ︙ | |||
1283 1284 1285 1286 1287 1288 1289 1290 | } } /* ** Generate code that will open cursors for a table and for all ** indices of that table. The "base" parameter is the cursor number used ** for the table. Indices are opened on subsequent cursors. */ | > > | | > | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 | } } /* ** Generate code that will open cursors for a table and for all ** indices of that table. The "base" parameter is the cursor number used ** for the table. Indices are opened on subsequent cursors. ** ** Return the number of indices on the table. */ int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ Table *pTab, /* Table to be opened */ int base, /* Cursor number assigned to the table */ int op /* OP_OpenRead or OP_OpenWrite */ ){ int i; int iDb; Index *pIdx; Vdbe *v; if( IsVirtual(pTab) ) return 0; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); v = sqlite3GetVdbe(pParse); assert( v!=0 ); sqlite3OpenTable(pParse, base, iDb, pTab, op); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp4(v, op, i+base, pIdx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); } if( pParse->nTab<=base+i ){ pParse->nTab = base+i; } return i-1; } #ifdef SQLITE_TEST /* ** The following global variable is incremented whenever the ** transfer optimization is used. This is used for testing |
︙ | ︙ | |||
1610 1611 1612 1613 1614 1615 1616 | VdbeComment((v, "%s", pSrcIdx->zName)); pKey = sqlite3IndexKeyinfo(pParse, pDestIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest, (char*)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, 0); | | | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 | VdbeComment((v, "%s", pSrcIdx->zName)); pKey = sqlite3IndexKeyinfo(pParse, pDestIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest, (char*)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, 0); sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, 0, 1); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); sqlite3VdbeJumpHere(v, addr1); } sqlite3VdbeJumpHere(v, emptySrcTest); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); if( emptyDestTest ){ |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.642 2008/01/08 02:57:56 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds |
︙ | ︙ | |||
1385 1386 1387 1388 1389 1390 1391 | u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 parseError; /* True after a parsing error. Ticket #1794 */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int nSet; /* Number of sets used so far */ | | | 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 parseError; /* True after a parsing error. Ticket #1794 */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int nSet; /* Number of sets used so far */ int ckBase; /* Base register of data during check constraints */ u32 writeMask; /* Start a write transaction on these databases */ u32 cookieMask; /* Bitmask of schema verified databases */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ |
︙ | ︙ | |||
1770 1771 1772 1773 1774 1775 1776 | void sqlite3RollbackTransaction(Parse*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int); | | | | | | 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 | void sqlite3RollbackTransaction(Parse*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int); void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*); void sqlite3GenerateIndexKey(Vdbe*, Index*, int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int*,int,int,int,int); void sqlite3CompleteInsertion(Parse*, Table*, int, int*, int, int, int, int); int sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int); Expr *sqlite3ExprDup(sqlite3*,Expr*); void sqlite3TokenCopy(sqlite3*,Token*, Token*); ExprList *sqlite3ExprListDup(sqlite3*,ExprList*); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.163 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ |
︙ | ︙ | |||
86 87 88 89 90 91 92 | int i, j; /* Loop counters */ Table *pTab; /* The table to be updated */ int addr = 0; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ int nIdx; /* Number of indices that need updating */ | < | < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | int i, j; /* Loop counters */ Table *pTab; /* The table to be updated */ int addr = 0; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ int nIdx; /* Number of indices that need updating */ int iCur; /* VDBE Cursor number of pTab */ sqlite3 *db; /* The database structure */ int *aRegIdx = 0; /* One register assigned to each index to be updated */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ int chngRowid; /* True if the record number is being changed */ Expr *pRowidExpr = 0; /* Expression defining the new record number */ int openAll = 0; /* True if all indices need to be opened */ AuthContext sContext; /* The authorization context */ |
︙ | ︙ | |||
223 224 225 226 227 228 229 | }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } | | | | | | < < < < < < < < < | | | < | > | > | > > | | < < < < < > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } /* Allocate memory for the array aRegIdx[]. There is one entry in the ** array for each index associated with table being updated. Fill in ** the value with a register number for indices that are to be used ** and with zero for unused indices. */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} if( nIdx>0 ){ aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx ); if( aRegIdx==0 ) goto update_cleanup; } for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; if( chngRowid ){ reg = ++pParse->nMem; }else{ reg = 0; for(i=0; i<pIdx->nColumn; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ){ reg = ++pParse->nMem; break; } } } aRegIdx[j] = reg; } /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); |
︙ | ︙ | |||
376 377 378 379 380 381 382 | if( pIdx->onError==OE_Replace ){ openAll = 1; break; } } } for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | if( pIdx->onError==OE_Replace ){ openAll = 1; break; } } } for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aRegIdx[i]>0 ){ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); assert( pParse->nTab>iCur+i+1 ); } } } |
︙ | ︙ | |||
482 483 484 485 486 487 488 | }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, 0); } } /* Do constraint checks */ | | | | | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, 0); } } /* Do constraint checks */ sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aRegIdx, chngRowid, 1, onError, addr); /* Delete the old indices for the current record. */ sqlite3GenerateRowIndexDelete(v, pTab, iCur, aRegIdx); /* If changing the record number, delete the old record. */ if( chngRowid ){ sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0); } /* Create the new index entries and the new record. */ sqlite3CompleteInsertion(pParse, pTab, iCur, aRegIdx, chngRowid, 1, -1, 0); } /* Increment the row counter */ if( db->flags & SQLITE_CountRows && !pParse->trigStack){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } |
︙ | ︙ | |||
522 523 524 525 526 527 528 | ** all record selected by the WHERE clause have been updated. */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeJumpHere(v, addr); /* Close all tables */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | ** all record selected by the WHERE clause have been updated. */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeJumpHere(v, addr); /* Close all tables */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aRegIdx[i]>0 ){ sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0); } } sqlite3VdbeAddOp2(v, OP_Close, iCur, 0); if( triggers_exist ){ sqlite3VdbeAddOp2(v, OP_Close, newIdx, 0); sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0); |
︙ | ︙ | |||
545 546 547 548 549 550 551 | sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC); } update_cleanup: sqlite3AuthContextPop(&sContext); | | | 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC); } update_cleanup: sqlite3AuthContextPop(&sContext); sqlite3_free(aRegIdx); sqlite3_free(aXRef); sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pChanges); sqlite3ExprDelete(pWhere); return; } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.688 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
712 713 714 715 716 717 718 719 720 721 722 723 724 725 | nPop = 0; } pOut = &pTos[-nPop]; }else{ assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; } } } switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a | > > > > > > > > > > > > > > > > > > > > | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | nPop = 0; } pOut = &pTos[-nPop]; }else{ assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; } } }else if( (opProperty & OPFLG_IN2)!=0 ){ assert( pOp->p2>=0 ); if( pOp->p2==0 ){ pIn2 = pTos; nPop = 1; }else{ assert( pOp->p2<=p->nMem ); pIn2 = &p->aMem[pOp->p2]; REGISTER_TRACE(pOp->p2, pIn2); } }else if( (opProperty & OPFLG_IN3)!=0 ){ assert( pOp->p3>=0 ); if( pOp->p3==0 ){ pIn3 = pTos; nPop = 1; }else{ assert( pOp->p3<=p->nMem ); pIn3 = &p->aMem[pOp->p3]; REGISTER_TRACE(pOp->p3, pIn3); } } switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a |
︙ | ︙ | |||
4162 4163 4164 4165 4166 4167 4168 | }else{ pC->nullRow = 1; } pC->rowidIsValid = 0; break; } | | | | | | < | | | | | < < | | < | | < | | < < | 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 | }else{ pC->nullRow = 1; } pC->rowidIsValid = 0; break; } /* Opcode: IdxInsert P1 P2 P3 ** ** Register P2 holds a SQL index key made using the ** MakeIdxRec instructions. This opcode writes that key ** into the index P1. Data for the entry is nil. ** ** P3 is a flag that provides a hint to the b-tree layer that this ** insert is likely to be an append. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_IdxInsert: { /* no-push, in2 */ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( pIn2->flags & MEM_Blob ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc==SQLITE_OK ){ int nKey = pIn2->n; const char *zKey = pIn2->z; rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } } break; } /* Opcode: IdxDelete P1 P2 * ** ** The content of register P2 is an index key built using the either the ** MakeIdxRec opcode. Removes that entry from the index. */ case OP_IdxDelete: { /* no-push, in2 */ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pIn2->flags & MEM_Blob ); assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res; rc = sqlite3BtreeMoveto(pCrsr, pIn2->z, pIn2->n, 0, &res); if( rc==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } break; } /* Opcode: IdxRowid P1 P2 * * * ** ** Write into register P2 an integer which is the last entry in the record at ** the end of the index key pointed to by cursor P1. This integer should be |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 | pMem->n = sprintf(pMem->zShort, "%.2x", pOp->p5); /* P5 */ pMem->z = pMem->zShort; pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; pMem->flags = MEM_Null; /* Comment */ if( pOp->zComment ){ pMem->flags = MEM_Str|MEM_Term; pMem->z = pOp->zComment; pMem->n = strlen(pMem->z); pMem->enc = SQLITE_UTF8; } } p->nResColumn = 8 - 5*(p->explain-1); p->pTos = pMem; p->rc = SQLITE_OK; rc = SQLITE_ROW; } | > > | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | pMem->n = sprintf(pMem->zShort, "%.2x", pOp->p5); /* P5 */ pMem->z = pMem->zShort; pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; pMem->flags = MEM_Null; /* Comment */ #ifdef SQLITE_DEBUG if( pOp->zComment ){ pMem->flags = MEM_Str|MEM_Term; pMem->z = pOp->zComment; pMem->n = strlen(pMem->z); pMem->enc = SQLITE_UTF8; } #endif } p->nResColumn = 8 - 5*(p->explain-1); p->pTos = pMem; p->rc = SQLITE_OK; rc = SQLITE_ROW; } |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
525 526 527 528 529 530 531 | } memcpy(pTo, pFrom, sizeof(Mem)); if( pFrom->flags & MEM_Short ){ pTo->z = pTo->zShort; } pFrom->flags = MEM_Null; pFrom->xDel = 0; | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | } memcpy(pTo, pFrom, sizeof(Mem)); if( pFrom->flags & MEM_Short ){ pTo->z = pTo->zShort; } pFrom->flags = MEM_Null; pFrom->xDel = 0; if( 0 /* pTo->flags & MEM_Ephem */ ){ rc = sqlite3VdbeMemMakeWriteable(pTo); }else{ rc = SQLITE_OK; } return rc; } |
︙ | ︙ |