Implement type affinity for table and index records (CVS 1375)
FossilOrigin-Name: dbfe6e93166d9557d66cab9dca7977baa3501e5e
This commit is contained in:
parent
b6f4148607
commit
3d1bfeaa22
48
manifest
48
manifest
@ -1,5 +1,5 @@
|
||||
C Changes\sto\sbtree\sand\spager\sin\spreparation\sfor\smoving\sto\srun-time\spage\nsize\sdetermination.\s(CVS\s1374)
|
||||
D 2004-05-14T01:58:12
|
||||
C Implement\stype\saffinity\sfor\stable\sand\sindex\srecords\s(CVS\s1375)
|
||||
D 2004-05-14T11:00:53
|
||||
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 2b85dc8f6b169bbe6bc0dab1730757f77d72811b
|
||||
F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
|
||||
F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
|
||||
F src/build.c f25e4ac9f102efd70188bc09a459c2b461fe2135
|
||||
F src/build.c e93f443a20eab57ffb77ff6244b1e09a1f7d9390
|
||||
F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
|
||||
F src/date.c 1564caa119511a1bb23dd0b1530ad38ed8c3349b
|
||||
F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
|
||||
F src/delete.c 30c8c4375e75e811c3668abf3f78970fe549f375
|
||||
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
||||
F src/expr.c a3aed7057bafb3a01e8af98a5f74a102621b7a91
|
||||
F src/func.c 4b3147e841a4db9bf41768d79aaa46e6655b239a
|
||||
F src/func.c 4053dc2141ea46e8e35df089d87bfcbab54320bc
|
||||
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
|
||||
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
||||
F src/insert.c 1e63d2774c4d893363e0c072f19d4c92a4ab982d
|
||||
F src/insert.c 5d4d1a59f66b558213984391985a418efc1c2797
|
||||
F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
|
||||
F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
|
||||
F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
|
||||
@ -47,9 +47,9 @@ F src/pragma.c 2ab2a12b62ec5370b9221f44b4743a633a90bfa8
|
||||
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
|
||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||
F src/select.c ca99ae4db14a45a436ec51d3e6bd48d44a3efb3c
|
||||
F src/shell.c 255b8b9023cb5274f56d87df437e8ce6ef810b91
|
||||
F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
|
||||
F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
|
||||
F src/sqliteInt.h 168f441f72f5d1ab476ea85ac544712fe57f31c0
|
||||
F src/sqliteInt.h 3b593addbd54228a545ec3ea4f7689c261ae5fa1
|
||||
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 6ca82fc4a0fb4d7f134e961921c906f6f3c8bc74
|
||||
F src/update.c 0441f8b64d616ef244583449e66c984e536c6c9b
|
||||
F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
|
||||
F src/util.c 778a8cd03ad6e52778602d20a3132c7d2d1b0a0c
|
||||
F src/util.c 58407b133dfe0b21af23e0aa89c058a2b3d8cb0f
|
||||
F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
|
||||
F src/vdbe.c a6ba83386f8137cb5aff7980a519c1529052849a
|
||||
F src/vdbe.c a6e1bfe1188f16783260a1fdc391ecc2c6a1dab6
|
||||
F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
|
||||
F src/vdbeInt.h d53f38078ca4727c5f2851bc47ad648645bfab82
|
||||
F src/vdbeaux.c 8bf71f7ba91a208c5e0a8bcf5da03889bc858041
|
||||
F src/where.c 487e55b1f64c8fbf0f46a9a90c2247fc45ae6a9a
|
||||
F src/vdbeInt.h 03f4c3642482570a697a42a9bbb12908c6535bbe
|
||||
F src/vdbeaux.c d8dc16e7bfb6201a2e2e4c020ba813e295de717f
|
||||
F src/where.c 292f3d3d056d69197573eceb5578d7ba905725df
|
||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||
F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
|
||||
F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56
|
||||
@ -89,10 +89,10 @@ F test/delete.test 92256384f1801760180ded129f7427884cf28886
|
||||
F test/expr.test 8b62f3fcac64fbd5c3d43d7a7984245743dcbe65
|
||||
F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7
|
||||
F test/format3.test 149cc166c97923fa60def047e90dd3fb32bba916
|
||||
F test/func.test 000515779001ac6899eec4b54e65c6e2501279d4
|
||||
F test/func.test e77f46af34c23081c3aacb84f25238b808bd7202
|
||||
F test/hook.test 1a67ce0cd64a6455d016962542f2822458dccc49
|
||||
F test/in.test 0de39b02ceeca90993b096822fb5a884661c5b47
|
||||
F test/index.test 9295deefbdb6dedbe01be8905f0c448fe5bd4079
|
||||
F test/index.test 231ff7a4c9d4d002c07d8383dc44184dad06e6ec
|
||||
F test/insert.test 6ec324659656f4a86e4abfcf1a1fd2795ba6b603
|
||||
F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
|
||||
F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91
|
||||
@ -120,16 +120,16 @@ F test/pager2.test 7ff175a28484fd324df9315dfe35f6fb159910ec
|
||||
F test/pragma.test 06c4e51998dd68115ef7a60abeeff7accf198f83
|
||||
F test/printf.test 46b3d07d59d871d0831b4a657f6dfcafe0574850
|
||||
F test/progress.test 701b6115c2613128ececdfe1398a1bd0e1a4cfb3 x
|
||||
F test/quick.test b9dc7ad37e96da28f7d0c5e9e154024307ef568b
|
||||
F test/quick.test fa37bb9bf8f6a531b33f852284fa03f89a407697
|
||||
F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
|
||||
F test/rowid.test 863e6e75878cccf03d166fe52023f20e09508683
|
||||
F test/select1.test 3bfcccd2eadcddbb07f1f5da6550aee8484ea4fb
|
||||
F test/select2.test 2115d8f7a34fcb5c0cbe8491f441830bc44d3398
|
||||
F test/select2.test bafe576b76616f101c06a780a8155d5a6c363127
|
||||
F test/select3.test 445a1a3dde4e2fd32541b311f55da5e2f8079d76
|
||||
F test/select4.test 804b48d637aeee5e952333a997cfba316b489a3a
|
||||
F test/select4.test d2443e558c5013b22eaa25533fa22ef0ff0b1095
|
||||
F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
|
||||
F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
|
||||
F test/sort.test ba07b107c16070208e6aab3cadea66ba079d85ba
|
||||
F test/sort.test 63e1b0e982f08f0ff5b55d420db31f6f8c0d4c1c
|
||||
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
|
||||
F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
|
||||
F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
|
||||
@ -191,7 +191,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||
P 790226c94493a6d58a7e52fd3ed35ef495fab11e
|
||||
R 1732d9617f45de2d10dd8c0de779aa14
|
||||
U drh
|
||||
Z 4d4be7c36b4d139bc06baaeae3481d2d
|
||||
P f63fb6dd4e8e33d4c1983396b1a0305836ee4df7
|
||||
R 063a4d7caa30f9e2870f52d893366e1a
|
||||
U danielk1977
|
||||
Z 458386d9c0f0338b7a617dad680da64b
|
||||
|
@ -1 +1 @@
|
||||
f63fb6dd4e8e33d4c1983396b1a0305836ee4df7
|
||||
dbfe6e93166d9557d66cab9dca7977baa3501e5e
|
@ -23,7 +23,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.182 2004/05/12 11:24:03 danielk1977 Exp $
|
||||
** $Id: build.c,v 1.183 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -350,6 +350,9 @@ void sqlite3DeleteTable(sqlite *db, Table *pTable){
|
||||
}
|
||||
sqliteFree(pTable->zName);
|
||||
sqliteFree(pTable->aCol);
|
||||
if( pTable->zColAff ){
|
||||
sqliteFree(pTable->zColAff);
|
||||
}
|
||||
sqlite3SelectDelete(pTable->pSelect);
|
||||
sqliteFree(pTable);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: date.c,v 1.18 2004/05/10 10:34:35 danielk1977 Exp $
|
||||
** $Id: date.c,v 1.19 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
**
|
||||
** NOTES:
|
||||
**
|
||||
@ -321,7 +321,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}else if( sqlite3IsNumber(zDate) ){
|
||||
}else if( sqlite3IsNumber(zDate, 0) ){
|
||||
p->rJD = sqlite3AtoF(zDate, 0);
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
|
@ -16,7 +16,7 @@
|
||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.46 2004/05/13 11:34:16 danielk1977 Exp $
|
||||
** $Id: func.c,v 1.47 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
@ -295,7 +295,7 @@ static void quoteFunc(sqlite_func *context, int argc, const char **argv){
|
||||
if( argc<1 ) return;
|
||||
if( argv[0]==0 ){
|
||||
sqlite3_set_result_string(context, "NULL", 4);
|
||||
}else if( sqlite3IsNumber(argv[0]) ){
|
||||
}else if( sqlite3IsNumber(argv[0], 0) ){
|
||||
sqlite3_set_result_string(context, argv[0], -1);
|
||||
}else{
|
||||
int i,j,n;
|
||||
|
56
src/insert.c
56
src/insert.c
@ -12,10 +12,61 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.97 2004/05/11 07:11:53 danielk1977 Exp $
|
||||
** $Id: insert.c,v 1.98 2004/05/14 11:00:53 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
|
||||
** for each column in the table, according to the affinity of the column:
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'n' NUMERIC
|
||||
** 'i' INTEGER
|
||||
** 't' TEXT
|
||||
** 'o' NONE
|
||||
*/
|
||||
int sqlite3AddRecordType(Vdbe *v, Table *pTab){
|
||||
assert( 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.
|
||||
**
|
||||
** The column affinity string will eventually be deleted by
|
||||
** sqlite3DeleteTable() when the Table structure itself is cleaned up.
|
||||
*/
|
||||
if( !pTab->zColAff ){
|
||||
char *zColAff;
|
||||
int i;
|
||||
|
||||
zColAff = sqliteMalloc(pTab->nCol+1);
|
||||
if( !zColAff ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pTab->aCol[i].sortOrder&SQLITE_SO_TEXT ){
|
||||
zColAff[i] = 't';
|
||||
}else{
|
||||
zColAff[i] = 'n';
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine is call to handle SQL of the following forms:
|
||||
**
|
||||
@ -216,6 +267,7 @@ void sqlite3Insert(
|
||||
srcTab = pParse->nTab++;
|
||||
sqlite3VdbeResolveLabel(v, iInsertBlock);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqlite3AddRecordType(v, pTab);
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, srcTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, srcTab, 0);
|
||||
@ -394,6 +446,7 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqlite3AddRecordType(v, pTab);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
|
||||
/* Fire BEFORE or INSTEAD OF triggers */
|
||||
@ -883,6 +936,7 @@ void sqlite3CompleteInsertion(
|
||||
sqlite3VdbeAddOp(v, OP_IdxPut, base+i+1, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqlite3AddRecordType(v, pTab);
|
||||
if( newIdx>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.95 2004/05/10 10:34:52 danielk1977 Exp $
|
||||
** $Id: shell.c,v 1.96 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -80,7 +80,7 @@ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
|
||||
/*
|
||||
** Determines if a string is a number of not.
|
||||
*/
|
||||
extern int sqlite3IsNumber(const char*);
|
||||
extern int sqlite3IsNumber(const char*, int*);
|
||||
|
||||
/*
|
||||
** This routine reads a line of text from standard input, stores
|
||||
@ -392,7 +392,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
char *zSep = i>0 ? ",": "";
|
||||
if( azArg[i]==0 ){
|
||||
fprintf(p->out,"%sNULL",zSep);
|
||||
}else if( sqlite3IsNumber(azArg[i]) ){
|
||||
}else if( sqlite3IsNumber(azArg[i], 0) ){
|
||||
fprintf(p->out,"%s%s",zSep, azArg[i]);
|
||||
}else{
|
||||
if( zSep[0] ) fprintf(p->out,"%s",zSep);
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.231 2004/05/12 11:24:03 danielk1977 Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.232 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "sqlite.h"
|
||||
@ -520,6 +520,7 @@ struct Table {
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
Trigger *pTrigger; /* List of SQL triggers on this table */
|
||||
FKey *pFKey; /* Linked list of all foreign keys in this table */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1110,7 +1111,7 @@ extern int always_code_trigger_setup;
|
||||
int sqlite3StrICmp(const char *, const char *);
|
||||
int sqlite3StrNICmp(const char *, const char *, int);
|
||||
int sqlite3HashNoCase(const char *, int);
|
||||
int sqlite3IsNumber(const char*);
|
||||
int sqlite3IsNumber(const char*, int*);
|
||||
int sqlite3Compare(const char *, const char *);
|
||||
int sqlite3SortCompare(const char *, const char *);
|
||||
void sqlite3RealToSortable(double r, char *);
|
||||
@ -1289,5 +1290,6 @@ void sqlite3utf16to16be(void *pData, int N);
|
||||
int sqlite3PutVarint(unsigned char *, u64);
|
||||
int sqlite3GetVarint(const unsigned char *, u64 *);
|
||||
int sqlite3VarintLen(u64 v);
|
||||
int sqlite3AddRecordType(Vdbe*, Table*);
|
||||
|
||||
|
||||
|
@ -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.72 2004/05/10 10:35:00 danielk1977 Exp $
|
||||
** $Id: update.c,v 1.73 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -287,6 +287,7 @@ void sqlite3Update(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqlite3AddRecordType(v, pTab);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
|
19
src/util.c
19
src/util.c
@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.80 2004/05/11 06:17:22 danielk1977 Exp $
|
||||
** $Id: util.c,v 1.81 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
@ -516,27 +516,32 @@ int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
|
||||
|
||||
/*
|
||||
** Return TRUE if z is a pure numeric string. Return FALSE if the
|
||||
** string contains any character which is not part of a number.
|
||||
** string contains any character which is not part of a number. If
|
||||
** the string is numeric and contains the '.' character, set *realnum
|
||||
** to TRUE (otherwise FALSE).
|
||||
**
|
||||
** Am empty string is considered non-numeric.
|
||||
*/
|
||||
int sqlite3IsNumber(const char *z){
|
||||
int sqlite3IsNumber(const char *z, int *realnum){
|
||||
if( *z=='-' || *z=='+' ) z++;
|
||||
if( !isdigit(*z) ){
|
||||
return 0;
|
||||
}
|
||||
z++;
|
||||
if( realnum ) *realnum = 0;
|
||||
while( isdigit(*z) ){ z++; }
|
||||
if( *z=='.' ){
|
||||
z++;
|
||||
if( !isdigit(*z) ) return 0;
|
||||
while( isdigit(*z) ){ z++; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
if( *z=='e' || *z=='E' ){
|
||||
z++;
|
||||
if( *z=='+' || *z=='-' ) z++;
|
||||
if( !isdigit(*z) ) return 0;
|
||||
while( isdigit(*z) ){ z++; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
return *z==0;
|
||||
}
|
||||
@ -644,8 +649,8 @@ int sqlite3Compare(const char *atext, const char *btext){
|
||||
}else if( btext==0 ){
|
||||
return 1;
|
||||
}
|
||||
isNumA = sqlite3IsNumber(atext);
|
||||
isNumB = sqlite3IsNumber(btext);
|
||||
isNumA = sqlite3IsNumber(atext, 0);
|
||||
isNumB = sqlite3IsNumber(btext, 0);
|
||||
if( isNumA ){
|
||||
if( !isNumB ){
|
||||
result = -1;
|
||||
@ -736,8 +741,8 @@ int sqlite3SortCompare(const char *a, const char *b){
|
||||
res = strcmp(&a[1],&b[1]);
|
||||
if( res ) break;
|
||||
}else{
|
||||
isNumA = sqlite3IsNumber(&a[1]);
|
||||
isNumB = sqlite3IsNumber(&b[1]);
|
||||
isNumA = sqlite3IsNumber(&a[1], 0);
|
||||
isNumB = sqlite3IsNumber(&b[1], 0);
|
||||
if( isNumA ){
|
||||
double rA, rB;
|
||||
if( !isNumB ){
|
||||
|
240
src/vdbe.c
240
src/vdbe.c
@ -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.287 2004/05/13 13:38:52 danielk1977 Exp $
|
||||
** $Id: vdbe.c,v 1.288 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -285,8 +285,8 @@ static void popStack(Mem **ppTos, int N){
|
||||
** Under Linux (RedHat 7.2) this routine is much faster than atoi()
|
||||
** for converting strings into integers.
|
||||
*/
|
||||
static int toInt(const char *zNum, int *pNum){
|
||||
int v = 0;
|
||||
static int toInt(const char *zNum, i64 *pNum){
|
||||
i64 v = 0;
|
||||
int neg;
|
||||
int i, c;
|
||||
if( *zNum=='-' ){
|
||||
@ -302,7 +302,8 @@ static int toInt(const char *zNum, int *pNum){
|
||||
v = v*10 + c - '0';
|
||||
}
|
||||
*pNum = neg ? -v : v;
|
||||
return c==0 && i>0 && (i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0));
|
||||
return c==0 && i>0 &&
|
||||
(i<10 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -421,6 +422,68 @@ static int expandCursorArraySize(Vdbe *p, int mxCursor){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Apply any conversion required by the supplied column affinity to
|
||||
** memory cell pRec. affinity may be one of:
|
||||
**
|
||||
** SQLITE_AFF_NUM
|
||||
** SQLITE_AFF_TEXT
|
||||
** SQLITE_AFF_NONE
|
||||
** SQLITE_AFF_INTEGER
|
||||
**
|
||||
*/
|
||||
static void applyAffinity(Mem *pRec, int affinity){
|
||||
switch( affinity ){
|
||||
case SQLITE_SO_NUM:
|
||||
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
|
||||
** it looks like a number.
|
||||
*/
|
||||
int realnum;
|
||||
if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum) ){
|
||||
if( realnum ){
|
||||
Realify(pRec);
|
||||
}else{
|
||||
Integerify(pRec);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SQLITE_SO_TEXT:
|
||||
/* Only attempt the conversion if there is an integer or real
|
||||
** representation (blob and NULL do not get converted) but no string
|
||||
** representation.
|
||||
*/
|
||||
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
|
||||
Stringify(pRec);
|
||||
}
|
||||
pRec->flags &= ~(MEM_Real|MEM_Int);
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
case SQLITE_AFF_INTEGER:
|
||||
case SQLITE_AFF_NONE:
|
||||
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.
|
||||
@ -499,6 +562,9 @@ int sqlite3VdbeExec(
|
||||
int nProgressOps = 0; /* Opcodes executed since progress callback. */
|
||||
#endif
|
||||
|
||||
/* FIX ME. */
|
||||
expandCursorArraySize(p, 100);
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
|
||||
assert( db->magic==SQLITE_MAGIC_BUSY );
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
|
||||
@ -1213,7 +1279,7 @@ case OP_ForceInt: {
|
||||
int v;
|
||||
assert( pTos>=p->aStack );
|
||||
if( (pTos->flags & (MEM_Int|MEM_Real))==0
|
||||
&& ((pTos->flags & MEM_Str)==0 || sqlite3IsNumber(pTos->z)==0) ){
|
||||
&& ((pTos->flags & MEM_Str)==0 || sqlite3IsNumber(pTos->z, 0)==0) ){
|
||||
Release(pTos);
|
||||
pTos--;
|
||||
pc = pOp->p2 - 1;
|
||||
@ -1256,10 +1322,10 @@ case OP_MustBeInt: {
|
||||
}
|
||||
pTos->i = i;
|
||||
}else if( pTos->flags & MEM_Str ){
|
||||
int v;
|
||||
i64 v;
|
||||
if( !toInt(pTos->z, &v) ){
|
||||
double r;
|
||||
if( !sqlite3IsNumber(pTos->z) ){
|
||||
if( !sqlite3IsNumber(pTos->z, 0) ){
|
||||
goto mismatch;
|
||||
}
|
||||
Realify(pTos);
|
||||
@ -1406,7 +1472,7 @@ case OP_Le:
|
||||
case OP_Gt:
|
||||
case OP_Ge: {
|
||||
Mem *pNos = &pTos[-1];
|
||||
int c, v;
|
||||
i64 c, v;
|
||||
int ft, fn;
|
||||
assert( pNos>=p->aStack );
|
||||
ft = pTos->flags;
|
||||
@ -2023,7 +2089,7 @@ case OP_Column: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode MakeRecord3 P1 * *
|
||||
/* Opcode MakeRecord P1 * P3
|
||||
**
|
||||
** This opcode (not yet in use) is a replacement for the current
|
||||
** OP_MakeRecord that supports the SQLite3 manifest typing feature.
|
||||
@ -2034,6 +2100,20 @@ case OP_Column: {
|
||||
** details of the format are irrelavant as long as the OP_Column
|
||||
** opcode can decode the record later. Refer to source code
|
||||
** comments for the details of the record format.
|
||||
**
|
||||
** P3 may be a string that is P1 characters long. The nth character of the
|
||||
** string indicates the column affinity that should be used for the nth
|
||||
** field of the index key (i.e. the first character of P3 corresponds to the
|
||||
** lowest element on the stack).
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'n' NUMERIC
|
||||
** 'i' INTEGER
|
||||
** 't' TEXT
|
||||
** 'o' NONE
|
||||
**
|
||||
** If P3 is NULL then all index fields have the affinity NONE.
|
||||
*/
|
||||
case OP_MakeRecord: {
|
||||
/* Assuming the record contains N fields, the record format looks
|
||||
@ -2056,18 +2136,24 @@ case OP_MakeRecord: {
|
||||
int nField = pOp->p1;
|
||||
unsigned char *zNewRecord;
|
||||
unsigned char *zCsr;
|
||||
char *zAffinity;
|
||||
Mem *pRec;
|
||||
int nBytes; /* Space required for this record */
|
||||
|
||||
Mem *pData0 = &pTos[1-nField];
|
||||
assert( pData0>=p->aStack );
|
||||
zAffinity = pOp->p3;
|
||||
|
||||
/* Loop through the elements that will make up the record to figure
|
||||
** out how much space is required for the new record.
|
||||
*/
|
||||
nBytes = sqlite3VarintLen(nField);
|
||||
for(pRec=pData0; pRec<=pTos; pRec++){
|
||||
u64 serial_type = sqlite3VdbeSerialType(pRec);
|
||||
u64 serial_type;
|
||||
if( zAffinity ){
|
||||
applyAffinityByChar(pRec, zAffinity[pRec-pData0]);
|
||||
}
|
||||
serial_type = sqlite3VdbeSerialType(pRec);
|
||||
nBytes += sqlite3VdbeSerialTypeLen(serial_type);
|
||||
nBytes += sqlite3VarintLen(serial_type);
|
||||
}
|
||||
@ -2213,7 +2299,7 @@ case OP_MakeKey2: {
|
||||
Stringify(pRec);
|
||||
pRec->flags &= ~(MEM_Int|MEM_Real);
|
||||
nByte += pRec->n+1;
|
||||
}else if( (flags & (MEM_Real|MEM_Int))!=0 || sqlite3IsNumber(pRec->z) ){
|
||||
}else if( (flags & (MEM_Real|MEM_Int))!=0 || sqlite3IsNumber(pRec->z, 0) ){
|
||||
if( (flags & (MEM_Real|MEM_Int))==MEM_Int ){
|
||||
pRec->r = pRec->i;
|
||||
}else if( (flags & (MEM_Real|MEM_Int))==0 ){
|
||||
@ -2285,15 +2371,43 @@ case OP_MakeKey2: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: MakeIdxKey3 P1 P2 *
|
||||
/* Opcode: MakeKey P1 P2 P3
|
||||
**
|
||||
** Convert the top P1 entries of the stack into a single entry suitable
|
||||
** for use as the key in an index. If P2 is not zero, then the original
|
||||
** entries are popped off the stack. If P2 is zero, the original entries
|
||||
** remain on the stack.
|
||||
**
|
||||
** P3 is interpreted in the same way as for MakeIdxKey.
|
||||
*/
|
||||
/* Opcode: MakeIdxKey P1 P2 P3
|
||||
**
|
||||
** Convert the top P1 entries of the stack into a single entry suitable
|
||||
** for use as the key in an index. In addition, take one additional integer
|
||||
** off of the stack, treat that integer as an eight-byte record number, and
|
||||
** append the integer to the key as a varint. Thus a total of P1+1 entries
|
||||
** are popped from the stack for this instruction and a single entry is
|
||||
** pushed back. The first P1 entries that are popped are strings and the
|
||||
** last entry (the lowest on the stack) is an integer record number.
|
||||
** pushed back.
|
||||
**
|
||||
** If P2 is not zero and one or more of the P1 entries that go into the
|
||||
** generated key is NULL, then jump to P2 after the new key has been
|
||||
** pushed on the stack. In other words, jump to P2 if the key is
|
||||
** guaranteed to be unique. This jump can be used to skip a subsequent
|
||||
** uniqueness test.
|
||||
**
|
||||
** P3 may be a string that is P1 characters long. The nth character of the
|
||||
** string indicates the column affinity that should be used for the nth
|
||||
** field of the index key (i.e. the first character of P3 corresponds to the
|
||||
** lowest element on the stack).
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'n' NUMERIC
|
||||
** 'i' INTEGER
|
||||
** 't' TEXT
|
||||
** 'o' NONE
|
||||
**
|
||||
** If P3 is NULL then all index fields have the affinity NUMERIC.
|
||||
*/
|
||||
case OP_MakeKey:
|
||||
case OP_MakeIdxKey: {
|
||||
@ -2306,25 +2420,46 @@ case OP_MakeIdxKey: {
|
||||
int containsNull = 0;
|
||||
char *zKey; /* The new key */
|
||||
int offset = 0;
|
||||
char *zAffinity = pOp->p3;
|
||||
|
||||
assert( zAffinity );
|
||||
nField = pOp->p1;
|
||||
pData0 = &pTos[1-nField];
|
||||
assert( pData0>=p->aStack );
|
||||
|
||||
addRowid = ((pOp->opcode==OP_MakeIdxKey)?1:0);
|
||||
|
||||
/* Calculate the number of bytes required for the new index key and
|
||||
** store that number in nByte. Also set rowid to the record number to
|
||||
** append to the index key.
|
||||
/* Loop through the P1 elements that will make up the new index
|
||||
** key. Call applyAffinity() to perform any conversion required
|
||||
** the column affinity string P3 to modify stack elements in place.
|
||||
** Set containsNull to 1 if a NULL value is encountered.
|
||||
**
|
||||
** Once the value has been coerced, figure out how much space is required
|
||||
** to store the coerced values serial-type and blob, and add this
|
||||
** quantity to nByte.
|
||||
**
|
||||
** TODO: Figure out if the in-place coercion causes a problem for
|
||||
** OP_MakeKey when P2 is 0 (used by DISTINCT).
|
||||
*/
|
||||
for(pRec=pData0; pRec<=pTos; pRec++){
|
||||
u64 serial_type = sqlite3VdbeSerialType(pRec);
|
||||
if( serial_type==0 ){
|
||||
u64 serial_type;
|
||||
if( zAffinity ){
|
||||
applyAffinityByChar(pRec, zAffinity[pRec-pData0]);
|
||||
}else{
|
||||
applyAffinity(pRec, SQLITE_SO_NUM);
|
||||
}
|
||||
if( pRec->flags&MEM_Null ){
|
||||
containsNull = 1;
|
||||
}
|
||||
serial_type = sqlite3VdbeSerialType(pRec);
|
||||
nByte += sqlite3VarintLen(serial_type);
|
||||
nByte += sqlite3VdbeSerialTypeLen(serial_type);
|
||||
}
|
||||
|
||||
/* If we have to append a varint rowid to this record, set 'rowid'
|
||||
** to the value of the rowid and increase nByte by the amount of space
|
||||
** required to store it and the 0x00 seperator byte.
|
||||
*/
|
||||
if( addRowid ){
|
||||
pRec = &pTos[0-nField];
|
||||
assert( pRec>=p->aStack );
|
||||
@ -2366,7 +2501,10 @@ case OP_MakeIdxKey: {
|
||||
pTos->z = zKey;
|
||||
pTos->n = nByte;
|
||||
|
||||
if( pOp->p2 && containsNull ){
|
||||
/* If P2 is non-zero, and if the key contains a NULL value, and if this
|
||||
** was an OP_MakeIdxKey instruction, not OP_MakeKey, jump to P2.
|
||||
*/
|
||||
if( pOp->p2 && containsNull && addRowid ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
@ -2379,6 +2517,7 @@ case OP_MakeIdxKey: {
|
||||
** byte of that key by one. This is used so that the MoveTo opcode
|
||||
** will move to the first entry greater than the key rather than to
|
||||
** the key itself.
|
||||
**
|
||||
*/
|
||||
case OP_IncrKey: {
|
||||
assert( pTos>=p->aStack );
|
||||
@ -2388,6 +2527,11 @@ case OP_IncrKey: {
|
||||
** are always free to modify the string in place.
|
||||
*/
|
||||
assert( pTos->flags & (MEM_Dyn|MEM_Short) );
|
||||
/*
|
||||
** FIX ME: This technique is now broken due to manifest types in index
|
||||
** keys.
|
||||
*/
|
||||
assert(0);
|
||||
pTos->z[pTos->n-1]++;
|
||||
break;
|
||||
}
|
||||
@ -2684,7 +2828,7 @@ case OP_OpenWrite: {
|
||||
** sqlite3VdbeKeyCompare(). If the table being opened is of type
|
||||
** INTKEY, the btree layer won't call the comparison function anyway.
|
||||
*/
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, sqlite3VdbeKeyCompare, 0,
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, sqlite3VdbeKeyCompare, pCur,
|
||||
&pCur->pCursor);
|
||||
switch( rc ){
|
||||
case SQLITE_BUSY: {
|
||||
@ -2817,6 +2961,11 @@ case OP_Close: {
|
||||
** If there are no records greater than the key and P2 is not zero,
|
||||
** then an immediate jump to P2 is made.
|
||||
**
|
||||
** If P3 is not NULL, then the cursor is left pointing at the first
|
||||
** record that is greater than the key of which the key is not a prefix.
|
||||
** This is the same effect that executing OP_IncrKey on the key value
|
||||
** before OP_MoveTo used to have.
|
||||
**
|
||||
** See also: Found, NotFound, Distinct, MoveLt
|
||||
*/
|
||||
/* Opcode: MoveLt P1 P2 *
|
||||
@ -2827,6 +2976,11 @@ case OP_Close: {
|
||||
** If there are no records less than than the key and P2
|
||||
** is not zero then an immediate jump to P2 is made.
|
||||
**
|
||||
** If P3 is not NULL, and keys exist in the index of which the stack key
|
||||
** is a prefix, leave the cursor pointing at the largest of these.
|
||||
** This is the same effect that executing OP_IncrKey on the key value
|
||||
** before OP_MoveLt used to have.
|
||||
**
|
||||
** See also: MoveTo
|
||||
*/
|
||||
case OP_MoveLt:
|
||||
@ -2842,6 +2996,7 @@ case OP_MoveTo: {
|
||||
pC->nullRow = 0;
|
||||
if( pC->intKey ){
|
||||
i64 iKey;
|
||||
assert( !pOp->p3 );
|
||||
Integerify(pTos);
|
||||
iKey = intToKey(pTos->i);
|
||||
if( pOp->p2==0 && pOp->opcode==OP_MoveTo ){
|
||||
@ -2855,11 +3010,16 @@ case OP_MoveTo: {
|
||||
pC->lastRecno = pTos->i;
|
||||
pC->recnoIsValid = res==0;
|
||||
}else{
|
||||
if( pOp->p3 ){
|
||||
pC->incrKey = 1;
|
||||
}
|
||||
Stringify(pTos);
|
||||
sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
|
||||
pC->incrKey = 0;
|
||||
pC->recnoIsValid = 0;
|
||||
}
|
||||
pC->deferredMoveto = 0;
|
||||
pC->incrKey = 0;
|
||||
sqlite3_search_count++;
|
||||
oc = pOp->opcode;
|
||||
if( oc==OP_MoveTo && res<0 ){
|
||||
@ -3015,7 +3175,7 @@ case OP_IsUnique: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = sqlite3VdbeIdxKeyCompare(pCrsr, len, zKey, 0, &res);
|
||||
rc = sqlite3VdbeIdxKeyCompare(pCx, len, zKey, 0, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
if( res>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
@ -3645,8 +3805,8 @@ case OP_IdxPut: {
|
||||
while( res!=0 ){
|
||||
int c;
|
||||
sqlite3BtreeKeySize(pCrsr, &n);
|
||||
if( n==nKey
|
||||
&& sqlite3VdbeIdxKeyCompare(pCrsr, len, zKey, 0, &c)==SQLITE_OK
|
||||
if( n==nKey &&
|
||||
sqlite3VdbeIdxKeyCompare(&p->aCsr[i], len, zKey, 0, &c)==SQLITE_OK
|
||||
&& c==0
|
||||
){
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
@ -3711,19 +3871,24 @@ case OP_IdxRecno: {
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pTos++;
|
||||
if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
u64 sz;
|
||||
int len;
|
||||
char buf[9];
|
||||
i64 rowid;
|
||||
|
||||
assert( p->aCsr[i].deferredMoveto==0 );
|
||||
assert( p->aCsr[i].intKey==0 );
|
||||
rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = rowid;
|
||||
|
||||
#if 0
|
||||
/* Read the final 9 bytes of the key into buf[]. If the whole key is
|
||||
** less than 9 bytes then just load the whole thing. Set len to the
|
||||
** number of bytes read.
|
||||
*/
|
||||
sqlite3BtreeKeySize(pCrsr, &sz);
|
||||
len = ((sz>9)?9:sz);
|
||||
len = ((sz>10)?10:sz);
|
||||
rc = sqlite3BtreeKey(pCrsr, sz-len, len, buf);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
@ -3747,6 +3912,7 @@ case OP_IdxRecno: {
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = sz;
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
pTos->flags = MEM_Null;
|
||||
}
|
||||
@ -3788,10 +3954,15 @@ case OP_IdxGE: {
|
||||
assert( pTos>=p->aStack );
|
||||
if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int res, rc;
|
||||
Cursor *pC = &p->aCsr[i];
|
||||
|
||||
Stringify(pTos);
|
||||
assert( p->aCsr[i].deferredMoveto==0 );
|
||||
rc = sqlite3VdbeIdxKeyCompare(pCrsr, pTos->n, pTos->z, 0, &res);
|
||||
if( pOp->p3 ){
|
||||
pC->incrKey = 1;
|
||||
}
|
||||
rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, 0, &res);
|
||||
pC->incrKey = 0;
|
||||
if( rc!=SQLITE_OK ){
|
||||
break;
|
||||
}
|
||||
@ -3828,12 +3999,13 @@ case OP_IdxIsNull: {
|
||||
z = pTos->z;
|
||||
n = pTos->n;
|
||||
for(k=0; k<n && i>0; i--){
|
||||
if( z[k]=='a' ){
|
||||
u64 serial_type;
|
||||
k += sqlite3GetVarint(&z[k], &serial_type);
|
||||
if( serial_type==6 ){ /* Serial type 6 is a NULL */
|
||||
pc = pOp->p2-1;
|
||||
break;
|
||||
}
|
||||
while( k<n && z[k] ){ k++; }
|
||||
k++;
|
||||
k += sqlite3VdbeSerialTypeLen(serial_type);
|
||||
}
|
||||
Release(pTos);
|
||||
pTos--;
|
||||
@ -3955,7 +4127,9 @@ case OP_IntegrityCk: {
|
||||
aRoot = sqliteMallocRaw( sizeof(int)*(nRoot+1) );
|
||||
if( aRoot==0 ) goto no_mem;
|
||||
for(j=0, i=sqliteHashFirst(&pSet->hash); i; i=sqliteHashNext(i), j++){
|
||||
toInt((char*)sqliteHashKey(i), &aRoot[j]);
|
||||
i64 root64;
|
||||
toInt((char*)sqliteHashKey(i), &root64);
|
||||
aRoot[j] = root64;
|
||||
}
|
||||
aRoot[j] = 0;
|
||||
sqlite3HashClear(&pSet->hash);
|
||||
|
@ -72,6 +72,7 @@ struct Cursor {
|
||||
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
Bool intKey; /* True if the table requires integer keys */
|
||||
Bool zeroData; /* True if table contains keys only - no data */
|
||||
Bool incrKey; /* Searches on the table simulate OP_IncrKey */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int nData; /* Number of bytes in pData */
|
||||
@ -322,5 +323,5 @@ int sqlite3VdbeSerialPut(unsigned char *, const Mem *);
|
||||
int sqlite3VdbeSerialGet(const unsigned char *, u64, Mem *);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(BtCursor*, int , const unsigned char*, int, int*);
|
||||
int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int, int*);
|
||||
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
||||
|
@ -1054,6 +1054,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
|
||||
}else{
|
||||
sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res);
|
||||
}
|
||||
p->incrKey = 0;
|
||||
p->lastRecno = keyToInt(p->movetoTarget);
|
||||
p->recnoIsValid = res==0;
|
||||
if( res<0 ){
|
||||
@ -1347,9 +1348,12 @@ int compareMemCells(Mem *pMem1, Mem *pMem2){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( pMem1->i < pMem2->i ) return -1;
|
||||
if( pMem1->i > pMem2->i ) return 1;
|
||||
return 0;
|
||||
return (pMem1->i - pMem2->i);
|
||||
}
|
||||
|
||||
rc = (pMem2->flags&MEM_Null) - (pMem1->flags&MEM_Null);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Both values must be strings or blobs. If only one is a string, then
|
||||
@ -1357,18 +1361,12 @@ int compareMemCells(Mem *pMem1, Mem *pMem2){
|
||||
** returns 0 and one value is longer than the other, then that value
|
||||
** is greater.
|
||||
*/
|
||||
rc = (pMem2->flags&MEM_Null) - (pMem1->flags&MEM_Null);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( pMem1->n < pMem2->n ) return -1;
|
||||
if( pMem1->n > pMem2->n ) return 1;
|
||||
return 0;
|
||||
return (pMem1->n - pMem2->n);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1386,10 +1384,11 @@ int compareMemCells(Mem *pMem1, Mem *pMem2){
|
||||
** compared to.
|
||||
*/
|
||||
int sqlite3VdbeKeyCompare(
|
||||
void *userData, /* not used yet */
|
||||
void *userData,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
Cursor *pC = (Cursor *)userData;
|
||||
int offset1 = 0;
|
||||
int offset2 = 0;
|
||||
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
||||
@ -1413,6 +1412,7 @@ int sqlite3VdbeKeyCompare(
|
||||
*/
|
||||
if( !serial_type1 || !serial_type2 ){
|
||||
assert( !serial_type1 && !serial_type2 );
|
||||
assert( !pC || !pC->incrKey );
|
||||
sqlite3GetVarint(&aKey1[offset1], &serial_type1);
|
||||
sqlite3GetVarint(&aKey2[offset2], &serial_type2);
|
||||
return ( (i64)serial_type1 - (i64)serial_type2 );
|
||||
@ -1438,12 +1438,24 @@ int sqlite3VdbeKeyCompare(
|
||||
}
|
||||
}
|
||||
|
||||
/* One of the keys ran out of fields, but all the fields up to that point
|
||||
** were equal. If the incrKey flag is true, then the second key is
|
||||
** treated as larger.
|
||||
*/
|
||||
if( pC && pC->incrKey ){
|
||||
assert( offset2==nKey2 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( offset1<nKey1 ){
|
||||
return 1;
|
||||
}
|
||||
if( offset2<nKey2 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
return_result:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1455,7 +1467,7 @@ int sqlite3VdbeKeyCompare(
|
||||
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
||||
i64 sz;
|
||||
int rc;
|
||||
char buf[9];
|
||||
char buf[10];
|
||||
int len;
|
||||
u64 r;
|
||||
|
||||
@ -1463,24 +1475,33 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
len = ((sz>9)?9:sz);
|
||||
assert( len>=2 );
|
||||
len = ((sz>10)?10:sz);
|
||||
|
||||
/* If there are less than 2 bytes in the key, this cannot be
|
||||
** a valid index entry. In practice this comes up for a query
|
||||
** of the sort "SELECT max(x) FROM t1;" when t1 is an empty table
|
||||
** with an index on x. In this case just call the rowid 0.
|
||||
*/
|
||||
if( len<2 ){
|
||||
*rowid = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeKey(pCur, sz-len, len, buf);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
len = len - 2;
|
||||
while( buf[len] && --len );
|
||||
len--;
|
||||
while( buf[len-1] && --len );
|
||||
|
||||
sqlite3GetVarint(buf, &r);
|
||||
sqlite3GetVarint(&buf[len], &r);
|
||||
*rowid = r;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int sqlite3VdbeIdxKeyCompare(
|
||||
BtCursor *pCur,
|
||||
Cursor *pC,
|
||||
int nKey, const unsigned char *pKey,
|
||||
int ignorerowid,
|
||||
int *res
|
||||
@ -1490,6 +1511,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
int freeCellKey = 0;
|
||||
int rc;
|
||||
int len;
|
||||
BtCursor *pCur = pC->pCursor;
|
||||
|
||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
if( nCellKey<=0 ){
|
||||
@ -1518,7 +1540,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
nKey--;
|
||||
while( pKey[nKey] && --nKey );
|
||||
}
|
||||
*res = sqlite3VdbeKeyCompare(0, len, pCellKey, nKey, pKey);
|
||||
*res = sqlite3VdbeKeyCompare(pC, len, pCellKey, nKey, pKey);
|
||||
|
||||
if( freeCellKey ){
|
||||
sqliteFree(pCellKey);
|
||||
|
25
src/where.c
25
src/where.c
@ -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.91 2004/05/10 10:37:19 danielk1977 Exp $
|
||||
** $Id: where.c,v 1.92 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -799,19 +799,22 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MakeKey, nColumn, 0);
|
||||
sqlite3AddIdxKeyType(v, pIdx);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
|
||||
if( nColumn==pIdx->nColumn || pLevel->bRev ){
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
|
||||
testOp = OP_IdxGT;
|
||||
}else{
|
||||
/*
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
*/
|
||||
testOp = OP_IdxGE;
|
||||
}
|
||||
if( pLevel->bRev ){
|
||||
/* Scan in reverse order */
|
||||
sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
|
||||
/* sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0); */
|
||||
sqlite3VdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk);
|
||||
pLevel->op = OP_Prev;
|
||||
@ -820,6 +823,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
|
||||
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, testOp, pLevel->iCur, brk);
|
||||
if( testOp==OP_IdxGE ){
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
pLevel->op = OP_Next;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
|
||||
@ -1004,11 +1010,16 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0);
|
||||
sqlite3AddIdxKeyType(v, pIdx);
|
||||
/*
|
||||
if( leFlag ){
|
||||
sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
|
||||
}
|
||||
*/
|
||||
if( pLevel->bRev ){
|
||||
sqlite3VdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
|
||||
if( !geFlag ){
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
}
|
||||
@ -1060,15 +1071,20 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0);
|
||||
sqlite3AddIdxKeyType(v, pIdx);
|
||||
/*
|
||||
if( !geFlag ){
|
||||
sqlite3VdbeAddOp(v, OP_IncrKey, 0, 0);
|
||||
}
|
||||
*/
|
||||
if( pLevel->bRev ){
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
testOp = OP_IdxLT;
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
|
||||
if( !geFlag ){
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
}
|
||||
}else if( pLevel->bRev ){
|
||||
testOp = OP_Noop;
|
||||
@ -1084,6 +1100,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( testOp!=OP_Noop ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, testOp, pLevel->iCur, brk);
|
||||
if( (leFlag && !pLevel->bRev) || (!geFlag && pLevel->bRev) ){
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont);
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing built-in functions.
|
||||
#
|
||||
# $Id: func.test,v 1.16 2002/11/04 19:32:26 drh Exp $
|
||||
# $Id: func.test,v 1.17 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -167,7 +167,7 @@ do_test func-4.3 {
|
||||
} {0 {2 1.2345678901234 2}}
|
||||
do_test func-4.4 {
|
||||
catchsql {SELECT abs(c) FROM t1 ORDER BY a}
|
||||
} {0 {3 12345.67890 5}}
|
||||
} {0 {3 12345.6789 5}}
|
||||
do_test func-4.4.1 {
|
||||
execsql {SELECT abs(a) FROM t2}
|
||||
} {1 {} 345 {} 67890}
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE INDEX statement.
|
||||
#
|
||||
# $Id: index.test,v 1.24 2003/09/27 00:41:28 drh Exp $
|
||||
# $Id: index.test,v 1.25 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -335,7 +335,7 @@ do_test index-11.1 {
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
|
||||
} {0.10 3}
|
||||
} {0.1 3}
|
||||
integrity_check index-11.2
|
||||
|
||||
|
||||
@ -344,6 +344,9 @@ integrity_check index-11.2
|
||||
# same number they should compare equal to one another. Verify that this
|
||||
# is true in indices.
|
||||
#
|
||||
# Updated for sqlite v3: SQLite will now store these values as numbers
|
||||
# (because the affinity of column a is NUMERIC) so the quirky
|
||||
# representations are not retained. i.e. '+1.0' becomes '1'.
|
||||
do_test index-12.1 {
|
||||
execsql {
|
||||
CREATE TABLE t4(a,b);
|
||||
@ -356,38 +359,38 @@ do_test index-12.1 {
|
||||
INSERT INTO t4 VALUES('00000',7);
|
||||
SELECT a FROM t4 ORDER BY b;
|
||||
}
|
||||
} {0.0 0.00 abc -1.0 +1.0 0 00000}
|
||||
} {0 0 abc -1 1 0 0}
|
||||
do_test index-12.2 {
|
||||
execsql {
|
||||
SELECT a FROM t4 WHERE a==0 ORDER BY b
|
||||
}
|
||||
} {0.0 0.00 0 00000}
|
||||
} {0 0 0 0}
|
||||
do_test index-12.3 {
|
||||
execsql {
|
||||
SELECT a FROM t4 WHERE a<0.5 ORDER BY b
|
||||
}
|
||||
} {0.0 0.00 -1.0 0 00000}
|
||||
} {0 0 -1 0 0}
|
||||
do_test index-12.4 {
|
||||
execsql {
|
||||
SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
|
||||
}
|
||||
} {0.0 0.00 abc +1.0 0 00000}
|
||||
} {0 0 abc 1 0 0}
|
||||
do_test index-12.5 {
|
||||
execsql {
|
||||
CREATE INDEX t4i1 ON t4(a);
|
||||
SELECT a FROM t4 WHERE a==0 ORDER BY b
|
||||
}
|
||||
} {0.0 0.00 0 00000}
|
||||
} {0 0 0 0}
|
||||
do_test index-12.6 {
|
||||
execsql {
|
||||
SELECT a FROM t4 WHERE a<0.5 ORDER BY b
|
||||
}
|
||||
} {0.0 0.00 -1.0 0 00000}
|
||||
} {0 0 -1 0 0}
|
||||
do_test index-12.7 {
|
||||
execsql {
|
||||
SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
|
||||
}
|
||||
} {0.0 0.00 abc +1.0 0 00000}
|
||||
} {0 0 abc 1 0 0}
|
||||
integrity_check index-12.8
|
||||
|
||||
# Make sure we cannot drop an automatically created index.
|
||||
|
@ -10,7 +10,7 @@
|
||||
#***********************************************************************
|
||||
# This file runs all tests.
|
||||
#
|
||||
# $Id: quick.test,v 1.10 2004/05/13 13:38:52 danielk1977 Exp $
|
||||
# $Id: quick.test,v 1.11 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -32,30 +32,21 @@ lappend EXCLUDE interrupt.test ;# assert() fails in btree
|
||||
lappend EXCLUDE ioerr.test ;# seg-faults (?)
|
||||
lappend EXCLUDE memdb.test ;# fails - malformed database
|
||||
lappend EXCLUDE misc3.test ;# seg-faults (?)
|
||||
lappend EXCLUDE printf.test ;# sqlite3_XX vs sqlite_XX problem
|
||||
lappend EXCLUDE table.test ;# assert() fails in pager
|
||||
lappend EXCLUDE trans.test ;# assert() fails in pager
|
||||
lappend EXCLUDE vacuum.test ;# seg-fault
|
||||
|
||||
lappend EXCLUDE printf.test ;# sqlite3_XX vs sqlite_XX problem
|
||||
lappend EXCLUDE auth.test ;# Cannot attach empty databases.
|
||||
lappend EXCLUDE tableapi.test ;# sqlite3_XX vs sqlite_XX problem
|
||||
lappend EXCLUDE version.test ;# uses the btree_meta API (not updated)
|
||||
|
||||
# Some tests fail in these file, possibly because of the manifest
|
||||
# type-aware indices (or possibly not).
|
||||
lappend EXCLUDE delete.test
|
||||
lappend EXCLUDE update.test
|
||||
# Some tests fail in these file as a result of the partial manifest types
|
||||
# implementation.
|
||||
lappend EXCLUDE misc1.test
|
||||
lappend EXCLUDE index.test
|
||||
lappend EXCLUDE copy.test
|
||||
lappend EXCLUDE conflict.test
|
||||
lappend EXCLUDE capi2.test
|
||||
lappend EXCLUDE null.test
|
||||
lappend EXCLUDE trigger2.test
|
||||
lappend EXCLUDE sort.test
|
||||
lappend EXCLUDE where.test
|
||||
lappend EXCLUDE unique.test
|
||||
lappend EXCLUDE limit.test
|
||||
lappend EXCLUDE intpkey.test
|
||||
|
||||
|
||||
if {[sqlite -has-codec]} {
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the SELECT statement.
|
||||
#
|
||||
# $Id: select2.test,v 1.19 2004/05/13 05:16:17 danielk1977 Exp $
|
||||
# $Id: select2.test,v 1.20 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -83,26 +83,23 @@ do_test select2-3.1 {
|
||||
execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}
|
||||
} {500}
|
||||
|
||||
# SQLite v3: Change the expressions in the following four test cases
|
||||
# from 1000=f2 to '1000'=f2. This is because fields read in using
|
||||
# the COPY command have manifest type TEXT.
|
||||
do_test select2-3.2a {
|
||||
execsql {CREATE INDEX idx1 ON tbl2(f2)}
|
||||
} {}
|
||||
do_test select2-3.2b {
|
||||
execsql {SELECT f1 FROM tbl2 WHERE '1000'=f2}
|
||||
execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}
|
||||
} {500}
|
||||
do_test select2-3.2c {
|
||||
execsql {SELECT f1 FROM tbl2 WHERE f2='1000'}
|
||||
execsql {SELECT f1 FROM tbl2 WHERE f2=1000}
|
||||
} {500}
|
||||
do_test select2-3.2d {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT * FROM tbl2 WHERE '1000'=f2}
|
||||
execsql {SELECT * FROM tbl2 WHERE 1000=f2}
|
||||
set sqlite_search_count
|
||||
} {3}
|
||||
do_test select2-3.2e {
|
||||
set sqlite_search_count 0
|
||||
execsql {SELECT * FROM tbl2 WHERE f2='1000'}
|
||||
execsql {SELECT * FROM tbl2 WHERE f2=1000}
|
||||
set sqlite_search_count
|
||||
} {3}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
# focus of this file is testing UNION, INTERSECT and EXCEPT operators
|
||||
# in SELECT statements.
|
||||
#
|
||||
# $Id: select4.test,v 1.14 2004/05/13 05:16:17 danielk1977 Exp $
|
||||
# $Id: select4.test,v 1.15 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -197,13 +197,9 @@ do_test select4-4.1.1 {
|
||||
}
|
||||
} {5}
|
||||
|
||||
# Update for sqlite 3:
|
||||
# Change the "UNION ALL SELECT 6" in each of the select statements
|
||||
# for the next three test cases to "UNION ALL SELECT '6'". This is
|
||||
# to accomadate manifest typing.
|
||||
do_test select4-4.1.2 {
|
||||
execsql {
|
||||
SELECT DISTINCT log FROM t1 UNION ALL SELECT '6'
|
||||
SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
|
||||
INTERSECT
|
||||
SELECT n FROM t1 WHERE log=3
|
||||
ORDER BY log;
|
||||
@ -212,7 +208,7 @@ do_test select4-4.1.2 {
|
||||
do_test select4-4.1.3 {
|
||||
execsql {
|
||||
CREATE TABLE t2 AS
|
||||
SELECT DISTINCT log FROM t1 UNION ALL SELECT '6'
|
||||
SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
|
||||
INTERSECT
|
||||
SELECT n FROM t1 WHERE log=3
|
||||
ORDER BY log;
|
||||
@ -223,7 +219,7 @@ execsql {DROP TABLE t2}
|
||||
do_test select4-4.1.4 {
|
||||
execsql {
|
||||
CREATE TABLE t2 AS
|
||||
SELECT DISTINCT log FROM t1 UNION ALL SELECT '6'
|
||||
SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
|
||||
INTERSECT
|
||||
SELECT n FROM t1 WHERE log=3
|
||||
ORDER BY log DESC;
|
||||
@ -473,19 +469,16 @@ do_test select4-7.4 {
|
||||
} {n 1 log 0 n 2 log 1}
|
||||
|
||||
# Make sure DISTINCT works appropriately on TEXT and NUMERIC columns.
|
||||
#
|
||||
# Update for sqlite v3:
|
||||
# Insert X+0.0 instead of X to make sure X has manifest type NUMERIC.
|
||||
do_test select4-8.1 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t3(a text, b float, c text);
|
||||
INSERT INTO t3 VALUES(1, 1.1 + 0.0, '1.1');
|
||||
INSERT INTO t3 VALUES(2, 1.10 + 0.0, '1.10');
|
||||
INSERT INTO t3 VALUES(3, 1.10 + 0.0, '1.1');
|
||||
INSERT INTO t3 VALUES(4, 1.1 + 0.0, '1.10');
|
||||
INSERT INTO t3 VALUES(5, 1.2 + 0.0, '1.2');
|
||||
INSERT INTO t3 VALUES(6, 1.3 + 0.0, '1.3');
|
||||
INSERT INTO t3 VALUES(1, 1.1, '1.1');
|
||||
INSERT INTO t3 VALUES(2, 1.10, '1.10');
|
||||
INSERT INTO t3 VALUES(3, 1.10, '1.1');
|
||||
INSERT INTO t3 VALUES(4, 1.1, '1.10');
|
||||
INSERT INTO t3 VALUES(5, 1.2, '1.2');
|
||||
INSERT INTO t3 VALUES(6, 1.3, '1.3');
|
||||
COMMIT;
|
||||
}
|
||||
execsql {
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the CREATE TABLE statement.
|
||||
#
|
||||
# $Id: sort.test,v 1.9 2003/04/18 17:45:15 drh Exp $
|
||||
# $Id: sort.test,v 1.10 2004/05/14 11:00:53 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -66,10 +66,10 @@ do_test sort-1.4 {
|
||||
} {2 3 6 7 1 4 5 8}
|
||||
do_test sort-1.5 {
|
||||
execsql {SELECT flt FROM t1 ORDER BY flt}
|
||||
} {-11 -1.6 -0.0013442 0.123 2.15 3.141592653 123.0 4221.0}
|
||||
} {-11 -1.6 -0.0013442 0.123 2.15 3.141592653 123 4221}
|
||||
do_test sort-1.6 {
|
||||
execsql {SELECT flt FROM t1 ORDER BY flt DESC}
|
||||
} {4221.0 123.0 3.141592653 2.15 0.123 -0.0013442 -1.6 -11}
|
||||
} {4221 123 3.141592653 2.15 0.123 -0.0013442 -1.6 -11}
|
||||
do_test sort-1.7 {
|
||||
execsql {SELECT roman FROM t1 ORDER BY roman}
|
||||
} {I II III IV V VI VII VIII}
|
||||
@ -356,6 +356,6 @@ do_test sort-8.1 {
|
||||
INSERT INTO t5 VALUES(100.0,'A2');
|
||||
SELECT * FROM t5 ORDER BY a, b;
|
||||
}
|
||||
} {100 A1 100.0 A2}
|
||||
} {100 A1 100 A2}
|
||||
|
||||
finish_test
|
||||
|
Loading…
x
Reference in New Issue
Block a user