]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
More changes to support the manifest type model. A few things are currently
authordanielk1977 <danielk1977@noemail.net>
Sun, 16 May 2004 11:15:36 +0000 (11:15 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Sun, 16 May 2004 11:15:36 +0000 (11:15 +0000)
broken. (CVS 1385)

FossilOrigin-Name: a4af838f8d1b81ec6c8db97655c6876aca0738d9

16 files changed:
manifest
manifest.uuid
src/build.c
src/delete.c
src/expr.c
src/func.c
src/insert.c
src/pragma.c
src/sqliteInt.h
src/update.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/where.c
test/types.test
test/types2.test [new file with mode: 0644]

index d5be51814033953cb9f654cc4d3f488094379dc0..3b0084ec2fcc8d688301610b9fbbbfa1c81fd82a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C More\sspeed\simprovements\sto\sbtree.\s(CVS\s1384)
-D 2004-05-15T00:29:24
+C More\schanges\sto\ssupport\sthe\smanifest\stype\smodel.\sA\sfew\sthings\sare\scurrently\nbroken.\s(CVS\s1385)
+D 2004-05-16T11:15:36
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -26,16 +26,16 @@ F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
 F src/btree.c 05aefd3eec56690d9731bf090203b57d8ae4bf19
 F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
-F src/build.c e93f443a20eab57ffb77ff6244b1e09a1f7d9390
+F src/build.c 6c0463907ba80e0269f0b7fdf4210a049275b48a
 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
 F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
-F src/delete.c 30c8c4375e75e811c3668abf3f78970fe549f375
+F src/delete.c ea8212a44b5c0dad8fb1794fe7297654f7ed05f9
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
-F src/expr.c a3aed7057bafb3a01e8af98a5f74a102621b7a91
-F src/func.c 4053dc2141ea46e8e35df089d87bfcbab54320bc
+F src/expr.c d2d1ddc0ee98f1d70c6caddc11b46a0121d9bddd
+F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a
 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 5d4d1a59f66b558213984391985a418efc1c2797
+F src/insert.c 76e13b736391a342bd0fc152ade2558588322868
 F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
 F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
 F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
@@ -43,13 +43,13 @@ F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
 F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
 F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
 F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
-F src/pragma.c 2ab2a12b62ec5370b9221f44b4743a633a90bfa8
+F src/pragma.c 351836bce186f4eee45a32868b7a379c22ac344a
 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
 F src/select.c ca99ae4db14a45a436ec51d3e6bd48d44a3efb3c
 F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
 F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
-F src/sqliteInt.h e94edafb9924f22f038c6a8209c29ddd04cd326a
+F src/sqliteInt.h bc118a7a701afb954f4cd2110cd0986478e1a741
 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
 F src/tclsqlite.c fbf0fac73624ae246551a6c671f1de0235b5faa1
 F src/test1.c 12ef76b8aaba4408422f21f269256b630d4dd627
@@ -59,15 +59,15 @@ F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296
 F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847
 F src/trigger.c 8df308e09113410bb895e88a2db65b55490268db
-F src/update.c 0441f8b64d616ef244583449e66c984e536c6c9b
+F src/update.c 04492438aee57a6be5a8a8e54e3add12c1d598ca
 F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
 F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf
 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
-F src/vdbe.c c12726cf16c9a4e70ff606f87dc0e10e55a11988
+F src/vdbe.c 38a477ae68e78936adb62ef9c6cffebdebbb5be5
 F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
-F src/vdbeInt.h 67c3b2cf924e176c10ba75b36d295b165d55c451
-F src/vdbeaux.c 8411f411b421bc19ded1e992db82434aef740f5f
-F src/where.c 6957bbd333cc7ffa7b3878adbe67a095319daa54
+F src/vdbeInt.h 311c2a046ea419781d0ef331198b7b0a65eebc92
+F src/vdbeaux.c bd259da3ae52cd4f6febb0c83f60c0b9170f3ebb
+F src/where.c 610fadd08c5a25c2aa3bdd8700c3173de64298d0
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
 F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56
@@ -144,7 +144,8 @@ F test/trigger1.test 4538c1c7d6bbca5dfe619ea6e1682b07ece95b21
 F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263
 F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d
 F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8
-F test/types.test 53e3d97c33651afad7bc8bd4cf71b97b473b19ad
+F test/types.test d30ee85040cec5c12ebd98a6419916cc29a6c11e
+F test/types2.test bc684cc2a75edb240f9fd49275f3cacb025c0f1e
 F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
 F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
 F test/vacuum.test a2a44544df719666efb51afbfeb6062fd59a672a
@@ -191,7 +192,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P d8bacc16801606176fe8639b2f55b4584ad549df
-R d43b2b97f5dc394b60a54b98133aa83a
-U drh
-Z 06eabac28a7b451889010e7a03f02723
+P aab4b794b4238bad5c4a6aee7d4443732921127d
+R b2648c3d83df0dd5d82ceb6fe4e0bc60
+U danielk1977
+Z a958d50ee5923975cc30d387e46d379d
index 3ffb256fc739b6a4973061f2230b648b70f14954..e70830ee5720aa75460fd1f1bf2140b15f4f0655 100644 (file)
@@ -1 +1 @@
-aab4b794b4238bad5c4a6aee7d4443732921127d
\ No newline at end of file
+a4af838f8d1b81ec6c8db97655c6876aca0738d9
\ No newline at end of file
index 1881aba2496759ed13df0a01c61ca458132ba6ca..9ccba2b9871182e6668ddf435c67e9e57f3ba8ba 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.183 2004/05/14 11:00:53 danielk1977 Exp $
+** $Id: build.c,v 1.184 2004/05/16 11:15:36 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -184,6 +184,9 @@ static void sqliteDeleteIndex(sqlite *db, Index *p){
     sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
                      strlen(pOld->zName)+1, pOld);
   }
+  if( p->zColAff ){
+    sqliteFree(p->zColAff);
+  }
   sqliteFree(p);
 }
 
@@ -581,7 +584,12 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
   pCol = &p->aCol[p->nCol];
   memset(pCol, 0, sizeof(p->aCol[0]));
   pCol->zName = z;
-  pCol->sortOrder = SQLITE_SO_NUM;
+  /* If there is no type specified, columns have the default affinity
+  ** 'NONE'. If there is a type specified, then sqlite3AddColumnType()
+  ** will be called next to set pCol->affinity correctly.
+  */
+  pCol->affinity = SQLITE_AFF_NONE;
   p->nCol++;
 }
 
@@ -629,7 +637,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
     z[j++] = c;
   }
   z[j] = 0;
