Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | NULL values are distinct. A comparison involving a NULL is always false. Operations on a NULL value yield a NULL result. This change makes SQLite operate more like the SQL spec, but it may break existing applications that assumed the old behavior. All the old tests pass but we still need to add new tests to better verify the new behavior. Fix for ticket #44. (CVS 589) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9051173742f1b0e15a809d12a0c9c98f |
User & Date: | drh 2002-05-26 20:54:33.000 |
Context
2002-05-26
| ||
21:34 | Change functions to handle NULLs correctly. Added the NULLIF() function. (CVS 590) (check-in: 46ce1a9ab6 user: drh tags: trunk) | |
20:54 | NULL values are distinct. A comparison involving a NULL is always false. Operations on a NULL value yield a NULL result. This change makes SQLite operate more like the SQL spec, but it may break existing applications that assumed the old behavior. All the old tests pass but we still need to add new tests to better verify the new behavior. Fix for ticket #44. (CVS 589) (check-in: 9051173742 user: drh tags: trunk) | |
2002-05-25
| ||
00:18 | Additional testing of LEFT OUTER JOIN. (CVS 588) (check-in: d8d04c14f1 user: drh tags: trunk) | |
Changes
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.64 2002/05/26 20:54:33 drh Exp $ */ #include "sqliteInt.h" /* ** Construct a new expression node and return a pointer to it. Memory ** for this node is obtained from sqliteMalloc(). The calling function |
︙ | ︙ | |||
814 815 816 817 818 819 820 | case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: case TK_REM: case TK_BITAND: case TK_BITOR: | | > > > > > > < < < < < < < < < < < < < < < | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: case TK_REM: case TK_BITAND: case TK_BITOR: case TK_SLASH: case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pRight); sqliteVdbeAddOp(v, op, 0, 0); break; } case TK_LSHIFT: case TK_RSHIFT: { sqliteExprCode(pParse, pExpr->pRight); sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, op, 0, 0); break; } case TK_CONCAT: { sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pRight); sqliteVdbeAddOp(v, OP_Concat, 2, 0); break; } case TK_UMINUS: { assert( pExpr->pLeft ); if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){ Token *p = &pExpr->pLeft->token; char *z = sqliteMalloc( p->n + 2 ); sprintf(z, "-%.*s", p->n, p->z); if( pExpr->pLeft->op==TK_INTEGER ){ |
︙ | ︙ | |||
877 878 879 880 881 882 883 | } case TK_ISNULL: case TK_NOTNULL: { int dest; sqliteVdbeAddOp(v, OP_Integer, 1, 0); sqliteExprCode(pParse, pExpr->pLeft); dest = sqliteVdbeCurrentAddr(v) + 2; | | | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | } case TK_ISNULL: case TK_NOTNULL: { int dest; sqliteVdbeAddOp(v, OP_Integer, 1, 0); sqliteExprCode(pParse, pExpr->pLeft); dest = sqliteVdbeCurrentAddr(v) + 2; sqliteVdbeAddOp(v, op, 1, dest); sqliteVdbeAddOp(v, OP_AddImm, -1, 0); break; } case TK_AGG_FUNCTION: { sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); break; } |
︙ | ︙ | |||
909 910 911 912 913 914 915 916 | break; } case TK_IN: { int addr; sqliteVdbeAddOp(v, OP_Integer, 1, 0); sqliteExprCode(pParse, pExpr->pLeft); addr = sqliteVdbeCurrentAddr(v); if( pExpr->pSelect ){ | > > > > | | > > > | | | | | > > > | > | > > | < | < | | < | | > > > > > | | > | < < | | < | | | > > > > > > > | | | | | | | | > > > > > | | | | | > > > | | | | | | | | > > > > > | | | | 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 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 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 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 | break; } case TK_IN: { int addr; sqliteVdbeAddOp(v, OP_Integer, 1, 0); sqliteExprCode(pParse, pExpr->pLeft); addr = sqliteVdbeCurrentAddr(v); sqliteVdbeAddOp(v, OP_NotNull, -1, addr+4); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr+6); if( pExpr->pSelect ){ sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, addr+6); }else{ sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+6); } sqliteVdbeAddOp(v, OP_AddImm, -1, 0); break; } case TK_BETWEEN: { sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteExprCode(pParse, pExpr->pList->a[0].pExpr); sqliteVdbeAddOp(v, OP_Ge, 0, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteExprCode(pParse, pExpr->pList->a[1].pExpr); sqliteVdbeAddOp(v, OP_Le, 0, 0); sqliteVdbeAddOp(v, OP_And, 0, 0); break; } case TK_AS: { sqliteExprCode(pParse, pExpr->pLeft); break; } case TK_CASE: { int expr_end_label; int null_result_label; int jumpInst; int addr; int nExpr; int i; assert(pExpr->pList); assert((pExpr->pList->nExpr % 2) == 0); assert(pExpr->pList->nExpr > 0); nExpr = pExpr->pList->nExpr; expr_end_label = sqliteVdbeMakeLabel(v); null_result_label = sqliteVdbeMakeLabel(v); if( pExpr->pLeft ){ sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, OP_IsNull, -1, expr_end_label); } for(i=0; i<nExpr; i=i+2){ sqliteExprCode(pParse, pExpr->pList->a[i].pExpr); sqliteVdbeAddOp(v, OP_IsNull, -1, null_result_label); if( pExpr->pLeft ){ sqliteVdbeAddOp(v, OP_Dup, 1, 1); jumpInst = sqliteVdbeAddOp(v, OP_Ne, 0, 0); }else{ jumpInst = sqliteVdbeAddOp(v, OP_IfNot, 0, 0); } sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr); sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label); if( i>=nExpr-2 ){ sqliteVdbeResolveLabel(v, null_result_label); sqliteVdbeAddOp(v, OP_Pop, 1, 0); if( pExpr->pRight!=0 ){ sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label); } } addr = sqliteVdbeCurrentAddr(v); sqliteVdbeChangeP2(v, jumpInst, addr); } if( pExpr->pRight ){ sqliteExprCode(pParse, pExpr->pRight); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0); } sqliteVdbeResolveLabel(v, expr_end_label); if( pExpr->pLeft ){ sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_Pop, 1, 0); } } break; } } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is true but execution ** continues straight thru if the expression is false. ** ** If the expression evaluates to NULL (neither true nor false), then ** take the jump if the jumpIfNull flag is true. */ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; if( v==0 || pExpr==0 ) return; switch( pExpr->op ){ case TK_LT: op = OP_Lt; break; case TK_LE: op = OP_Le; break; case TK_GT: op = OP_Gt; break; case TK_GE: op = OP_Ge; break; case TK_NE: op = OP_Ne; break; case TK_EQ: op = OP_Eq; break; case TK_ISNULL: op = OP_IsNull; break; case TK_NOTNULL: op = OP_NotNull; break; default: break; } switch( pExpr->op ){ case TK_AND: { int d2 = sqliteVdbeMakeLabel(v); sqliteExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull); sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqliteVdbeResolveLabel(v, d2); break; } case TK_OR: { sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); break; } case TK_NOT: { sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pRight); sqliteVdbeAddOp(v, op, jumpIfNull, dest); break; } case TK_ISNULL: case TK_NOTNULL: { sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, op, 1, dest); break; } case TK_IN: { int addr; sqliteExprCode(pParse, pExpr->pLeft); addr = sqliteVdbeCurrentAddr(v); sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4); if( pExpr->pSelect ){ sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, dest); }else{ sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, dest); } break; } case TK_BETWEEN: { int addr; sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteExprCode(pParse, pExpr->pList->a[0].pExpr); addr = sqliteVdbeAddOp(v, OP_Lt, !jumpIfNull, 0); sqliteExprCode(pParse, pExpr->pList->a[1].pExpr); sqliteVdbeAddOp(v, OP_Le, jumpIfNull, dest); sqliteVdbeAddOp(v, OP_Integer, 0, 0); sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); sqliteVdbeAddOp(v, OP_Pop, 1, 0); break; } default: { sqliteExprCode(pParse, pExpr); sqliteVdbeAddOp(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 sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; if( v==0 || pExpr==0 ) return; switch( pExpr->op ){ case TK_LT: op = OP_Ge; break; case TK_LE: op = OP_Gt; break; case TK_GT: op = OP_Le; break; case TK_GE: op = OP_Lt; break; case TK_NE: op = OP_Eq; break; case TK_EQ: op = OP_Ne; break; case TK_ISNULL: op = OP_NotNull; break; case TK_NOTNULL: op = OP_IsNull; break; default: break; } switch( pExpr->op ){ case TK_AND: { sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); break; } case TK_OR: { int d2 = sqliteVdbeMakeLabel(v); sqliteExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull); sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqliteVdbeResolveLabel(v, d2); break; } case TK_NOT: { sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pRight); sqliteVdbeAddOp(v, op, jumpIfNull, dest); break; } case TK_ISNULL: case TK_NOTNULL: { sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, op, 1, dest); break; } case TK_IN: { int addr; sqliteExprCode(pParse, pExpr->pLeft); addr = sqliteVdbeCurrentAddr(v); sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4); if( pExpr->pSelect ){ sqliteVdbeAddOp(v, OP_NotFound, pExpr->iTable, dest); }else{ sqliteVdbeAddOp(v, OP_SetNotFound, pExpr->iTable, dest); } break; } case TK_BETWEEN: { int addr; sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteExprCode(pParse, pExpr->pList->a[0].pExpr); addr = sqliteVdbeCurrentAddr(v); sqliteVdbeAddOp(v, OP_Ge, !jumpIfNull, addr+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, dest); sqliteExprCode(pParse, pExpr->pList->a[1].pExpr); sqliteVdbeAddOp(v, OP_Gt, jumpIfNull, dest); break; } default: { sqliteExprCode(pParse, pExpr); sqliteVdbeAddOp(v, OP_Not, 0, 0); sqliteVdbeAddOp(v, OP_If, jumpIfNull, dest); break; } } } /* ** Do a deep comparison of two expression trees. Return TRUE (non-zero) |
︙ | ︙ |
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.59 2002/05/26 20:54:33 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) |
︙ | ︙ | |||
286 287 288 289 290 291 292 | ** case the record number is the same as that column. */ if( !pTab->pSelect ){ if( keyColumn>=0 ){ if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); }else{ | < < | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | ** case the record number is the same as that column. */ if( !pTab->pSelect ){ if( keyColumn>=0 ){ if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); }else{ sqliteExprCode(pParse, pList->a[keyColumn].pExpr); /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno ** to generate a unique primary key value. */ sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_NewRecno, base, 0); } sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); }else{ sqliteVdbeAddOp(v, OP_NewRecno, base, 0); } |
︙ | ︙ | |||
495 496 497 498 499 500 501 | int nCol; int onError; int addr; int extra; int iCur; Index *pIdx; int seenReplace = 0; | | | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | int nCol; int onError; int addr; int extra; int iCur; Index *pIdx; int seenReplace = 0; int jumpInst1, jumpInst2; int contAddr; int hasTwoRecnos = (isUpdate && recnoChng); v = sqliteGetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; |
︙ | ︙ | |||
523 524 525 526 527 528 529 | onError = pParse->db->onError; if( onError==OE_Default ) onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){ onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); | | | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | onError = pParse->db->onError; if( onError==OE_Default ) onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){ onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); break; } |
︙ | ︙ | |||
561 562 563 564 565 566 567 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = pParse->db->onError; if( onError==OE_Default ) onError = OE_Abort; } if( onError!=OE_Replace ){ | < | | | | | | | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = pParse->db->onError; if( onError==OE_Default ) onError = OE_Abort; } if( onError!=OE_Replace ){ if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); } sqliteVdbeAddOp(v, OP_Dup, nCol, 1); jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); break; } case OE_Ignore: { sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } default: assert(0); } contAddr = sqliteVdbeCurrentAddr(v); sqliteVdbeChangeP2(v, jumpInst2, contAddr); if( isUpdate ){ sqliteVdbeChangeP2(v, jumpInst1, contAddr); sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } } } extra = 0; for(extra=(-1), iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; extra++; sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1); for(i=0; i<pIdx->nColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1); }else{ sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); } } jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); onError = pIdx->onError; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = pParse->db->onError; if( onError==OE_Default ) onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); break; } |
︙ | ︙ | |||
641 642 643 644 645 646 647 | } seenReplace = 1; break; } default: assert(0); } contAddr = sqliteVdbeCurrentAddr(v); | | > | 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | } seenReplace = 1; break; } default: assert(0); } contAddr = sqliteVdbeCurrentAddr(v); sqliteVdbeChangeP2(v, jumpInst1, contAddr); sqliteVdbeChangeP2(v, jumpInst2, contAddr); } } /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqliteGenerateConstraintChecks. ** The stack must contain keys for all active indices followed by data |
︙ | ︙ |
Changes to src/select.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 SELECT 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 SELECT statements in SQLite. ** ** $Id: select.c,v 1.86 2002/05/26 20:54:34 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
321 322 323 324 325 326 327 | } } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ | | | | < | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | } } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( distinct>=0 && pEList && pEList->nExpr>0 ){ sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7); sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1); sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, distinct, 0); } /* If there is an ORDER BY clause, then store the results ** in a sorter. */ |
︙ | ︙ | |||
355 356 357 358 359 360 361 | sqliteVdbeAddOp(v, OP_SortPut, 0, 0); }else /* In this mode, write each query result to the key of the temporary ** table iParm. */ if( eDest==SRT_Union ){ | | | | > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | sqliteVdbeAddOp(v, OP_SortPut, 0, 0); }else /* In this mode, write each query result to the key of the temporary ** table iParm. */ if( eDest==SRT_Union ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 1); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); }else /* Store the result as data using a unique key. */ if( eDest==SRT_Table || eDest==SRT_TempTable ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0); }else /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from ** the temporary table iParm. */ if( eDest==SRT_Except ){ int addr = sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 1); sqliteVdbeAddOp(v, OP_NotFound, iParm, addr+3); sqliteVdbeAddOp(v, OP_Delete, iParm, 0); }else /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ if( eDest==SRT_Set ){ assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_IsNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); }else /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out |
︙ | ︙ | |||
1734 1735 1736 1737 1738 1739 1740 | */ if( isAgg ){ int endagg = sqliteVdbeMakeLabel(v); int startagg; startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg); pParse->useAgg = 1; if( pHaving ){ | | | 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 | */ if( isAgg ){ int endagg = sqliteVdbeMakeLabel(v); int startagg; startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg); pParse->useAgg = 1; if( pHaving ){ sqliteExprIfFalse(pParse, pHaving, startagg, 1); } if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm, startagg, endagg) ){ goto select_end; } sqliteVdbeAddOp(v, OP_Goto, 0, startagg); sqliteVdbeResolveLabel(v, endagg); |
︙ | ︙ |
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.117 2002/05/26 20:54:34 drh Exp $ */ #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> |
︙ | ︙ | |||
813 814 815 816 817 818 819 | Table *sqliteTableNameToTable(Parse*, const char*); SrcList *sqliteTableTokenToSrcList(Parse*, Token*); void sqliteDeleteFrom(Parse*, Token*, Expr*); void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int); WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int); void sqliteWhereEnd(WhereInfo*); void sqliteExprCode(Parse*, Expr*); | | | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | Table *sqliteTableNameToTable(Parse*, const char*); SrcList *sqliteTableTokenToSrcList(Parse*, Token*); void sqliteDeleteFrom(Parse*, Token*, Expr*); void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int); WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int); void sqliteWhereEnd(WhereInfo*); void sqliteExprCode(Parse*, Expr*); void sqliteExprIfTrue(Parse*, Expr*, int, int); void sqliteExprIfFalse(Parse*, Expr*, int, int); Table *sqliteFindTable(sqlite*,const char*); Index *sqliteFindIndex(sqlite*,const char*); void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); void sqliteCopy(Parse*, Token*, Token*, Token*, int); void sqliteVacuum(Parse*, Token*); int sqliteGlobCompare(const unsigned char*,const unsigned char*); int sqliteLikeCompare(const unsigned char*,const unsigned char*); |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
583 584 585 586 587 588 589 | whenExpr = sqliteExprDup(pTrigger->pWhen); if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ pParse->trigStack = pParse->trigStack->pNext; sqliteFree(pTriggerStack); sqliteExprDelete(whenExpr); return 1; } | | | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | whenExpr = sqliteExprDup(pTrigger->pWhen); if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ pParse->trigStack = pParse->trigStack->pNext; sqliteFree(pTriggerStack); sqliteExprDelete(whenExpr); return 1; } sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); sqliteExprDelete(whenExpr); codeTriggerProgram(pParse, pTrigger->step_list, orconf); /* Pop the entry off the trigger stack */ pParse->trigStack = pParse->trigStack->pNext; sqliteFree(pTriggerStack); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.149 2002/05/26 20:54:34 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 | "ListPop", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortCallback", "SortReset", "FileOpen", "FileRead", "FileColumn", "AggReset", "AggFocus", "AggNext", "AggSet", "AggGet", "AggFunc", "AggInit", "AggPush", "AggPop", "SetInsert", "SetFound", "SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey", "Goto", | | | | | | | | | | | | | 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | "ListPop", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortCallback", "SortReset", "FileOpen", "FileRead", "FileColumn", "AggReset", "AggFocus", "AggNext", "AggSet", "AggGet", "AggFunc", "AggInit", "AggPush", "AggPop", "SetInsert", "SetFound", "SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey", "Goto", "If", "IfNot", "Halt", "ColumnCount", "ColumnName", "Callback", "NullCallback", "Integer", "String", "Pop", "Dup", "Pull", "Push", "MustBeInt", "Add", "AddImm", "Subtract", "Multiply", "Divide", "Remainder", "BitAnd", "BitOr", "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", "Function", "Limit", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. |
︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ Btree *pBt = p->pBt; /* The backend driver */ sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ int errorAction = OE_Abort; /* Recovery action to do in case of an error */ int undoTransOnError = 0; /* If error, either ROLLBACK or COMMIT */ char zBuf[100]; /* Space to sprintf() an integer */ /* No instruction ever pushes more than a single element onto the ** stack. And the stack never grows on successive executions of the | > | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ Btree *pBt = p->pBt; /* The backend driver */ sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ unsigned uniqueCnt = 0; /* Used by OP_MakeRecord when P2!=0 */ int errorAction = OE_Abort; /* Recovery action to do in case of an error */ int undoTransOnError = 0; /* If error, either ROLLBACK or COMMIT */ char zBuf[100]; /* Space to sprintf() an integer */ /* No instruction ever pushes more than a single element onto the ** stack. And the stack never grows on successive executions of the |
︙ | ︙ | |||
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | /* Opcode: Add * * * ** ** Pop the top two elements from the stack, add them together, ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the addition. */ /* Opcode: Multiply * * * ** ** Pop the top two elements from the stack, multiply them together, ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the multiplication. */ /* Opcode: Subtract * * * ** ** Pop the top two elements from the stack, subtract the ** first (what was on top of the stack) from the second (the ** next on stack) ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the subtraction. */ /* Opcode: Divide * * * ** ** Pop the top two elements from the stack, divide the ** first (what was on top of the stack) from the second (the ** next on stack) ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the division. Division by zero returns NULL. */ /* Opcode: Remainder * * * ** ** Pop the top two elements from the stack, divide the ** first (what was on top of the stack) from the second (the ** next on stack) ** and push the remainder after division onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the division. Division by zero returns NULL. */ case OP_Add: case OP_Subtract: case OP_Multiply: case OP_Divide: case OP_Remainder: { int tos = p->tos; int nos = tos - 1; VERIFY( if( nos<0 ) goto not_enough_stack; ) | > > > > > > > > > | | 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | /* Opcode: Add * * * ** ** Pop the top two elements from the stack, add them together, ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the addition. ** If either operand is NULL, the result is NULL. */ /* Opcode: Multiply * * * ** ** Pop the top two elements from the stack, multiply them together, ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the multiplication. ** If either operand is NULL, the result is NULL. */ /* Opcode: Subtract * * * ** ** Pop the top two elements from the stack, subtract the ** first (what was on top of the stack) from the second (the ** next on stack) ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the subtraction. ** If either operand is NULL, the result is NULL. */ /* Opcode: Divide * * * ** ** Pop the top two elements from the stack, divide the ** first (what was on top of the stack) from the second (the ** next on stack) ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the division. Division by zero returns NULL. ** If either operand is NULL, the result is NULL. */ /* Opcode: Remainder * * * ** ** Pop the top two elements from the stack, divide the ** first (what was on top of the stack) from the second (the ** next on stack) ** and push the remainder after division onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the division. Division by zero returns NULL. ** If either operand is NULL, the result is NULL. */ case OP_Add: case OP_Subtract: case OP_Multiply: case OP_Divide: case OP_Remainder: { int tos = p->tos; int nos = tos - 1; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( ((aStack[tos].flags | aStack[nos].flags) & STK_Null)!=0 ){ POPSTACK; Release(p, nos); aStack[nos].flags = STK_Null; }else if( (aStack[tos].flags & aStack[nos].flags & STK_Int)==STK_Int ){ int a, b; a = aStack[tos].i; b = aStack[nos].i; switch( pOp->opcode ){ case OP_Add: b += a; break; case OP_Subtract: b -= a; break; case OP_Multiply: b *= a; break; |
︙ | ︙ | |||
1834 1835 1836 1837 1838 1839 1840 | int n, i; sqlite_func ctx; n = pOp->p1; VERIFY( if( n<0 ) goto bad_instruction; ) VERIFY( if( p->tos+1<n ) goto not_enough_stack; ) for(i=p->tos-n+1; i<=p->tos; i++){ | | > > | 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 | int n, i; sqlite_func ctx; n = pOp->p1; VERIFY( if( n<0 ) goto bad_instruction; ) VERIFY( if( p->tos+1<n ) goto not_enough_stack; ) for(i=p->tos-n+1; i<=p->tos; i++){ if( aStack[i].flags & STK_Null ){ zStack[i] = 0; }else{ if( Stringify(p, i) ) goto no_mem; } } ctx.pFunc = (FuncDef*)pOp->p3; ctx.s.flags = STK_Null; ctx.z = 0; ctx.isError = 0; |
︙ | ︙ | |||
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 | } /* Opcode: BitAnd * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the bit-wise AND of the ** two elements. */ /* Opcode: BitOr * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the bit-wise OR of the ** two elements. */ /* Opcode: ShiftLeft * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the top element shifted ** left by N bits where N is the second element on the stack. */ /* Opcode: ShiftRight * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the top element shifted ** right by N bits where N is the second element on the stack. */ case OP_BitAnd: case OP_BitOr: case OP_ShiftLeft: case OP_ShiftRight: { int tos = p->tos; int nos = tos - 1; int a, b; VERIFY( if( nos<0 ) goto not_enough_stack; ) Integerify(p, tos); Integerify(p, nos); a = aStack[tos].i; b = aStack[nos].i; switch( pOp->opcode ){ case OP_BitAnd: a &= b; break; case OP_BitOr: a |= b; break; | > > > > > > > > > > | 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 | } /* Opcode: BitAnd * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the bit-wise AND of the ** two elements. ** If either operand is NULL, the result is NULL. */ /* Opcode: BitOr * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the bit-wise OR of the ** two elements. ** If either operand is NULL, the result is NULL. */ /* Opcode: ShiftLeft * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the top element shifted ** left by N bits where N is the second element on the stack. ** If either operand is NULL, the result is NULL. */ /* Opcode: ShiftRight * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the top element shifted ** right by N bits where N is the second element on the stack. ** If either operand is NULL, the result is NULL. */ case OP_BitAnd: case OP_BitOr: case OP_ShiftLeft: case OP_ShiftRight: { int tos = p->tos; int nos = tos - 1; int a, b; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( (aStack[tos].flags | aStack[nos].flags) & STK_Null ){ POPSTACK; Release(p,nos); aStack[nos].flags = STK_Null; break; } Integerify(p, tos); Integerify(p, nos); a = aStack[tos].i; b = aStack[nos].i; switch( pOp->opcode ){ case OP_BitAnd: a &= b; break; case OP_BitOr: a |= b; break; |
︙ | ︙ | |||
1969 1970 1971 1972 1973 1974 1975 | goto abort_due_to_error; }else{ pc = pOp->p2 - 1; } break; } | | > > > > > > > | > > > > > > > | > > > > > > > | > > > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > | | 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 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 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 | goto abort_due_to_error; }else{ pc = pOp->p2 - 1; } break; } /* Opcode: Eq P1 P2 * ** ** Pop the top two elements from the stack. If they are equal, then ** jump to instruction P2. Otherwise, continue to the next instruction. ** ** If either operand is NULL (and thus if the result is unknown) then ** take the jump if P1 is true. ** ** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. */ /* Opcode: Ne P1 P2 * ** ** Pop the top two elements from the stack. If they are not equal, then ** jump to instruction P2. Otherwise, continue to the next instruction. ** ** If either operand is NULL (and thus if the result is unknown) then ** take the jump if P1 is true. ** ** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. */ /* Opcode: Lt P1 P2 * ** ** Pop the top two elements from the stack. If second element (the ** next on stack) is less than the first (the top of stack), then ** jump to instruction P2. Otherwise, continue to the next instruction. ** In other words, jump if NOS<TOS. ** ** If either operand is NULL (and thus if the result is unknown) then ** take the jump if P1 is true. ** ** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. */ /* Opcode: Le P1 P2 * ** ** Pop the top two elements from the stack. If second element (the ** next on stack) is less than or equal to the first (the top of stack), ** then jump to instruction P2. In other words, jump if NOS<=TOS. ** ** If either operand is NULL (and thus if the result is unknown) then ** take the jump if P1 is true. ** ** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. */ /* Opcode: Gt P1 P2 * ** ** Pop the top two elements from the stack. If second element (the ** next on stack) is greater than the first (the top of stack), ** then jump to instruction P2. In other words, jump if NOS>TOS. ** ** If either operand is NULL (and thus if the result is unknown) then ** take the jump if P1 is true. ** ** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. */ /* Opcode: Ge P1 P2 * ** ** Pop the top two elements from the stack. If second element (the next ** on stack) is greater than or equal to the first (the top of stack), ** then jump to instruction P2. In other words, jump if NOS>=TOS. ** ** If either operand is NULL (and thus if the result is unknown) then ** take the jump if P1 is true. ** ** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. */ case OP_Eq: case OP_Ne: case OP_Lt: case OP_Le: case OP_Gt: case OP_Ge: { int tos = p->tos; int nos = tos - 1; int c; int ft, fn; VERIFY( if( nos<0 ) goto not_enough_stack; ) ft = aStack[tos].flags; fn = aStack[nos].flags; if( (ft | fn) & STK_Null ){ POPSTACK; POPSTACK; if( pOp->p2 ){ if( pOp->p1 ) pc = pOp->p2-1; }else{ p->tos++; aStack[nos].flags = STK_Null; } break; }else if( (ft & fn & STK_Int)==STK_Int ){ c = aStack[nos].i - aStack[tos].i; }else if( (ft & STK_Int)!=0 && (fn & STK_Str)!=0 && isInteger(zStack[nos]) ){ Integerify(p, nos); c = aStack[nos].i - aStack[tos].i; }else if( (fn & STK_Int)!=0 && (ft & STK_Str)!=0 && isInteger(zStack[tos]) ){ Integerify(p, tos); c = aStack[nos].i - aStack[tos].i; |
︙ | ︙ | |||
2039 2040 2041 2042 2043 2044 2045 | case OP_Lt: c = c<0; break; case OP_Le: c = c<=0; break; case OP_Gt: c = c>0; break; default: c = c>=0; break; } POPSTACK; POPSTACK; | > | > > > > > > > > > > > > > | > | > > > | > > | > > | > > > < < < < < < < < < < | | | > > | > > | > | > > > > > > | > | > > > > > > > > > > > > > > > > | > | > > > < | | < | > > > > > > > > > > > | 2113 2114 2115 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 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 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 | case OP_Lt: c = c<0; break; case OP_Le: c = c<=0; break; case OP_Gt: c = c>0; break; default: c = c>=0; break; } POPSTACK; POPSTACK; if( pOp->p2 ){ if( c ) pc = pOp->p2-1; }else{ p->tos++; aStack[nos].flags = STK_Int; aStack[nos].i = c; } break; } /* Opcode: And * * * ** ** Pop two values off the stack. Take the logical AND of the ** two values and push the resulting boolean value back onto the ** stack. ** If either operand is NULL, the result is NULL. */ /* Opcode: Or * * * ** ** Pop two values off the stack. Take the logical OR of the ** two values and push the resulting boolean value back onto the ** stack. ** If either operand is NULL, the result is NULL. */ case OP_And: case OP_Or: { int tos = p->tos; int nos = tos - 1; int c; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( (aStack[tos].flags | aStack[nos].flags) & STK_Null ){ POPSTACK; Release(p, nos); aStack[nos].flags = STK_Null; break; } Integerify(p, tos); Integerify(p, nos); if( pOp->opcode==OP_And ){ c = aStack[tos].i && aStack[nos].i; }else{ c = aStack[tos].i || aStack[nos].i; } POPSTACK; Release(p, nos); aStack[nos].i = c; aStack[nos].flags = STK_Int; break; } /* Opcode: Negative * * * ** ** Treat the top of the stack as a numeric quantity. Replace it ** with its additive inverse. If the top of the stack is NULL ** its value is unchanged. */ /* Opcode: AbsValue * * * ** ** Treat the top of the stack as a numeric quantity. Replace it ** with its absolute value. If the top of the stack is NULL ** its value is unchanged. */ case OP_Negative: case OP_AbsValue: { int tos = p->tos; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( aStack[tos].flags & STK_Real ){ Release(p, tos); if( pOp->opcode==OP_Negative || aStack[tos].r<0.0 ){ aStack[tos].r = -aStack[tos].r; } aStack[tos].flags = STK_Real; }else if( aStack[tos].flags & STK_Int ){ Release(p, tos); if( pOp->opcode==OP_Negative || aStack[tos].i<0 ){ aStack[tos].i = -aStack[tos].i; } aStack[tos].flags = STK_Int; }else if( aStack[tos].flags & STK_Null ){ /* Do nothing */ }else{ Realify(p, tos); Release(p, tos); if( pOp->opcode==OP_Negative || aStack[tos].r<0.0 ){ aStack[tos].r = -aStack[tos].r; } aStack[tos].flags = STK_Real; } break; } /* Opcode: Not * * * ** ** Interpret the top of the stack as a boolean value. Replace it ** with its complement. If the top of the stack is NULL its value ** is unchanged. */ case OP_Not: { int tos = p->tos; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) if( aStack[tos].flags & STK_Null ) break; /* Do nothing to NULLs */ Integerify(p, tos); Release(p, tos); aStack[tos].i = !aStack[tos].i; aStack[tos].flags = STK_Int; break; } /* Opcode: BitNot * * * ** ** Interpret the top of the stack as an value. Replace it ** with its ones-complement. If the top of the stack is NULL its ** value is unchanged. */ case OP_BitNot: { int tos = p->tos; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) if( aStack[tos].flags & STK_Null ) break; /* Do nothing to NULLs */ Integerify(p, tos); Release(p, tos); aStack[tos].i = ~aStack[tos].i; aStack[tos].flags = STK_Int; break; } /* Opcode: Noop * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ case OP_Noop: { break; } /* Opcode: If P1 P2 * ** ** Pop a single boolean from the stack. If the boolean popped is ** true, then jump to p2. Otherwise continue to the next instruction. ** An integer is false if zero and true otherwise. A string is ** false if it has zero length and true otherwise. ** ** If the value popped of the stack is NULL, then take the jump if P1 ** is true and fall through if P1 is false. */ /* Opcode: IfNot P1 P2 * ** ** Pop a single boolean from the stack. If the boolean popped is ** false, then jump to p2. Otherwise continue to the next instruction. ** An integer is false if zero and true otherwise. A string is ** false if it has zero length and true otherwise. ** ** If the value popped of the stack is NULL, then take the jump if P1 ** is true and fall through if P1 is false. */ case OP_If: case OP_IfNot: { int c; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) if( aStack[p->tos].flags & STK_Null ){ c = pOp->p1; }else{ Integerify(p, p->tos); c = aStack[p->tos].i; if( pOp->opcode==OP_IfNot ) c = !c; } POPSTACK; if( c ) pc = pOp->p2-1; break; } /* Opcode: IsNull P1 P2 * ** ** If any of the top abs(P1) values on the stack are NULL, then jump ** to P2. The stack is popped P1 times if P1>0. If P1<0 then all values ** are left unchanged on the stack. */ case OP_IsNull: { int i, cnt; cnt = pOp->p1; if( cnt<0 ) cnt = -cnt; VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; ) for(i=0; i<cnt; i++){ if( aStack[p->tos-i].flags & STK_Null ){ pc = pOp->p2-1; break; } } if( pOp->p1>0 ) PopStack(p, cnt); break; } /* Opcode: NotNull P1 P2 * ** ** Jump to P2 if the top value on the stack is not NULL. Pop the ** stack if P1 is greater than zero. If P1 is less than or equal to ** zero then leave the value on the stack. */ case OP_NotNull: { VERIFY( if( p->tos<0 ) goto not_enough_stack; ) if( (aStack[p->tos].flags & STK_Null)==0 ) pc = pOp->p2-1; if( pOp->p1>0 ){ POPSTACK; } break; } /* Opcode: MakeRecord P1 P2 * ** ** Convert the top P1 entries of the stack into a single entry ** suitable for use as a data record in a database table. The ** details of the format are irrelavant as long as the OP_Column ** opcode can decode the record later. Refer to source code ** comments for the details of the record format. ** ** If P2 is true (non-zero) and one or more of the P1 entries ** that go into building the record is NULL, then add some extra ** bytes to the record to make it distinct for other entries created ** during the same run of the VDBE. The extra bytes added are a ** counter that is reset with each run of the VDBE, so records ** created this way will not necessarily be distinct across runs. ** But they should be distinct for transient tables (created using ** OP_OpenTemp) which is what they are intended for. */ case OP_MakeRecord: { char *zNewRecord; int nByte; int nField; int i, j; int idxWidth; u32 addr; int addUnique = 0; /* True to cause bytes to be added to make the ** generated record distinct */ /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------- ** | idx0 | idx1 | ... | idx(N-1) | idx(N) | data0 | ... | data(N-1) | ** ------------------------------------------------------------------- |
︙ | ︙ | |||
2236 2237 2238 2239 2240 2241 2242 | ** of data(0). Idx(k) contains the offset to the start of data(k). ** Idx(N) contains the total number of bytes in the record. */ nField = pOp->p1; VERIFY( if( p->tos+1<nField ) goto not_enough_stack; ) nByte = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ | | > > > | > > > > > | 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 | ** of data(0). Idx(k) contains the offset to the start of data(k). ** Idx(N) contains the total number of bytes in the record. */ nField = pOp->p1; VERIFY( if( p->tos+1<nField ) goto not_enough_stack; ) nByte = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ if( (aStack[i].flags & STK_Null) ){ addUnique = pOp->p2; }else{ if( Stringify(p, i) ) goto no_mem; nByte += aStack[i].n; } } if( addUnique ) nByte += sizeof(uniqueCnt); if( nByte + nField + 1 < 256 ){ idxWidth = 1; }else if( nByte + 2*nField + 2 < 65536 ){ idxWidth = 2; }else{ idxWidth = 3; } nByte += idxWidth*(nField + 1); if( nByte>MAX_BYTES_PER_ROW ){ rc = SQLITE_TOOBIG; goto abort_due_to_error; } zNewRecord = sqliteMalloc( nByte ); if( zNewRecord==0 ) goto no_mem; j = 0; addr = idxWidth*(nField+1) + addUnique*sizeof(uniqueCnt); for(i=p->tos-nField+1; i<=p->tos; i++){ zNewRecord[j++] = addr & 0xff; if( idxWidth>1 ){ zNewRecord[j++] = (addr>>8)&0xff; if( idxWidth>2 ){ zNewRecord[j++] = (addr>>16)&0xff; } } if( (aStack[i].flags & STK_Null)==0 ){ addr += aStack[i].n; } } zNewRecord[j++] = addr & 0xff; if( idxWidth>1 ){ zNewRecord[j++] = (addr>>8)&0xff; if( idxWidth>2 ){ zNewRecord[j++] = (addr>>16)&0xff; } } if( addUnique ){ memcpy(&zNewRecord[j], &uniqueCnt, sizeof(uniqueCnt)); uniqueCnt++; j += sizeof(uniqueCnt); } for(i=p->tos-nField+1; i<=p->tos; i++){ if( (aStack[i].flags & STK_Null)==0 ){ memcpy(&zNewRecord[j], zStack[i], aStack[i].n); j += aStack[i].n; } } PopStack(p, nField); |
︙ | ︙ | |||
2307 2308 2309 2310 2311 2312 2313 | ** If P2 is not zero, then the original entries remain on the stack ** and the new key is pushed on top. If P2 is zero, the original ** data is popped off the stack first then the new key is pushed ** back in its place. ** ** See also: MakeIdxKey, SortMakeKey */ | | > > > > > > > > | 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 | ** If P2 is not zero, then the original entries remain on the stack ** and the new key is pushed on top. If P2 is zero, the original ** data is popped off the stack first then the new key is pushed ** back in its place. ** ** See also: MakeIdxKey, SortMakeKey */ /* Opcode: MakeIdxKey P1 P2 * ** ** Convert the top P1 entries of the stack into a single entry suitable ** for use as the key in an index. In addition, take one additional integer ** off of the stack, treat that integer as a four-byte record number, and ** append the four bytes to the key. Thus a total of P1+1 entries are ** popped from the stack for this instruction and a single entry is pushed ** back. The first P1 entries that are popped are strings and the last ** entry (the lowest on the stack) is an integer record number. ** ** The converstion of the first P1 string entries occurs just like in ** MakeKey. Each entry is separated from the others by a null. ** The entire concatenation is null-terminated. The lowest entry ** in the stack is the first field and the top of the stack becomes the ** last. ** ** If P2 is not zero and one or more of the P1 entries that go into the ** generated key is NULL, then jump to P2 after the new key has been ** pushed on the stack. In other words, jump to P2 if the key is ** guaranteed to be unique. This jump can be used to skip a subsequent ** uniqueness test. ** ** See also: MakeKey, SortMakeKey */ case OP_MakeIdxKey: case OP_MakeKey: { char *zNewKey; int nByte; int nField; int addRowid; int i, j; int containsNull = 0; addRowid = pOp->opcode==OP_MakeIdxKey; nField = pOp->p1; VERIFY( if( p->tos+1+addRowid<nField ) goto not_enough_stack; ) nByte = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ int flags = aStack[i].flags; int len; char *z; if( flags & STK_Null ){ nByte += 2; containsNull = 1; }else if( flags & STK_Real ){ z = aStack[i].z; sqliteRealToSortable(aStack[i].r, &z[1]); z[0] = 0; Release(p, i); len = strlen(&z[1]); zStack[i] = 0; |
︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 | } } if( addRowid ){ u32 iKey; Integerify(p, p->tos-nField); iKey = intToKey(aStack[p->tos-nField].i); memcpy(&zNewKey[j], &iKey, sizeof(u32)); | > > | | > | 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 | } } if( addRowid ){ u32 iKey; Integerify(p, p->tos-nField); iKey = intToKey(aStack[p->tos-nField].i); memcpy(&zNewKey[j], &iKey, sizeof(u32)); PopStack(p, nField+1); if( pOp->p2 && containsNull ) pc = pOp->p2 - 1; }else{ if( pOp->p2==0 ) PopStack(p, nField+addRowid); } VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; zStack[p->tos] = zNewKey; break; } |
︙ | ︙ | |||
4369 4370 4371 4372 4373 4374 4375 | Mem *pMem; sqlite_func ctx; VERIFY( if( n<0 ) goto bad_instruction; ) VERIFY( if( p->tos+1<n ) goto not_enough_stack; ) VERIFY( if( aStack[p->tos].flags!=STK_Int ) goto bad_instruction; ) for(i=p->tos-n; i<p->tos; i++){ | | > > | 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 | Mem *pMem; sqlite_func ctx; VERIFY( if( n<0 ) goto bad_instruction; ) VERIFY( if( p->tos+1<n ) goto not_enough_stack; ) VERIFY( if( aStack[p->tos].flags!=STK_Int ) goto bad_instruction; ) for(i=p->tos-n; i<p->tos; i++){ if( aStack[i].flags & STK_Null ){ zStack[i] = 0; }else{ if( Stringify(p, i) ) goto no_mem; } } i = aStack[p->tos].i; VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; ) ctx.pFunc = (FuncDef*)pOp->p3; pMem = &p->agg.pCurrent->aMem[i]; |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** ** $Id: vdbe.h,v 1.53 2002/05/26 20:54:34 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
153 154 155 156 157 158 159 | #define OP_MakeRecord 72 #define OP_MakeKey 73 #define OP_MakeIdxKey 74 #define OP_IncrKey 75 #define OP_Goto 76 #define OP_If 77 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | #define OP_MakeRecord 72 #define OP_MakeKey 73 #define OP_MakeIdxKey 74 #define OP_IncrKey 75 #define OP_Goto 76 #define OP_If 77 #define OP_IfNot 78 #define OP_Halt 79 #define OP_ColumnCount 80 #define OP_ColumnName 81 #define OP_Callback 82 #define OP_NullCallback 83 #define OP_Integer 84 #define OP_String 85 #define OP_Pop 86 #define OP_Dup 87 #define OP_Pull 88 #define OP_Push 89 #define OP_MustBeInt 90 #define OP_Add 91 #define OP_AddImm 92 #define OP_Subtract 93 #define OP_Multiply 94 #define OP_Divide 95 #define OP_Remainder 96 #define OP_BitAnd 97 #define OP_BitOr 98 #define OP_BitNot 99 #define OP_ShiftLeft 100 #define OP_ShiftRight 101 #define OP_AbsValue 102 #define OP_Eq 103 #define OP_Ne 104 #define OP_Lt 105 #define OP_Le 106 #define OP_Gt 107 #define OP_Ge 108 #define OP_IsNull 109 #define OP_NotNull 110 #define OP_Negative 111 #define OP_And 112 #define OP_Or 113 #define OP_Not 114 #define OP_Concat 115 #define OP_Noop 116 #define OP_Function 117 #define OP_Limit 118 #define OP_MAX 118 /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqliteVdbeCreate(sqlite*); void sqliteVdbeCreateCallback(Vdbe*, int*); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** ** $Id: where.c,v 1.48 2002/05/26 20:54:34 drh Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
195 196 197 198 199 200 201 | pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab; pWInfo->iBreak = sqliteVdbeMakeLabel(v); /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ if( pWhere && sqliteExprIsConstant(pWhere) ){ | | | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab; pWInfo->iBreak = sqliteVdbeMakeLabel(v); /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ if( pWhere && sqliteExprIsConstant(pWhere) ){ sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1); } /* Split the WHERE clause into as many as 32 separate subexpressions ** where each subexpression is separated by an AND operator. Any additional ** subexpressions are attached in the aExpr[32] and will not enter ** into the query optimizer computations. 32 is chosen as the cutoff ** since that is the number of bits in an integer that we use for an |
︙ | ︙ | |||
791 792 793 794 795 796 797 | for(j=0; j<nExpr; j++){ if( aExpr[j].p==0 ) continue; if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue; if( haveKey ){ haveKey = 0; sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); } | | | 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 | for(j=0; j<nExpr; j++){ if( aExpr[j].p==0 ) continue; if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue; if( haveKey ){ haveKey = 0; sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); } sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1); aExpr[j].p = 0; } brk = cont; /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ |
︙ | ︙ |
Changes to test/expr.test.
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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing expressions. # | | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing expressions. # # $Id: expr.test,v 1.20 2002/05/26 20:54:34 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table to work with. # execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)} execsql {INSERT INTO test1 VALUES(1,2,1.1,2.2,'hello','world')} proc test_expr {name settings expr result} { do_test $name [format { execsql {BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK;} } $settings $expr] $result } test_expr expr-1.1 {i1=10, i2=20} {i1+i2} 30 test_expr expr-1.2 {i1=10, i2=20} {i1-i2} -10 test_expr expr-1.3 {i1=10, i2=20} {i1*i2} 200 test_expr expr-1.4 {i1=10, i2=20} {i1/i2} 0.5 |
︙ | ︙ | |||
59 60 61 62 63 64 65 | test_expr expr-1.30 {i1=1, i2=2} {i1=2 AND i2=2} {0} test_expr expr-1.31 {i1=1, i2=2} {i1==1 OR i2=2} {1} test_expr expr-1.32 {i1=1, i2=2} {i1=2 OR i2=1} {0} test_expr expr-1.33 {i1=1, i2=2} {i1=1 OR i2=1} {1} test_expr expr-1.34 {i1=1, i2=2} {i1=2 OR i2=2} {1} test_expr expr-1.35 {i1=1, i2=2} {i1-i2=-1} {1} test_expr expr-1.36 {i1=1, i2=0} {not i1} {0} | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | test_expr expr-1.30 {i1=1, i2=2} {i1=2 AND i2=2} {0} test_expr expr-1.31 {i1=1, i2=2} {i1==1 OR i2=2} {1} test_expr expr-1.32 {i1=1, i2=2} {i1=2 OR i2=1} {0} test_expr expr-1.33 {i1=1, i2=2} {i1=1 OR i2=1} {1} test_expr expr-1.34 {i1=1, i2=2} {i1=2 OR i2=2} {1} test_expr expr-1.35 {i1=1, i2=2} {i1-i2=-1} {1} test_expr expr-1.36 {i1=1, i2=0} {not i1} {0} test_expr expr-1.37 {i1=1, i2=0} {not i2} {1} test_expr expr-1.38 {i1=1} {-i1} {-1} test_expr expr-1.39 {i1=1} {+i1} {1} test_expr expr-1.40 {i1=1, i2=2} {+(i2+i1)} {3} test_expr expr-1.41 {i1=1, i2=2} {-(i2+i1)} {-3} test_expr expr-1.42 {i1=1, i2=2} {i1|i2} {3} test_expr expr-1.43 {i1=1, i2=2} {i1&i2} {0} test_expr expr-1.44 {i1=1} {~i1} {-2} |
︙ | ︙ | |||
316 317 318 319 320 321 322 | execsql {SELECT a FROM test1 WHERE %s ORDER BY a} } $expr] $result } test_expr2 expr-7.2 {a<10 AND a>8} {9} test_expr2 expr-7.3 {a<=10 AND a>=8} {8 9 10} test_expr2 expr-7.4 {a>=8 AND a<=10} {8 9 10} | | | | | | | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | execsql {SELECT a FROM test1 WHERE %s ORDER BY a} } $expr] $result } test_expr2 expr-7.2 {a<10 AND a>8} {9} test_expr2 expr-7.3 {a<=10 AND a>=8} {8 9 10} test_expr2 expr-7.4 {a>=8 AND a<=10} {8 9 10} test_expr2 expr-7.5 {a>=20 OR a<=1} {1 20} test_expr2 expr-7.6 {b!=4 AND a<=3} {1 3} test_expr2 expr-7.7 {b==8 OR b==16 OR b==32} {3 4 5} test_expr2 expr-7.8 {NOT b<>8 OR b==1024} {3 10} test_expr2 expr-7.9 {b LIKE '10%'} {10 20} test_expr2 expr-7.10 {b LIKE '_4'} {6} test_expr2 expr-7.11 {a GLOB '1?'} {10 11 12 13 14 15 16 17 18 19} test_expr2 expr-7.12 {b GLOB '1*4'} {10 14} test_expr2 expr-7.13 {b GLOB '*1[456]'} {4} test_expr2 expr-7.14 {a ISNULL} {{}} test_expr2 expr-7.15 {a NOTNULL AND a<3} {1 2} test_expr2 expr-7.16 {a AND a<3} {1 2} test_expr2 expr-7.17 {NOT a} {} test_expr2 expr-7.18 {a==11 OR (b>1000 AND b<2000)} {10 11} test_expr2 expr-7.19 {a<=1 OR a>=20} {1 20} test_expr2 expr-7.20 {a<1 OR a>20} {} test_expr2 expr-7.21 {a>19 OR a<1} {20} test_expr2 expr-7.22 {a!=1 OR a=100} \ {2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20} test_expr2 expr-7.23 {(a notnull AND a<4) OR a==8} {1 2 3 8} test_expr2 expr-7.24 {a LIKE '2_' OR a==8} {8 20} test_expr2 expr-7.25 {a GLOB '2?' OR a==8} {8 20} test_expr2 expr-7.26 {a isnull OR a=8} {{} 8} test_expr2 expr-7.27 {a notnull OR a=8} \ {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20} finish_test |
Changes to test/select4.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing UNION, INTERSECT and EXCEPT operators # in SELECT statements. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing UNION, INTERSECT and EXCEPT operators # in SELECT statements. # # $Id: select4.test,v 1.7 2002/05/26 20:54:35 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # set fd [open data1.txt w] |
︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 253 254 255 256 257 | execsql { SELECT log, count(*) FROM t1 GROUP BY log UNION SELECT log, n FROM t1 WHERE n=7 ORDER BY count(*), log; } } {0 1 1 1 2 2 3 4 3 7 4 8 5 15} # Make sure column names are correct when a compound select appears as # an expression in the WHERE clause. # do_test select4-7.1 { execsql { CREATE TABLE t2 AS SELECT log AS 'x', count(*) AS 'y' FROM t1 GROUP BY log; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | execsql { SELECT log, count(*) FROM t1 GROUP BY log UNION SELECT log, n FROM t1 WHERE n=7 ORDER BY count(*), log; } } {0 1 1 1 2 2 3 4 3 7 4 8 5 15} # NULLs are distinct. Make sure the UNION operator recognizes this # do_test select4-6.3 { execsql { SELECT NULL UNION SELECT NULL UNION SELECT 1 UNION SELECT 2 AS 'x' ORDER BY x; } } {{} {} 1 2} do_test select4-6.3 { execsql { SELECT NULL UNION ALL SELECT NULL UNION ALL SELECT 1 UNION ALL SELECT 2 AS 'x' ORDER BY x; } } {{} {} 1 2} # Make sure the DISTINCT keyword treats NULLs as DISTINCT # do_test select4-6.4 { execsql { SELECT * FROM ( SELECT NULL, 1 UNION ALL SELECT NULL, 1 ); } } {{} 1 {} 1} do_test select4-6.5 { execsql { SELECT DISTINCT * FROM ( SELECT NULL, 1 UNION ALL SELECT NULL, 1 ); } } {{} 1 {} 1} do_test select4-6.6 { execsql { SELECT DISTINCT * FROM ( SELECT 1,2 UNION ALL SELECT 1,2 ); } } {1 2} # Make sure column names are correct when a compound select appears as # an expression in the WHERE clause. # do_test select4-7.1 { execsql { CREATE TABLE t2 AS SELECT log AS 'x', count(*) AS 'y' FROM t1 GROUP BY log; |
︙ | ︙ |
Changes to test/subselect.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing SELECT statements that are part of # expressions. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing SELECT statements that are part of # expressions. # # $Id: subselect.test,v 1.5 2002/05/26 20:54:35 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Basic sanity checking. Try a simple subselect. # do_test subselect-1.1 { |
︙ | ︙ | |||
51 52 53 54 55 56 57 | execsql {SELECT b from t1 where a = (SELECT a FROM t1 WHERE b=8)} } {} # What if the subselect doesn't return any value. We should get # NULL as the result. Check it out. # do_test subselect-1.4 { | < | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | execsql {SELECT b from t1 where a = (SELECT a FROM t1 WHERE b=8)} } {} # What if the subselect doesn't return any value. We should get # NULL as the result. Check it out. # do_test subselect-1.4 { execsql {SELECT b from t1 where a = coalesce((SELECT a FROM t1 WHERE b=5),1)} } {2} # Try multiple subselects within a single expression. # do_test subselect-1.5 { execsql { CREATE TABLE t2(x int, y int); INSERT INTO t2 VALUES(1,2); |
︙ | ︙ |
Changes to test/trigger2.test.
︙ | ︙ | |||
73 74 75 76 77 78 79 | INSERT INTO tbl VALUES(3, 4); CREATE TABLE rlog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b); CREATE TABLE clog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b); CREATE TRIGGER before_update_row BEFORE UPDATE ON tbl FOR EACH ROW BEGIN | | | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | INSERT INTO tbl VALUES(3, 4); CREATE TABLE rlog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b); CREATE TABLE clog (idx, old_a, old_b, db_sum_a, db_sum_b, new_a, new_b); CREATE TRIGGER before_update_row BEFORE UPDATE ON tbl FOR EACH ROW BEGIN INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), old.a, old.b, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), new.a, new.b); END; CREATE TRIGGER after_update_row AFTER UPDATE ON tbl FOR EACH ROW BEGIN INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), old.a, old.b, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), new.a, new.b); END; CREATE TRIGGER conditional_update_row AFTER UPDATE ON tbl FOR EACH ROW WHEN old.a = 1 BEGIN INSERT INTO clog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM clog), old.a, old.b, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), new.a, new.b); END; } do_test trig-1.1.$ii { |
︙ | ︙ | |||
116 117 118 119 120 121 122 | execsql { DELETE FROM rlog; DELETE FROM tbl; INSERT INTO tbl VALUES (100, 100); INSERT INTO tbl VALUES (300, 200); CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW BEGIN | | | | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | execsql { DELETE FROM rlog; DELETE FROM tbl; INSERT INTO tbl VALUES (100, 100); INSERT INTO tbl VALUES (300, 200); CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW BEGIN INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), old.a, old.b, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), 0, 0); END; CREATE TRIGGER delete_after_row AFTER DELETE ON tbl FOR EACH ROW BEGIN INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), old.a, old.b, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), 0, 0); END; } do_test trig-1.2.$ii { execsql { DELETE FROM tbl; SELECT * FROM rlog; } } [list 1 100 100 400 300 0 0 \ 2 100 100 300 200 0 0 \ 3 300 200 300 200 0 0 \ 4 300 200 0 0 0 0 ] execsql { DELETE FROM rlog; CREATE TRIGGER insert_before_row BEFORE INSERT ON tbl FOR EACH ROW BEGIN INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 0, 0, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), new.a, new.b); END; CREATE TRIGGER insert_after_row AFTER INSERT ON tbl FOR EACH ROW BEGIN INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 0, 0, (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), new.a, new.b); END; } do_test trig-1.3.$ii { execsql { |
︙ | ︙ |
Changes to test/unique.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE UNIQUE INDEX statement, # and primary keys, and the UNIQUE constraint on table columns # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE UNIQUE INDEX statement, # and primary keys, and the UNIQUE constraint on table columns # # $Id: unique.test,v 1.4 2002/05/26 20:54:35 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to create a table with two primary keys. # (This is allowed in SQLite even that it is not valid SQL) # |
︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 | } {0 {1 2 3 4 1 2 3 5}} do_test unique-3.4 { catchsql { INSERT INTO t3(a,b,c,d) VALUES(1,4,3,5); SELECT * FROM t3 ORDER BY a,b,c,d; } } {1 {constraint failed}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | } {0 {1 2 3 4 1 2 3 5}} do_test unique-3.4 { catchsql { INSERT INTO t3(a,b,c,d) VALUES(1,4,3,5); SELECT * FROM t3 ORDER BY a,b,c,d; } } {1 {constraint failed}} # Make sure NULLs are distinct as far as the UNIQUE tests are # concerned. # do_test unique-4.1 { execsql { CREATE TABLE t4(a UNIQUE, b, c, UNIQUE(b,c)); INSERT INTO t4 VALUES(1,2,3); INSERT INTO t4 VALUES(NULL, 2, NULL); SELECT * FROM t4; } } {1 2 3 {} 2 {}} do_test unique-4.2 { catchsql { INSERT INTO t4 VALUES(NULL, 3, 4); } } {0 {}} do_test unique-4.3 { execsql { SELECT * FROM t4 } } {1 2 3 {} 2 {} {} 3 4} do_test unique-4.4 { catchsql { INSERT INTO t4 VALUES(2, 2, NULL); } } {0 {}} do_test unique-4.5 { execsql { SELECT * FROM t4 } } {1 2 3 {} 2 {} {} 3 4 2 2 {}} finish_test |