1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

:-) (CVS 218)

FossilOrigin-Name: 523d52dfa6ae3028cbcc88d406501f3ebb6cbd2d
This commit is contained in:
drh
2001-05-21 13:45:10 +00:00
parent 2af926b95a
commit 306dc21379
7 changed files with 171 additions and 82 deletions

View File

@@ -1,5 +1,5 @@
C :-)\s(CVS\s217)
D 2001-05-15T00:39:25
C :-)\s(CVS\s218)
D 2001-05-21T13:45:10
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -12,7 +12,7 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
F notes/notes2.txt 49b4d7ba35f183feb1fb098a27272b82f5c76eca
F notes/notes3.txt cd5e7bd2167d7ef89b1077abdfa68f0af6337744
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
F src/btree.c f6d724fccaf108c4452dba6589e6027ba8f3e88a
F src/btree.c bc1525234a8b169cae6f903f9cfacbcf971be942
F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
@@ -31,7 +31,7 @@ F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
F src/main.c 0a13c7a2beb8ce36aee43daf8c95989b200727a7
F src/pager.c 4081e3e9765c272554e22d1dcec0647ac71ea706
F src/pager.c e45946aaf080aed251653f21667d62c89e539a97
F src/pager.h ed12ac3ddebd3afe61a0ed4bf530e7846d578e46
F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
@@ -64,7 +64,7 @@ F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a
F test/main.test da635f9e078cd21ddf074e727381a715064489ff
F test/malloc.test 3daa97f6a9577d8f4c6e468b274333af19ce5861
F test/pager.test 3416a155c2dc3b1b3c07d4bb0192cbb15b76a90c
F test/pager.test c1eb25faa0938f803d1e6eb5201e5e976ea88256
F test/printf.test 4c71871e1a75a2dacb673945fc13ddb30168798f
F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3
F test/select1.test 223507655cdb4f9901d83fa7f5c5328e022c211f
@@ -99,14 +99,14 @@ F www/changes.tcl 822b425cc50cb8e21563dd1aa0e4b79cf780f3dc
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
F www/index.tcl 553a41c4157fe411465aefe391bec5687027e73f
F www/lang.tcl 7fec414487ebee2cbb17c90addf5a026cd10396a
F www/index.tcl 199abaf346d5fed6cf5b462a327faae39fb117b9
F www/lang.tcl 0969ba9f13b3555e54ccdb8ec462dee2de0bf223
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
P c3e521190f02120a34f1e9244fe1ea3a975a6caa
R d3ffc66c90d6f5774a5954932275df58
P ee6760fb62e81af95796c0fcf1e65e5dc0701194
R 6bf7ed657f22039e86c99aa04cca003e
U drh
Z 0f43bc31472b172caca9953860c2e8b6
Z 4c32ca5182d7191fa6afdab861fed35d

View File

@@ -1 +1 @@
ee6760fb62e81af95796c0fcf1e65e5dc0701194
523d52dfa6ae3028cbcc88d406501f3ebb6cbd2d

View File