-  pCol->sortOrder = sqlite3CollateType(z, n);
+//  pCol->sortOrder = sqlite3CollateType(z, n);
+  pCol->affinity = sqlite3AffinityType(z, n);
 }
 
 /*
@@ -751,7 +760,42 @@ void sqlite3AddCollateType(Parse *pParse, int collType){
   int i;
   if( (p = pParse->pNewTable)==0 ) return;
   i = p->nCol-1;
-  if( i>=0 ) p->aCol[i].sortOrder = collType;
+
+  /* FIX ME */
+  /* if( i>=0 ) p->aCol[i].sortOrder = collType; */
+}
+
+/*
+** Parse the column type name zType (length nType) and return the
+** associated affinity type.
+*/
+char sqlite3AffinityType(const char *zType, int nType){
+  /* FIX ME: This could be done more efficiently */
+  int n, i;
+  struct {
+    const char *zSub;
+    int nSub;
+    char affinity;
+  } substrings[] = {
+    {"INT", 3, SQLITE_AFF_INTEGER},
+    {"REAL", 4, SQLITE_AFF_NUMERIC},
+    {"FLOAT", 5, SQLITE_AFF_NUMERIC},
+    {"DOUBLE", 6, SQLITE_AFF_NUMERIC},
+    {"NUM", 3, SQLITE_AFF_NUMERIC},
+    {"CHAR", 4, SQLITE_AFF_TEXT},
+    {"CLOB", 4, SQLITE_AFF_TEXT},
+    {"TEXT", 4, SQLITE_AFF_TEXT}
+  };
+
+  for(n=0; n<(nType-3); n++){
+    for(i=0; i<sizeof(substrings)/sizeof(substrings[0]); i++){
+      if( 0==sqlite3StrNICmp(zType, substrings[i].zSub, substrings[i].nSub) ){
+        return substrings[i].affinity;
+      }
+    }
+  }
+
+  return SQLITE_AFF_NONE;
 }
 
 /*
@@ -1295,39 +1339,6 @@ void sqlite3DropTable(Parse *pParse, Token *pName, int isView){
   sqliteViewResetAll(db, iDb);
 }
 
-/*
-** This routine constructs a P3 string suitable for an OP_MakeIdxKey
-** opcode and adds that P3 string to the most recently inserted instruction
-** in the virtual machine.  The P3 string consists of a single character
-** for each column in the index pIdx of table pTab.  If the column uses
-** a numeric sort order, then the P3 string character corresponding to
-** that column is 'n'.  If the column uses a text sort order, then the
-** P3 string is 't'.  See the OP_MakeIdxKey opcode documentation for
-** additional information.  See also the sqlite3AddKeyType() routine.
-*/
-void sqlite3AddIdxKeyType(Vdbe *v, Index *pIdx){
-  char *zType;
-  Table *pTab;
-  int i, n;
-  assert( pIdx!=0 && pIdx->pTable!=0 );
-  pTab = pIdx->pTable;
-  n = pIdx->nColumn;
-  zType = sqliteMallocRaw( n+1 );
-  if( zType==0 ) return;
-  for(i=0; i<n; i++){
-    int iCol = pIdx->aiColumn[i];
-    assert( iCol>=0 && iCol<pTab->nCol );
-    if( (pTab->aCol[iCol].sortOrder & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){
-      zType[i] = 't';
-    }else{
-      zType[i] = 'n';
-    }
-  }
-  zType[n] = 0;
-  sqlite3VdbeChangeP3(v, -1, zType, n);
-  sqliteFree(zType);
-}
-
 /*
 ** This routine is called to create a new foreign key on the table
 ** currently under construction.  pFromCol determines which columns
@@ -1725,7 +1736,7 @@ void sqlite3CreateIndex(
         }
       }
       sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
-      sqlite3AddIdxKeyType(v, pIndex);
+      sqlite3IndexAffinityStr(v, pIndex);
       sqlite3VdbeOp3(v, OP_IdxPut, 1, pIndex->onError!=OE_None,
                       "indexed columns are not unique", P3_STATIC);
       sqlite3VdbeAddOp(v, OP_Next, 2, lbl1);
index 0e7b9a29a480e448ba24273ff145172083b86c8b..4d6b3342590e019551ef43fc8743a342b659d185 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.64 2004/05/11 07:11:53 danielk1977 Exp $
+** $Id: delete.c,v 1.65 2004/05/16 11:15:37 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -387,7 +387,7 @@ void sqlite3GenerateRowIndexDelete(
       }
     }
     sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    sqlite3AddIdxKeyType(v, pIdx);
+    sqlite3IndexAffinityStr(v, pIdx);
     sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
   }
 }
index 405ecb3a49f909667c872ba989dd6e5d166b6f26..7fdd5e3ab4b059ffae2d66816ba9bc4ce565d161 100644 (file)
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.117 2004/05/11 07:11:53 danielk1977 Exp $
+** $Id: expr.c,v 1.118 2004/05/16 11:15:37 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
 
+static char exprAffinity(Expr *pExpr){
+  if( pExpr->op==TK_AS ){
+    return exprAffinity(pExpr->pLeft);
+  }
+  if( pExpr->op==TK_SELECT ){
+    return exprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
+  }
+  return pExpr->affinity;
+}
+
+/*
+** Return the P1 value that should be used for a binary comparison
+** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
+** If jumpIfNull is true, then set the low byte of the returned
+** P1 value to tell the opcode to jump if either expression
+** evaluates to NULL.
+*/
+int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
+  char aff1 = exprAffinity(pExpr1);
+  char aff2 = exprAffinity(pExpr2);
+
+  if( aff1 && aff2 ){
+    /* Both sides of the comparison are columns. If one has numeric or
+    ** integer affinity, use that. Otherwise use no affinity.
+    */
+    if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
+      aff1 = SQLITE_AFF_INTEGER;
+    }else
+    if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
+      aff1 = SQLITE_AFF_NUMERIC;
+    }else{
+      aff1 = SQLITE_AFF_NONE;
+    }
+  }else if( !aff1 ){
+    aff1 = aff2;
+  }
+
+  return (((int)aff1)<<8)+(jumpIfNull?1:0);
+}
+
 /*
 ** Construct a new expression node and return a pointer to it.  Memory
 ** for this node is obtained from sqliteMalloc().  The calling function
@@ -472,7 +512,11 @@ static int lookupName(
         pExpr->iDb = pTab->iDb;
         /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
         pExpr->iColumn = j==pTab->iPKey ? -1 : j;
-        pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK;
+        pExpr->affinity = pTab->aCol[j].affinity;
+
+        /* FIX ME: Expr::dataType will be removed... */
+        pExpr->dataType =
+            (pCol->affinity==SQLITE_AFF_TEXT?SQLITE_SO_TEXT:SQLITE_SO_NUM);
         break;
       }
     }
@@ -504,7 +548,10 @@ static int lookupName(
         if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
           cnt++;
           pExpr->iColumn = j==pTab->iPKey ? -1 : j;
-          pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK;
+          pExpr->affinity = pTab->aCol[j].affinity;
+          /* FIX ME: Expr::dataType will be removed... */
+          pExpr->dataType =
+              (pCol->affinity==SQLITE_AFF_TEXT?SQLITE_SO_TEXT:SQLITE_SO_NUM);
           break;
         }
       }
@@ -518,6 +565,7 @@ static int lookupName(
     cnt = 1;
     pExpr->iColumn = -1;
     pExpr->dataType = SQLITE_SO_NUM;
+    pExpr->affinity = SQLITE_AFF_INTEGER;
   }
 
   /*
@@ -1050,6 +1098,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
     case TK_INTEGER: {
       if( pExpr->op==TK_INTEGER && sqlite3FitsIn32Bits(pExpr->token.z) ){
         sqlite3VdbeAddOp(v, OP_Integer, atoi(pExpr->token.z), 0);
+      }else if( pExpr->op==TK_FLOAT ){
+        sqlite3VdbeAddOp(v, OP_Real, 0, 0);
       }else{
         sqlite3VdbeAddOp(v, OP_String, 0, 0);
       }
@@ -1072,10 +1122,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
     case TK_GE:
     case TK_NE:
     case TK_EQ: {
+      int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, 0);
+      sqlite3ExprCode(pParse, pExpr->pLeft);
+      sqlite3ExprCode(pParse, pExpr->pRight);
+      sqlite3VdbeAddOp(v, op, p1, 0);
+      break;
+#if 0
       if( sqlite3ExprType(pExpr)==SQLITE_SO_TEXT ){
         op += 6;  /* Convert numeric opcodes to text opcodes */
       }
       /* Fall through into the next case */
