Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | A partial fix for ticket #3292. This fixes the original problem but there are other similar problems lurking in the code still. (CVS 5561) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
055f173ab1b6fb657bf817faa3a37335 |
User & Date: | drh 2008-08-13 14:07:40.000 |
Context
2008-08-13
| ||
19:11 | Additional changes toward fixing ticket #3292. (CVS 5562) (check-in: 0b92cbf525 user: drh tags: trunk) | |
14:07 | A partial fix for ticket #3292. This fixes the original problem but there are other similar problems lurking in the code still. (CVS 5561) (check-in: 055f173ab1 user: drh tags: trunk) | |
2008-08-12
| ||
15:48 | Make sure the lookaside test script saturates the lookaside buffer even when SQLITE_DEBUG is off. Ticket #3289 (CVS 5560) (check-in: d6aacc5dc7 user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* ** $Id: btree.c,v 1.496 2008/08/13 14:07:40 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
3770 3771 3772 3773 3774 3775 3776 | c = +1; } }else{ int available; pCellKey = (void *)fetchPayload(pCur, &available, 0); nCellKey = pCur->info.nKey; if( available>=nCellKey ){ | | | | 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 | c = +1; } }else{ int available; pCellKey = (void *)fetchPayload(pCur, &available, 0); nCellKey = pCur->info.nKey; if( available>=nCellKey ){ c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey); }else{ pCellKey = sqlite3Malloc( nCellKey ); if( pCellKey==0 ){ rc = SQLITE_NOMEM; goto moveto_finish; } rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey); c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, 0, pUnKey); sqlite3_free(pCellKey); if( rc ) goto moveto_finish; } } if( c==0 ){ pCur->info.nKey = nCellKey; if( pPage->intKey && !pPage->leaf ){ |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.754 2008/08/13 14:07:40 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build |
︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 | ** otherwise be equal, then return a result as if the second key ** were larger. */ struct KeyInfo { sqlite3 *db; /* The database connection */ u8 enc; /* Text encoding - one of the TEXT_Utf* values */ u8 incrKey; /* Increase 2nd key by epsilon before comparison */ | | | 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | ** otherwise be equal, then return a result as if the second key ** were larger. */ struct KeyInfo { sqlite3 *db; /* The database connection */ u8 enc; /* Text encoding - one of the TEXT_Utf* values */ u8 incrKey; /* Increase 2nd key by epsilon before comparison */ u8 ckPrefixOnly; /* Records are equal if shorter is a prefix of longer */ int nField; /* Number of entries in aColl[] */ u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; /* ** Each SQL index is represented in memory by an |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.774 2008/08/13 14:07:40 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
3054 3055 3056 3057 3058 3059 3060 | assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor!=0 ){ int res; assert( pC->isTable==0 ); assert( pIn3->flags & MEM_Blob ); if( pOp->opcode==OP_Found ){ | | | | 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 | assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor!=0 ){ int res; assert( pC->isTable==0 ); assert( pIn3->flags & MEM_Blob ); if( pOp->opcode==OP_Found ){ pC->pKeyInfo->ckPrefixOnly = 1; } rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res); pC->pKeyInfo->ckPrefixOnly = 0; if( rc!=SQLITE_OK ){ break; } alreadyExists = (res==0); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** ** $Id: vdbe.h,v 1.136 2008/08/13 14:07:41 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
186 187 188 189 190 191 192 | void sqlite3VdbeSwap(Vdbe*,Vdbe*); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int sqlite3VdbeReleaseMemory(int); #endif UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int); void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | void sqlite3VdbeSwap(Vdbe*,Vdbe*); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int sqlite3VdbeReleaseMemory(int); #endif UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int); void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,int,UnpackedRecord*); #ifndef NDEBUG void sqlite3VdbeComment(Vdbe*, const char*, ...); # define VdbeComment(X) sqlite3VdbeComment X void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); # define VdbeNoopComment(X) sqlite3VdbeNoopComment X #else # define VdbeComment(X) # define VdbeNoopComment(X) #endif #endif |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** ** $Id: vdbeaux.c,v 1.406 2008/08/13 14:07:41 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" |
︙ | ︙ | |||
2270 2271 2272 2273 2274 2275 2276 | ** or positive integer if {nKey1, pKey1} is less than, equal to or ** greater than pPKey2. The {nKey1, pKey1} key must be a blob ** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from ** sqlite3VdbeParseRecord. ** ** Key1 and Key2 do not have to contain the same number of fields. | > > > > > > > > > > > > > | | | > | > | 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 | ** or positive integer if {nKey1, pKey1} is less than, equal to or ** greater than pPKey2. The {nKey1, pKey1} key must be a blob ** created by th OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from ** sqlite3VdbeParseRecord. ** ** Key1 and Key2 do not have to contain the same number of fields. ** The key with fewer fields is usually considered lessor than the ** longer. However if pPKey2->pKeyInfo->incrKey is set and ** the common prefixes are equal, then key1 is less than key2. ** Or if pPKey2->pKeyInfo->ckPrefixOnly flag is set and the ** prefixes are equal, then the keys are considered to be equal and ** the parts beyond the common prefix are ignored. ** ** The last nHdrIgnore1 bytes of the header of pKey1 are ignored, ** as if they do not exist. Usually nHdrIgnore1 is 0 which means ** that we look at the entire key. But sometimes nHdrIgnore1 is 1. ** When nHdrIgnore1 is 1, the keys are index records and so the last ** column is a rowid. The type code is always one byte in length. ** Hence, setting nHdrIgnore1 to 1 means that the final rowid at the ** end of the record should be treated as if it does not exist. ** ** Historical note: In earlier versions of this routine both Key1 ** and Key2 were blobs obtained from OP_MakeRecord. But we found ** that in typical use the same Key2 would be submitted multiple times ** in a row. So an optimization was added to parse the Key2 key ** separately and submit the parsed version. In this way, we avoid ** parsing the same Key2 multiple times. */ int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ int nHdrIgnore1, /* Omit this much from end of key1 header */ UnpackedRecord *pPKey2 /* Right key */ ){ u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ u32 szHdr1; /* Number of bytes in header */ int i = 0; int nField; int rc = 0; const unsigned char *aKey1 = (const unsigned char *)pKey1; KeyInfo *pKeyInfo; Mem mem1; pKeyInfo = pPKey2->pKeyInfo; mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = 0; mem1.zMalloc = 0; idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; szHdr1 -= nHdrIgnore1; nField = pKeyInfo->nField; while( idx1<szHdr1 && i<pPKey2->nField ){ u32 serial_type1; /* Read the serial types for the next element in each key. */ idx1 += getVarint32( aKey1+idx1, serial_type1 ); if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break; |
︙ | ︙ | |||
2324 2325 2326 2327 2328 2329 2330 | if( rc!=0 ){ break; } i++; } if( mem1.zMalloc ) sqlite3VdbeMemRelease(&mem1); | > | | > | > > > | < | > | | < | | | 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 | if( rc!=0 ){ break; } i++; } if( mem1.zMalloc ) sqlite3VdbeMemRelease(&mem1); if( rc==0 ){ /* rc==0 here means that one of the keys ran out of fields and ** all the fields up to that point were equal. If the incrKey ** flag is true, then break the tie by treating the second key ** as larger. If ckPrefixOnly is true, then keys with common prefixes ** are considered to be equal. Otherwise, the longer key is the ** larger. As it happens, the pPKey2 will always be the longer ** if there is a difference. */ if( pKeyInfo->incrKey ){ rc = -1; }else if( pKeyInfo->ckPrefixOnly ){ /* Leave rc==0 */ }else if( idx1<szHdr1 ){ rc = 1; } }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){ rc = -rc; } return rc; } /* ** The argument is an index entry composed using the OP_MakeRecord opcode. ** The last entry in this record should be an integer (specifically ** an integer rowid). This routine returns the number of bytes in ** that integer. */ int sqlite3VdbeIdxRowidLen(const u8 *aKey, int nKey, int *pRowidLen){ u32 szHdr; /* Size of the header */ u32 typeRowid; /* Serial type of the rowid */ (void)getVarint32(aKey, szHdr); if( szHdr>nKey ){ return SQLITE_CORRUPT_BKPT; } (void)getVarint32(&aKey[szHdr-1], typeRowid); *pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid); return SQLITE_OK; } /* ** pCur points at an index entry created using the OP_MakeRecord opcode. ** Read the rowid (the last field in the record) and store it in *rowid. ** Return SQLITE_OK if everything works, or an error code otherwise. */ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ |
︙ | ︙ | |||
2405 2406 2407 2408 2409 2410 2411 | ** Compare the key of the index entry that cursor pC is point to against ** the key string in pKey (of length nKey). Write into *pRes a number ** that is negative, zero, or positive if pC is less than, equal to, ** or greater than pKey. Return SQLITE_OK on success. ** ** pKey is either created without a rowid or is truncated so that it ** omits the rowid at the end. The rowid at the end of the index entry | | > > > > | < | < | | | 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 | ** Compare the key of the index entry that cursor pC is point to against ** the key string in pKey (of length nKey). Write into *pRes a number ** that is negative, zero, or positive if pC is less than, equal to, ** or greater than pKey. Return SQLITE_OK on success. ** ** pKey is either created without a rowid or is truncated so that it ** omits the rowid at the end. The rowid at the end of the index entry ** is ignored as well. Hence, this routine only compares the prefixes ** of the keys prior to the final rowid, not the entire key. ** ** pUnpacked may be an unpacked version of pKey,nKey. If pUnpacked is ** supplied it is used in place of pKey,nKey. */ int sqlite3VdbeIdxKeyCompare( Cursor *pC, /* The cursor to compare against */ UnpackedRecord *pUnpacked, /* Unpacked version of pKey and nKey */ int nKey, const u8 *pKey, /* The key to compare */ int *res /* Write the comparison result here */ ){ i64 nCellKey = 0; int rc; BtCursor *pCur = pC->pCursor; Mem m; UnpackedRecord *pRec; char zSpace[200]; sqlite3BtreeKeySize(pCur, &nCellKey); if( nCellKey<=0 ){ *res = 0; return SQLITE_OK; } m.db = 0; m.flags = 0; m.zMalloc = 0; rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m); if( rc ){ return rc; } if( !pUnpacked ){ pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey, zSpace, sizeof(zSpace)); }else{ pRec = pUnpacked; } if( pRec==0 ){ return SQLITE_NOMEM; } *res = sqlite3VdbeRecordCompare(m.n, m.z, 1, pRec); if( !pUnpacked ){ sqlite3VdbeDeleteUnpackedRecord(pRec); } sqlite3VdbeMemRelease(&m); return SQLITE_OK; } |
︙ | ︙ |
Changes to test/corrupt7.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. It specifically focuses # on corrupt cell offsets in a btree page. # | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. It specifically focuses # on corrupt cell offsets in a btree page. # # $Id: corrupt7.test,v 1.5 2008/08/13 14:07:41 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { |
︙ | ︙ | |||
68 69 70 71 72 73 74 | db close hexio_write test.db 1062 04 sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** Corruption detected in cell 15 on page 2}} | > > > | | | | | | | | < > | | | | | | | | | | | | | | | < > | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | db close hexio_write test.db 1062 04 sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** Corruption detected in cell 15 on page 2}} # The code path that was causing the buffer overrun that this test # case was checking for was removed. # #do_test corrupt7-3.1 { # execsql { # DROP TABLE t1; # CREATE TABLE t1(a, b); # INSERT INTO t1 VALUES(1, 'one'); # INSERT INTO t1 VALUES(100, 'one hundred'); # INSERT INTO t1 VALUES(100000, 'one hundred thousand'); # CREATE INDEX i1 ON t1(b); # } # db close # # # Locate the 3rd cell in the index. # set cell_offset [hexio_get_int [hexio_read test.db [expr 1024*2 + 12] 2]] # incr cell_offset [expr 1024*2] # incr cell_offset 1 # # # This write corrupts the "header-size" field of the database record # # stored in the index cell. At one point this was causing sqlite to # # reference invalid memory. # hexio_write test.db $cell_offset FFFF7F # # sqlite3 db test.db # catchsql { # SELECT b FROM t1 WHERE b > 'o' AND b < 'p'; # } #} {1 {database disk image is malformed}} finish_test |
Added test/tkt3292.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | # 2008 August 12 # # 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. # Specifically, it tests the behavior of the sqlite3VdbeRecordCompare() # routine in cases where the rowid is 0 or 1 in file format 4 # (meaning that the rowid has type code 8 or 9 with zero bytes of # data). Ticket #3292. # # $Id: tkt3292.test,v 1.1 2008/08/13 14:07:41 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3292-1.1 { execsql { PRAGMA legacy_file_format=OFF; CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); INSERT INTO t1 VALUES(0, 1); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 1); CREATE INDEX i1 ON t1(b); SELECT * FROM t1 WHERE b>=1; } } {0 1 1 1 2 1} do_test tkt3292-1.2 { execsql { INSERT INTO t1 VALUES(3, 0); INSERT INTO t1 VALUES(4, 2); SELECT * FROM t1 WHERE b>=1; } } {0 1 1 1 2 1 4 2} do_test tkt3292-2.1 { execsql { CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c, d); INSERT INTO t2 VALUES(0, 1, 'hello', x'012345'); INSERT INTO t2 VALUES(1, 1, 'hello', x'012345'); INSERT INTO t2 VALUES(2, 1, 'hello', x'012345'); CREATE INDEX i2 ON t2(b,c,d); SELECT a FROM t2 WHERE b=1 AND c='hello' AND d>=x'012345'; } } {0 1 2} do_test tkt3292-2.2 { execsql { INSERT INTO t2 VALUES(3, 1, 'hello', x'012344'); INSERT INTO t2 VALUES(4, 1, 'hello', x'012346'); SELECT a FROM t2 WHERE b=1 AND c='hello' AND d>=x'012345'; } } {0 1 2 4} finish_test |