-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
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
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
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
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
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
-aab4b794b4238bad5c4a6aee7d4443732921127d
\ No newline at end of file
+a4af838f8d1b81ec6c8db97655c6876aca0738d9
\ No newline at end of file
** 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>
sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
strlen(pOld->zName)+1, pOld);
}
+ if( p->zColAff ){
+ sqliteFree(p->zColAff);
+ }
sqliteFree(p);
}
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++;
}
z[j++] = c;
}
z[j] = 0;
- pCol->sortOrder = sqlite3CollateType(z, n);
+// pCol->sortOrder = sqlite3CollateType(z, n);
+ pCol->affinity = sqlite3AffinityType(z, n);
}
/*
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;
}
/*
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
}
}
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);
** 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"
}
}
sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
- sqlite3AddIdxKeyType(v, pIdx);
+ sqlite3IndexAffinityStr(v, pIdx);
sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
}
}
** 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
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;
}
}
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;
}
}
cnt = 1;
pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM;
+ pExpr->affinity = SQLITE_AFF_INTEGER;
}
/*
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);
}
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:
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;
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: {
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:
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:
** 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>
{ "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 },
** 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.
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;
}
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);
}
}
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 */
}
}
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;
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);
*************************************************************************
** 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>
}
}
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);
*************************************************************************
** 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"
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 */
};
#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.
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 */
};
** 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 */
};
/*
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 *);
+
** 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"
}
}
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);
** 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"
** 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
}
}
}
+
+ 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.
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.
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
** 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 *
**
** 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:
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;
}
break;
}
+#endif
/* INSERT NO CODE HERE!
**
** The opcode numbers are extracted from this source file by doing
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
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{
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);
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);
}
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 *);
**
** 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;
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);
}
** 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"
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;
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 ){
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);
# 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.
# 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);
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;
}
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]
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;
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]
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
+
--- /dev/null
+# 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
+
+