+#endif
     }
     case TK_AND:
     case TK_OR:
@@ -1135,8 +1192,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
       dest = sqlite3VdbeCurrentAddr(v) + 2;
       sqlite3VdbeAddOp(v, op, 1, dest);
       sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
-      break;
     }
+    break;
     case TK_AGG_FUNCTION: {
       sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
       break;
@@ -1153,7 +1210,13 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
       pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, 0);
       assert( pDef!=0 );
       nExpr = sqlite3ExprCodeExprList(pParse, pList, pDef->includeTypes);
-      sqlite3VdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_POINTER);
+      /* FIX ME: The following is a temporary hack. */
+      if( 0==sqlite3StrNICmp(zId, "classof", nId) ){
+        assert( nExpr==1 );
+        sqlite3VdbeOp3(v, OP_Class, nExpr, 0, 0, 0);
+      }else{
+        sqlite3VdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_POINTER);
+      }
       break;
     }
     case TK_SELECT: {
@@ -1332,12 +1395,10 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
     case TK_GE:
     case TK_NE:
     case TK_EQ: {
+      int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
       sqlite3ExprCode(pParse, pExpr->pLeft);
       sqlite3ExprCode(pParse, pExpr->pRight);
-      if( sqlite3ExprType(pExpr)==SQLITE_SO_TEXT ){
-        op += 6;  /* Convert numeric opcodes to text opcodes */
-      }
-      sqlite3VdbeAddOp(v, op, jumpIfNull, dest);
+      sqlite3VdbeAddOp(v, op, p1, dest);
       break;
     }
     case TK_ISNULL:
@@ -1427,18 +1488,10 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
     case TK_GE:
     case TK_NE:
     case TK_EQ: {
-      if( sqlite3ExprType(pExpr)==SQLITE_SO_TEXT ){
-        /* Convert numeric comparison opcodes into text comparison opcodes.
-        ** This step depends on the fact that the text comparision opcodes are
-        ** always 6 greater than their corresponding numeric comparison
-        ** opcodes.
-        */
-        assert( OP_Eq+6 == OP_StrEq );
-        op += 6;
-      }
+      int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
       sqlite3ExprCode(pParse, pExpr->pLeft);
       sqlite3ExprCode(pParse, pExpr->pRight);
-      sqlite3VdbeAddOp(v, op, jumpIfNull, dest);
+      sqlite3VdbeAddOp(v, op, p1, dest);
       break;
     }
     case TK_ISNULL:
index 5a4a46147dd41042c6a35cf3a3adcd9899c82509..3f623aaac3af455011fdbfabc5b5ee2e1eb9724d 100644 (file)
@@ -16,7 +16,7 @@
 ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: func.c,v 1.47 2004/05/14 11:00:53 danielk1977 Exp $
+** $Id: func.c,v 1.48 2004/05/16 11:15:38 danielk1977 Exp $
 */
 #include <ctype.h>
 #include <math.h>
@@ -571,6 +571,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){
     { "max",       -1, SQLITE_ARGS,    2, minmaxFunc },
     { "max",        0, 0,              2, 0          },
     { "typeof",     1, SQLITE_TEXT,    0, typeofFunc },
+    { "classof",    1, SQLITE_TEXT,    0, typeofFunc }, /* FIX ME: hack */
     { "length",     1, SQLITE_NUMERIC, 0, lengthFunc },
     { "substr",     3, SQLITE_TEXT,    0, substrFunc },
     { "abs",        1, SQLITE_NUMERIC, 0, absFunc    },
index 86c2fcc2ed9d7712b08f63d3b4270d7f079f9de1..a3c12ed12568f24e5b3ce1a1d48e420e6d74c700 100644 (file)
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.98 2004/05/14 11:00:53 danielk1977 Exp $
+** $Id: insert.c,v 1.99 2004/05/16 11:15:38 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
 /*
 ** Set P3 of the most recently inserted opcode to a column affinity
-** string for table pTab. A column affinity string has one character
+** string for index pIdx. A column affinity string has one character
 ** for each column in the table, according to the affinity of the column:
 **
 **  Character      Column affinity
 **  't'            TEXT
 **  'o'            NONE
 */
-int sqlite3AddRecordType(Vdbe *v, Table *pTab){
-  assert( pTab );
+void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
+  if( !pIdx->zColAff ){
+    /* The first time a column affinity string for a particular table is
+    ** required, it is allocated and populated here. It is then stored as
+    ** a member of the Table structure for subsequent use.
+    **
+    ** The column affinity string will eventually be deleted by
+    ** sqliteDeleteIndex() when the Table structure itself is cleaned
+    ** up.
+    */
+    int n;
+    Table *pTab = pIdx->pTable;
+    pIdx->zColAff = (char *)sqliteMalloc(pIdx->nColumn+1);
+    if( !pIdx->zColAff ){
+      return;
+    }
+    for(n=0; n<pIdx->nColumn; n++){
+      pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
+    }
+    pIdx->zColAff[pIdx->nColumn] = '\0';
+  }
  
+  sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, P3_STATIC);
+}
+
+/*
+** Set P3 of the most recently inserted opcode to a column affinity
+** string for table pTab. A column affinity string has one character
+** for each column indexed by the index, according to the affinity of the
+** column:
+**
+**  Character      Column affinity
+**  ------------------------------
+**  'n'            NUMERIC
+**  'i'            INTEGER
+**  't'            TEXT
+**  'o'            NONE
+*/
+void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
   /* The first time a column affinity string for a particular table
   ** is required, it is allocated and populated here. It is then 
   ** stored as a member of the Table structure for subsequent use.
@@ -42,28 +78,20 @@ int sqlite3AddRecordType(Vdbe *v, Table *pTab){
     char *zColAff;
     int i;
 
-    zColAff = sqliteMalloc(pTab->nCol+1);
+    zColAff = (char *)sqliteMalloc(pTab->nCol+1);
     if( !zColAff ){
-      return SQLITE_NOMEM;
+      return;
     }
 
     for(i=0; i<pTab->nCol; i++){
-      if( pTab->aCol[i].sortOrder&SQLITE_SO_TEXT ){
-        zColAff[i] = 't';
-      }else{
-        zColAff[i] = 'n';
-      }
+      zColAff[i] = pTab->aCol[i].affinity;
     }
     zColAff[pTab->nCol] = '\0';
 
     pTab->zColAff = zColAff;
   }
 
-  /* Set the memory management at the vdbe to P3_STATIC, as the column
-  ** affinity string is managed as part of the Table structure.
-  */
   sqlite3VdbeChangeP3(v, -1, pTab->zColAff, P3_STATIC);
-  return SQLITE_OK;
 }
 
 
@@ -267,7 +295,7 @@ void sqlite3Insert(
       srcTab = pParse->nTab++;
       sqlite3VdbeResolveLabel(v, iInsertBlock);
       sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
-      sqlite3AddRecordType(v, pTab);
+      sqlite3TableAffinityStr(v, pTab);
       sqlite3VdbeAddOp(v, OP_NewRecno, srcTab, 0);
       sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
       sqlite3VdbeAddOp(v, OP_PutIntKey, srcTab, 0);
@@ -446,7 +474,15 @@ void sqlite3Insert(
       }
     }
     sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