@@ -21,7 +21,7 @@
** http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: btree.c,v 1.5 2001/05/15 00:39:25 drh Exp $
** $Id: btree.c,v 1.6 2001/05/21 13:45:10 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@@ -39,8 +39,8 @@
** database entry. If the entry contains more data than this, the
** extra goes onto overflow pages.
*/
#define MX_LOCAL_PAYLOAD ((SQLITE_PAGE_SIZE-sizeof(PageHdr)-4*sizeof(Cell))/4)
#define MX_LOCAL_PAYLOAD \
((SQLITE_PAGE_SIZE-sizeof(PageHdr)-4*(sizeof(Cell)+sizeof(Pgno)))/4)
/*
** The in-memory image of a disk page has the auxiliary information appended
@@ -54,9 +54,9 @@
*/
#define OVERFLOW_SIZE (SQLITE_PAGE_SIZE-sizeof(Pgno))
/*
** Primitive data types. u32 must be 4 bytes and u16 must be 2 bytes.
** Change these typedefs when porting to new architectures.
*/
typedef unsigned int u32;
typedef unsigned short int u16;
@@ -74,10 +74,12 @@ typedef struct OverflowPage OverflowPage;
/*
** All structures on a database page are aligned to 4-byte boundries.
** This routine rounds up a number of bytes to the next multiple of 4.
**
** This might need to change for computer architectures that require
** and 8-byte alignment boundry for structures.
*/
#define ROUNDUP(X) ((X+3) & ~3)
/*
** The first pages of the database file contains some additional
** information used for housekeeping and sanity checking. Otherwise,
@@ -92,7 +94,6 @@ struct Page1Header {
#define MAGIC_1 0x7264dc61
#define MAGIC_2 0x54e55d9e
/*
** Each database page has a header as follows:
**
@@ -102,17 +103,30 @@ struct Page1Header {
** first_free Index of first free block
**
** MemPage.pStart always points to the rightmost_pgno. First_free is
** 0 if there is no free space on this page. Otherwise it points to
** an area like this:
** 0 if there is no free space on this page. Otherwise, first_free is
** the index in MemPage.aPage[] of a FreeBlk structure that describes
** the first block of free space. All free space is defined by a linked
** list of FreeBlk structures.
**
** nByte Number of free bytes in this block
** next_free Next free block or 0 if this is the end
** Data is stored in a linked list of Cell structures. First_cell is
** the index into MemPage.aPage[] of the first cell on the page. The
** Cells are kept in sorted order.
*/
struct PageHdr {
Pgno pgno; /* Child page that comes after all cells on this page */
u16 firstCell; /* Index in MemPage.aPage[] of the first cell */
u16 firstFree; /* Index in MemPage.aPage[] of the first free block */
};
/*
** Data on a database page is stored as a linked list of Cell structures.
** Both the key and the data are stored in aData[]. The key always comes
** first. The aData[] field grows as necessary to hold the key and data,
** up to a maximum of MX_LOCAL_PAYLOAD bytes. If the size of the key and
** data combined exceeds MX_LOCAL_PAYLOAD bytes, then the 4 bytes beginning
** at Cell.aData[MX_LOCAL_PAYLOAD] are the page number of the first overflow
** page.
*/
struct Cell {
Pgno pgno; /* Child page that comes before this cell */
u16 nKey; /* Number of bytes in the key */
@@ -120,10 +134,28 @@ struct Cell {
u32 nData; /* Number of bytes of data */
char aData[4]; /* Key and data */
};
/*
** Free space on a page is remembered using a linked list of the FreeBlk
** structures. Space on a database page is allocated in increments of
** at least 4 bytes and is always aligned to a 4-byte boundry.
*/
struct FreeBlk {
u16 iSize; /* Number of u32-sized slots in the block of free space */
u16 iNext; /* Index in MemPage.aPage[] of the next free block */
};
/*
** When the key and data for a single entry in the BTree will not fit in
** the MX_LOACAL_PAYLOAD bytes of space available on the database page,
** then all extra data is written to a linked list of overflow pages.
** Each overflow page is an instance of the following structure.
**
** Unused pages in the database are also represented by instances of
** the OverflowPage structure. The Page1Header.freeList field is the
** page number of the first page in a linked list of unused database
** pages.
*/
struct OverflowPage {
Pgno next;
char aData[SQLITE_PAGE_SIZE-sizeof(Pgno)];
@@ -132,22 +164,29 @@ struct OverflowPage {
/*
** For every page in the database file, an instance of the following structure
** is stored in memory. The aPage[] array contains the data obtained from
** the disk. The rest is auxiliary data that held in memory only.
** the disk. The rest is auxiliary data that held in memory only. The
** auxiliary data is only valid for regular database pages - the auxiliary
** data is meaningless for overflow pages and pages on the freelist.
**
** Of particular interest in the auxiliary data is the aCell[] entry. Each
** aCell[] entry is a pointer to a Cell structure in aPage[]. The cells
** put in this array so that they can be accessed in constant time, rather
** than in linear time which would be needed if we walked the linked list.
*/
struct MemPage {
char aPage[SQLITE_PAGE_SIZE]; /* Page data stored on disk */
unsigned char isInit; /* True if sequel is initialized */
unsigned char isInit; /* True if auxiliary data is initialized */
unsigned char validUp; /* True if MemPage.up is valid */
unsigned char validLeft; /* True if MemPage.left is valid */
unsigned char validRight; /* True if MemPage.right is valid */
Pgno up; /* The parent page. 0 means this is the root */
Pgno left; /* Left sibling page. 0==none */
Pgno right; /* Right sibling page. 0==none */
int idxStart; /* Index in aPage[] of real data */
PageHdr *pStart; /* Points to aPage[idxStart] */
int nFree; /* Number of free bytes in aPage[] */
int nCell; /* Number of entries on this page */
u32 *aCell[MX_CELL]; /* All entires in sorted order */
Pgno up; /* The parent page. 0 means this is the root */
Pgno left; /* Left sibling page. 0==none */
Pgno right; /* Right sibling page. 0==none */
int idxStart; /* Index in aPage[] of real data */
PageHdr *pStart; /* Points to aPage[idxStart] */
int nFree; /* Number of free bytes in aPage[] */
int nCell; /* Number of entries on this page */
Cell *aCell[MX_CELL]; /* All data entires in sorted order */
}
/*
@@ -155,9 +194,9 @@ struct MemPage {
*/
struct Btree {
Pager *pPager; /* The page cache */
BtCursor *pCursor; /* All open cursors */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *page1; /* First page of the database */
int inTrans; /* True if a transaction is current */
int inTrans; /* True if a transaction is in progress */
};
typedef Btree Bt;
@@ -213,7 +252,8 @@ static void defragmentPage(MemPage *pPage){
** nByte bytes in size. (Actually, all allocations are rounded
** up to the next even multiple of 4.) Return the index into
** pPage->aPage[] of the first byte of the new allocation.
** Or return 0 if there is not enough space.
** Or return 0 if there is not enough free space on the page to
** satisfy the allocation request.
**
** This routine will call defragmentPage if necessary to consolidate
** free space.
@@ -249,7 +289,10 @@ static int allocSpace(MemPage *pPage, int nByte){
/*
** Return a section of the MemPage.aPage[] to the freelist.
** The first byte of the new free block is pPage->aPage[start]
** and there are a told of size bytes to be freed.
** and the size of the block is "size".
**
** Most of the effort here is involved in coalesing adjacent
** free blocks into a single big free block.
*/
static void freeSpace(MemPage *pPage, int start, int size){
int end = start + size;
@@ -307,6 +350,7 @@ static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
idx = pPage->pStart->firstCell;
while( idx!=0 ){
if( idx>SQLITE_PAGE_SIZE-sizeof(Cell) ) goto page_format_error;
if( idx<pPage->idxStart + sizeof(PageHeader) ) goto page_format_error;
pCell = (Cell*)&pPage->aPage[idx];
pPage->aCell[pPage->nCell++] = pCell;
idx = pCell->iNext;
@@ -315,6 +359,7 @@ static int initPage(MemPage *pPage, Pgno pgnoThis, Pgno pgnoParent){
idx = pPage->pStart->firstFree;
while( idx!=0 ){
if( idx>SQLITE_PAGE_SIZE-sizeof(FreeBlk) ) goto page_format_error;
if( idx<pPage->idxStart + sizeof(PageHeader) ) goto page_format_error;
pFBlk = (FreeBlk*)&pPage->aPage[idx];
pPage->nFree += pFBlk->iSize;
if( pFBlk->iNext <= idx ) goto page_format_error;
@@ -327,7 +372,11 @@ page_format_error:
}
/*
** Open a new database
** Open a new database.
**
** Actually, this routine just sets up the internal data structures
** for accessing the database. We do not actually open the database
** file until the first page is loaded.
*/
int sqliteBtreeOpen(const char *zFilename, int mode, Btree **ppBtree){
Btree *pBt;
@@ -362,6 +411,41 @@ int sqliteBtreeClose(Btree *pBt){
return SQLITE_OK;
}
/*
** Get a reference to page1 of the database file. This will
** also acquire a readlock on that file.
**
** SQLITE_OK is returned on success. If the file is not a
** well-formed database file, then SQLITE_CORRUPT is returned.
** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
** is returned if we run out of memory. SQLITE_PROTOCOL is returned
** if there is a locking protocol violation.
*/
static int lockBtree(Btree *pBt){
int rc;
if( pBt->page1 ) return SQLITE_OK;
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
if( rc!=SQLITE_OK ) return rc;
rc = initPage(pBt->page1, 1, 0);
if( rc!=SQLITE_OK ) goto lock_failed;
/* Do some checking to help insure the file we opened really is
** a valid database file.
*/
if( sqlitepager_pagecount(pBt->pPager)>0 ){
Page1Header *pP1 = (Page1Header*)pBt->page1;
if( pP1->magic1!=MAGIC_1 || pP1->magic2!=MAGIC_2 ){
rc = SQLITE_CORRUPT;
goto lock_failed;
}
}
return rc;
lock_failed:
sqlitepager_unref(pBt->page1);
pBt->page1 = 0;
}
/*
** Start a new transaction
*/
@@ -379,25 +463,6 @@ int sqliteBtreeBeginTrans(Btree *pBt){
return rc;
}
/*
** Get a reference to page1 of the database file. This will
** also acquire a readlock on that file.
*/
static int lockBtree(Btree *pBt){
int rc;
if( pBt->page1 ) return SQLITE_OK;
rc = sqlitepager_get(pBt->pPager, 1, &pBt->page1);
if( rc!=SQLITE_OK ) return rc;
rc = initPage(pBt->page1, 1, 0);
if( rc!=SQLITE_OK ){
sqlitepager_unref(pBt->page1);
pBt->page1 = 0;
return rc;
}
/* Sanity checking on the database file format */
return rc;
}
/*
** Remove the last reference to the database file. This will
** remove the read lock.

View File

@@ -25,9 +25,9 @@
**
** The page cache is used to access a database file. The pager journals
** all writes in order to support rollback. Locking is used to limit
** access to one or more reader or on writer.
** access to one or more reader or one writer.
**
** @(#) $Id: pager.c,v 1.5 2001/04/28 16:52:42 drh Exp $
** @(#) $Id: pager.c,v 1.6 2001/05/21 13:45:10 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@@ -56,13 +56,16 @@
** threads can be reading or writing while one
** process is writing.
**
** The page cache comes up in PCS_UNLOCK. The first time a
** sqlite_page_get() occurs, the state transitions to PCS_READLOCK.
** The page cache comes up in SQLITE_UNLOCK. The first time a
** sqlite_page_get() occurs, the state transitions to SQLITE_READLOCK.
** After all pages have been released using sqlite_page_unref(),
** the state transitions back to PCS_UNLOCK. The first time
** the state transitions back to SQLITE_UNLOCK. The first time
** that sqlite_page_write() is called, the state transitions to
** PCS_WRITELOCK. The sqlite_page_rollback() and sqlite_page_commit()
** functions transition the state back to PCS_READLOCK.
** SQLITE_WRITELOCK. (Note that sqlite_page_write() can only be
** called on an outstanding page which means that the pager must
** be in SQLITE_READLOCK before it transitions to SQLITE_WRITELOCK.)
** The sqlite_page_rollback() and sqlite_page_commit() functions
** transition the state from SQLITE_WRITELOCK back to SQLITE_READLOCK.
*/
#define SQLITE_UNLOCK 0
#define SQLITE_READLOCK 1
@@ -96,7 +99,7 @@ struct PgHdr {
/*
** How big to make the hash table used for locating in-memory pages
** by page number.
** by page number. Knuth says this should be a prime number.
*/
#define N_PG_HASH 101
@@ -336,8 +339,9 @@ static int pager_unwritelock(Pager *pPager){
** file-type string for sanity checking. Then there is a single
** Pgno number which is the number of pages in the database before
** changes were made. The database is truncated to this size.
** Next come zero or more page records which each page record
** consists of a Pgno, SQLITE_PAGE_SIZE bytes of data.
** Next come zero or more page records where each page record
** consists of a Pgno and SQLITE_PAGE_SIZE bytes of data. See
** the PageRecord structure for details.
**
** For playback, the pages have to be read from the journal in
** reverse order and put back into the original database file.
@@ -568,6 +572,12 @@ static void sqlitepager_ref(PgHdr *pPg){
** A read lock is obtained for the first page acquired. The lock
** is dropped when the last page is released.
**
** A _get works for any page number greater than 0. If the database
** file is smaller than the requested page, then no actual disk
** read occurs and the memory image of the page is initialized to
** all zeros. The extra data appended to a page is always initialized
** to zeros the first time a page is loaded into memory.
**
** The acquisition might fail for several reasons. In all cases,
** an appropriate error code is returned and *ppPage is set to NULL.
**
@@ -727,8 +737,13 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
assert( pPg->pNextHash->pPrevHash==0 );
pPg->pNextHash->pPrevHash = pPg;
}
pager_seek(pPager->fd, (pgno-1)*SQLITE_PAGE_SIZE);
pager_read(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager);
if( pPager->dbSize<pgno ){
memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
}else{
pager_seek(pPager->fd, (pgno-1)*SQLITE_PAGE_SIZE);
pager_read(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
}
if( pPager->nExtra>0 ){
memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
}
@@ -749,8 +764,8 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
** See also sqlitepager_get(). The difference between this routine
** and sqlitepager_get() is that _get() will go to the disk and read
** in the page if the page is not already in cache. This routine
** returns NULL if the page is not in cache and no disk I/O ever
** occurs.
** returns NULL if the page is not in cache of if a disk I/O has ever
** happened.
*/
void *sqlitepager_lookup(Pager *pPager, Pgno pgno){
PgHdr *pPg;
@@ -824,7 +839,7 @@ int sqlitepager_unref(void *pData){
** The first time this routine is called, the pager creates a new
** journal and acquires a write lock on the database. If the write
** lock could not be acquired, this routine returns SQLITE_BUSY. The
** calling routine must check for that routine and be careful not to
** calling routine must check for that return value and be careful not to
** change any page data until this routine returns SQLITE_OK.
**
** If the journal file could not be written because the disk is full,
@@ -889,6 +904,9 @@ int sqlitepager_write(void *pData){
}
}
pPg->inJournal = 1;
if( pPager->dbSize<pPg->pgno ){
pPager->dbSize = pPg->pgno;
}
return rc;
}

View File

@@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is page cache subsystem.
#
# $Id: pager.test,v 1.3 2001/04/17 20:09:11 drh Exp $
# $Id: pager.test,v 1.4 2001/05/21 13:45:10 drh Exp $
set testdir [file dirname $argv0]
@@ -75,7 +75,7 @@ do_test pager-2.3 {
} {0}
do_test pager-2.4 {
pager_stats $::p1
} {ref 1 page 1 max 10 size -1 state 1 err 0 hit 0 miss 1 ovfl 0}
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
do_test pager-2.5 {
pager_pagecount $::p1
} {0}
@@ -103,7 +103,7 @@ do_test pager-2.12 {
} {1}
do_test pager-2.13 {
pager_stats $::p1
} {ref 1 page 1 max 10 size -1 state 1 err 0 hit 0 miss 2 ovfl 0}
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 2 ovfl 0}
do_test pager-2.14 {
set v [catch {
page_write $::g1 "Page-One"
@@ -112,7 +112,7 @@ do_test pager-2.14 {
} {0 {}}
do_test pager-2.15 {
pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 2 err 0 hit 0 miss 2 ovfl 0}
} {ref 1 page 1 max 10 size 1 state 2 err 0 hit 0 miss 2 ovfl 0}
do_test pager-2.16 {
page_read $::g1
} {Page-One}

View File

@@ -1,7 +1,7 @@
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.36 2001/04/05 16:49:44 drh Exp $}
set rcsid {$Id: index.tcl,v 1.37 2001/05/21 13:45:10 drh Exp $}
puts {<html>
<head><title>SQLite: An SQL Database Library Built Atop GDBM</title></head>
@@ -69,7 +69,7 @@ only reached when <tt>malloc()</tt> fails.</p>
But it only ignores case for 7-bit Latin characters.
The case of 8-bit iso8859 characters or UTF-8 characters is
signification. Hence, <b>'a'&nbsp;LIKE&nbsp;'A'</b> returns
TRUE but <b>'&aelig;'&nbsp;LIKE&nbsp;'&AElig;'</b>" returns FALSE.
TRUE but <b>'&aelig;'&nbsp;LIKE&nbsp;'&AElig;'</b> returns FALSE.
</p></li>
</ul>
@@ -147,7 +147,7 @@ found <a href="crosscompile.html">here</a>.
puts {<h2>Command-line Usage Example</h2>
<p>Download the source archive and compile the <b>sqlite</b>
program as described above. The type:</p>
program as described above. Then type:</p>
<blockquote><pre>
bash$ sqlite ~/newdb <i>Directory ~/newdb created automatically</i>

View File

@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: lang.tcl,v 1.7 2001/04/04 11:48:58 drh Exp $}
set rcsid {$Id: lang.tcl,v 1.8 2001/05/21 13:45:10 drh Exp $}
puts {<html>
<head>
@@ -384,10 +384,16 @@ to the right contains the wildcards.}
puts "A percent symbol [Operator %] in the right operand
matches any sequence of zero or more characters on the left.
An underscore [Operator _] on the right
matches any single character on the left. The LIKE operator is
matches any single character on the left."
puts {The LIKE operator is
not case sensitive and will match upper case characters on one
side against lower case characters on the other.</p>"
puts {
side against lower case characters on the other.
(A bug: SQLite only understands upper/lower case for 7-bit Latin
characters. Hence the LIKE operator is case sensitive for
8-bit iso8859 characters or UTF-8 characters. For example,
the expression <b>'a'&nbsp;LIKE&nbsp;'A'</b> is TRUE but
<b>'&aelig;'&nbsp;LIKE&nbsp;'&AElig;'</b> is FALSE.)
</p>
<p>The GLOB operator is similar to LIKE but uses the Unix
file globbing syntax for its wildcards. Also, GLOB is case
@@ -398,7 +404,7 @@ the NOT keyword to invert the sense of the test.</p>
statement or one of the following special identifiers: "<b>ROWID</b>",
"<b>OID</b>", or "<b>_ROWID_</b>".
These special identifiers all describe the
unique random integer key (the "row key") associated every every
unique random integer key (the "row key") associated with every
row of every table.
The special identifiers only refer to the row key if the CREATE TABLE
statement does not define a real column with the same name. Row keys