-    sqlite3AddRecordType(v, pTab);
+
+    /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
+    ** do not attempt any conversions before assembling the record.
+    ** If this is a real table, attempt conversions as required by the
+    ** table column affinities.
+    */
+    if( !isView ){
+      sqlite3TableAffinityStr(v, pTab);
+    }
     sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
 
     /* Fire BEFORE or INSTEAD OF triggers */
@@ -826,7 +862,7 @@ void sqlite3GenerateConstraintChecks(
       }
     }
     jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-    sqlite3AddIdxKeyType(v, pIdx);
+    sqlite3IndexAffinityStr(v, pIdx);
 
     /* Find out what action to take in case there is an indexing conflict */
     onError = pIdx->onError;
@@ -936,7 +972,7 @@ void sqlite3CompleteInsertion(
     sqlite3VdbeAddOp(v, OP_IdxPut, base+i+1, 0);
   }
   sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
-  sqlite3AddRecordType(v, pTab);
+  sqlite3TableAffinityStr(v, pTab);
   if( newIdx>=0 ){
     sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
     sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
index a344864d6e39b35e420d7a6e1ee8520a60930ccf..23e275a1ecc20d1159d0480884202d606a03ad7c 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the PRAGMA command.
 **
-** $Id: pragma.c,v 1.22 2004/05/11 08:48:11 danielk1977 Exp $
+** $Id: pragma.c,v 1.23 2004/05/16 11:15:38 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -667,7 +667,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
             }
           }
           sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
-          sqlite3AddIdxKeyType(v, pIdx);
+          sqlite3IndexAffinityStr(v, pIdx);
           jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
           addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
           sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
index 4db520187010fe4b2f9a1b350ac90b9d1440b623..ee88619605b0f002fdad29415d6066734a041403 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.233 2004/05/14 16:50:06 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.234 2004/05/16 11:15:39 danielk1977 Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -457,7 +457,8 @@ struct Column {
   char *zType;     /* Data type for this column */
   u8 notNull;      /* True if there is a NOT NULL constraint */
   u8 isPrimKey;    /* True if this column is part of the PRIMARY KEY */
-  u8 sortOrder;    /* Some combination of SQLITE_SO_... values */
+//  u8 sortOrder;    /* Some combination of SQLITE_SO_... values */ 
+  char affinity;   /* One of the SQLITE_AFF_... values */
   u8 dottedName;   /* True if zName contains a "." character */
 };
 
@@ -475,6 +476,15 @@ struct Column {
 #define SQLITE_SO_DESC      1  /* Sort in descending order */
 #define SQLITE_SO_DIRMASK   1  /* Mask to extract the sort direction */
 
+/*
+** Column affinity types.
+*/
+#define SQLITE_AFF_INTEGER  'i'
+#define SQLITE_AFF_NUMERIC  'n'
+#define SQLITE_AFF_TEXT     't'
+#define SQLITE_AFF_NONE     'o'
+
+
 /*
 ** Each SQL table is represented in memory by an instance of the
 ** following structure.
@@ -638,6 +648,7 @@ struct Index {
   u8 onError;      /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
   u8 autoIndex;    /* True if is automatically created (ex: by UNIQUE) */
   u8 iDb;          /* Index in sqlite.aDb[] of where this index is stored */
+  char *zColAff;   /* String defining the affinity of each column */
   Index *pNext;    /* The next index associated with the same table */
 };
 
@@ -707,6 +718,7 @@ struct Expr {
                          ** result from the iAgg-th element of the aggregator */
   Select *pSelect;       /* When the expression is a sub-select.  Also the
                          ** right side of "<expr> IN (<select>)" */
+  char affinity;         /* The affinity of the column or 0 if not a column */
 };
 
 /*
@@ -1291,4 +1303,7 @@ int sqlite3PutVarint(unsigned char *, u64);
 int sqlite3GetVarint(const unsigned char *, u64 *);
 int sqlite3GetVarint32(const unsigned char *, u32 *);
 int sqlite3VarintLen(u64 v);
-int sqlite3AddRecordType(Vdbe*, Table*);
+char sqlite3AffinityType(const char *, int);
+void sqlite3IndexAffinityStr(Vdbe *, Index *);
+void sqlite3TableAffinityStr(Vdbe *, Table *);
+
index 2c3c3c300d082e53494b66aef3c78f03e44f92fe..f8dca1bef6f61de8090b3f9768f8fb0d8f3be2cc 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.73 2004/05/14 11:00:53 danielk1977 Exp $
+** $Id: update.c,v 1.74 2004/05/16 11:15:39 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -287,7 +287,10 @@ void sqlite3Update(
       }
     }
     sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
-    sqlite3AddRecordType(v, pTab);
+    if( !isView ){
+      sqlite3TableAffinityStr(v, pTab);
+    }
+    if( pParse->nErr ) goto update_cleanup;
     sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
     if( !isView ){
       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
index c4223c6f32eab330bfc9c95d1f731ddf757e7ed3..32fb41f1c0067877d1e399ea265c8679c8b4774a 100644 (file)
@@ -43,7 +43,7 @@
 ** 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.293 2004/05/14 21:59:40 drh Exp $
+** $Id: vdbe.c,v 1.294 2004/05/16 11:15:40 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -428,15 +428,16 @@ static int expandCursorArraySize(Vdbe *p, int mxCursor){
 ** Apply any conversion required by the supplied column affinity to
 ** memory cell pRec. affinity may be one of:
 **
-** SQLITE_AFF_NUM
+** SQLITE_AFF_NUMERIC
 ** SQLITE_AFF_TEXT
 ** SQLITE_AFF_NONE
 ** SQLITE_AFF_INTEGER
 **
 */
-static void applyAffinity(Mem *pRec, int affinity){
+static void applyAffinity(Mem *pRec, char affinity){
   switch( affinity ){
-    case SQLITE_SO_NUM:
+    case SQLITE_AFF_INTEGER:
+    case SQLITE_AFF_NUMERIC:
       if( 0==(pRec->flags&(MEM_Real|MEM_Int)) ){
         /* pRec does not have a valid integer or real representation. 
         ** Attempt a conversion if pRec has a string representation and
@@ -451,8 +452,19 @@ static void applyAffinity(Mem *pRec, int affinity){
           }
         }
       }
+
+      if( affinity==SQLITE_AFF_INTEGER ){
+        /* For INTEGER affinity, try to convert a real value to an int */
+        if( pRec->flags&MEM_Real ){
+          pRec->i = pRec->r;
+          if( ((double)pRec->i)==pRec->r ){
+            pRec->flags |= MEM_Int;
+          }
+        }
+      }
       break;
-    case SQLITE_SO_TEXT:
+
+    case SQLITE_AFF_TEXT:
       /* Only attempt the conversion if there is an integer or real
       ** representation (blob and NULL do not get converted) but no string
       ** representation.
@@ -464,28 +476,15 @@ static void applyAffinity(Mem *pRec, int affinity){
 
       break;
 
-/*
-    case SQLITE_AFF_INTEGER:
     case SQLITE_AFF_NONE:
+      /* Affinity NONE. Do nothing. */
       break;
-*/
+
     default:
       assert(0);
   }
 }
 
-/*
-** This function interprets the character 'affinity' according to the 
-** following table and calls the applyAffinity() function.
-*/
-static void applyAffinityByChar(Mem *pRec, char affinity){
-  switch( affinity ){
-    case 'n': return applyAffinity(pRec, SQLITE_SO_NUM);
-    case 't': return applyAffinity(pRec, SQLITE_SO_TEXT);
-    default: assert(0);
-  }
-}
-
 #ifdef VDBE_PROFILE
 /*
 ** The following routine only works on pentium-class processors.
@@ -773,6 +772,24 @@ case OP_String: {
   break;
 }
 
+/* Opcode: Real * * P3
+**
+** The string value P3 is converted to a real and pushed on to the stack.
+*/
+case OP_Real: {
+  char *z = pOp->p3;
+
+  assert( z );
+  assert( sqlite3IsNumber(z, 0) );
+
+  pTos++;
+  pTos->r = sqlite3AtoF(z, 0);
+  pTos->z = z;
+  pTos->n = strlen(z)+1;
+  pTos->flags = MEM_Real|MEM_Str|MEM_Static;
+  break;
+}
+
 /* Opcode: Variable P1 * *
 **
 ** Push the value of variable P1 onto the stack.  A variable is
@@ -1358,17 +1375,31 @@ mismatch:
 ** 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.
+** The least significant byte of P1 may be either 0x00 or 0x01. If either
+** operand is NULL (and thus if the result is unknown) then take the jump
+** only if the least significant byte of P1 is 0x01.
 **
-** If both values are numeric, they are converted to doubles using atof()
-** and compared for equality that way.  Otherwise the strcmp() library
-** routine is used for the comparison.  For a pure text comparison
-** use OP_StrEq.
+** The second least significant byte of P1 determines whether any
+** conversions are applied to the two values before the comparison is made.
+** If this byte is 0x00, and one of the values being compared is numeric
+** and the other text, an attempt is made to convert the text value to 
+** a numeric form.
+**
+** If the second least significant byte of P1 is not 0x00, then it must
+** be an affinity character - 'n', 't', 'i' or 'o'. In this case an 
+** attempt is made to coerce both values according to the affinity before
+** the comparison is made.
+**
+** Once any conversions have taken place, and neither value is NULL, 
+** the values are compared. If both values are blobs, or both are text,
+** then memcmp() is used to determine the results of the comparison. If
+** both values are numeric, then a numeric comparison is used. If the
+** two values are of different types, then they are inequal.
 **
 ** 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 *
 **
@@ -1463,6 +1494,8 @@ mismatch:
 ** 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.
+**
+** FIX ME: The comment for OP_Eq is up to date, but none of the others are.
 */
 case OP_Eq:
 case OP_Ne:
@@ -1470,6 +1503,62 @@ case OP_Lt:
 case OP_Le:
 case OP_Gt:
 case OP_Ge: {
+  Mem *pNos;
+  int flags;
+  int res;
+  char affinity;
+
+  pNos = &pTos[-1];
+  flags = pTos->flags|pNos->flags;
+
+  /* If either value is a NULL P2 is not zero, take the jump if the least
+  ** significant byte of P1 is true. If P2 is zero, then push a NULL onto
+  ** the stack.
+  */
+  if( flags&MEM_Null ){
+    popStack(&pTos, 2);
+    if( pOp->p2 ){
+      if( pOp->p1 ) pc = pOp->p2-1;
+    }else{
+      pTos++;
+      pTos->flags = MEM_Null;
+    }
+    break;
+  }
+
+  affinity = (pOp->p1>>8)&0xFF;
+  if( !affinity && (flags&(MEM_Real|MEM_Int)) ){
+    affinity = SQLITE_AFF_NUMERIC;
+  }
+  if( affinity ){
+    applyAffinity(pNos, affinity);
+    applyAffinity(pTos, affinity);
+  }
+
+  res = sqlite3MemCompare(pNos, pTos);
+  switch( pOp->opcode ){
+    case OP_Eq:    res = res==0;     break;
+    case OP_Ne:    res = res!=0;     break;
+    case OP_Lt:    res = res<0;      break;
+    case OP_Le:    res = res<=0;     break;
+    case OP_Gt:    res = res>0;      break;
+    default:       res = res>=0;     break;
+  }
+
+  popStack(&pTos, 2);
+  if( pOp->p2 ){
+    if( res ){
+      pc = pOp->p2-1;
+    }
+  }else{
+    pTos++;
+    pTos->flags = MEM_Int;
+    pTos->i = res;
+  }
+  break;
+}
+
+#if 0
   Mem *pNos = &pTos[-1];
   i64 c, v;
   int ft, fn;
@@ -1514,6 +1603,7 @@ case OP_Ge: {
   }
   break;
 }
+#endif
 /* INSERT NO CODE HERE!
 **
 ** The opcode numbers are extracted from this source file by doing
@@ -1874,6 +1964,44 @@ case OP_NotNull: {
   break;
 }
 
+/* Opcode: Class * * *
+**
+** Pop a single value from the top of the stack and push on one of the
+** following strings, according to the storage class of the value just
+** popped:
+**
+** "NULL", "INTEGER", "REAL", "TEXT", "BLOB"
+**
+** This opcode is probably temporary.
+*/
+case OP_Class: {
+  int flags = pTos->flags;
+  int i;
+
+  struct {
+    int mask;
+    char * zClass;
+  } classes[] = {
+    {MEM_Null, "NULL"},
+    {MEM_Int, "INTEGER"},
+    {MEM_Real, "REAL"},
+    {MEM_Str, "TEXT"},
+    {MEM_Blob, "BLOB"}
+  };
+
+  Release(pTos);
+  pTos->flags = MEM_Str|MEM_Static;
+
+  for(i=0; i<5; i++){
+    if( classes[i].mask&flags ){
+      pTos->z = classes[i].zClass;
+      break;
+    }
+  }
+  assert( i<5 );
+  break;
+}
+
 /* Opcode: Column P1 P2 *
 **
 ** Interpret the data that cursor P1 points to as a structure built using
@@ -1958,11 +2086,11 @@ case OP_Column: {
     if( zRec ){
       zData = zRec;
     }else{
-      /* We can assume that 9 bytes (maximum length of a varint) fits
+      /* We can assume that 10 bytes (maximum length of a varint) fits
       ** on the main page in all cases.
       */
-      int n = 9;
-      if( payloadSize<9 ) n = payloadSize;
+      int n = 10;
+      if( payloadSize<10 ) n = payloadSize;
       if( pC->keyAsData ){
         zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n);
       }else{
@@ -2152,7 +2280,7 @@ case OP_MakeRecord: {
   for(pRec=pData0; pRec<=pTos; pRec++){
     u64 serial_type;
     if( zAffinity ){
-      applyAffinityByChar(pRec, zAffinity[pRec-pData0]);
+      applyAffinity(pRec, zAffinity[pRec-pData0]);
     }
     serial_type = sqlite3VdbeSerialType(pRec);
     nBytes += sqlite3VdbeSerialTypeLen(serial_type);
@@ -2274,7 +2402,7 @@ case OP_MakeIdxKey: {
   for(pRec=pData0; pRec<=pTos; pRec++){
     u64 serial_type;
     if( zAffinity ){
-      applyAffinityByChar(pRec, zAffinity[pRec-pData0]);
+      applyAffinity(pRec, zAffinity[pRec-pData0]);
     }else{
       applyAffinity(pRec, SQLITE_SO_NUM);
     }
index 682774bbb205caa2630bc5cc4baab74da44252ca..71765a5df74158c9aa4ac13aeb2a90b6709f5a28 100644 (file)
@@ -333,3 +333,4 @@ int sqlite3VdbeSerialGet(const unsigned char *, u64, Mem *);
 int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
 int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int, int*);
 int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
+int sqlite3MemCompare(Mem *, Mem *);
index 5e3672f918ba1a5223f5e6951d2cff80e3e28b7b..80a0f9a9b1ce99af380d82348820d967f1402770 100644 (file)
@@ -1317,7 +1317,7 @@ int sqlite3VdbeSerialGet(const unsigned char *buf, u64 serial_type, Mem *pMem){
 **
 ** Two NULL values are considered equal by this function.
 */
-int compareMemCells(Mem *pMem1, Mem *pMem2){
+int sqlite3MemCompare(Mem *pMem1, Mem *pMem2){
   int rc;
   int combined_flags = pMem1->flags|pMem2->flags; 
  
@@ -1430,7 +1430,7 @@ int sqlite3VdbeKeyCompare(
     offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1);
     offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2);
 
-    rc = compareMemCells(&mem1, &mem2);
+    rc = sqlite3MemCompare(&mem1, &mem2);
     if( mem1.flags&MEM_Dyn ){
       sqliteFree(mem1.z);
     }
index a148e1e1ade044e2e13e379cbb498b8b97d0ec07..aa3f3283b0f0c1b8f34740e47b8852ae645702ae 100644 (file)
@@ -12,7 +12,7 @@
 ** This module contains C code that generates VDBE code used to process
 ** the WHERE clause of SQL statements.
 **
-** $Id: where.c,v 1.93 2004/05/14 11:16:56 danielk1977 Exp $
+** $Id: where.c,v 1.94 2004/05/16 11:15:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -798,7 +798,7 @@ WhereInfo *sqlite3WhereBegin(
       sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
       sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
       sqlite3VdbeAddOp(v, OP_MakeKey, nColumn, 0);
-      sqlite3AddIdxKeyType(v, pIdx);
+      sqlite3IndexAffinityStr(v, pIdx);
       sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
       if( nColumn==pIdx->nColumn || pLevel->bRev ){
         testOp = OP_IdxGT;
@@ -1003,7 +1003,7 @@ WhereInfo *sqlite3WhereBegin(
         sqlite3VdbeAddOp(v, OP_Pop, nCol, 0);
         sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
         sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0);
-        sqlite3AddIdxKeyType(v, pIdx);
+        sqlite3IndexAffinityStr(v, pIdx);
         if( pLevel->bRev ){
           sqlite3VdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
           if( !geFlag ){
@@ -1059,7 +1059,7 @@ WhereInfo *sqlite3WhereBegin(
         sqlite3VdbeAddOp(v, OP_Pop, nCol, 0);
         sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
         sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0);
-        sqlite3AddIdxKeyType(v, pIdx);
+        sqlite3IndexAffinityStr(v, pIdx);
         if( pLevel->bRev ){
           pLevel->iMem = pParse->nMem++;
           sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
index a0ca2bf3252f737c5f63e7876d49569fd215d590..18b5918c62432121c391fb25ebf4920baadc5460 100644 (file)
 #    May you share freely, never taking more than you give.
 #
 #***********************************************************************
-# This file implements regression tests for SQLite library. 
+# This file implements regression tests for SQLite library. Specfically
+# it tests that the different storage classes (integer, real, text etc.)
+# all work correctly.
 #
-# $Id:
-
+# $Id: types.test,v 1.2 2004/05/16 11:15:42 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
+# Tests in this file are organized roughly as follows:
+#
+# types-1.*.*: Test that values are stored using the expected storage
+#              classes when various forms of literals are inserted into
+#              columns with different affinities.
+# types-1.1.*: INSERT INTO <table> VALUES(...)
+# types-1.2.*: INSERT INTO <table> SELECT...
+# types-1.3.*: UPDATE <table> SET...
 #
-# Test cases are organized as follows:
+# types-2.*.*: Check that values can be stored and retrieving using the
+#              various storage classes.
+# types-2.1.*: INTEGER
+# types-2.2.*: REAL
+# types-2.3.*: NULL
+# types-2.4.*: TEXT
+# types-2.5.*: Records with a few different storage classes.
 #
-# types-1.*: Insert some records with integers of various sizes, checking 
-#            that the integers are stored correctly and can be retrieved.
-# types-2.*: Insert and retrieve some records with reals.
-# types-3.*: Insert and retrieve some records with NULLs.
-# types-4.*: Insert and retrieve some records with strings of various sizes.
-# types-5.*: Some tests inserting and retrieving records with several
-#            fields each.
+# types-3.*: Test that the '=' operator respects manifest types.
 #
 
+
+# Create a table with one column for each type of affinity
+do_test types-1.1.0 {
+  execsql {
+    CREATE TABLE t1(i integer, n numeric, t text, o);
+  }
+} {}
+
+# Each element of the following list represents one test case.
+#
+# The first value of each sub-list is an SQL literal. The following
+# four value are the storage classes that would be used if the
+# literal were inserted into a column with affinity INTEGER, NUMERIC, TEXT
+# or NONE, respectively.
+set values [list \
+  [list 5.0   INTEGER REAL    TEXT REAL] \
+  [list 5     INTEGER INTEGER TEXT INTEGER] \
+  [list '5.0' INTEGER REAL    TEXT TEXT] \
+  [list '5'   INTEGER INTEGER TEXT TEXT] \
+  [list 'abc' TEXT    TEXT    TEXT TEXT] \
+  [list NULL  NULL    NULL    NULL NULL] \
+]
+
+# This code tests that the storage classes specified above (in the $values
+# table) are correctly assigned when values are inserted using a statement
+# of the form:
+#
+# INSERT INTO <table> VALUE(<values>);
+#
+set tnum 1
+foreach val $values {
+  set lit [lindex $val 0]
+  execsql "DELETE FROM t1;"
+  execsql "INSERT INTO t1 VALUES($lit, $lit, $lit, $lit);"
+  do_test types-1.1.$tnum {
+    execsql {
+      SELECT classof(i), classof(n), classof(t), classof(o) FROM t1;
+    }
+  } [lrange $val 1 end]
+  incr tnum
+}
+
+# This code tests that the storage classes specified above (in the $values
+# table) are correctly assigned when values are inserted using a statement
+# of the form:
+#
+# INSERT INTO t1 SELECT ....
+#
+set tnum 1
+foreach val $values {
+  set lit [lindex $val 0]
+  execsql "DELETE FROM t1;"
+  execsql "INSERT INTO t1 SELECT $lit, $lit, $lit, $lit;"
+  do_test types-1.2.$tnum {
+    execsql {
+      SELECT classof(i), classof(n), classof(t), classof(o) FROM t1;
+    }
+  } [lrange $val 1 end]
+  incr tnum
+}
+
+# This code tests that the storage classes specified above (in the $values
+# table) are correctly assigned when values are inserted using a statement
+# of the form:
+#
+# UPDATE <table> SET <column> = <value>;
+#
+set tnum 1
+foreach val $values {
+  set lit [lindex $val 0]
+  execsql "UPDATE t1 SET i = $lit, n = $lit, t = $lit, o = $lit;"
+  do_test types-1.3.$tnum {
+    execsql {
+      SELECT classof(i), classof(n), classof(t), classof(o) FROM t1;
+    }
+  } [lrange $val 1 end]
+  incr tnum
+}
+
+execsql {
+  DROP TABLE t1;
+}
+
 # Open the table with root-page $rootpage at the btree
 # level. Return a list that is the length of each record
 # in the table, in the tables default scanning order.
@@ -47,7 +139,7 @@ proc record_sizes {rootpage} {
 
 # Create a table and insert some 1-byte integers. Make sure they 
 # can be read back OK. These should be 3 byte records.
-do_test types-1.1 {
+do_test types-2.1.1 {
   execsql {
     CREATE TABLE t1(a integer);
     INSERT INTO t1 VALUES(0);
@@ -55,46 +147,46 @@ do_test types-1.1 {
     INSERT INTO t1 VALUES(-120);
   }
 } {}
-do_test types-1.2 {
+do_test types-2.1.2 {
   execsql {
     SELECT a FROM t1;
   }
 } {0 120 -120}
 
 # Try some 2-byte integers (4 byte records)
-do_test types-1.3 {
+do_test types-2.1.3 {
   execsql {
     INSERT INTO t1 VALUES(30000);
     INSERT INTO t1 VALUES(-30000);
   }
 } {}
-do_test types-1.4 {
+do_test types-2.1.4 {
   execsql {
     SELECT a FROM t1;
   }
 } {0 120 -120 30000 -30000}
 
 # 4-byte integers (6 byte records)
-do_test types-1.5 {
+do_test types-2.1.5 {
   execsql {
     INSERT INTO t1 VALUES(2100000000);
     INSERT INTO t1 VALUES(-2100000000);
   }
 } {}
-do_test types-1.6 {
+do_test types-2.1.6 {
   execsql {
     SELECT a FROM t1;
   }
 } {0 120 -120 30000 -30000 2100000000 -2100000000}
 
 # 8-byte integers (10 byte records)
-do_test types-1.7 {
+do_test types-2.1.7 {
   execsql {
     INSERT INTO t1 VALUES(9000000*1000000*1000000);
     INSERT INTO t1 VALUES(-9000000*1000000*1000000);
   }
 } {}
-do_test types-1.8 {
+do_test types-2.1.8 {
   execsql {
     SELECT a FROM t1;
   }
@@ -102,53 +194,53 @@ do_test types-1.8 {
         9000000000000000000 -9000000000000000000]
 
 # Check that all the record sizes are as we expected.
-do_test types-1.9 {
+do_test types-2.1.9 {
   set root [db eval {select rootpage from sqlite_master where name = 't1'}]
   record_sizes $root
 } {3 3 3 4 4 6 6 10 10}
 
 # Insert some reals. These should be 10 byte records.
-do_test types-2.1 {
+do_test types-2.2.1 {
   execsql {
     CREATE TABLE t2(a float);
-    INSERT INTO t2 VALUES(0.0 + 0.0);
-    INSERT INTO t2 VALUES(12345.678 + 0.0);
-    INSERT INTO t2 VALUES(-12345.678 + 0.0);
+    INSERT INTO t2 VALUES(0.0);
+    INSERT INTO t2 VALUES(12345.678);
+    INSERT INTO t2 VALUES(-12345.678);
   }
 } {}
-do_test types-2.2 {
+do_test types-2.2.2 {
   execsql {
     SELECT a FROM t2;
   }
 } {0 12345.678 -12345.678}
 
 # Check that all the record sizes are as we expected.
-do_test types-2.3 {
+do_test types-2.2.3 {
   set root [db eval {select rootpage from sqlite_master where name = 't2'}]
   record_sizes $root
 } {10 10 10}
 
 # Insert a NULL. This should be a two byte record.
-do_test types-3.1 {
+do_test types-2.3.1 {
   execsql {
     CREATE TABLE t3(a nullvalue);
     INSERT INTO t3 VALUES(NULL);
   }
 } {}
-do_test types-3.2 {
+do_test types-2.3.2 {
   execsql {
     SELECT a ISNULL FROM t3;
   }
 } {1}
 
 # Check that all the record sizes are as we expected.
-do_test types-3.3 {
+do_test types-2.3.3 {
   set root [db eval {select rootpage from sqlite_master where name = 't3'}]
   record_sizes $root
 } {2}
 
 # Insert a couple of strings.
-do_test types-4.1 {
+do_test types-2.4.1 {
   set string10 abcdefghij
   set string500 [string repeat $string10 50]
   set string500000 [string repeat $string10 50000]
@@ -160,19 +252,19 @@ do_test types-4.1 {
     INSERT INTO t4 VALUES('$string500000');
   "
 } {}
-do_test types-4.2 {
+do_test types-2.4.2 {
   execsql {
     SELECT a FROM t4;
   }
 } [list $string10 $string500 $string500000]
 
 # Check that all the record sizes are as we expected.
-do_test types-4.3 {
+do_test types-2.4.3 {
   set root [db eval {select rootpage from sqlite_master where name = 't4'}]
   record_sizes $root
 } {13 504 500005}
 
-do_test types-5.1 {
+do_test types-2.5.1 {
   execsql {
     DROP TABLE t1;
     DROP TABLE t2;
@@ -181,7 +273,7 @@ do_test types-5.1 {
     CREATE TABLE t1(a, b, c);
   }
 } {}
-do_test types-5.2 {
+do_test types-2.5.2 {
   set string10 abcdefghij
   set string500 [string repeat $string10 50]
   set string500000 [string repeat $string10 50000]
@@ -190,11 +282,11 @@ do_test types-5.2 {
   execsql "INSERT INTO t1 VALUES('$string500', 4000, NULL);"
   execsql "INSERT INTO t1 VALUES(4000, NULL, '$string500000');"
 } {}
-do_test types-5.3 {
+do_test types-2.5.3 {
   execsql {
     SELECT * FROM t1;
   }
 } [list {} $string10 4000 $string500 4000 {} 4000 {} $string500000]
 
-
 finish_test
+
diff --git a/test/types2.test b/test/types2.test
new file mode 100644 (file)
index 0000000..40a4569
--- /dev/null
@@ -0,0 +1,189 @@
+# 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 the interaction of manifest types, type affinity
+# and comparison expressions.
+#
+# $Id: types2.test,v 1.1 2004/05/16 11:15:42 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Tests in this file are organized roughly as follows:
+#
+# types2-1.*: The '=' operator in the absence of an index.
+# types2-2.*: The '=' operator implemented using an index.
+# types2-2.*: The '<' operator implemented using an index.
+# types2-3.*: The '>' operator in the absense of an index.
+#
+
+execsql {
+  CREATE TABLE t1(
+    i1 INTEGER,
+    i2 INTEGER,
+    n1 NUMERIC,
+    n2 NUMERIC,
+    t1 TEXT,
+    t2 TEXT,
+    o1,
+    o2
+  );
+  INSERT INTO t1 VALUES(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+}
+
+proc test_bool {testname vars expr res} {
+  if { $vars != "" } {
+    execsql "UPDATE t1 SET $vars"
+  }
+
+  foreach {t e r} [list $testname $expr $res] {}
+
+  do_test $t.1 "execsql {SELECT $e FROM t1}" $r
+  do_test $t.2 "execsql {SELECT 1 FROM t1 WHERE $expr}" [expr $r?"1":""]
+  do_test $t.3 "execsql {SELECT 1 FROM t1 WHERE NOT ($e)}" [expr $r?"":"1"]
+}
+
+# Compare literals against literals
+test_bool types2-1.1 "" {500 = 500.0} 1
+test_bool types2-1.2 "" {'500' = 500.0} 1
+test_bool types2-1.3 "" {500 = '500.0'} 1
+test_bool types2-1.4 "" {'500' = '500.0'} 0
+
+# Compare literals against a column with TEXT affinity
+test_bool types2-1.5 {t1=500} {500 = t1} 1
+test_bool types2-1.6 {t1=500} {'500' = t1} 1
+test_bool types2-1.7 {t1=500} {500.0 = t1} 0
+test_bool types2-1.8 {t1=500} {'500.0' = t1} 0
+test_bool types2-1.9 {t1='500'} {500 = t1} 1
+test_bool types2-1.10 {t1='500'} {'500' = t1} 1
+test_bool types2-1.11 {t1='500'} {500.0 = t1} 0
+test_bool types2-1.12 {t1='500'} {'500.0' = t1} 0
+
+# Compare literals against a column with NUMERIC affinity
+test_bool types2-1.13 {n1=500} {500 = n1} 1
+test_bool types2-1.14 {n1=500} {'500' = n1} 1
+test_bool types2-1.15 {n1=500} {500.0 = n1} 1
+test_bool types2-1.16 {n1=500} {'500.0' = n1} 1
+test_bool types2-1.17 {n1='500'} {500 = n1} 1
+test_bool types2-1.18 {n1='500'} {'500' = n1} 1
+test_bool types2-1.19 {n1='500'} {500.0 = n1} 1
+test_bool types2-1.20 {n1='500'} {'500.0' = n1} 1
+
+# Compare literals against a column with affinity NONE
+test_bool types2-1.21 {o1=500} {500 = o1} 1
+test_bool types2-1.22 {o1=500} {'500' = o1} 0
+test_bool types2-1.23 {o1=500} {500.0 = o1} 1
+test_bool types2-1.24 {o1=500} {'500.0' = o1} 0
+test_bool types2-1.25 {o1='500'} {500 = o1} 0
+test_bool types2-1.26 {o1='500'} {'500' = o1} 1
+test_bool types2-1.27 {o1='500'} {500.0 = o1} 0
+test_bool types2-1.28 {o1='500'} {'500.0' = o1} 0
+
+set vals [list 10 10.0 '10' '10.0' 20 20.0 '20' '20.0' 30 30.0 '30' '30.0']
+#              1  2    3    4      5  6    7    8      9  10   11   12
+
+execsql {
+  CREATE TABLE t2(i INTEGER, n NUMERIC, t TEXT, o);
+  CREATE INDEX t2i1 ON t2(i);
+  CREATE INDEX t2i2 ON t2(n);
+  CREATE INDEX t2i3 ON t2(t);
+  CREATE INDEX t2i4 ON t2(o);
+}
+foreach v $vals {
+  execsql "INSERT INTO t2 VALUES($v, $v, $v, $v);"
+}
+
+proc test_boolset {testname where set} {
+  set ::tb_sql "SELECT rowid FROM t2 WHERE $where"
+  do_test $testname {
+    lsort -integer [execsql $::tb_sql]
+  } $set
+}
+
+test_boolset types2-2.1 {i = 10} {1 2 3 4}
+test_boolset types2-2.2 {i = 10.0} {1 2 3 4}
+test_boolset types2-2.3 {i = '10'} {1 2 3 4}
+test_boolset types2-2.4 {i = '10.0'} {1 2 3 4}
+
+test_boolset types2-2.5 {n = 20} {5 6 7 8}
+test_boolset types2-2.6 {n = 20.0} {5 6 7 8}
+test_boolset types2-2.7 {n = '20'} {5 6 7 8}
+test_boolset types2-2.8 {n = '20.0'} {5 6 7 8}
+
+test_boolset types2-2.9 {t = 20} {5 7}
+test_boolset types2-2.10 {t = 20.0} {6 8}
+test_boolset types2-2.11 {t = '20'} {5 7}
+test_boolset types2-2.12 {t = '20.0'} {6 8}
+
+test_boolset types2-2.10 {o = 30} {9 10}
+test_boolset types2-2.11 {o = 30.0} {9 10}
+test_boolset types2-2.12 {o = '30'} 11
+test_boolset types2-2.13 {o = '30.0'} 12
+
+test_boolset types2-3.1 {i < 20} {1 2 3 4}
+test_boolset types2-3.2 {i < 20.0} {1 2 3 4}
+test_boolset types2-3.3 {i < '20'} {1 2 3 4}
+test_boolset types2-3.4 {i < '20.0'} {1 2 3 4}
+
+test_boolset types2-3.1 {n < 20} {1 2 3 4}
+test_boolset types2-3.2 {n < 20.0} {1 2 3 4}
+test_boolset types2-3.3 {n < '20'} {1 2 3 4}
+test_boolset types2-3.4 {n < '20.0'} {1 2 3 4}
+
+test_boolset types2-3.1 {t < 20} {1 2 3 4}
+test_boolset types2-3.2 {t < 20.0} {1 2 3 4 5 7}
+test_boolset types2-3.3 {t < '20'} {1 2 3 4}
+test_boolset types2-3.4 {t < '20.0'} {1 2 3 4 5 7}
+
+test_boolset types2-3.1 {o < 20} {1 2}
+test_boolset types2-3.2 {o < 20.0} {1 2}
+test_boolset types2-3.3 {o < '20'} {1 2 3 4 5 6 9 10}
+test_boolset types2-3.3 {o < '20.0'} {1 2 3 4 5 6 7 9 10}
+
+# Compare literals against literals
+test_bool types2-4.1 "" {500 > 60.0} 1
+test_bool types2-4.2 "" {'500' > 60.0} 1
+test_bool types2-4.3 "" {500 > '60.0'} 1
+test_bool types2-4.4 "" {'500' > '60.0'} 0
+
+# Compare literals against a column with TEXT affinity
+test_bool types2-4.5 {t1=500.0} {t1 > 500} 1
+test_bool types2-4.6 {t1=500.0} {t1 > '500' } 1
+test_bool types2-4.7 {t1=500.0} {t1 > 500.0 } 0
+test_bool types2-4.8 {t1=500.0} {t1 > '500.0' } 0
+test_bool types2-4.9 {t1='500.0'} {t1 > 500 } 1
+test_bool types2-4.10 {t1='500.0'} {t1 > '500' } 1
+test_bool types2-4.11 {t1='500.0'} {t1 > 500.0 } 0
+test_bool types2-4.12 {t1='500.0'} {t1 > '500.0' } 0
+
+# Compare literals against a column with NUMERIC affinity
+test_bool types2-4.13 {n1=400} {500 > n1} 1
+test_bool types2-4.14 {n1=400} {'500' > n1} 1
+test_bool types2-4.15 {n1=400} {500.0 > n1} 1
+test_bool types2-4.16 {n1=400} {'500.0' > n1} 1
+test_bool types2-4.17 {n1='400'} {500 > n1} 1
+test_bool types2-4.18 {n1='400'} {'500' > n1} 1
+test_bool types2-4.19 {n1='400'} {500.0 > n1} 1
+test_bool types2-4.20 {n1='400'} {'500.0' > n1} 1
+
+# Compare literals against a column with affinity NONE
+test_bool types2-4.21 {o1=500} {500 > o1} 0
+test_bool types2-4.22 {o1=500} {'500' > o1} 1
+test_bool types2-4.23 {o1=500} {500.0 > o1} 0
+test_bool types2-4.24 {o1=500} {'500.0' > o1} 1
+test_bool types2-4.25 {o1='500'} {500 > o1} 0
+test_bool types2-4.26 {o1='500'} {'500' > o1} 0
+test_bool types2-4.27 {o1='500'} {500.0 > o1} 0
+test_bool types2-4.28 {o1='500'} {'500.0' > o1} 1
+
+finish_test
+
+