Bug 328213, r=vladimir Upgrade to sqlite 3.3.4.
This commit is contained in:
Родитель
28c1f4ad33
Коммит
b06468ea47
|
@ -1,5 +1,5 @@
|
|||
|
||||
This is sqlite 3.3.3
|
||||
This is sqlite 3.3.4
|
||||
|
||||
See http://www.sqlite.org/ for more info.
|
||||
|
||||
|
@ -13,11 +13,20 @@ we just bring in *.c *.h (including a full sqlite3.h).
|
|||
|
||||
To move to a new version:
|
||||
|
||||
Update opcodes.c, opcodes.h, parse.c, parse.h, all of which are
|
||||
Update opcodes.c, opcodes.h, parse.c, parse.h, and sqlite3.h, all of which are
|
||||
normally generated as part of the sqlite build. Pull these out of the
|
||||
sqlite3 windows source .zip, or autoconfiscate and build a tarball and
|
||||
copy them out. Yes, this sucks, but it's better than having to build
|
||||
the parser and all that goop as part of our build.
|
||||
|
||||
If you do a configure, you may want to --disable-tcl because the tcl
|
||||
part may not work on all systems.
|
||||
|
||||
You will also need to apply sqlite3-param-indexes.patch.
|
||||
|
||||
They you need to update sqlite3file.h, which pulls out random bits of the
|
||||
internal files that we need to export. If any of these internal structures
|
||||
change, they need to be changed in sqlite3file.h as well.
|
||||
|
||||
-- Vlad Vukicevic <vladimir@pobox.com> 02/2006
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that used to generate VDBE code
|
||||
** that implements the ALTER TABLE command.
|
||||
**
|
||||
** $Id: alter.c,v 1.5 2006-02-08 21:10:09 vladimir%pobox.com Exp $
|
||||
** $Id: alter.c,v 1.7 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -541,6 +541,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
|||
for(i=0; i<pNew->nCol; i++){
|
||||
Column *pCol = &pNew->aCol[i];
|
||||
pCol->zName = sqliteStrDup(pCol->zName);
|
||||
pCol->zColl = 0;
|
||||
pCol->zType = 0;
|
||||
pCol->pDflt = 0;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.311 2006/01/24 16:37:58 danielk1977 Exp $
|
||||
** $Id: btree.c,v 1.315 2006/02/22 03:08:33 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
|
@ -411,8 +411,8 @@ struct BtCursor {
|
|||
** The table that this cursor was opened on still exists, but has been
|
||||
** modified since the cursor was last used. The cursor position is saved
|
||||
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
|
||||
** this state, restoreOrClearCursorPosition() can be called to attempt to seek
|
||||
** the cursor to the saved position.
|
||||
** this state, restoreOrClearCursorPosition() can be called to attempt to
|
||||
** seek the cursor to the saved position.
|
||||
*/
|
||||
#define CURSOR_INVALID 0
|
||||
#define CURSOR_VALID 1
|
||||
|
@ -756,9 +756,19 @@ static void unlockAllTables(Btree *p){
|
|||
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
|
||||
** this test.
|
||||
*/
|
||||
#define PTRMAP_PAGENO(pgsz, pgno) (((pgno-2)/(pgsz/5+1))*(pgsz/5+1)+2)
|
||||
#define PTRMAP_PTROFFSET(pgsz, pgno) (((pgno-2)%(pgsz/5+1)-1)*5)
|
||||
#define PTRMAP_ISPAGE(pgsz, pgno) (PTRMAP_PAGENO(pgsz,pgno)==pgno)
|
||||
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
|
||||
#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
|
||||
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
|
||||
|
||||
static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
|
||||
int nPagesPerMapPage = (pBt->usableSize/5)+1;
|
||||
int iPtrMap = (pgno-2)/nPagesPerMapPage;
|
||||
int ret = (iPtrMap*nPagesPerMapPage) + 2;
|
||||
if( ret==PENDING_BYTE_PAGE(pBt) ){
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** The pointer map is a lookup table that identifies the parent page for
|
||||
|
@ -810,16 +820,19 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
|
|||
int offset; /* Offset in pointer map page */
|
||||
int rc;
|
||||
|
||||
/* The master-journal page number must never be used as a pointer map page */
|
||||
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
|
||||
|
||||
assert( pBt->autoVacuum );
|
||||
if( key==0 ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
|
||||
iPtrmap = PTRMAP_PAGENO(pBt, key);
|
||||
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
|
||||
offset = PTRMAP_PTROFFSET(pBt, key);
|
||||
|
||||
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
|
||||
TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
|
||||
|
@ -847,13 +860,13 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
|||
int offset; /* Offset of entry in pointer map */
|
||||
int rc;
|
||||
|
||||
iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
|
||||
iPtrmap = PTRMAP_PAGENO(pBt, key);
|
||||
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
|
||||
if( rc!=0 ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
|
||||
offset = PTRMAP_PTROFFSET(pBt, key);
|
||||
if( pEType ) *pEType = pPtrmap[offset];
|
||||
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
|
||||
|
||||
|
@ -1260,6 +1273,12 @@ static void freeSpace(MemPage *pPage, int start, int size){
|
|||
assert( (start + size)<=pPage->pBt->usableSize );
|
||||
if( size<4 ) size = 4;
|
||||
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
/* Overwrite deleted information with zeros when the SECURE_DELETE
|
||||
** option is enabled at compile-time */
|
||||
memset(&data[start], 0, size);
|
||||
#endif
|
||||
|
||||
/* Add the space back into the linked list of freeblocks */
|
||||
hdr = pPage->hdrOffset;
|
||||
addr = hdr + 1;
|
||||
|
@ -1790,9 +1809,9 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
|
|||
** probability of damage to near zero but with a write performance reduction.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
int sqlite3BtreeSetSafetyLevel(Btree *p, int level){
|
||||
int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
|
||||
BtShared *pBt = p->pBt;
|
||||
sqlite3pager_set_safety_level(pBt->pPager, level);
|
||||
sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -2344,7 +2363,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
|
|||
#endif
|
||||
|
||||
assert( pBt->autoVacuum );
|
||||
if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
|
||||
if( PTRMAP_ISPAGE(pBt, sqlite3pager_pagecount(pPager)) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
|
@ -2357,14 +2376,26 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* This block figures out how many pages there are in the database
|
||||
** now (variable origSize), and how many there will be after the
|
||||
** truncation (variable finSize).
|
||||
**
|
||||
** The final size is the original size, less the number of free pages
|
||||
** in the database, less any pointer-map pages that will no longer
|
||||
** be required, less 1 if the pending-byte page was part of the database
|
||||
** but is not after the truncation.
|
||||
**/
|
||||
origSize = sqlite3pager_pagecount(pPager);
|
||||
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
|
||||
if( origSize==PENDING_BYTE_PAGE(pBt) ){
|
||||
origSize--;
|
||||
}
|
||||
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pBt, origSize)+pgsz/5)/(pgsz/5);
|
||||
finSize = origSize - nFreeList - nPtrMap;
|
||||
if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
||||
if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
||||
finSize--;
|
||||
}
|
||||
while( PTRMAP_ISPAGE(pBt, finSize) || finSize==PENDING_BYTE_PAGE(pBt) ){
|
||||
finSize--;
|
||||
if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
|
||||
finSize--;
|
||||
}
|
||||
}
|
||||
TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
|
||||
|
||||
|
@ -2376,7 +2407,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
|
|||
*/
|
||||
for( iDbPage=finSize+1; iDbPage<=origSize; iDbPage++ ){
|
||||
/* If iDbPage is a pointer map page, or the pending-byte page, skip it. */
|
||||
if( PTRMAP_ISPAGE(pgsz, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
|
||||
if( PTRMAP_ISPAGE(pBt, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2434,6 +2465,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
|
|||
put4byte(&pBt->pPage1->aData[36], 0);
|
||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
||||
*nTrunc = finSize;
|
||||
assert( finSize!=PENDING_BYTE_PAGE(pBt) );
|
||||
|
||||
autovacuum_out:
|
||||
assert( nRef==*sqlite3pager_stats(pPager) );
|
||||
|
@ -3806,7 +3838,7 @@ static int allocatePage(
|
|||
*pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt->usableSize, *pPgno) ){
|
||||
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
|
||||
/* If *pPgno refers to a pointer-map page, allocate two new pages
|
||||
** at the end of the file instead of one. The first allocated page
|
||||
** becomes a new pointer-map page, the second is used by the caller.
|
||||
|
@ -3853,6 +3885,15 @@ static int freePage(MemPage *pPage){
|
|||
n = get4byte(&pPage1->aData[36]);
|
||||
put4byte(&pPage1->aData[36], n+1);
|
||||
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
/* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
|
||||
** always fully overwrite deleted information with zeros.
|
||||
*/
|
||||
rc = sqlite3pager_write(pPage->aData);
|
||||
if( rc ) return rc;
|
||||
memset(pPage->aData, 0, pPage->pBt->pageSize);
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
/* If the database supports auto-vacuum, write an entry in the pointer-map
|
||||
** to indicate that the page is free.
|
||||
|
@ -3893,7 +3934,9 @@ static int freePage(MemPage *pPage){
|
|||
if( rc ) return rc;
|
||||
put4byte(&pTrunk->aData[4], k+1);
|
||||
put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
|
||||
#ifndef SQLITE_SECURE_DELETE
|
||||
sqlite3pager_dont_write(pBt->pPager, pPage->pgno);
|
||||
#endif
|
||||
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
|
||||
}
|
||||
releasePage(pTrunk);
|
||||
|
@ -5440,7 +5483,7 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
|
|||
/* The new root-page may not be allocated on a pointer-map page, or the
|
||||
** PENDING_BYTE page.
|
||||
*/
|
||||
if( pgnoRoot==PTRMAP_PAGENO(pBt->usableSize, pgnoRoot) ||
|
||||
if( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
|
||||
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
|
||||
pgnoRoot++;
|
||||
}
|
||||
|
@ -5713,7 +5756,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
|
|||
if( maxRootPgno==PENDING_BYTE_PAGE(pBt) ){
|
||||
maxRootPgno--;
|
||||
}
|
||||
if( maxRootPgno==PTRMAP_PAGENO(pBt->usableSize, maxRootPgno) ){
|
||||
if( maxRootPgno==PTRMAP_PAGENO(pBt, maxRootPgno) ){
|
||||
maxRootPgno--;
|
||||
}
|
||||
assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
|
@ -6390,11 +6433,11 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
|||
** references to pointer-map pages.
|
||||
*/
|
||||
if( sCheck.anRef[i]==0 &&
|
||||
(PTRMAP_PAGENO(pBt->usableSize, i)!=i || !pBt->autoVacuum) ){
|
||||
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
|
||||
}
|
||||
if( sCheck.anRef[i]!=0 &&
|
||||
(PTRMAP_PAGENO(pBt->usableSize, i)==i && pBt->autoVacuum) ){
|
||||
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
|
||||
}
|
||||
#endif
|
||||
|
@ -6522,19 +6565,21 @@ int sqlite3BtreeIsInStmt(Btree *p){
|
|||
** the write-transaction for this database file is to delete the journal.
|
||||
*/
|
||||
int sqlite3BtreeSync(Btree *p, const char *zMaster){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->inTrans==TRANS_WRITE ){
|
||||
BtShared *pBt = p->pBt;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
Pgno nTrunc = 0;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum ){
|
||||
int rc = autoVacuumCommit(pBt, &nTrunc);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = autoVacuumCommit(pBt, &nTrunc);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
|
||||
#endif
|
||||
return sqlite3pager_sync(pBt->pPager, zMaster, 0);
|
||||
rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite B-Tree file
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.69 2006/01/07 13:21:04 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
|
||||
/* TODO: This definition is just included so other modules compile. It
|
||||
** needs to be revisited.
|
||||
*/
|
||||
#define SQLITE_N_BTREE_META 10
|
||||
|
||||
/*
|
||||
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
|
||||
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_AUTOVACUUM
|
||||
#define SQLITE_DEFAULT_AUTOVACUUM 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Forward declarations of structure
|
||||
*/
|
||||
typedef struct Btree Btree;
|
||||
typedef struct BtCursor BtCursor;
|
||||
typedef struct BtShared BtShared;
|
||||
|
||||
|
||||
int sqlite3BtreeOpen(
|
||||
const char *zFilename, /* Name of database file to open */
|
||||
sqlite3 *db, /* Associated database connection */
|
||||
Btree **, /* Return open Btree* here */
|
||||
int flags /* Flags */
|
||||
);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
|
||||
** following values.
|
||||
**
|
||||
** NOTE: These values must match the corresponding PAGER_ values in
|
||||
** pager.h.
|
||||
*/
|
||||
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
|
||||
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
|
||||
#define BTREE_MEMORY 4 /* In-memory DB. No argument */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
int sqlite3BtreeSetSafetyLevel(Btree*,int);
|
||||
int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree*,int,int);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeGetReserve(Btree*);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
int sqlite3BtreeBeginStmt(Btree*);
|
||||
int sqlite3BtreeCommitStmt(Btree*);
|
||||
int sqlite3BtreeRollbackStmt(Btree*);
|
||||
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
|
||||
int sqlite3BtreeSchemaLocked(Btree *);
|
||||
int sqlite3BtreeLockTable(Btree *, int, u8);
|
||||
|
||||
const char *sqlite3BtreeGetFilename(Btree *);
|
||||
const char *sqlite3BtreeGetDirname(Btree *);
|
||||
const char *sqlite3BtreeGetJournalname(Btree *);
|
||||
int sqlite3BtreeCopyFile(Btree *, Btree *);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
||||
** of the following flags:
|
||||
*/
|
||||
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
|
||||
#define BTREE_ZERODATA 2 /* Table has keys only - no data */
|
||||
#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
|
||||
|
||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int);
|
||||
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
|
||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
|
||||
void*, /* First argument to compare function */
|
||||
BtCursor **ppCursor /* Returned cursor */
|
||||
);
|
||||
|
||||
void sqlite3BtreeSetCompare(
|
||||
BtCursor *,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void*
|
||||
);
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
|
||||
int sqlite3BtreeDelete(BtCursor*);
|
||||
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
|
||||
const void *pData, int nData);
|
||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeNext(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeEof(BtCursor*);
|
||||
int sqlite3BtreeFlags(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
|
||||
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
|
||||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
void sqlite3BtreeCursorList(Btree*);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||
#else
|
||||
#define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#endif /* _BTREE_H_ */
|
|
@ -22,7 +22,7 @@
|
|||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.383 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
** $Id: build.c,v 1.388 2006/02/18 16:36:45 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -135,8 +135,8 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
if( !pParse->pVdbe ){
|
||||
if( pParse->rc==SQLITE_OK && pParse->nErr ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin by generating some termination code at the end of the
|
||||
|
@ -185,7 +185,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
|
||||
/* Get the VDBE program ready for execution
|
||||
*/
|
||||
if( v && pParse->nErr==0 ){
|
||||
if( v && pParse->nErr==0 && !sqlite3MallocFailed() ){
|
||||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||
sqlite3VdbeTrace(v, trace);
|
||||
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
|
||||
|
@ -1662,12 +1662,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|||
** Actually, this error is caught previously and so the following test
|
||||
** should always fail. But we will leave it in place just to be safe.
|
||||
*/
|
||||
#if 0
|
||||
if( pTable->nCol<0 ){
|
||||
sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
assert( pTable->nCol>=0 );
|
||||
|
||||
/* If we get this far, it means we need to compute the table names.
|
||||
|
@ -2364,10 +2362,10 @@ void sqlite3CreateIndex(
|
|||
nExtra /* Collation sequence names */
|
||||
);
|
||||
if( sqlite3MallocFailed() ) goto exit_create_index;
|
||||
pIndex->aiColumn = (int *)(&pIndex[1]);
|
||||
pIndex->azColl = (char**)(&pIndex[1]);
|
||||
pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
|
||||
pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]);
|
||||
pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]);
|
||||
pIndex->aSortOrder = (u8 *)(&pIndex->azColl[nCol]);
|
||||
pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]);
|
||||
pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
|
||||
zExtra = (char *)(&pIndex->zName[nName+1]);
|
||||
strcpy(pIndex->zName, zName);
|
||||
|
@ -2849,6 +2847,7 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
|
|||
pItem->zName = sqlite3NameFromToken(pTable);
|
||||
pItem->zDatabase = sqlite3NameFromToken(pDatabase);
|
||||
pItem->iCursor = -1;
|
||||
pItem->isPopulated = 0;
|
||||
pList->nSrc++;
|
||||
return pList;
|
||||
}
|
||||
|
@ -2959,7 +2958,7 @@ void sqlite3RollbackTransaction(Parse *pParse){
|
|||
** Make sure the TEMP database is open and available for use. Return
|
||||
** the number of errors. Leave any error messages in the pParse structure.
|
||||
*/
|
||||
static int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( db->aDb[1].pBt==0 && !pParse->explain ){
|
||||
int rc = sqlite3BtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
|
||||
|
|
|
@ -1,998 +0,0 @@
|
|||
/*
|
||||
** 2003 October 31
|
||||
**
|
||||
** 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 contains the C functions that implement date and time
|
||||
** functions for SQLite.
|
||||
**
|
||||
** There is only one exported symbol in this file - the function
|
||||
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: date.c,v 1.53 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
**
|
||||
** NOTES:
|
||||
**
|
||||
** SQLite processes all times and dates as Julian Day numbers. The
|
||||
** dates and times are stored as the number of days since noon
|
||||
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
|
||||
** calendar system.
|
||||
**
|
||||
** 1970-01-01 00:00:00 is JD 2440587.5
|
||||
** 2000-01-01 00:00:00 is JD 2451544.5
|
||||
**
|
||||
** This implemention requires years to be expressed as a 4-digit number
|
||||
** which means that only dates between 0000-01-01 and 9999-12-31 can
|
||||
** be represented, even though julian day numbers allow a much wider
|
||||
** range of dates.
|
||||
**
|
||||
** The Gregorian calendar system is used for all dates and times,
|
||||
** even those that predate the Gregorian calendar. Historians usually
|
||||
** use the Julian calendar for dates prior to 1582-10-15 and for some
|
||||
** dates afterwards, depending on locale. Beware of this difference.
|
||||
**
|
||||
** The conversion algorithms are implemented based on descriptions
|
||||
** in the following text:
|
||||
**
|
||||
** Jean Meeus
|
||||
** Astronomical Algorithms, 2nd Edition, 1998
|
||||
** ISBM 0-943396-61-1
|
||||
** Willmann-Bell, Inc
|
||||
** Richmond, Virginia (USA)
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
|
||||
/*
|
||||
** A structure for holding a single date and time.
|
||||
*/
|
||||
typedef struct DateTime DateTime;
|
||||
struct DateTime {
|
||||
double rJD; /* The julian day number */
|
||||
int Y, M, D; /* Year, month, and day */
|
||||
int h, m; /* Hour and minutes */
|
||||
int tz; /* Timezone offset in minutes */
|
||||
double s; /* Seconds */
|
||||
char validYMD; /* True if Y,M,D are valid */
|
||||
char validHMS; /* True if h,m,s are valid */
|
||||
char validJD; /* True if rJD is valid */
|
||||
char validTZ; /* True if tz is valid */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Convert zDate into one or more integers. Additional arguments
|
||||
** come in groups of 5 as follows:
|
||||
**
|
||||
** N number of digits in the integer
|
||||
** min minimum allowed value of the integer
|
||||
** max maximum allowed value of the integer
|
||||
** nextC first character after the integer
|
||||
** pVal where to write the integers value.
|
||||
**
|
||||
** Conversions continue until one with nextC==0 is encountered.
|
||||
** The function returns the number of successful conversions.
|
||||
*/
|
||||
static int getDigits(const char *zDate, ...){
|
||||
va_list ap;
|
||||
int val;
|
||||
int N;
|
||||
int min;
|
||||
int max;
|
||||
int nextC;
|
||||
int *pVal;
|
||||
int cnt = 0;
|
||||
va_start(ap, zDate);
|
||||
do{
|
||||
N = va_arg(ap, int);
|
||||
min = va_arg(ap, int);
|
||||
max = va_arg(ap, int);
|
||||
nextC = va_arg(ap, int);
|
||||
pVal = va_arg(ap, int*);
|
||||
val = 0;
|
||||
while( N-- ){
|
||||
if( !isdigit(*(u8*)zDate) ){
|
||||
goto end_getDigits;
|
||||
}
|
||||
val = val*10 + *zDate - '0';
|
||||
zDate++;
|
||||
}
|
||||
if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
|
||||
goto end_getDigits;
|
||||
}
|
||||
*pVal = val;
|
||||
zDate++;
|
||||
cnt++;
|
||||
}while( nextC );
|
||||
va_end(ap);
|
||||
end_getDigits:
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read text from z[] and convert into a floating point number. Return
|
||||
** the number of digits converted.
|
||||
*/
|
||||
#define getValue sqlite3AtoF
|
||||
|
||||
/*
|
||||
** Parse a timezone extension on the end of a date-time.
|
||||
** The extension is of the form:
|
||||
**
|
||||
** (+/-)HH:MM
|
||||
**
|
||||
** If the parse is successful, write the number of minutes
|
||||
** of change in *pnMin and return 0. If a parser error occurs,
|
||||
** return 0.
|
||||
**
|
||||
** A missing specifier is not considered an error.
|
||||
*/
|
||||
static int parseTimezone(const char *zDate, DateTime *p){
|
||||
int sgn = 0;
|
||||
int nHr, nMn;
|
||||
while( isspace(*(u8*)zDate) ){ zDate++; }
|
||||
p->tz = 0;
|
||||
if( *zDate=='-' ){
|
||||
sgn = -1;
|
||||
}else if( *zDate=='+' ){
|
||||
sgn = +1;
|
||||
}else{
|
||||
return *zDate!=0;
|
||||
}
|
||||
zDate++;
|
||||
if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 5;
|
||||
p->tz = sgn*(nMn + nHr*60);
|
||||
while( isspace(*(u8*)zDate) ){ zDate++; }
|
||||
return *zDate!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
|
||||
** The HH, MM, and SS must each be exactly 2 digits. The
|
||||
** fractional seconds FFFF can be one or more digits.
|
||||
**
|
||||
** Return 1 if there is a parsing error and 0 on success.
|
||||
*/
|
||||
static int parseHhMmSs(const char *zDate, DateTime *p){
|
||||
int h, m, s;
|
||||
double ms = 0.0;
|
||||
if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 5;
|
||||
if( *zDate==':' ){
|
||||
zDate++;
|
||||
if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 2;
|
||||
if( *zDate=='.' && isdigit((u8)zDate[1]) ){
|
||||
double rScale = 1.0;
|
||||
zDate++;
|
||||
while( isdigit(*(u8*)zDate) ){
|
||||
ms = ms*10.0 + *zDate - '0';
|
||||
rScale *= 10.0;
|
||||
zDate++;
|
||||
}
|
||||
ms /= rScale;
|
||||
}
|
||||
}else{
|
||||
s = 0;
|
||||
}
|
||||
p->validJD = 0;
|
||||
p->validHMS = 1;
|
||||
p->h = h;
|
||||
p->m = m;
|
||||
p->s = s + ms;
|
||||
if( parseTimezone(zDate, p) ) return 1;
|
||||
p->validTZ = p->tz!=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
|
||||
** that the YYYY-MM-DD is according to the Gregorian calendar.
|
||||
**
|
||||
** Reference: Meeus page 61
|
||||
*/
|
||||
static void computeJD(DateTime *p){
|
||||
int Y, M, D, A, B, X1, X2;
|
||||
|
||||
if( p->validJD ) return;
|
||||
if( p->validYMD ){
|
||||
Y = p->Y;
|
||||
M = p->M;
|
||||
D = p->D;
|
||||
}else{
|
||||
Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */
|
||||
M = 1;
|
||||
D = 1;
|
||||
}
|
||||
if( M<=2 ){
|
||||
Y--;
|
||||
M += 12;
|
||||
}
|
||||
A = Y/100;
|
||||
B = 2 - A + (A/4);
|
||||
X1 = 365.25*(Y+4716);
|
||||
X2 = 30.6001*(M+1);
|
||||
p->rJD = X1 + X2 + D + B - 1524.5;
|
||||
p->validJD = 1;
|
||||
p->validYMD = 0;
|
||||
if( p->validHMS ){
|
||||
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
|
||||
if( p->validTZ ){
|
||||
p->rJD -= p->tz*60/86400.0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse dates of the form
|
||||
**
|
||||
** YYYY-MM-DD HH:MM:SS.FFF
|
||||
** YYYY-MM-DD HH:MM:SS
|
||||
** YYYY-MM-DD HH:MM
|
||||
** YYYY-MM-DD
|
||||
**
|
||||
** Write the result into the DateTime structure and return 0
|
||||
** on success and 1 if the input string is not a well-formed
|
||||
** date.
|
||||
*/
|
||||
static int parseYyyyMmDd(const char *zDate, DateTime *p){
|
||||
int Y, M, D, neg;
|
||||
|
||||
if( zDate[0]=='-' ){
|
||||
zDate++;
|
||||
neg = 1;
|
||||
}else{
|
||||
neg = 0;
|
||||
}
|
||||
if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 10;
|
||||
while( isspace(*(u8*)zDate) || 'T'==*(u8*)zDate ){ zDate++; }
|
||||
if( parseHhMmSs(zDate, p)==0 ){
|
||||
/* We got the time */
|
||||
}else if( *zDate==0 ){
|
||||
p->validHMS = 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
p->validJD = 0;
|
||||
p->validYMD = 1;
|
||||
p->Y = neg ? -Y : Y;
|
||||
p->M = M;
|
||||
p->D = D;
|
||||
if( p->validTZ ){
|
||||
computeJD(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to parse the given string into a Julian Day Number. Return
|
||||
** the number of errors.
|
||||
**
|
||||
** The following are acceptable forms for the input string:
|
||||
**
|
||||
** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
|
||||
** DDDD.DD
|
||||
** now
|
||||
**
|
||||
** In the first form, the +/-HH:MM is always optional. The fractional
|
||||
** seconds extension (the ".FFF") is optional. The seconds portion
|
||||
** (":SS.FFF") is option. The year and date can be omitted as long
|
||||
** as there is a time string. The time string can be omitted as long
|
||||
** as there is a year and date.
|
||||
*/
|
||||
static int parseDateOrTime(const char *zDate, DateTime *p){
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( parseYyyyMmDd(zDate,p)==0 ){
|
||||
return 0;
|
||||
}else if( parseHhMmSs(zDate, p)==0 ){
|
||||
return 0;
|
||||
}else if( sqlite3StrICmp(zDate,"now")==0){
|
||||
double r;
|
||||
sqlite3OsCurrentTime(&r);
|
||||
p->rJD = r;
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
|
||||
getValue(zDate, &p->rJD);
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the Year, Month, and Day from the julian day number.
|
||||
*/
|
||||
static void computeYMD(DateTime *p){
|
||||
int Z, A, B, C, D, E, X1;
|
||||
if( p->validYMD ) return;
|
||||
if( !p->validJD ){
|
||||
p->Y = 2000;
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
}else{
|
||||
Z = p->rJD + 0.5;
|
||||
A = (Z - 1867216.25)/36524.25;
|
||||
A = Z + 1 + A - (A/4);
|
||||
B = A + 1524;
|
||||
C = (B - 122.1)/365.25;
|
||||
D = 365.25*C;
|
||||
E = (B-D)/30.6001;
|
||||
X1 = 30.6001*E;
|
||||
p->D = B - D - X1;
|
||||
p->M = E<14 ? E-1 : E-13;
|
||||
p->Y = p->M>2 ? C - 4716 : C - 4715;
|
||||
}
|
||||
p->validYMD = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the Hour, Minute, and Seconds from the julian day number.
|
||||
*/
|
||||
static void computeHMS(DateTime *p){
|
||||
int Z, s;
|
||||
if( p->validHMS ) return;
|
||||
Z = p->rJD + 0.5;
|
||||
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
|
||||
p->s = 0.001*s;
|
||||
s = p->s;
|
||||
p->s -= s;
|
||||
p->h = s/3600;
|
||||
s -= p->h*3600;
|
||||
p->m = s/60;
|
||||
p->s += s - p->m*60;
|
||||
p->validHMS = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute both YMD and HMS
|
||||
*/
|
||||
static void computeYMD_HMS(DateTime *p){
|
||||
computeYMD(p);
|
||||
computeHMS(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the YMD and HMS and the TZ
|
||||
*/
|
||||
static void clearYMD_HMS_TZ(DateTime *p){
|
||||
p->validYMD = 0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the difference (in days) between localtime and UTC (a.k.a. GMT)
|
||||
** for the time value p where p is in UTC.
|
||||
*/
|
||||
static double localtimeOffset(DateTime *p){
|
||||
DateTime x, y;
|
||||
time_t t;
|
||||
struct tm *pTm;
|
||||
x = *p;
|
||||
computeYMD_HMS(&x);
|
||||
if( x.Y<1971 || x.Y>=2038 ){
|
||||
x.Y = 2000;
|
||||
x.M = 1;
|
||||
x.D = 1;
|
||||
x.h = 0;
|
||||
x.m = 0;
|
||||
x.s = 0.0;
|
||||
} else {
|
||||
int s = x.s + 0.5;
|
||||
x.s = s;
|
||||
}
|
||||
x.tz = 0;
|
||||
x.validJD = 0;
|
||||
computeJD(&x);
|
||||
t = (x.rJD-2440587.5)*86400.0 + 0.5;
|
||||
sqlite3OsEnterMutex();
|
||||
pTm = localtime(&t);
|
||||
y.Y = pTm->tm_year + 1900;
|
||||
y.M = pTm->tm_mon + 1;
|
||||
y.D = pTm->tm_mday;
|
||||
y.h = pTm->tm_hour;
|
||||
y.m = pTm->tm_min;
|
||||
y.s = pTm->tm_sec;
|
||||
sqlite3OsLeaveMutex();
|
||||
y.validYMD = 1;
|
||||
y.validHMS = 1;
|
||||
y.validJD = 0;
|
||||
y.validTZ = 0;
|
||||
computeJD(&y);
|
||||
return y.rJD - x.rJD;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process a modifier to a date-time stamp. The modifiers are
|
||||
** as follows:
|
||||
**
|
||||
** NNN days
|
||||
** NNN hours
|
||||
** NNN minutes
|
||||
** NNN.NNNN seconds
|
||||
** NNN months
|
||||
** NNN years
|
||||
** start of month
|
||||
** start of year
|
||||
** start of week
|
||||
** start of day
|
||||
** weekday N
|
||||
** unixepoch
|
||||
** localtime
|
||||
** utc
|
||||
**
|
||||
** Return 0 on success and 1 if there is any kind of error.
|
||||
*/
|
||||
static int parseModifier(const char *zMod, DateTime *p){
|
||||
int rc = 1;
|
||||
int n;
|
||||
double r;
|
||||
char *z, zBuf[30];
|
||||
z = zBuf;
|
||||
for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
|
||||
z[n] = tolower(zMod[n]);
|
||||
}
|
||||
z[n] = 0;
|
||||
switch( z[0] ){
|
||||
case 'l': {
|
||||
/* localtime
|
||||
**
|
||||
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
|
||||
** show local time.
|
||||
*/
|
||||
if( strcmp(z, "localtime")==0 ){
|
||||
computeJD(p);
|
||||
p->rJD += localtimeOffset(p);
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
/*
|
||||
** unixepoch
|
||||
**
|
||||
** Treat the current value of p->rJD as the number of
|
||||
** seconds since 1970. Convert to a real julian day number.
|
||||
*/
|
||||
if( strcmp(z, "unixepoch")==0 && p->validJD ){
|
||||
p->rJD = p->rJD/86400.0 + 2440587.5;
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}else if( strcmp(z, "utc")==0 ){
|
||||
double c1;
|
||||
computeJD(p);
|
||||
c1 = localtimeOffset(p);
|
||||
p->rJD -= c1;
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->rJD += c1 - localtimeOffset(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
/*
|
||||
** weekday N
|
||||
**
|
||||
** Move the date to the same time on the next occurrence of
|
||||
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
|
||||
** date is already on the appropriate weekday, this is a no-op.
|
||||
*/
|
||||
if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
|
||||
&& (n=r)==r && n>=0 && r<7 ){
|
||||
int Z;
|
||||
computeYMD_HMS(p);
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
Z = p->rJD + 1.5;
|
||||
Z %= 7;
|
||||
if( Z>n ) Z -= 7;
|
||||
p->rJD += n - Z;
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
/*
|
||||
** start of TTTTT
|
||||
**
|
||||
** Move the date backwards to the beginning of the current day,
|
||||
** or month or year.
|
||||
*/
|
||||
if( strncmp(z, "start of ", 9)!=0 ) break;
|
||||
z += 9;
|
||||
computeYMD(p);
|
||||
p->validHMS = 1;
|
||||
p->h = p->m = 0;
|
||||
p->s = 0.0;
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
if( strcmp(z,"month")==0 ){
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( strcmp(z,"year")==0 ){
|
||||
computeYMD(p);
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( strcmp(z,"day")==0 ){
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '+':
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': {
|
||||
n = getValue(z, &r);
|
||||
if( n<=0 ) break;
|
||||
if( z[n]==':' ){
|
||||
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
|
||||
** specified number of hours, minutes, seconds, and fractional seconds
|
||||
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
|
||||
** omitted.
|
||||
*/
|
||||
const char *z2 = z;
|
||||
DateTime tx;
|
||||
int day;
|
||||
if( !isdigit(*(u8*)z2) ) z2++;
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
if( parseHhMmSs(z2, &tx) ) break;
|
||||
computeJD(&tx);
|
||||
tx.rJD -= 0.5;
|
||||
day = (int)tx.rJD;
|
||||
tx.rJD -= day;
|
||||
if( z[0]=='-' ) tx.rJD = -tx.rJD;
|
||||
computeJD(p);
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->rJD += tx.rJD;
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
z += n;
|
||||
while( isspace(*(u8*)z) ) z++;
|
||||
n = strlen(z);
|
||||
if( n>10 || n<3 ) break;
|
||||
if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
|
||||
computeJD(p);
|
||||
rc = 0;
|
||||
if( n==3 && strcmp(z,"day")==0 ){
|
||||
p->rJD += r;
|
||||
}else if( n==4 && strcmp(z,"hour")==0 ){
|
||||
p->rJD += r/24.0;
|
||||
}else if( n==6 && strcmp(z,"minute")==0 ){
|
||||
p->rJD += r/(24.0*60.0);
|
||||
}else if( n==6 && strcmp(z,"second")==0 ){
|
||||
p->rJD += r/(24.0*60.0*60.0);
|
||||
}else if( n==5 && strcmp(z,"month")==0 ){
|
||||
int x, y;
|
||||
computeYMD_HMS(p);
|
||||
p->M += r;
|
||||
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
||||
p->Y += x;
|
||||
p->M -= x*12;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
y = r;
|
||||
if( y!=r ){
|
||||
p->rJD += (r - y)*30.0;
|
||||
}
|
||||
}else if( n==4 && strcmp(z,"year")==0 ){
|
||||
computeYMD_HMS(p);
|
||||
p->Y += r;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
clearYMD_HMS_TZ(p);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process time function arguments. argv[0] is a date-time stamp.
|
||||
** argv[1] and following are modifiers. Parse them all and write
|
||||
** the resulting time into the DateTime structure p. Return 0
|
||||
** on success and 1 if there are any errors.
|
||||
*/
|
||||
static int isDate(int argc, sqlite3_value **argv, DateTime *p){
|
||||
int i;
|
||||
if( argc==0 ) return 1;
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
|
||||
parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1;
|
||||
for(i=1; i<argc; i++){
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
|
||||
parseModifier((char*)sqlite3_value_text(argv[i]), p) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The following routines implement the various date and time functions
|
||||
** of SQLite.
|
||||
*/
|
||||
|
||||
/*
|
||||
** julianday( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return the julian day number of the date specified in the arguments
|
||||
*/
|
||||
static void juliandayFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
computeJD(&x);
|
||||
sqlite3_result_double(context, x.rJD);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** datetime( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return YYYY-MM-DD HH:MM:SS
|
||||
*/
|
||||
static void datetimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
char zBuf[100];
|
||||
computeYMD_HMS(&x);
|
||||
sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
|
||||
(int)(x.s));
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** time( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return HH:MM:SS
|
||||
*/
|
||||
static void timeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
char zBuf[100];
|
||||
computeHMS(&x);
|
||||
sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** date( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return YYYY-MM-DD
|
||||
*/
|
||||
static void dateFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
char zBuf[100];
|
||||
computeYMD(&x);
|
||||
sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return a string described by FORMAT. Conversions as follows:
|
||||
**
|
||||
** %d day of month
|
||||
** %f ** fractional seconds SS.SSS
|
||||
** %H hour 00-24
|
||||
** %j day of year 000-366
|
||||
** %J ** Julian day number
|
||||
** %m month 01-12
|
||||
** %M minute 00-59
|
||||
** %s seconds since 1970-01-01
|
||||
** %S seconds 00-59
|
||||
** %w day of week 0-6 sunday==0
|
||||
** %W week of year 00-53
|
||||
** %Y year 0000-9999
|
||||
** %% %
|
||||
*/
|
||||
static void strftimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
int n, i, j;
|
||||
char *z;
|
||||
const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
|
||||
char zBuf[100];
|
||||
if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
|
||||
for(i=0, n=1; zFmt[i]; i++, n++){
|
||||
if( zFmt[i]=='%' ){
|
||||
switch( zFmt[i+1] ){
|
||||
case 'd':
|
||||
case 'H':
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'S':
|
||||
case 'W':
|
||||
n++;
|
||||
/* fall thru */
|
||||
case 'w':
|
||||
case '%':
|
||||
break;
|
||||
case 'f':
|
||||
n += 8;
|
||||
break;
|
||||
case 'j':
|
||||
n += 3;
|
||||
break;
|
||||
case 'Y':
|
||||
n += 8;
|
||||
break;
|
||||
case 's':
|
||||
case 'J':
|
||||
n += 50;
|
||||
break;
|
||||
default:
|
||||
return; /* ERROR. return a NULL */
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if( n<sizeof(zBuf) ){
|
||||
z = zBuf;
|
||||
}else{
|
||||
z = sqliteMalloc( n );
|
||||
if( z==0 ) return;
|
||||
}
|
||||
computeJD(&x);
|
||||
computeYMD_HMS(&x);
|
||||
for(i=j=0; zFmt[i]; i++){
|
||||
if( zFmt[i]!='%' ){
|
||||
z[j++] = zFmt[i];
|
||||
}else{
|
||||
i++;
|
||||
switch( zFmt[i] ){
|
||||
case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
|
||||
case 'f': {
|
||||
int s = x.s;
|
||||
int ms = (x.s - s)*1000.0;
|
||||
sprintf(&z[j],"%02d.%03d",s,ms);
|
||||
j += strlen(&z[j]);
|
||||
break;
|
||||
}
|
||||
case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
|
||||
case 'W': /* Fall thru */
|
||||
case 'j': {
|
||||
int nDay; /* Number of days since 1st day of year */
|
||||
DateTime y = x;
|
||||
y.validJD = 0;
|
||||
y.M = 1;
|
||||
y.D = 1;
|
||||
computeJD(&y);
|
||||
nDay = x.rJD - y.rJD;
|
||||
if( zFmt[i]=='W' ){
|
||||
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
|
||||
wd = ((int)(x.rJD+0.5)) % 7;
|
||||
sprintf(&z[j],"%02d",(nDay+7-wd)/7);
|
||||
j += 2;
|
||||
}else{
|
||||
sprintf(&z[j],"%03d",nDay+1);
|
||||
j += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'J': sprintf(&z[j],"%.16g",x.rJD); j+=strlen(&z[j]); break;
|
||||
case 'm': sprintf(&z[j],"%02d",x.M); j+=2; break;
|
||||
case 'M': sprintf(&z[j],"%02d",x.m); j+=2; break;
|
||||
case 's': {
|
||||
sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5));
|
||||
j += strlen(&z[j]);
|
||||
break;
|
||||
}
|
||||
case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
|
||||
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
|
||||
case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
|
||||
case '%': z[j++] = '%'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
z[j] = 0;
|
||||
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
|
||||
if( z!=zBuf ){
|
||||
sqliteFree(z);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** current_time()
|
||||
**
|
||||
** This function returns the same value as time('now').
|
||||
*/
|
||||
static void ctimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_value *pVal = sqlite3ValueNew();
|
||||
if( pVal ){
|
||||
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
|
||||
timeFunc(context, 1, &pVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** current_date()
|
||||
**
|
||||
** This function returns the same value as date('now').
|
||||
*/
|
||||
static void cdateFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_value *pVal = sqlite3ValueNew();
|
||||
if( pVal ){
|
||||
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
|
||||
dateFunc(context, 1, &pVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** current_timestamp()
|
||||
**
|
||||
** This function returns the same value as datetime('now').
|
||||
*/
|
||||
static void ctimestampFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_value *pVal = sqlite3ValueNew();
|
||||
if( pVal ){
|
||||
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
|
||||
datetimeFunc(context, 1, &pVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
|
||||
|
||||
#ifdef SQLITE_OMIT_DATETIME_FUNCS
|
||||
/*
|
||||
** If the library is compiled to omit the full-scale date and time
|
||||
** handling (to get a smaller binary), the following minimal version
|
||||
** of the functions current_time(), current_date() and current_timestamp()
|
||||
** are included instead. This is to support column declarations that
|
||||
** include "DEFAULT CURRENT_TIME" etc.
|
||||
**
|
||||
** This function uses the C-library functions time(), gmtime()
|
||||
** and strftime(). The format string to pass to strftime() is supplied
|
||||
** as the user-data for the function.
|
||||
*/
|
||||
static void currentTimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
time_t t;
|
||||
char *zFormat = (char *)sqlite3_user_data(context);
|
||||
char zBuf[20];
|
||||
|
||||
time(&t);
|
||||
#ifdef SQLITE_TEST
|
||||
{
|
||||
extern int sqlite3_current_time; /* See os_XXX.c */
|
||||
if( sqlite3_current_time ){
|
||||
t = sqlite3_current_time;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3OsEnterMutex();
|
||||
strftime(zBuf, 20, zFormat, gmtime(&t));
|
||||
sqlite3OsLeaveMutex();
|
||||
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
** external linkage.
|
||||
*/
|
||||
void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
static const struct {
|
||||
char *zName;
|
||||
int nArg;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} aFuncs[] = {
|
||||
{ "julianday", -1, juliandayFunc },
|
||||
{ "date", -1, dateFunc },
|
||||
{ "time", -1, timeFunc },
|
||||
{ "datetime", -1, datetimeFunc },
|
||||
{ "strftime", -1, strftimeFunc },
|
||||
{ "current_time", 0, ctimeFunc },
|
||||
{ "current_timestamp", 0, ctimestampFunc },
|
||||
{ "current_date", 0, cdateFunc },
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
|
||||
}
|
||||
#else
|
||||
static const struct {
|
||||
char *zName;
|
||||
char *zFormat;
|
||||
} aFuncs[] = {
|
||||
{ "current_time", "%H:%M:%S" },
|
||||
{ "current_date", "%Y-%m-%d" },
|
||||
{ "current_timestamp", "%Y-%m-%d %H:%M:%S" }
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, 0, SQLITE_UTF8,
|
||||
aFuncs[i].zFormat, currentTimeFunc, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.120 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
** $Id: delete.c,v 1.121 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -343,7 +343,7 @@ void sqlite3DeleteFrom(
|
|||
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
|
||||
}
|
||||
|
||||
delete_from_cleanup:
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are not a part of the official
|
||||
** SQLite API. These routines are unsupported.
|
||||
**
|
||||
** $Id: experimental.c,v 1.2 2006-02-08 21:10:10 vladimir%pobox.com Exp $
|
||||
** $Id: experimental.c,v 1.4 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.253 2006/01/30 14:36:59 drh Exp $
|
||||
** $Id: expr.c,v 1.254 2006/02/10 07:07:15 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -495,6 +495,7 @@ SrcList *sqlite3SrcListDup(SrcList *p){
|
|||
pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
|
||||
pNewItem->jointype = pOldItem->jointype;
|
||||
pNewItem->iCursor = pOldItem->iCursor;
|
||||
pNewItem->isPopulated = pOldItem->isPopulated;
|
||||
pTab = pNewItem->pTab = pOldItem->pTab;
|
||||
if( pTab ){
|
||||
pTab->nRef++;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.117 2006/01/17 13:21:40 danielk1977 Exp $
|
||||
** $Id: func.c,v 1.122 2006/02/11 17:34:00 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -817,9 +817,11 @@ static void test_error(
|
|||
*/
|
||||
typedef struct SumCtx SumCtx;
|
||||
struct SumCtx {
|
||||
double sum; /* Sum of terms */
|
||||
int cnt; /* Number of elements summed */
|
||||
u8 seenFloat; /* True if there has been any floating point value */
|
||||
double rSum; /* Floating point sum */
|
||||
i64 iSum; /* Integer sum */
|
||||
i64 cnt; /* Number of elements summed */
|
||||
u8 overflow; /* True if integer overflow seen */
|
||||
u8 approx; /* True if non-integer value was input to the sum */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -830,18 +832,38 @@ struct SumCtx {
|
|||
** 0.0 in that case. In addition, TOTAL always returns a float where
|
||||
** SUM might return an integer if it never encounters a floating point
|
||||
** value.
|
||||
**
|
||||
** I am told that SUM() should raise an exception if it encounters
|
||||
** a integer overflow. But after pondering this, I decided that
|
||||
** behavior leads to brittle programs. So instead, I have coded
|
||||
** SUM() to revert to using floating point if it encounters an
|
||||
** integer overflow. The answer may not be exact, but it will be
|
||||
** close. If the SUM() function returns an integer, the value is
|
||||
** exact. If SUM() returns a floating point value, it means the
|
||||
** value might be approximated.
|
||||
*/
|
||||
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
SumCtx *p;
|
||||
int type;
|
||||
assert( argc==1 );
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
type = sqlite3_value_type(argv[0]);
|
||||
type = sqlite3_value_numeric_type(argv[0]);
|
||||
if( p && type!=SQLITE_NULL ){
|
||||
p->sum += sqlite3_value_double(argv[0]);
|
||||
p->cnt++;
|
||||
if( type==SQLITE_FLOAT ){
|
||||
p->seenFloat = 1;
|
||||
if( type==SQLITE_INTEGER ){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum += v;
|
||||
if( (p->approx|p->overflow)==0 ){
|
||||
i64 iNewSum = p->iSum + v;
|
||||
int s1 = p->iSum >> (sizeof(i64)*8-1);
|
||||
int s2 = v >> (sizeof(i64)*8-1);
|
||||
int s3 = iNewSum >> (sizeof(i64)*8-1);
|
||||
p->overflow = (s1&s2&~s3) | (~s1&~s2&s3);
|
||||
p->iSum = iNewSum;
|
||||
}
|
||||
}else{
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
p->approx = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -849,10 +871,12 @@ static void sumFinalize(sqlite3_context *context){
|
|||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
if( p && p->cnt>0 ){
|
||||
if( p->seenFloat ){
|
||||
sqlite3_result_double(context, p->sum);
|
||||
if( p->overflow ){
|
||||
sqlite3_result_error(context,"integer overflow",-1);
|
||||
}else if( p->approx ){
|
||||
sqlite3_result_double(context, p->rSum);
|
||||
}else{
|
||||
sqlite3_result_int64(context, (i64)p->sum);
|
||||
sqlite3_result_int64(context, p->iSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -860,33 +884,22 @@ static void avgFinalize(sqlite3_context *context){
|
|||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
if( p && p->cnt>0 ){
|
||||
sqlite3_result_double(context, p->sum/(double)p->cnt);
|
||||
sqlite3_result_double(context, p->rSum/(double)p->cnt);
|
||||
}
|
||||
}
|
||||
static void totalFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
sqlite3_result_double(context, p ? p->sum : 0.0);
|
||||
sqlite3_result_double(context, p ? p->rSum : 0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds the context of a
|
||||
** variance or standard deviation computation.
|
||||
*/
|
||||
typedef struct StdDevCtx StdDevCtx;
|
||||
struct StdDevCtx {
|
||||
double sum; /* Sum of terms */
|
||||
double sum2; /* Sum of the squares of terms */
|
||||
int cnt; /* Number of terms counted */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following structure keeps track of state information for the
|
||||
** count() aggregate function.
|
||||
*/
|
||||
typedef struct CountCtx CountCtx;
|
||||
struct CountCtx {
|
||||
int n;
|
||||
i64 n;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -902,7 +915,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||
static void countFinalize(sqlite3_context *context){
|
||||
CountCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
sqlite3_result_int(context, p ? p->n : 0);
|
||||
sqlite3_result_int64(context, p ? p->n : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,392 +0,0 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** 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 is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.c,v 1.17 2005/10/03 15:11:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "pNew" is a pointer to the hash table that is to be initialized.
|
||||
** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER,
|
||||
** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass
|
||||
** determines what kind of key the hash table will use. "copyKey" is
|
||||
** true if the hash table should make its own private copy of keys and
|
||||
** false if it should just use the supplied pointer. CopyKey only makes
|
||||
** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
|
||||
** for other key classes.
|
||||
*/
|
||||
void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){
|
||||
assert( pNew!=0 );
|
||||
assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY );
|
||||
pNew->keyClass = keyClass;
|
||||
#if 0
|
||||
if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0;
|
||||
#endif
|
||||
pNew->copyKey = copyKey;
|
||||
pNew->first = 0;
|
||||
pNew->count = 0;
|
||||
pNew->htsize = 0;
|
||||
pNew->ht = 0;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
void sqlite3HashClear(Hash *pH){
|
||||
HashElem *elem; /* For looping over all elements of the table */
|
||||
|
||||
assert( pH!=0 );
|
||||
elem = pH->first;
|
||||
pH->first = 0;
|
||||
if( pH->ht ) sqliteFree(pH->ht);
|
||||
pH->ht = 0;
|
||||
pH->htsize = 0;
|
||||
while( elem ){
|
||||
HashElem *next_elem = elem->next;
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
sqliteFree(elem->pKey);
|
||||
}
|
||||
sqliteFree(elem);
|
||||
elem = next_elem;
|
||||
}
|
||||
pH->count = 0;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_INT
|
||||
*/
|
||||
static int intHash(const void *pKey, int nKey){
|
||||
return nKey ^ (nKey<<8) ^ (nKey>>8);
|
||||
}
|
||||
static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
return n2 - n1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
|
||||
*/
|
||||
static int ptrHash(const void *pKey, int nKey){
|
||||
uptr x = Addr(pKey);
|
||||
return x ^ (x<<8) ^ (x>>8);
|
||||
}
|
||||
static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( pKey1==pKey2 ) return 0;
|
||||
if( pKey1<pKey2 ) return -1;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_STRING
|
||||
*/
|
||||
static int strHash(const void *pKey, int nKey){
|
||||
const char *z = (const char *)pKey;
|
||||
int h = 0;
|
||||
if( nKey<=0 ) nKey = strlen(z);
|
||||
while( nKey > 0 ){
|
||||
h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
|
||||
nKey--;
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
|
||||
*/
|
||||
static int binHash(const void *pKey, int nKey){
|
||||
int h = 0;
|
||||
const char *z = (const char *)pKey;
|
||||
while( nKey-- > 0 ){
|
||||
h = (h<<3) ^ h ^ *(z++);
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
return memcmp(pKey1,pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the appropriate hash function given the key class.
|
||||
**
|
||||
** The C syntax in this function definition may be unfamilar to some
|
||||
** programmers, so we provide the following additional explanation:
|
||||
**
|
||||
** The name of the function is "hashFunction". The function takes a
|
||||
** single parameter "keyClass". The return value of hashFunction()
|
||||
** is a pointer to another function. Specifically, the return value
|
||||
** of hashFunction() is a pointer to a function that takes two parameters
|
||||
** with types "const void*" and "int" and returns an "int".
|
||||
*/
|
||||
static int (*hashFunction(int keyClass))(const void*,int){
|
||||
#if 0 /* HASH_INT and HASH_POINTER are never used */
|
||||
switch( keyClass ){
|
||||
case SQLITE_HASH_INT: return &intHash;
|
||||
case SQLITE_HASH_POINTER: return &ptrHash;
|
||||
case SQLITE_HASH_STRING: return &strHash;
|
||||
case SQLITE_HASH_BINARY: return &binHash;;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
if( keyClass==SQLITE_HASH_STRING ){
|
||||
return &strHash;
|
||||
}else{
|
||||
assert( keyClass==SQLITE_HASH_BINARY );
|
||||
return &binHash;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the appropriate hash function given the key class.
|
||||
**
|
||||
** For help in interpreted the obscure C code in the function definition,
|
||||
** see the header comment on the previous function.
|
||||
*/
|
||||
static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
|
||||
#if 0 /* HASH_INT and HASH_POINTER are never used */
|
||||
switch( keyClass ){
|
||||
case SQLITE_HASH_INT: return &intCompare;
|
||||
case SQLITE_HASH_POINTER: return &ptrCompare;
|
||||
case SQLITE_HASH_STRING: return &strCompare;
|
||||
case SQLITE_HASH_BINARY: return &binCompare;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
if( keyClass==SQLITE_HASH_STRING ){
|
||||
return &strCompare;
|
||||
}else{
|
||||
assert( keyClass==SQLITE_HASH_BINARY );
|
||||
return &binCompare;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Link an element into the hash table
|
||||
*/
|
||||
static void insertElement(
|
||||
Hash *pH, /* The complete hash table */
|
||||
struct _ht *pEntry, /* The entry into which pNew is inserted */
|
||||
HashElem *pNew /* The element to be inserted */
|
||||
){
|
||||
HashElem *pHead; /* First element already in pEntry */
|
||||
pHead = pEntry->chain;
|
||||
if( pHead ){
|
||||
pNew->next = pHead;
|
||||
pNew->prev = pHead->prev;
|
||||
if( pHead->prev ){ pHead->prev->next = pNew; }
|
||||
else { pH->first = pNew; }
|
||||
pHead->prev = pNew;
|
||||
}else{
|
||||
pNew->next = pH->first;
|
||||
if( pH->first ){ pH->first->prev = pNew; }
|
||||
pNew->prev = 0;
|
||||
pH->first = pNew;
|
||||
}
|
||||
pEntry->count++;
|
||||
pEntry->chain = pNew;
|
||||
}
|
||||
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
** "new_size" must be a power of 2. The hash table might fail
|
||||
** to resize if sqliteMalloc() fails.
|
||||
*/
|
||||
static void rehash(Hash *pH, int new_size){
|
||||
struct _ht *new_ht; /* The new hash table */
|
||||
HashElem *elem, *next_elem; /* For looping over existing elements */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( (new_size & (new_size-1))==0 );
|
||||
new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
|
||||
if( new_ht==0 ) return;
|
||||
if( pH->ht ) sqliteFree(pH->ht);
|
||||
pH->ht = new_ht;
|
||||
pH->htsize = new_size;
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
|
||||
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
|
||||
next_elem = elem->next;
|
||||
insertElement(pH, &new_ht[h], elem);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
static HashElem *findElementGivenHash(
|
||||
const Hash *pH, /* The pH to be searched */
|
||||
const void *pKey, /* The key we are searching for */
|
||||
int nKey,
|
||||
int h /* The hash for this key. */
|
||||
){
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
|
||||
|
||||
if( pH->ht ){
|
||||
struct _ht *pEntry = &pH->ht[h];
|
||||
elem = pEntry->chain;
|
||||
count = pEntry->count;
|
||||
xCompare = compareFunction(pH->keyClass);
|
||||
while( count-- && elem ){
|
||||
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
||||
return elem;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
static void removeElementGivenHash(
|
||||
Hash *pH, /* The pH containing "elem" */
|
||||
HashElem* elem, /* The element to be removed from the pH */
|
||||
int h /* Hash value for the element */
|
||||
){
|
||||
struct _ht *pEntry;
|
||||
if( elem->prev ){
|
||||
elem->prev->next = elem->next;
|
||||
}else{
|
||||
pH->first = elem->next;
|
||||
}
|
||||
if( elem->next ){
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
pEntry = &pH->ht[h];
|
||||
if( pEntry->chain==elem ){
|
||||
pEntry->chain = elem->next;
|
||||
}
|
||||
pEntry->count--;
|
||||
if( pEntry->count<=0 ){
|
||||
pEntry->chain = 0;
|
||||
}
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
sqliteFree(elem->pKey);
|
||||
}
|
||||
sqliteFree( elem );
|
||||
pH->count--;
|
||||
if( pH->count<=0 ){
|
||||
assert( pH->first==0 );
|
||||
assert( pH->count==0 );
|
||||
sqlite3HashClear(pH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
** that matches pKey,nKey. Return the data for this element if it is
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
|
||||
int h; /* A hash on key */
|
||||
HashElem *elem; /* The element that matches key */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
if( pH==0 || pH->ht==0 ) return 0;
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
h = (*xHash)(pKey,nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
|
||||
return elem ? elem->data : 0;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
** and the data is "data".
|
||||
**
|
||||
** If no element exists with a matching key, then a new
|
||||
** element is created. A copy of the key is made if the copyKey
|
||||
** flag is set. NULL is returned.
|
||||
**
|
||||
** If another element already exists with the same key, then the
|
||||
** new data replaces the old data and the old data is returned.
|
||||
** The key is not copied in this instance. If a malloc fails, then
|
||||
** the new data is returned and the hash table is unchanged.
|
||||
**
|
||||
** If the "data" parameter to this function is NULL, then the
|
||||
** element corresponding to "key" is removed from the hash table.
|
||||
*/
|
||||
void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
|
||||
int hraw; /* Raw hash value of the key */
|
||||
int h; /* the hash of the key modulo hash table size */
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
HashElem *new_elem; /* New element added to the pH */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( pH!=0 );
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
hraw = (*xHash)(pKey, nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
elem = findElementGivenHash(pH,pKey,nKey,h);
|
||||
if( elem ){
|
||||
void *old_data = elem->data;
|
||||
if( data==0 ){
|
||||
removeElementGivenHash(pH,elem,h);
|
||||
}else{
|
||||
elem->data = data;
|
||||
}
|
||||
return old_data;
|
||||
}
|
||||
if( data==0 ) return 0;
|
||||
new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
|
||||
if( new_elem==0 ) return data;
|
||||
if( pH->copyKey && pKey!=0 ){
|
||||
new_elem->pKey = sqliteMallocRaw( nKey );
|
||||
if( new_elem->pKey==0 ){
|
||||
sqliteFree(new_elem);
|
||||
return data;
|
||||
}
|
||||
memcpy((void*)new_elem->pKey, pKey, nKey);
|
||||
}else{
|
||||
new_elem->pKey = (void*)pKey;
|
||||
}
|
||||
new_elem->nKey = nKey;
|
||||
pH->count++;
|
||||
if( pH->htsize==0 ){
|
||||
rehash(pH,8);
|
||||
if( pH->htsize==0 ){
|
||||
pH->count = 0;
|
||||
sqliteFree(new_elem);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
if( pH->count > pH->htsize ){
|
||||
rehash(pH,pH->htsize*2);
|
||||
}
|
||||
assert( pH->htsize>0 );
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
insertElement(pH, &pH->ht[h], new_elem);
|
||||
new_elem->data = data;
|
||||
return 0;
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** 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 is the header file for the generic hash-table implemenation
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.h,v 1.8 2004/08/20 14:08:51 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_HASH_H_
|
||||
#define _SQLITE_HASH_H_
|
||||
|
||||
/* Forward declarations of structures. */
|
||||
typedef struct Hash Hash;
|
||||
typedef struct HashElem HashElem;
|
||||
|
||||
/* A complete hash table is an instance of the following structure.
|
||||
** The internals of this structure are intended to be opaque -- client
|
||||
** code should not attempt to access or modify the fields of this structure
|
||||
** directly. Change this structure only by using the routines below.
|
||||
** However, many of the "procedures" and "functions" for modifying and
|
||||
** accessing this structure are really macros, so we can't really make
|
||||
** this structure opaque.
|
||||
*/
|
||||
struct Hash {
|
||||
char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
|
||||
char copyKey; /* True if copy of key made on insert */
|
||||
int count; /* Number of entries in this table */
|
||||
HashElem *first; /* The first element of the array */
|
||||
int htsize; /* Number of buckets in the hash table */
|
||||
struct _ht { /* the hash table */
|
||||
int count; /* Number of entries with this hash */
|
||||
HashElem *chain; /* Pointer to first entry with this hash */
|
||||
} *ht;
|
||||
};
|
||||
|
||||
/* Each element in the hash table is an instance of the following
|
||||
** structure. All elements are stored on a single doubly-linked list.
|
||||
**
|
||||
** Again, this structure is intended to be opaque, but it can't really
|
||||
** be opaque because it is used by macros.
|
||||
*/
|
||||
struct HashElem {
|
||||
HashElem *next, *prev; /* Next and previous elements in the table */
|
||||
void *data; /* Data associated with this element */
|
||||
void *pKey; int nKey; /* Key associated with this element */
|
||||
};
|
||||
|
||||
/*
|
||||
** There are 4 different modes of operation for a hash table:
|
||||
**
|
||||
** SQLITE_HASH_INT nKey is used as the key and pKey is ignored.
|
||||
**
|
||||
** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored.
|
||||
**
|
||||
** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long
|
||||
** (including the null-terminator, if any). Case
|
||||
** is ignored in comparisons.
|
||||
**
|
||||
** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long.
|
||||
** memcmp() is used to compare keys.
|
||||
**
|
||||
** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY
|
||||
** if the copyKey parameter to HashInit is 1.
|
||||
*/
|
||||
/* #define SQLITE_HASH_INT 1 // NOT USED */
|
||||
/* #define SQLITE_HASH_POINTER 2 // NOT USED */
|
||||
#define SQLITE_HASH_STRING 3
|
||||
#define SQLITE_HASH_BINARY 4
|
||||
|
||||
/*
|
||||
** Access routines. To delete, insert a NULL pointer.
|
||||
*/
|
||||
void sqlite3HashInit(Hash*, int keytype, int copyKey);
|
||||
void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
|
||||
void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
|
||||
void sqlite3HashClear(Hash*);
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
** like this:
|
||||
**
|
||||
** Hash h;
|
||||
** HashElem *p;
|
||||
** ...
|
||||
** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
|
||||
** SomeStructure *pData = sqliteHashData(p);
|
||||
** // do something with pData
|
||||
** }
|
||||
*/
|
||||
#define sqliteHashFirst(H) ((H)->first)
|
||||
#define sqliteHashNext(E) ((E)->next)
|
||||
#define sqliteHashData(E) ((E)->data)
|
||||
#define sqliteHashKey(E) ((E)->pKey)
|
||||
#define sqliteHashKeysize(E) ((E)->nKey)
|
||||
|
||||
/*
|
||||
** Number of entries in a hash table
|
||||
*/
|
||||
#define sqliteHashCount(H) ((H)->count)
|
||||
|
||||
#endif /* _SQLITE_HASH_H_ */
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.160 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
** $Id: insert.c,v 1.161 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -703,7 +703,7 @@ void sqlite3Insert(
|
|||
sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC);
|
||||
}
|
||||
|
||||
insert_cleanup:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.331 2006/01/24 16:37:58 danielk1977 Exp $
|
||||
** $Id: main.c,v 1.335 2006/02/16 18:16:37 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -29,7 +29,6 @@ const int sqlite3one = 1;
|
|||
/*
|
||||
** The version of the library
|
||||
*/
|
||||
const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
|
||||
const char sqlite3_version[] = SQLITE_VERSION;
|
||||
const char *sqlite3_libversion(void){ return sqlite3_version; }
|
||||
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
|
||||
|
@ -732,6 +731,10 @@ int sqlite3_errcode(sqlite3 *db){
|
|||
return db->errCode;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new collating function for database "db". The name is zName
|
||||
** and the encoding is enc.
|
||||
*/
|
||||
static int createCollation(
|
||||
sqlite3* db,
|
||||
const char *zName,
|
||||
|
@ -740,6 +743,7 @@ static int createCollation(
|
|||
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||
){
|
||||
CollSeq *pColl;
|
||||
int enc2;
|
||||
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
|
@ -749,15 +753,13 @@ static int createCollation(
|
|||
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
|
||||
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
|
||||
*/
|
||||
if( enc==SQLITE_UTF16 ){
|
||||
enc = SQLITE_UTF16NATIVE;
|
||||
enc2 = enc & ~SQLITE_UTF16_ALIGNED;
|
||||
if( enc2==SQLITE_UTF16 ){
|
||||
enc2 = SQLITE_UTF16NATIVE;
|
||||
}
|
||||
|
||||
if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
|
||||
sqlite3Error(db, SQLITE_ERROR,
|
||||
"Param 3 to sqlite3_create_collation() must be one of "
|
||||
"SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
|
||||
);
|
||||
if( (enc2&~3)!=0 ){
|
||||
sqlite3Error(db, SQLITE_ERROR, "unknown encoding");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -765,7 +767,7 @@ static int createCollation(
|
|||
** sequence. If so, and there are active VMs, return busy. If there
|
||||
** are no active VMs, invalidate any pre-compiled statements.
|
||||
*/
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 0);
|
||||
if( pColl && pColl->xCmp ){
|
||||
if( db->activeVdbeCnt ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
|
@ -775,11 +777,11 @@ static int createCollation(
|
|||
sqlite3ExpirePreparedStatements(db);
|
||||
}
|
||||
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 1);
|
||||
if( pColl ){
|
||||
pColl->xCmp = xCompare;
|
||||
pColl->pUser = pCtx;
|
||||
pColl->enc = enc;
|
||||
pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
|
||||
}
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
return SQLITE_OK;
|
||||
|
@ -817,8 +819,9 @@ static int openDatabase(
|
|||
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||
** conversions. The only error that can occur here is a malloc() failure.
|
||||
*/
|
||||
if( createCollation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
|
||||
createCollation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
|
||||
if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
|
||||
createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
|
||||
createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
|
||||
(db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
|
||||
){
|
||||
assert( sqlite3MallocFailed() );
|
||||
|
@ -1113,3 +1116,116 @@ void sqlite3_thread_cleanup(void){
|
|||
sqlite3OsThreadSpecificData(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return meta information about a specific column of a database table.
|
||||
** See comment in sqlite3.h (sqlite.h.in) for details.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
int sqlite3_table_column_metadata(
|
||||
sqlite3 *db, /* Connection handle */
|
||||
const char *zDbName, /* Database name or NULL */
|
||||
const char *zTableName, /* Table name */
|
||||
const char *zColumnName, /* Column name */
|
||||
char const **pzDataType, /* OUTPUT: Declared data type */
|
||||
char const **pzCollSeq, /* OUTPUT: Collation sequence name */
|
||||
int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
|
||||
int *pPrimaryKey, /* OUTPUT: True if column part of PK */
|
||||
int *pAutoinc /* OUTPUT: True if colums is auto-increment */
|
||||
){
|
||||
int rc;
|
||||
char *zErrMsg = 0;
|
||||
Table *pTab = 0;
|
||||
Column *pCol = 0;
|
||||
int iCol;
|
||||
|
||||
char const *zDataType = 0;
|
||||
char const *zCollSeq = 0;
|
||||
int notnull = 0;
|
||||
int primarykey = 0;
|
||||
int autoinc = 0;
|
||||
|
||||
/* Ensure the database schema has been loaded */
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
rc = sqlite3Init(db, &zErrMsg);
|
||||
if( SQLITE_OK!=rc ){
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Locate the table in question */
|
||||
pTab = sqlite3FindTable(db, zTableName, zDbName);
|
||||
if( !pTab || pTab->pSelect ){
|
||||
pTab = 0;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Find the column for which info is requested */
|
||||
if( sqlite3IsRowid(zColumnName) ){
|
||||
iCol = pTab->iPKey;
|
||||
if( iCol>=0 ){
|
||||
pCol = &pTab->aCol[iCol];
|
||||
}
|
||||
}else{
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
pCol = &pTab->aCol[iCol];
|
||||
if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iCol==pTab->nCol ){
|
||||
pTab = 0;
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* The following block stores the meta information that will be returned
|
||||
** to the caller in local variables zDataType, zCollSeq, notnull, primarykey
|
||||
** and autoinc. At this point there are two possibilities:
|
||||
**
|
||||
** 1. The specified column name was rowid", "oid" or "_rowid_"
|
||||
** and there is no explicitly declared IPK column.
|
||||
**
|
||||
** 2. The table is not a view and the column name identified an
|
||||
** explicitly declared column. Copy meta information from *pCol.
|
||||
*/
|
||||
if( pCol ){
|
||||
zDataType = pCol->zType;
|
||||
zCollSeq = pCol->zColl;
|
||||
notnull = (pCol->notNull?1:0);
|
||||
primarykey = (pCol->isPrimKey?1:0);
|
||||
autoinc = ((pTab->iPKey==iCol && pTab->autoInc)?1:0);
|
||||
}else{
|
||||
zDataType = "INTEGER";
|
||||
primarykey = 1;
|
||||
}
|
||||
if( !zCollSeq ){
|
||||
zCollSeq = "BINARY";
|
||||
}
|
||||
|
||||
error_out:
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/* Whether the function call succeeded or failed, set the output parameters
|
||||
** to whatever their local counterparts contain. If an error did occur,
|
||||
** this has the effect of zeroing all output parameters.
|
||||
*/
|
||||
if( pzDataType ) *pzDataType = zDataType;
|
||||
if( pzCollSeq ) *pzCollSeq = zCollSeq;
|
||||
if( pNotNull ) *pNotNull = notnull;
|
||||
if( pPrimaryKey ) *pPrimaryKey = primarykey;
|
||||
if( pAutoinc ) *pAutoinc = autoinc;
|
||||
|
||||
if( SQLITE_OK==rc && !pTab ){
|
||||
sqlite3SetString(&zErrMsg, "no such table column: ", zTableName, ".",
|
||||
zColumnName, 0);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
|
||||
sqliteFree(zErrMsg);
|
||||
return sqlite3ApiExit(db, rc);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodec.awk script for details. */
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
const char *const sqlite3OpcodeNames[] = { "?",
|
||||
/* 1 */ "MemLoad",
|
||||
/* 2 */ "Column",
|
||||
/* 3 */ "SetCookie",
|
||||
/* 4 */ "IfMemPos",
|
||||
/* 5 */ "Sequence",
|
||||
/* 6 */ "MoveGt",
|
||||
/* 7 */ "RowKey",
|
||||
/* 8 */ "OpenWrite",
|
||||
/* 9 */ "If",
|
||||
/* 10 */ "Pop",
|
||||
/* 11 */ "CollSeq",
|
||||
/* 12 */ "OpenRead",
|
||||
/* 13 */ "Expire",
|
||||
/* 14 */ "AutoCommit",
|
||||
/* 15 */ "IntegrityCk",
|
||||
/* 16 */ "Not",
|
||||
/* 17 */ "Sort",
|
||||
/* 18 */ "Function",
|
||||
/* 19 */ "Noop",
|
||||
/* 20 */ "Return",
|
||||
/* 21 */ "NewRowid",
|
||||
/* 22 */ "IfMemNeg",
|
||||
/* 23 */ "Variable",
|
||||
/* 24 */ "String",
|
||||
/* 25 */ "RealAffinity",
|
||||
/* 26 */ "ParseSchema",
|
||||
/* 27 */ "Close",
|
||||
/* 28 */ "CreateIndex",
|
||||
/* 29 */ "IsUnique",
|
||||
/* 30 */ "IdxIsNull",
|
||||
/* 31 */ "NotFound",
|
||||
/* 32 */ "Int64",
|
||||
/* 33 */ "MustBeInt",
|
||||
/* 34 */ "Halt",
|
||||
/* 35 */ "Rowid",
|
||||
/* 36 */ "IdxLT",
|
||||
/* 37 */ "AddImm",
|
||||
/* 38 */ "Statement",
|
||||
/* 39 */ "RowData",
|
||||
/* 40 */ "MemMax",
|
||||
/* 41 */ "Push",
|
||||
/* 42 */ "NotExists",
|
||||
/* 43 */ "MemIncr",
|
||||
/* 44 */ "Gosub",
|
||||
/* 45 */ "Integer",
|
||||
/* 46 */ "MemInt",
|
||||
/* 47 */ "Prev",
|
||||
/* 48 */ "CreateTable",
|
||||
/* 49 */ "Last",
|
||||
/* 50 */ "IdxRowid",
|
||||
/* 51 */ "MakeIdxRec",
|
||||
/* 52 */ "ResetCount",
|
||||
/* 53 */ "FifoWrite",
|
||||
/* 54 */ "Callback",
|
||||
/* 55 */ "ContextPush",
|
||||
/* 56 */ "DropTrigger",
|
||||
/* 57 */ "DropIndex",
|
||||
/* 58 */ "IdxGE",
|
||||
/* 59 */ "Or",
|
||||
/* 60 */ "And",
|
||||
/* 61 */ "IdxDelete",
|
||||
/* 62 */ "Vacuum",
|
||||
/* 63 */ "MoveLe",
|
||||
/* 64 */ "IsNull",
|
||||
/* 65 */ "NotNull",
|
||||
/* 66 */ "Ne",
|
||||
/* 67 */ "Eq",
|
||||
/* 68 */ "Gt",
|
||||
/* 69 */ "Le",
|
||||
/* 70 */ "Lt",
|
||||
/* 71 */ "Ge",
|
||||
/* 72 */ "IfNot",
|
||||
/* 73 */ "BitAnd",
|
||||
/* 74 */ "BitOr",
|
||||
/* 75 */ "ShiftLeft",
|
||||
/* 76 */ "ShiftRight",
|
||||
/* 77 */ "Add",
|
||||
/* 78 */ "Subtract",
|
||||
/* 79 */ "Multiply",
|
||||
/* 80 */ "Divide",
|
||||
/* 81 */ "Remainder",
|
||||
/* 82 */ "Concat",
|
||||
/* 83 */ "Negative",
|
||||
/* 84 */ "DropTable",
|
||||
/* 85 */ "BitNot",
|
||||
/* 86 */ "String8",
|
||||
/* 87 */ "MakeRecord",
|
||||
/* 88 */ "Delete",
|
||||
/* 89 */ "AggFinal",
|
||||
/* 90 */ "Dup",
|
||||
/* 91 */ "Goto",
|
||||
/* 92 */ "TableLock",
|
||||
/* 93 */ "FifoRead",
|
||||
/* 94 */ "Clear",
|
||||
/* 95 */ "IdxGT",
|
||||
/* 96 */ "MoveLt",
|
||||
/* 97 */ "VerifyCookie",
|
||||
/* 98 */ "AggStep",
|
||||
/* 99 */ "Pull",
|
||||
/* 100 */ "SetNumColumns",
|
||||
/* 101 */ "AbsValue",
|
||||
/* 102 */ "Transaction",
|
||||
/* 103 */ "ContextPop",
|
||||
/* 104 */ "Next",
|
||||
/* 105 */ "IdxInsert",
|
||||
/* 106 */ "Distinct",
|
||||
/* 107 */ "Insert",
|
||||
/* 108 */ "Destroy",
|
||||
/* 109 */ "ReadCookie",
|
||||
/* 110 */ "ForceInt",
|
||||
/* 111 */ "LoadAnalysis",
|
||||
/* 112 */ "OpenVirtual",
|
||||
/* 113 */ "Explain",
|
||||
/* 114 */ "IfMemZero",
|
||||
/* 115 */ "OpenPseudo",
|
||||
/* 116 */ "Null",
|
||||
/* 117 */ "Blob",
|
||||
/* 118 */ "MemStore",
|
||||
/* 119 */ "Rewind",
|
||||
/* 120 */ "MoveGe",
|
||||
/* 121 */ "MemMove",
|
||||
/* 122 */ "MemNull",
|
||||
/* 123 */ "Found",
|
||||
/* 124 */ "Real",
|
||||
/* 125 */ "HexBlob",
|
||||
/* 126 */ "NullRow",
|
||||
/* 127 */ "NotUsed_127",
|
||||
/* 128 */ "NotUsed_128",
|
||||
/* 129 */ "NotUsed_129",
|
||||
/* 130 */ "NotUsed_130",
|
||||
/* 131 */ "NotUsed_131",
|
||||
/* 132 */ "NotUsed_132",
|
||||
/* 133 */ "NotUsed_133",
|
||||
/* 134 */ "NotUsed_134",
|
||||
/* 135 */ "NotUsed_135",
|
||||
/* 136 */ "NotUsed_136",
|
||||
/* 137 */ "ToText",
|
||||
/* 138 */ "ToBlob",
|
||||
/* 139 */ "ToNumeric",
|
||||
/* 140 */ "ToInt",
|
||||
/* 141 */ "ToReal",
|
||||
};
|
||||
#endif
|
|
@ -1,159 +0,0 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
#define OP_MemLoad 1
|
||||
#define OP_HexBlob 125 /* same as TK_BLOB */
|
||||
#define OP_Column 2
|
||||
#define OP_SetCookie 3
|
||||
#define OP_IfMemPos 4
|
||||
#define OP_Real 124 /* same as TK_FLOAT */
|
||||
#define OP_Sequence 5
|
||||
#define OP_MoveGt 6
|
||||
#define OP_Ge 71 /* same as TK_GE */
|
||||
#define OP_RowKey 7
|
||||
#define OP_Eq 67 /* same as TK_EQ */
|
||||
#define OP_OpenWrite 8
|
||||
#define OP_NotNull 65 /* same as TK_NOTNULL */
|
||||
#define OP_If 9
|
||||
#define OP_ToInt 140 /* same as TK_TO_INT */
|
||||
#define OP_String8 86 /* same as TK_STRING */
|
||||
#define OP_Pop 10
|
||||
#define OP_CollSeq 11
|
||||
#define OP_OpenRead 12
|
||||
#define OP_Expire 13
|
||||
#define OP_AutoCommit 14
|
||||
#define OP_Gt 68 /* same as TK_GT */
|
||||
#define OP_IntegrityCk 15
|
||||
#define OP_Sort 17
|
||||
#define OP_Function 18
|
||||
#define OP_And 60 /* same as TK_AND */
|
||||
#define OP_Subtract 78 /* same as TK_MINUS */
|
||||
#define OP_Noop 19
|
||||
#define OP_Return 20
|
||||
#define OP_Remainder 81 /* same as TK_REM */
|
||||
#define OP_NewRowid 21
|
||||
#define OP_Multiply 79 /* same as TK_STAR */
|
||||
#define OP_IfMemNeg 22
|
||||
#define OP_Variable 23
|
||||
#define OP_String 24
|
||||
#define OP_RealAffinity 25
|
||||
#define OP_ParseSchema 26
|
||||
#define OP_Close 27
|
||||
#define OP_CreateIndex 28
|
||||
#define OP_IsUnique 29
|
||||
#define OP_IdxIsNull 30
|
||||
#define OP_NotFound 31
|
||||
#define OP_Int64 32
|
||||
#define OP_MustBeInt 33
|
||||
#define OP_Halt 34
|
||||
#define OP_Rowid 35
|
||||
#define OP_IdxLT 36
|
||||
#define OP_AddImm 37
|
||||
#define OP_Statement 38
|
||||
#define OP_RowData 39
|
||||
#define OP_MemMax 40
|
||||
#define OP_Push 41
|
||||
#define OP_Or 59 /* same as TK_OR */
|
||||
#define OP_NotExists 42
|
||||
#define OP_MemIncr 43
|
||||
#define OP_Gosub 44
|
||||
#define OP_Divide 80 /* same as TK_SLASH */
|
||||
#define OP_Integer 45
|
||||
#define OP_ToNumeric 139 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_MemInt 46
|
||||
#define OP_Prev 47
|
||||
#define OP_Concat 82 /* same as TK_CONCAT */
|
||||
#define OP_BitAnd 73 /* same as TK_BITAND */
|
||||
#define OP_CreateTable 48
|
||||
#define OP_Last 49
|
||||
#define OP_IsNull 64 /* same as TK_ISNULL */
|
||||
#define OP_IdxRowid 50
|
||||
#define OP_MakeIdxRec 51
|
||||
#define OP_ShiftRight 76 /* same as TK_RSHIFT */
|
||||
#define OP_ResetCount 52
|
||||
#define OP_FifoWrite 53
|
||||
#define OP_Callback 54
|
||||
#define OP_ContextPush 55
|
||||
#define OP_DropTrigger 56
|
||||
#define OP_DropIndex 57
|
||||
#define OP_IdxGE 58
|
||||
#define OP_IdxDelete 61
|
||||
#define OP_Vacuum 62
|
||||
#define OP_MoveLe 63
|
||||
#define OP_IfNot 72
|
||||
#define OP_DropTable 84
|
||||
#define OP_MakeRecord 87
|
||||
#define OP_ToBlob 138 /* same as TK_TO_BLOB */
|
||||
#define OP_Delete 88
|
||||
#define OP_AggFinal 89
|
||||
#define OP_ShiftLeft 75 /* same as TK_LSHIFT */
|
||||
#define OP_Dup 90
|
||||
#define OP_Goto 91
|
||||
#define OP_TableLock 92
|
||||
#define OP_FifoRead 93
|
||||
#define OP_Clear 94
|
||||
#define OP_IdxGT 95
|
||||
#define OP_MoveLt 96
|
||||
#define OP_Le 69 /* same as TK_LE */
|
||||
#define OP_VerifyCookie 97
|
||||
#define OP_AggStep 98
|
||||
#define OP_Pull 99
|
||||
#define OP_ToText 137 /* same as TK_TO_TEXT */
|
||||
#define OP_Not 16 /* same as TK_NOT */
|
||||
#define OP_ToReal 141 /* same as TK_TO_REAL */
|
||||
#define OP_SetNumColumns 100
|
||||
#define OP_AbsValue 101
|
||||
#define OP_Transaction 102
|
||||
#define OP_Negative 83 /* same as TK_UMINUS */
|
||||
#define OP_Ne 66 /* same as TK_NE */
|
||||
#define OP_ContextPop 103
|
||||
#define OP_BitOr 74 /* same as TK_BITOR */
|
||||
#define OP_Next 104
|
||||
#define OP_IdxInsert 105
|
||||
#define OP_Distinct 106
|
||||
#define OP_Lt 70 /* same as TK_LT */
|
||||
#define OP_Insert 107
|
||||
#define OP_Destroy 108
|
||||
#define OP_ReadCookie 109
|
||||
#define OP_ForceInt 110
|
||||
#define OP_LoadAnalysis 111
|
||||
#define OP_OpenVirtual 112
|
||||
#define OP_Explain 113
|
||||
#define OP_IfMemZero 114
|
||||
#define OP_OpenPseudo 115
|
||||
#define OP_Null 116
|
||||
#define OP_Blob 117
|
||||
#define OP_Add 77 /* same as TK_PLUS */
|
||||
#define OP_MemStore 118
|
||||
#define OP_Rewind 119
|
||||
#define OP_MoveGe 120
|
||||
#define OP_BitNot 85 /* same as TK_BITNOT */
|
||||
#define OP_MemMove 121
|
||||
#define OP_MemNull 122
|
||||
#define OP_Found 123
|
||||
#define OP_NullRow 126
|
||||
|
||||
/* The following opcode values are never used */
|
||||
#define OP_NotUsed_127 127
|
||||
#define OP_NotUsed_128 128
|
||||
#define OP_NotUsed_129 129
|
||||
#define OP_NotUsed_130 130
|
||||
#define OP_NotUsed_131 131
|
||||
#define OP_NotUsed_132 132
|
||||
#define OP_NotUsed_133 133
|
||||
#define OP_NotUsed_134 134
|
||||
#define OP_NotUsed_135 135
|
||||
#define OP_NotUsed_136 136
|
||||
|
||||
/* Opcodes that are guaranteed to never push a value onto the stack
|
||||
** contain a 1 their corresponding position of the following mask
|
||||
** set. See the opcodeNoPush() function in vdbeaux.c */
|
||||
#define NOPUSH_MASK_0 0x7f58
|
||||
#define NOPUSH_MASK_1 0xee5b
|
||||
#define NOPUSH_MASK_2 0x9f76
|
||||
#define NOPUSH_MASK_3 0xfff2
|
||||
#define NOPUSH_MASK_4 0xffff
|
||||
#define NOPUSH_MASK_5 0xdb3b
|
||||
#define NOPUSH_MASK_6 0xcfdf
|
||||
#define NOPUSH_MASK_7 0x49cd
|
||||
#define NOPUSH_MASK_8 0x3e00
|
||||
#define NOPUSH_MASK_9 0x0000
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** 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 contains macros and a little bit of code that is common to
|
||||
** all of the platform-specific files (os_*.c) and is #included into those
|
||||
** files.
|
||||
**
|
||||
** This file should be #included by the os_*.c files only. It is not a
|
||||
** general purpose header file.
|
||||
*/
|
||||
|
||||
/*
|
||||
** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
||||
** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
||||
** switch. The following code should catch this problem at compile-time.
|
||||
*/
|
||||
#ifdef MEMORY_DEBUG
|
||||
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* When testing, this global variable stores the location of the
|
||||
* pending-byte in the database file.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
unsigned int sqlite3_pending_byte = 0x40000000;
|
||||
#endif
|
||||
|
||||
int sqlite3_os_trace = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int last_page = 0;
|
||||
#define SEEK(X) last_page=(X)
|
||||
#define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
|
||||
#define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
|
||||
#define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
|
||||
#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
|
||||
#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
|
||||
#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define TRACE7(X,Y,Z,A,B,C,D) \
|
||||
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
|
||||
#else
|
||||
#define SEEK(X)
|
||||
#define TRACE1(X)
|
||||
#define TRACE2(X,Y)
|
||||
#define TRACE3(X,Y,Z)
|
||||
#define TRACE4(X,Y,Z,A)
|
||||
#define TRACE5(X,Y,Z,A,B)
|
||||
#define TRACE6(X,Y,Z,A,B,C)
|
||||
#define TRACE7(X,Y,Z,A,B,C,D)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros for performance tracing. Normally turned off. Only works
|
||||
** on i486 hardware.
|
||||
*/
|
||||
#ifdef SQLITE_PERFORMANCE_TRACE
|
||||
__inline__ unsigned long long int hwtime(void){
|
||||
unsigned long long int x;
|
||||
__asm__("rdtsc\n\t"
|
||||
"mov %%edx, %%ecx\n\t"
|
||||
:"=A" (x));
|
||||
return x;
|
||||
}
|
||||
static unsigned long long int g_start;
|
||||
static unsigned int elapse;
|
||||
#define TIMER_START g_start=hwtime()
|
||||
#define TIMER_END elapse=hwtime()-g_start
|
||||
#define TIMER_ELAPSED elapse
|
||||
#else
|
||||
#define TIMER_START
|
||||
#define TIMER_END
|
||||
#define TIMER_ELAPSED 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If we compile with the SQLITE_TEST macro set, then the following block
|
||||
** of code will give us the ability to simulate a disk I/O error. This
|
||||
** is used for testing the I/O recovery logic.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_io_error_hit = 0;
|
||||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
int sqlite3_diskfull = 0;
|
||||
#define SimulateIOError(A) \
|
||||
if( sqlite3_io_error_pending ) \
|
||||
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
|
||||
static void local_ioerr(){
|
||||
sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
|
||||
}
|
||||
#define SimulateDiskfullError \
|
||||
if( sqlite3_diskfull_pending ){ \
|
||||
if( sqlite3_diskfull_pending == 1 ){ \
|
||||
local_ioerr(); \
|
||||
sqlite3_diskfull = 1; \
|
||||
return SQLITE_FULL; \
|
||||
}else{ \
|
||||
sqlite3_diskfull_pending--; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define SimulateIOError(A)
|
||||
#define SimulateDiskfullError
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When testing, keep a count of the number of open files.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_open_file_count = 0;
|
||||
#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
||||
#else
|
||||
#define OpenCounter(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** sqlite3GenericMalloc
|
||||
** sqlite3GenericRealloc
|
||||
** sqlite3GenericOsFree
|
||||
** sqlite3GenericAllocationSize
|
||||
**
|
||||
** Implementation of the os level dynamic memory allocation interface in terms
|
||||
** of the standard malloc(), realloc() and free() found in many operating
|
||||
** systems. No rocket science here.
|
||||
**
|
||||
** There are two versions of these four functions here. The version
|
||||
** implemented here is only used if memory-management or memory-debugging is
|
||||
** enabled. This version allocates an extra 8-bytes at the beginning of each
|
||||
** block and stores the size of the allocation there.
|
||||
**
|
||||
** If neither memory-management or debugging is enabled, the second
|
||||
** set of implementations is used instead.
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || defined (SQLITE_MEMDEBUG)
|
||||
void *sqlite3GenericMalloc(int n){
|
||||
char *p = (char *)malloc(n+8);
|
||||
assert(n>0);
|
||||
assert(sizeof(int)<=8);
|
||||
if( p ){
|
||||
*(int *)p = n;
|
||||
p += 8;
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
||||
void *sqlite3GenericRealloc(void *p, int n){
|
||||
char *p2 = ((char *)p - 8);
|
||||
assert(n>0);
|
||||
p2 = realloc(p2, n+8);
|
||||
if( p2 ){
|
||||
*(int *)p2 = n;
|
||||
p2 += 8;
|
||||
}
|
||||
return (void *)p2;
|
||||
}
|
||||
void sqlite3GenericFree(void *p){
|
||||
assert(p);
|
||||
free((void *)((char *)p - 8));
|
||||
}
|
||||
int sqlite3GenericAllocationSize(void *p){
|
||||
return p ? *(int *)((char *)p - 8) : 0;
|
||||
}
|
||||
#else
|
||||
void *sqlite3GenericMalloc(int n){
|
||||
char *p = (char *)malloc(n);
|
||||
return (void *)p;
|
||||
}
|
||||
void *sqlite3GenericRealloc(void *p, int n){
|
||||
assert(n>0);
|
||||
p = realloc(p, n);
|
||||
return p;
|
||||
}
|
||||
void sqlite3GenericFree(void *p){
|
||||
assert(p);
|
||||
free(p);
|
||||
}
|
||||
/* Never actually used, but needed for the linker */
|
||||
int sqlite3GenericAllocationSize(void *p){ return 0; }
|
||||
#endif
|
|
@ -340,9 +340,10 @@ struct openCnt {
|
|||
** openKey structures) into lockInfo and openCnt structures. Access to
|
||||
** these hash tables must be protected by a mutex.
|
||||
*/
|
||||
static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
|
||||
static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
|
||||
|
||||
static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0,
|
||||
sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
|
||||
static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0,
|
||||
sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
|
||||
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
/*
|
||||
|
@ -353,14 +354,23 @@ static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
|
|||
** 1: Yes. Threads can override each others locks.
|
||||
** -1: We don't know yet.
|
||||
**
|
||||
** On some systems, we know at compile-time if threads can override each
|
||||
** others locks. On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro
|
||||
** will be set appropriately. On other systems, we have to check at
|
||||
** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is
|
||||
** undefined.
|
||||
**
|
||||
** This variable normally has file scope only. But during testing, we make
|
||||
** it a global so that the test code can change its value in order to verify
|
||||
** that the right stuff happens in either case.
|
||||
*/
|
||||
#ifndef SQLITE_THREAD_OVERRIDE_LOCK
|
||||
# define SQLITE_THREAD_OVERRIDE_LOCK -1
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
int threadsOverrideEachOthersLocks = -1;
|
||||
int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
|
||||
#else
|
||||
static int threadsOverrideEachOthersLocks = -1;
|
||||
static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -482,7 +492,7 @@ static void releaseLockInfo(struct lockInfo *pLock){
|
|||
pLock->nRef--;
|
||||
if( pLock->nRef==0 ){
|
||||
sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
|
||||
sqliteFree(pLock);
|
||||
sqlite3ThreadSafeFree(pLock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,7 +505,7 @@ static void releaseOpenCnt(struct openCnt *pOpen){
|
|||
if( pOpen->nRef==0 ){
|
||||
sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
|
||||
free(pOpen->aPending);
|
||||
sqliteFree(pOpen);
|
||||
sqlite3ThreadSafeFree(pOpen);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,7 +546,7 @@ static int findLockInfo(
|
|||
pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
|
||||
if( pLock==0 ){
|
||||
struct lockInfo *pOld;
|
||||
pLock = sqliteMallocRaw( sizeof(*pLock) );
|
||||
pLock = sqlite3ThreadSafeMalloc( sizeof(*pLock) );
|
||||
if( pLock==0 ){
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
|
@ -548,7 +558,7 @@ static int findLockInfo(
|
|||
pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
|
||||
if( pOld!=0 ){
|
||||
assert( pOld==pLock );
|
||||
sqliteFree(pLock);
|
||||
sqlite3ThreadSafeFree(pLock);
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
}
|
||||
|
@ -560,7 +570,7 @@ static int findLockInfo(
|
|||
pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
|
||||
if( pOpen==0 ){
|
||||
struct openCnt *pOld;
|
||||
pOpen = sqliteMallocRaw( sizeof(*pOpen) );
|
||||
pOpen = sqlite3ThreadSafeMalloc( sizeof(*pOpen) );
|
||||
if( pOpen==0 ){
|
||||
releaseLockInfo(pLock);
|
||||
rc = 1;
|
||||
|
@ -574,7 +584,7 @@ static int findLockInfo(
|
|||
pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
|
||||
if( pOld!=0 ){
|
||||
assert( pOld==pOpen );
|
||||
sqliteFree(pOpen);
|
||||
sqlite3ThreadSafeFree(pOpen);
|
||||
releaseLockInfo(pLock);
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
|
@ -972,6 +982,17 @@ int sqlite3_fullsync_count = 0;
|
|||
# define fdatasync fsync
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
|
||||
** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
|
||||
** only available on Mac OS X. But that could change.
|
||||
*/
|
||||
#ifdef F_FULLFSYNC
|
||||
# define HAVE_FULLFSYNC 1
|
||||
#else
|
||||
# define HAVE_FULLFSYNC 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** The fsync() system call does not work as advertised on many
|
||||
|
@ -1003,7 +1024,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
|||
rc = SQLITE_OK;
|
||||
#else
|
||||
|
||||
#ifdef F_FULLFSYNC
|
||||
#if HAVE_FULLFSYNC
|
||||
if( fullSync ){
|
||||
rc = fcntl(fd, F_FULLFSYNC, 0);
|
||||
}else{
|
||||
|
@ -1048,10 +1069,21 @@ static int unixSync(OsFile *id, int dataOnly){
|
|||
return SQLITE_IOERR;
|
||||
}
|
||||
if( pFile->dirfd>=0 ){
|
||||
TRACE2("DIRSYNC %-3d\n", pFile->dirfd);
|
||||
TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
|
||||
HAVE_FULLFSYNC, pFile->fullSync);
|
||||
#ifndef SQLITE_DISABLE_DIRSYNC
|
||||
if( full_fsync(pFile->dirfd, pFile->fullSync, 0) ){
|
||||
return SQLITE_IOERR;
|
||||
/* The directory sync is only attempted if full_fsync is
|
||||
** turned off or unavailable. If a full_fsync occurred above,
|
||||
** then the directory sync is superfluous.
|
||||
*/
|
||||
if( (!HAVE_FULLFSYNC || !pFile->fullSync) && full_fsync(pFile->dirfd,0,0) ){
|
||||
/*
|
||||
** We have received multiple reports of fsync() returning
|
||||
** errors when applied to directories on certain file systems.
|
||||
** A failed directory sync is not a big deal. So it seems
|
||||
** better to ignore the error. Ticket #1657
|
||||
*/
|
||||
/* return SQLITE_IOERR; */
|
||||
}
|
||||
#endif
|
||||
close(pFile->dirfd); /* Only need to sync once, so close the directory */
|
||||
|
@ -1495,7 +1527,7 @@ static int unixClose(OsFile **pId){
|
|||
id->isOpen = 0;
|
||||
TRACE2("CLOSE %-3d\n", id->h);
|
||||
OpenCounter(-1);
|
||||
sqliteFree(id);
|
||||
sqlite3ThreadSafeFree(id);
|
||||
*pId = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -1520,6 +1552,33 @@ char *sqlite3UnixFullPathname(const char *zRelative){
|
|||
(char*)0);
|
||||
sqliteFree(zBuf);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** Remove "/./" path elements and convert "/A/./" path elements
|
||||
** to just "/".
|
||||
*/
|
||||
if( zFull ){
|
||||
int i, j;
|
||||
for(i=j=0; zFull[i]; i++){
|
||||
if( zFull[i]=='/' ){
|
||||
if( zFull[i+1]=='/' ) continue;
|
||||
if( zFull[i+1]=='.' && zFull[i+2]=='/' ){
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){
|
||||
while( j>0 && zFull[j-1]!='/' ){ j--; }
|
||||
i += 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
zFull[j++] = zFull[i];
|
||||
}
|
||||
zFull[j] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return zFull;
|
||||
}
|
||||
|
||||
|
@ -1577,7 +1636,7 @@ static int allocateUnixFile(unixFile *pInit, OsFile **pId){
|
|||
pInit->fullSync = 0;
|
||||
pInit->locktype = 0;
|
||||
SET_THREADID(pInit);
|
||||
pNew = sqliteMalloc( sizeof(unixFile) );
|
||||
pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
|
||||
if( pNew==0 ){
|
||||
close(pInit->h);
|
||||
sqlite3OsEnterMutex();
|
||||
|
@ -1656,13 +1715,42 @@ int sqlite3UnixSleep(int ms){
|
|||
}
|
||||
|
||||
/*
|
||||
** Static variables used for thread synchronization
|
||||
** Static variables used for thread synchronization.
|
||||
**
|
||||
** inMutex the nesting depth of the recursive mutex. The thread
|
||||
** holding mutexMain can read this variable at any time.
|
||||
** But is must hold mutexAux to change this variable. Other
|
||||
** threads must hold mutexAux to read the variable and can
|
||||
** never write.
|
||||
**
|
||||
** mutexOwner The thread id of the thread holding mutexMain. Same
|
||||
** access rules as for inMutex.
|
||||
**
|
||||
** mutexOwnerValid True if the value in mutexOwner is valid. The same
|
||||
** access rules apply as for inMutex.
|
||||
**
|
||||
** mutexMain The main mutex. Hold this mutex in order to get exclusive
|
||||
** access to SQLite data structures.
|
||||
**
|
||||
** mutexAux An auxiliary mutex needed to access variables defined above.
|
||||
**
|
||||
** Mutexes are always acquired in this order: mutexMain mutexAux. It
|
||||
** is not necessary to acquire mutexMain in order to get mutexAux - just
|
||||
** do not attempt to acquire them in the reverse order: mutexAux mutexMain.
|
||||
** Either get the mutexes with mutexMain first or get mutexAux only.
|
||||
**
|
||||
** When running on a platform where the three variables inMutex, mutexOwner,
|
||||
** and mutexOwnerValid can be set atomically, the mutexAux is not required.
|
||||
** On many systems, all three are 32-bit integers and writing to a 32-bit
|
||||
** integer is atomic. I think. But there are no guarantees. So it seems
|
||||
** safer to protect them using mutexAux.
|
||||
*/
|
||||
static int inMutex = 0;
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
static pthread_t mutexOwner;
|
||||
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_t mutexOwner; /* Thread holding mutexMain */
|
||||
static int mutexOwnerValid = 0; /* True if mutexOwner is valid */
|
||||
static pthread_mutex_t mutexMain = PTHREAD_MUTEX_INITIALIZER; /* The mutex */
|
||||
static pthread_mutex_t mutexAux = PTHREAD_MUTEX_INITIALIZER; /* Aux mutex */
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -1677,25 +1765,34 @@ static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
|
|||
*/
|
||||
void sqlite3UnixEnterMutex(){
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
pthread_mutex_lock(&mutex1);
|
||||
if( inMutex==0 ){
|
||||
pthread_mutex_lock(&mutex2);
|
||||
pthread_mutex_lock(&mutexAux);
|
||||
if( !mutexOwnerValid || !pthread_equal(mutexOwner, pthread_self()) ){
|
||||
pthread_mutex_unlock(&mutexAux);
|
||||
pthread_mutex_lock(&mutexMain);
|
||||
assert( inMutex==0 );
|
||||
assert( !mutexOwnerValid );
|
||||
pthread_mutex_lock(&mutexAux);
|
||||
mutexOwner = pthread_self();
|
||||
mutexOwnerValid = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&mutex1);
|
||||
#endif
|
||||
inMutex++;
|
||||
pthread_mutex_unlock(&mutexAux);
|
||||
#else
|
||||
inMutex++;
|
||||
#endif
|
||||
}
|
||||
void sqlite3UnixLeaveMutex(){
|
||||
assert( inMutex>0 );
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
assert( pthread_equal(mutexOwner, pthread_self()) );
|
||||
pthread_mutex_lock(&mutex1);
|
||||
pthread_mutex_lock(&mutexAux);
|
||||
inMutex--;
|
||||
assert( pthread_equal(mutexOwner, pthread_self()) );
|
||||
if( inMutex==0 ){
|
||||
pthread_mutex_unlock(&mutex2);
|
||||
assert( mutexOwnerValid );
|
||||
mutexOwnerValid = 0;
|
||||
pthread_mutex_unlock(&mutexMain);
|
||||
}
|
||||
pthread_mutex_unlock(&mutex1);
|
||||
pthread_mutex_unlock(&mutexAux);
|
||||
#else
|
||||
inMutex--;
|
||||
#endif
|
||||
|
@ -1704,14 +1801,17 @@ void sqlite3UnixLeaveMutex(){
|
|||
/*
|
||||
** Return TRUE if the mutex is currently held.
|
||||
**
|
||||
** If the thisThreadOnly parameter is true, return true only if the
|
||||
** If the thisThrd parameter is true, return true only if the
|
||||
** calling thread holds the mutex. If the parameter is false, return
|
||||
** true if any thread holds the mutex.
|
||||
*/
|
||||
int sqlite3UnixInMutex(int thisThreadOnly){
|
||||
int sqlite3UnixInMutex(int thisThrd){
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
return inMutex>0 &&
|
||||
(thisThreadOnly==0 || pthread_equal(mutexOwner, pthread_self()));
|
||||
int rc;
|
||||
pthread_mutex_lock(&mutexAux);
|
||||
rc = inMutex>0 && (thisThrd==0 || pthread_equal(mutexOwner,pthread_self()));
|
||||
pthread_mutex_unlock(&mutexAux);
|
||||
return rc;
|
||||
#else
|
||||
return inMutex>0;
|
||||
#endif
|
||||
|
|
|
@ -1479,7 +1479,7 @@ int sqlite3_tsd_count = 0;
|
|||
ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){
|
||||
static int key;
|
||||
static int keyInit = 0;
|
||||
static const ThreadData zeroData;
|
||||
static const ThreadData zeroData = {0};
|
||||
ThreadData *pTsd;
|
||||
|
||||
if( !keyInit ){
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.257 2006/01/30 22:48:44 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.258 2006/02/11 01:25:51 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#include "sqliteInt.h"
|
||||
|
@ -244,6 +244,7 @@ struct Pager {
|
|||
u8 stmtAutoopen; /* Open stmt journal when main journal is opened*/
|
||||
u8 noSync; /* Do not sync the journal if true */
|
||||
u8 fullSync; /* Do extra syncs of the journal for robustness */
|
||||
u8 full_fsync; /* Use F_FULLFSYNC when available */
|
||||
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
|
||||
u8 errCode; /* One of several kinds of errors */
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
|
@ -1509,9 +1510,10 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
|
|||
** and FULL=3.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
void sqlite3pager_set_safety_level(Pager *pPager, int level){
|
||||
void sqlite3pager_set_safety_level(Pager *pPager, int level, int full_fsync){
|
||||
pPager->noSync = level==1 || pPager->tempFile;
|
||||
pPager->fullSync = level==3 && !pPager->tempFile;
|
||||
pPager->full_fsync = full_fsync;
|
||||
if( pPager->noSync ) pPager->needSync = 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -2204,7 +2206,7 @@ static int syncJournal(Pager *pPager){
|
|||
if( rc ) return rc;
|
||||
}
|
||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||
rc = sqlite3OsSync(pPager->jfd, pPager->fullSync);
|
||||
rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync);
|
||||
if( rc!=0 ) return rc;
|
||||
pPager->journalStarted = 1;
|
||||
}
|
||||
|
@ -2832,8 +2834,8 @@ static int pager_open_journal(Pager *pPager){
|
|||
if( rc!=SQLITE_OK ){
|
||||
goto failed_to_open_journal;
|
||||
}
|
||||
sqlite3OsSetFullSync(pPager->jfd, pPager->fullSync);
|
||||
sqlite3OsSetFullSync(pPager->fd, pPager->fullSync);
|
||||
sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
|
||||
sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync);
|
||||
sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory);
|
||||
pPager->journalOpen = 1;
|
||||
pPager->journalStarted = 0;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.48 2005/12/19 14:18:11 danielk1977 Exp $
|
||||
** @(#) $Id: pager.h,v 1.49 2006/02/11 01:25:51 drh Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PAGER_H_
|
||||
|
@ -99,7 +99,7 @@ int sqlite3pager_stmt_rollback(Pager*);
|
|||
void sqlite3pager_dont_rollback(void*);
|
||||
void sqlite3pager_dont_write(Pager*, Pgno);
|
||||
int *sqlite3pager_stats(Pager*);
|
||||
void sqlite3pager_set_safety_level(Pager*,int);
|
||||
void sqlite3pager_set_safety_level(Pager*,int,int);
|
||||
const char *sqlite3pager_filename(Pager*);
|
||||
const char *sqlite3pager_dirname(Pager*);
|
||||
const char *sqlite3pager_journalname(Pager*);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.114 2006/01/12 01:56:44 drh Exp $
|
||||
** $Id: pragma.c,v 1.119 2006/02/17 12:25:16 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -128,7 +128,7 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
|
|||
sqlite3VdbeAddOp(v, OP_Integer, value, 0);
|
||||
if( pParse->explain==0 ){
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
|||
{ "count_changes", SQLITE_CountRows },
|
||||
{ "empty_result_callbacks", SQLITE_NullCallback },
|
||||
{ "legacy_file_format", SQLITE_LegacyFileFmt },
|
||||
{ "fullfsync", SQLITE_FullFSync },
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
|
||||
#endif
|
||||
|
@ -180,10 +181,6 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
|||
db->flags &= ~p->mask;
|
||||
}
|
||||
}
|
||||
/* If one of these pragmas is executed, any prepared statements
|
||||
** need to be recompiled.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -230,6 +227,13 @@ void sqlite3Pragma(
|
|||
if( iDb<0 ) return;
|
||||
pDb = &db->aDb[iDb];
|
||||
|
||||
/* If the temp database has been explicitly named as part of the
|
||||
** pragma, make sure it is open.
|
||||
*/
|
||||
if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
|
||||
return;
|
||||
}
|
||||
|
||||
zLeft = sqlite3NameFromToken(pId);
|
||||
if( !zLeft ) return;
|
||||
if( minusFlag ){
|
||||
|
@ -274,7 +278,7 @@ void sqlite3Pragma(
|
|||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
|
||||
|
@ -392,7 +396,8 @@ void sqlite3Pragma(
|
|||
if( !zRight ){
|
||||
if( sqlite3_temp_directory ){
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "temp_store_directory", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
|
||||
"temp_store_directory", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
@ -436,7 +441,6 @@ void sqlite3Pragma(
|
|||
"Safety level may not be changed inside a transaction");
|
||||
}else{
|
||||
pDb->safety_level = getSafetyLevel(zRight)+1;
|
||||
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
@ -468,22 +472,23 @@ void sqlite3Pragma(
|
|||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab ){
|
||||
int i;
|
||||
Column *pCol;
|
||||
sqlite3VdbeSetNumCols(v, 6);
|
||||
sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "type", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
|
||||
pCol->zType ? pCol->zType : "numeric", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
|
||||
sqlite3ExprCode(pParse, pCol->pDflt);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
|
||||
}
|
||||
}
|
||||
|
@ -498,9 +503,9 @@ void sqlite3Pragma(
|
|||
int i;
|
||||
pTab = pIdx->pTable;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int cnum = pIdx->aiColumn[i];
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
|
@ -523,9 +528,9 @@ void sqlite3Pragma(
|
|||
if( pIdx ){
|
||||
int i = 0;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC);
|
||||
while(pIdx){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
|
||||
|
@ -542,9 +547,9 @@ void sqlite3Pragma(
|
|||
int i;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ) continue;
|
||||
assert( db->aDb[i].zName!=0 );
|
||||
|
@ -560,8 +565,8 @@ void sqlite3Pragma(
|
|||
int i = 0;
|
||||
HashElem *p;
|
||||
sqlite3VdbeSetNumCols(v, 2);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
|
||||
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
|
||||
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
|
||||
|
@ -583,11 +588,11 @@ void sqlite3Pragma(
|
|||
if( pFK ){
|
||||
int i = 0;
|
||||
sqlite3VdbeSetNumCols(v, 5);
|
||||
sqlite3VdbeSetColName(v, 0, "id", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "table", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 3, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 4, "to", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC);
|
||||
while(pFK){
|
||||
int j;
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
|
@ -649,7 +654,7 @@ void sqlite3Pragma(
|
|||
/* Initialize the VDBE program */
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
|
||||
|
||||
/* Do an integrity check on each database file */
|
||||
|
@ -794,7 +799,7 @@ void sqlite3Pragma(
|
|||
if( !zRight ){ /* "PRAGMA encoding" */
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( pEnc->enc==ENC(pParse->db) ){
|
||||
|
@ -900,8 +905,8 @@ void sqlite3Pragma(
|
|||
int i;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
sqlite3VdbeSetNumCols(v, 2);
|
||||
sqlite3VdbeSetColName(v, 0, "database", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "status", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt;
|
||||
Pager *pPager;
|
||||
|
@ -945,6 +950,17 @@ void sqlite3Pragma(
|
|||
** are only valid for a single execution.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
|
||||
|
||||
/*
|
||||
** Reset the safety level, in case the fullfsync flag or synchronous
|
||||
** setting changed.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
if( db->autoCommit ){
|
||||
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
|
||||
(db->flags&SQLITE_FullFSync)!=0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pragma_out:
|
||||
sqliteFree(zLeft);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** interface, and routines that contribute to loading the database schema
|
||||
** from disk.
|
||||
**
|
||||
** $Id: prepare.c,v 1.3 2006-02-08 21:10:11 vladimir%pobox.com Exp $
|
||||
** $Id: prepare.c,v 1.4 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -556,16 +556,16 @@ int sqlite3_prepare(
|
|||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||
if( sParse.explain==2 ){
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC);
|
||||
}else{
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.301 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
** $Id: select.c,v 1.304 2006/02/10 07:07:16 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -762,14 +762,31 @@ static void generateSortTail(
|
|||
** Return a pointer to a string containing the 'declaration type' of the
|
||||
** expression pExpr. The string may be treated as static by the caller.
|
||||
**
|
||||
** If the declaration type is the exact datatype definition extracted from
|
||||
** the original CREATE TABLE statement if the expression is a column.
|
||||
** The declaration type is the exact datatype definition extracted from the
|
||||
** original CREATE TABLE statement if the expression is a column. The
|
||||
** declaration type for a ROWID field is INTEGER. Exactly when an expression
|
||||
** is considered a column can be complex in the presence of subqueries. The
|
||||
** result-set expression in all of the following SELECT statements is
|
||||
** considered a column by this function.
|
||||
**
|
||||
** SELECT col FROM tbl;
|
||||
** SELECT (SELECT col FROM tbl;
|
||||
** SELECT (SELECT col FROM tbl);
|
||||
** SELECT abc FROM (SELECT col AS abc FROM tbl);
|
||||
**
|
||||
** The declaration type for an expression is either TEXT, NUMERIC or ANY.
|
||||
** The declaration type for a ROWID field is INTEGER.
|
||||
** The declaration type for any expression other than a column is NULL.
|
||||
*/
|
||||
static const char *columnType(NameContext *pNC, Expr *pExpr){
|
||||
char const *zType;
|
||||
static const char *columnType(
|
||||
NameContext *pNC,
|
||||
Expr *pExpr,
|
||||
const char **pzOriginDb,
|
||||
const char **pzOriginTab,
|
||||
const char **pzOriginCol
|
||||
){
|
||||
char const *zType = 0;
|
||||
char const *zOriginDb = 0;
|
||||
char const *zOriginTab = 0;
|
||||
char const *zOriginCol = 0;
|
||||
int j;
|
||||
if( pExpr==0 || pNC->pSrcList==0 ) return 0;
|
||||
|
||||
|
@ -781,17 +798,24 @@ static const char *columnType(NameContext *pNC, Expr *pExpr){
|
|||
|
||||
switch( pExpr->op ){
|
||||
case TK_COLUMN: {
|
||||
Table *pTab = 0;
|
||||
int iCol = pExpr->iColumn;
|
||||
/* The expression is a column. Locate the table the column is being
|
||||
** extracted from in NameContext.pSrcList. This table may be real
|
||||
** database table or a subquery.
|
||||
*/
|
||||
Table *pTab = 0; /* Table structure column is extracted from */
|
||||
Select *pS = 0; /* Select the column is extracted from */
|
||||
int iCol = pExpr->iColumn; /* Index of column in pTab */
|
||||
while( pNC && !pTab ){
|
||||
SrcList *pTabList = pNC->pSrcList;
|
||||
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
|
||||
if( j<pTabList->nSrc ){
|
||||
pTab = pTabList->a[j].pTab;
|
||||
pS = pTabList->a[j].pSelect;
|
||||
}else{
|
||||
pNC = pNC->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
if( pTab==0 ){
|
||||
/* FIX ME:
|
||||
** This can occurs if you have something like "SELECT new.x;" inside
|
||||
|
@ -806,30 +830,72 @@ static const char *columnType(NameContext *pNC, Expr *pExpr){
|
|||
zType = "TEXT";
|
||||
break;
|
||||
}
|
||||
|
||||
assert( pTab );
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||
if( iCol<0 ){
|
||||
zType = "INTEGER";
|
||||
}else{
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
if( pS ){
|
||||
/* The "table" is actually a sub-select or a view in the FROM clause
|
||||
** of the SELECT statement. Return the declaration type and origin
|
||||
** data for the result-set column of the sub-select.
|
||||
*/
|
||||
if( iCol>=0 && iCol<pS->pEList->nExpr ){
|
||||
/* If iCol is less than zero, then the expression requests the
|
||||
** rowid of the sub-select or view. This expression is legal (see
|
||||
** test case misc2.2.2) - it always evaluates to NULL.
|
||||
*/
|
||||
NameContext sNC;
|
||||
Expr *p = pS->pEList->a[iCol].pExpr;
|
||||
sNC.pSrcList = pS->pSrc;
|
||||
sNC.pNext = 0;
|
||||
sNC.pParse = pNC->pParse;
|
||||
zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
if( pTab->pSchema ){
|
||||
/* A real table */
|
||||
assert( !pS );
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||
if( iCol<0 ){
|
||||
zType = "INTEGER";
|
||||
zOriginCol = "rowid";
|
||||
}else{
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
zOriginCol = pTab->aCol[iCol].zName;
|
||||
}
|
||||
zOriginTab = pTab->zName;
|
||||
if( pNC->pParse ){
|
||||
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
|
||||
zOriginDb = pNC->pParse->db->aDb[iDb].zName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
case TK_SELECT: {
|
||||
/* The expression is a sub-select. Return the declaration type and
|
||||
** origin info for the single column in the result set of the SELECT
|
||||
** statement.
|
||||
*/
|
||||
NameContext sNC;
|
||||
Select *pS = pExpr->pSelect;
|
||||
sNC.pSrcList = pExpr->pSelect->pSrc;
|
||||
Expr *p = pS->pEList->a[0].pExpr;
|
||||
sNC.pSrcList = pS->pSrc;
|
||||
sNC.pNext = pNC;
|
||||
zType = columnType(&sNC, pS->pEList->a[0].pExpr);
|
||||
sNC.pParse = pNC->pParse;
|
||||
zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
zType = 0;
|
||||
}
|
||||
|
||||
if( pzOriginDb ){
|
||||
assert( pzOriginTab && pzOriginCol );
|
||||
*pzOriginDb = zOriginDb;
|
||||
*pzOriginTab = zOriginTab;
|
||||
*pzOriginCol = zOriginCol;
|
||||
}
|
||||
return zType;
|
||||
}
|
||||
|
||||
|
@ -846,14 +912,22 @@ static void generateColumnTypes(
|
|||
int i;
|
||||
NameContext sNC;
|
||||
sNC.pSrcList = pTabList;
|
||||
sNC.pParse = pParse;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
Expr *p = pEList->a[i].pExpr;
|
||||
const char *zType = columnType(&sNC, p);
|
||||
if( zType==0 ) continue;
|
||||
/* The vdbe must make it's own copy of the column-type, in case the
|
||||
** schema is reset before this virtual machine is deleted.
|
||||
const char *zOrigDb = 0;
|
||||
const char *zOrigTab = 0;
|
||||
const char *zOrigCol = 0;
|
||||
const char *zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
|
||||
|
||||
/* The vdbe must make it's own copy of the column-type and other
|
||||
** column specific strings, in case the schema is reset before this
|
||||
** virtual machine is deleted.
|
||||
*/
|
||||
sqlite3VdbeSetColName(v, i+pEList->nExpr, zType, strlen(zType));
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, P3_TRANSIENT);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, P3_TRANSIENT);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, P3_TRANSIENT);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, P3_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -891,7 +965,7 @@ static void generateColumnNames(
|
|||
if( p==0 ) continue;
|
||||
if( pEList->a[i].zName ){
|
||||
char *zName = pEList->a[i].zName;
|
||||
sqlite3VdbeSetColName(v, i, zName, strlen(zName));
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, strlen(zName));
|
||||
continue;
|
||||
}
|
||||
if( p->op==TK_COLUMN && pTabList ){
|
||||
|
@ -909,7 +983,7 @@ static void generateColumnNames(
|
|||
zCol = pTab->aCol[iCol].zName;
|
||||
}
|
||||
if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
|
||||
sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
|
||||
}else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
|
||||
char *zName = 0;
|
||||
char *zTab;
|
||||
|
@ -917,18 +991,18 @@ static void generateColumnNames(
|
|||
zTab = pTabList->a[j].zAlias;
|
||||
if( fullNames || zTab==0 ) zTab = pTab->zName;
|
||||
sqlite3SetString(&zName, zTab, ".", zCol, (char*)0);
|
||||
sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC);
|
||||
}else{
|
||||
sqlite3VdbeSetColName(v, i, zCol, strlen(zCol));
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol));
|
||||
}
|
||||
}else if( p->span.z && p->span.z[0] ){
|
||||
sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
|
||||
/* sqlite3VdbeCompressSpace(v, addr); */
|
||||
}else{
|
||||
char zName[30];
|
||||
assert( p->op!=TK_COLUMN || pTabList==0 );
|
||||
sprintf(zName, "column%d", i+1);
|
||||
sqlite3VdbeSetColName(v, i, zName, 0);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0);
|
||||
}
|
||||
}
|
||||
generateColumnTypes(pParse, pTabList, pEList);
|
||||
|
@ -1036,7 +1110,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||
*/
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pSrcList = pSelect->pSrc;
|
||||
zType = sqliteStrDup(columnType(&sNC, p));
|
||||
zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0));
|
||||
pCol->zType = zType;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
|
@ -2783,13 +2857,6 @@ int sqlite3Select(
|
|||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto select_end;
|
||||
|
||||
/* Identify column names if we will be using them in a callback. This
|
||||
** step is skipped if the output is going to some other destination.
|
||||
*/
|
||||
if( eDest==SRT_Callback ){
|
||||
generateColumnNames(pParse, pTabList, pEList);
|
||||
}
|
||||
|
||||
/* Generate code for all sub-queries in the FROM clause
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
|
@ -2798,7 +2865,7 @@ int sqlite3Select(
|
|||
int needRestoreContext;
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
|
||||
if( pItem->pSelect==0 ) continue;
|
||||
if( pItem->pSelect==0 || pItem->isPopulated ) continue;
|
||||
if( pItem->zName!=0 ){
|
||||
zSavedAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = pItem->zName;
|
||||
|
@ -3192,15 +3259,14 @@ int sqlite3Select(
|
|||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/* If this was a subquery, we have now converted the subquery into a
|
||||
** temporary table. So delete the subquery structure from the parent
|
||||
** to prevent this subquery from being evaluated again and to force the
|
||||
** the use of the temporary table.
|
||||
** temporary table. So set the SrcList_item.isPopulated flag to prevent
|
||||
** this subquery from being evaluated again and to force the use of
|
||||
** the temporary table.
|
||||
*/
|
||||
if( pParent ){
|
||||
assert( pParent->pSrc->nSrc>parentTab );
|
||||
assert( pParent->pSrc->a[parentTab].pSelect==p );
|
||||
sqlite3SelectDelete(p);
|
||||
pParent->pSrc->a[parentTab].pSelect = 0;
|
||||
pParent->pSrc->a[parentTab].isPopulated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3217,6 +3283,14 @@ int sqlite3Select(
|
|||
** successful coding of the SELECT.
|
||||
*/
|
||||
select_end:
|
||||
|
||||
/* Identify column names if we will be using them in a callback. This
|
||||
** step is skipped if the output is going to some other destination.
|
||||
*/
|
||||
if( rc==SQLITE_OK && eDest==SRT_Callback ){
|
||||
generateColumnNames(pParse, pTabList, pEList);
|
||||
}
|
||||
|
||||
sqliteFree(sAggInfo.aCol);
|
||||
sqliteFree(sAggInfo.aFunc);
|
||||
return rc;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.131 2006/01/25 15:55:38 drh Exp $
|
||||
** $Id: shell.c,v 1.133 2006/01/31 19:31:44 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -247,7 +247,7 @@ struct callback_data {
|
|||
#define MODE_Csv 7 /* Quote strings, numbers are plain */
|
||||
#define MODE_NUM_OF 8 /* The number of modes (not a mode itself) */
|
||||
|
||||
char *modeDescr[MODE_NUM_OF] = {
|
||||
static const char *modeDescr[MODE_NUM_OF] = {
|
||||
"line",
|
||||
"column",
|
||||
"list",
|
||||
|
@ -1040,7 +1040,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
||||
if( zSql==0 ) return 0;
|
||||
nByte = strlen(zSql);
|
||||
rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
|
||||
rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
||||
|
@ -1060,7 +1060,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
}
|
||||
zSql[j++] = ')';
|
||||
zSql[j] = 0;
|
||||
rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
|
||||
rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
|
||||
free(zSql);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
|
||||
|
@ -1618,7 +1618,7 @@ static void usage(int showDetail){
|
|||
/*
|
||||
** Initialize the state information in data
|
||||
*/
|
||||
void main_init(struct callback_data *data) {
|
||||
static void main_init(struct callback_data *data) {
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->mode = MODE_List;
|
||||
strcpy(data->separator,"|");
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.156 2006/01/12 02:50:10 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.163 2006/02/16 18:16:37 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
|
@ -31,7 +31,7 @@ extern "C" {
|
|||
#ifdef SQLITE_VERSION
|
||||
# undef SQLITE_VERSION
|
||||
#endif
|
||||
#define SQLITE_VERSION "3.3.3"
|
||||
#define SQLITE_VERSION "3.3.4"
|
||||
|
||||
/*
|
||||
** The format of the version string is "X.Y.Z<trailing string>", where
|
||||
|
@ -48,7 +48,7 @@ extern "C" {
|
|||
#ifdef SQLITE_VERSION_NUMBER
|
||||
# undef SQLITE_VERSION_NUMBER
|
||||
#endif
|
||||
#define SQLITE_VERSION_NUMBER 3003003
|
||||
#define SQLITE_VERSION_NUMBER 3003004
|
||||
|
||||
/*
|
||||
** The version string is also compiled into the library so that a program
|
||||
|
@ -164,6 +164,7 @@ int sqlite3_exec(
|
|||
** Return values for sqlite3_exec() and sqlite3_step()
|
||||
*/
|
||||
#define SQLITE_OK 0 /* Successful result */
|
||||
/* beginning-of-error-codes */
|
||||
#define SQLITE_ERROR 1 /* SQL error or missing database */
|
||||
#define SQLITE_INTERNAL 2 /* NOT USED. Internal logic error in SQLite */
|
||||
#define SQLITE_PERM 3 /* Access permission denied */
|
||||
|
@ -192,7 +193,7 @@ int sqlite3_exec(
|
|||
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||
/* end-of-return-codes */
|
||||
/* end-of-error-codes */
|
||||
|
||||
/*
|
||||
** Each entry in an SQLite table has a unique integer key. (The key is
|
||||
|
@ -724,6 +725,30 @@ int sqlite3_column_count(sqlite3_stmt *pStmt);
|
|||
const char *sqlite3_column_name(sqlite3_stmt*,int);
|
||||
const void *sqlite3_column_name16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** The first parameter to the following calls is a compiled SQL statement.
|
||||
** These functions return information about the Nth column returned by
|
||||
** the statement, where N is the second function argument.
|
||||
**
|
||||
** If the Nth column returned by the statement is not a column value,
|
||||
** then all of the functions return NULL. Otherwise, the return the
|
||||
** name of the attached database, table and column that the expression
|
||||
** extracts a value from.
|
||||
**
|
||||
** As with all other SQLite APIs, those postfixed with "16" return UTF-16
|
||||
** encoded strings, the other functions return UTF-8. The memory containing
|
||||
** the returned strings is valid until the statement handle is finalized().
|
||||
**
|
||||
** These APIs are only available if the library was compiled with the
|
||||
** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
|
||||
*/
|
||||
const char *sqlite3_column_database_name(sqlite3_stmt*,int);
|
||||
const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
|
||||
const char *sqlite3_column_table_name(sqlite3_stmt*,int);
|
||||
const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
|
||||
const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
|
||||
const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** The first parameter is a compiled SQL statement. If this statement
|
||||
** is a SELECT statement, the Nth column of the returned result set
|
||||
|
@ -736,7 +761,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*,int);
|
|||
**
|
||||
** And the following statement compiled:
|
||||
**
|
||||
** SELECT c1 + 1, 0 FROM t1;
|
||||
** SELECT c1 + 1, c1 FROM t1;
|
||||
**
|
||||
** Then this routine would return the string "VARIANT" for the second
|
||||
** result column (i==1), and a NULL pointer for the first result column
|
||||
|
@ -756,7 +781,7 @@ const char *sqlite3_column_decltype(sqlite3_stmt *, int i);
|
|||
**
|
||||
** And the following statement compiled:
|
||||
**
|
||||
** SELECT c1 + 1, 0 FROM t1;
|
||||
** SELECT c1 + 1, c1 FROM t1;
|
||||
**
|
||||
** Then this routine would return the string "INTEGER" for the second
|
||||
** result column (i==1), and a NULL pointer for the first result column
|
||||
|
@ -897,6 +922,7 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
|
|||
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
|
||||
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
|
||||
int sqlite3_column_type(sqlite3_stmt*, int iCol);
|
||||
int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);
|
||||
|
||||
/*
|
||||
** The sqlite3_finalize() function is called to delete a compiled
|
||||
|
@ -980,9 +1006,8 @@ int sqlite3_create_function16(
|
|||
);
|
||||
|
||||
/*
|
||||
** The next routine returns the number of calls to xStep for a particular
|
||||
** aggregate function instance. The current call to xStep counts so this
|
||||
** routine always returns at least 1.
|
||||
** This function is deprecated. Do not use it. It continues to exist
|
||||
** so as not to break legacy code. But new code should avoid using it.
|
||||
*/
|
||||
int sqlite3_aggregate_count(sqlite3_context*);
|
||||
|
||||
|
@ -1005,6 +1030,7 @@ const void *sqlite3_value_text16(sqlite3_value*);
|
|||
const void *sqlite3_value_text16le(sqlite3_value*);
|
||||
const void *sqlite3_value_text16be(sqlite3_value*);
|
||||
int sqlite3_value_type(sqlite3_value*);
|
||||
int sqlite3_value_numeric_type(sqlite3_value*);
|
||||
|
||||
/*
|
||||
** Aggregate functions use the following routine to allocate
|
||||
|
@ -1088,11 +1114,12 @@ void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
|
|||
** These are the allowed values for the eTextRep argument to
|
||||
** sqlite3_create_collation and sqlite3_create_function.
|
||||
*/
|
||||
#define SQLITE_UTF8 1
|
||||
#define SQLITE_UTF16LE 2
|
||||
#define SQLITE_UTF16BE 3
|
||||
#define SQLITE_UTF16 4 /* Use native byte order */
|
||||
#define SQLITE_ANY 5 /* sqlite3_create_function only */
|
||||
#define SQLITE_UTF8 1
|
||||
#define SQLITE_UTF16LE 2
|
||||
#define SQLITE_UTF16BE 3
|
||||
#define SQLITE_UTF16 4 /* Use native byte order */
|
||||
#define SQLITE_ANY 5 /* sqlite3_create_function only */
|
||||
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
|
||||
|
||||
/*
|
||||
** These two functions are used to add new collation sequences to the
|
||||
|
@ -1369,6 +1396,75 @@ void sqlite3_soft_heap_limit(int);
|
|||
*/
|
||||
void sqlite3_thread_cleanup(void);
|
||||
|
||||
/*
|
||||
** Return meta information about a specific column of a specific database
|
||||
** table accessible using the connection handle passed as the first function
|
||||
** argument.
|
||||
**
|
||||
** The column is identified by the second, third and fourth parameters to
|
||||
** this function. The second parameter is either the name of the database
|
||||
** (i.e. "main", "temp" or an attached database) containing the specified
|
||||
** table or NULL. If it is NULL, then all attached databases are searched
|
||||
** for the table using the same algorithm as the database engine uses to
|
||||
** resolve unqualified table references.
|
||||
**
|
||||
** The third and fourth parameters to this function are the table and column
|
||||
** name of the desired column, respectively. Neither of these parameters
|
||||
** may be NULL.
|
||||
**
|
||||
** Meta information is returned by writing to the memory locations passed as
|
||||
** the 5th and subsequent parameters to this function. Any of these
|
||||
** arguments may be NULL, in which case the corresponding element of meta
|
||||
** information is ommitted.
|
||||
**
|
||||
** Parameter Output Type Description
|
||||
** -----------------------------------
|
||||
**
|
||||
** 5th const char* Data type
|
||||
** 6th const char* Name of the default collation sequence
|
||||
** 7th int True if the column has a NOT NULL constraint
|
||||
** 8th int True if the column is part of the PRIMARY KEY
|
||||
** 9th int True if the column is AUTOINCREMENT
|
||||
**
|
||||
**
|
||||
** The memory pointed to by the character pointers returned for the
|
||||
** declaration type and collation sequence is valid only until the next
|
||||
** call to any sqlite API function.
|
||||
**
|
||||
** If the specified table is actually a view, then an error is returned.
|
||||
**
|
||||
** If the specified column is "rowid", "oid" or "_rowid_" and an
|
||||
** INTEGER PRIMARY KEY column has been explicitly declared, then the output
|
||||
** parameters are set for the explicitly declared column. If there is no
|
||||
** explicitly declared IPK column, then the output parameters are set as
|
||||
** follows:
|
||||
**
|
||||
** data type: "INTEGER"
|
||||
** collation sequence: "BINARY"
|
||||
** not null: 0
|
||||
** primary key: 1
|
||||
** auto increment: 0
|
||||
**
|
||||
** This function may load one or more schemas from database files. If an
|
||||
** error occurs during this process, or if the requested table or column
|
||||
** cannot be found, an SQLITE error code is returned and an error message
|
||||
** left in the database handle (to be retrieved using sqlite3_errmsg()).
|
||||
**
|
||||
** This API is only available if the library was compiled with the
|
||||
** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
|
||||
*/
|
||||
int sqlite3_table_column_metadata(
|
||||
sqlite3 *db, /* Connection handle */
|
||||
const char *zDbName, /* Database name or NULL */
|
||||
const char *zTableName, /* Table name */
|
||||
const char *zColumnName, /* Column name */
|
||||
char const **pzDataType, /* OUTPUT: Declared data type */
|
||||
char const **pzCollSeq, /* OUTPUT: Collation sequence name */
|
||||
int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
|
||||
int *pPrimaryKey, /* OUTPUT: True if column part of PK */
|
||||
int *pAutoinc /* OUTPUT: True if colums is auto-increment */
|
||||
);
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
|
|
|
@ -1,9 +1,58 @@
|
|||
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla History System
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brett Wilson <brettw@gmail.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* This file collects some internal sqlite data structures that are exported
|
||||
* for use by the storage asynchronous IO system. Using all real versions of
|
||||
* the internal sqlite header files became complicated because they depend
|
||||
* on one another and they have a lot of extra stuff we don't care about.
|
||||
*
|
||||
* THESE DECLARATIONS MUST BE KEPT IN SYNC with the internal versions, so if
|
||||
* you upgrade sqlite, be sure to update these.
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct ThreadData;
|
||||
|
||||
/*
|
||||
/* FROM sqliteInt.h
|
||||
** ----------------
|
||||
** Some compilers do not support the "long long" datatype. So we have
|
||||
** to do a typedef that for 64-bit integers that depends on what compiler
|
||||
** is being used.
|
||||
|
@ -16,13 +65,23 @@ struct ThreadData;
|
|||
typedef unsigned long long int sqlite_uint64;
|
||||
#endif
|
||||
|
||||
/* FROM sqliteInt.h
|
||||
** ----------------
|
||||
** Call this to check for out of memory errors when returning.
|
||||
** See definition in util.c
|
||||
*/
|
||||
struct sqlite3;
|
||||
int sqlite3ApiExit(sqlite3 *db, int);
|
||||
|
||||
|
||||
/*
|
||||
** Forward declarations
|
||||
*/
|
||||
typedef struct OsFile OsFile;
|
||||
typedef struct IoMethod IoMethod;
|
||||
|
||||
/*
|
||||
/* FROM os.h
|
||||
** ---------
|
||||
** An instance of the following structure contains pointers to all
|
||||
** methods on an OsFile object.
|
||||
*/
|
||||
|
@ -43,7 +102,8 @@ struct IoMethod {
|
|||
int (*xCheckReservedLock)(OsFile *id);
|
||||
};
|
||||
|
||||
/*
|
||||
/* FROM os.h
|
||||
** ---------
|
||||
** The OsFile object describes an open disk file in an OS-dependent way.
|
||||
** The version of OsFile defined here is a generic version. Each OS
|
||||
** implementation defines its own subclass of this structure that contains
|
||||
|
@ -55,7 +115,8 @@ struct OsFile {
|
|||
IoMethod const *pMethod;
|
||||
};
|
||||
|
||||
/*
|
||||
/* FROM os.h
|
||||
** ---------
|
||||
** When redefinable I/O is enabled, a single global instance of the
|
||||
** following structure holds pointers to the routines that SQLite
|
||||
** uses to talk with the underlying operating system. Modify this
|
||||
|
@ -89,7 +150,9 @@ struct sqlite3OsVtbl {
|
|||
int (*xAllocationSize)(void *);
|
||||
};
|
||||
|
||||
/* Macro used to comment out routines that do not exists when there is
|
||||
/* FROM os.h
|
||||
** ---------
|
||||
** Macro used to comment out routines that do not exists when there is
|
||||
** no disk I/O
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_DISKIO
|
||||
|
@ -132,6 +195,10 @@ struct sqlite3OsVtbl {
|
|||
#endif /* _SQLITE_OS_C_ */
|
||||
|
||||
|
||||
/* This additional API routine is available with redefinable I/O */
|
||||
/* FROM os.h
|
||||
** ---------
|
||||
** This additional API routine is available with redefinable I/O
|
||||
*/
|
||||
struct sqlite3OsVtbl *sqlite3_os_switch(void);
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.479 2006/01/24 16:37:58 danielk1977 Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.486 2006/02/17 15:01:36 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
@ -251,12 +251,6 @@ struct BusyHandler {
|
|||
#include "btree.h"
|
||||
#include "pager.h"
|
||||
|
||||
/*
|
||||
** This macro casts a pointer to an integer. Useful for doing
|
||||
** pointer arithmetic.
|
||||
*/
|
||||
#define Addr(X) ((uptr)X)
|
||||
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
/*
|
||||
** The following global variables are used for testing and debugging
|
||||
|
@ -267,7 +261,6 @@ extern int sqlite3_nFree; /* Number of sqliteFree() calls */
|
|||
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
|
||||
|
||||
|
||||
extern void *sqlite3_pFirst; /* Pointer to linked list of allocations */
|
||||
extern int sqlite3_nMaxAlloc; /* High water mark of ThreadData.nAlloc */
|
||||
extern int sqlite3_mallocDisallowed; /* assert() in sqlite3Malloc() if set */
|
||||
|
@ -276,8 +269,8 @@ extern const char *sqlite3_zFile; /* Filename to associate debug info with */
|
|||
extern int sqlite3_iLine; /* Line number for debug info */
|
||||
|
||||
#define ENTER_MALLOC (sqlite3_zFile = __FILE__, sqlite3_iLine = __LINE__)
|
||||
#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x))
|
||||
#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x))
|
||||
#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x,1))
|
||||
#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x,1))
|
||||
#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y))
|
||||
#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x))
|
||||
#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y))
|
||||
|
@ -285,8 +278,9 @@ extern int sqlite3_iLine; /* Line number for debug info */
|
|||
|
||||
#else
|
||||
|
||||
#define sqliteMalloc(x) sqlite3Malloc(x)
|
||||
#define sqliteMallocRaw(x) sqlite3MallocRaw(x)
|
||||
#define ENTER_MALLOC 0
|
||||
#define sqliteMalloc(x) sqlite3Malloc(x,1)
|
||||
#define sqliteMallocRaw(x) sqlite3MallocRaw(x,1)
|
||||
#define sqliteRealloc(x,y) sqlite3Realloc(x,y)
|
||||
#define sqliteStrDup(x) sqlite3StrDup(x)
|
||||
#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y)
|
||||
|
@ -544,6 +538,7 @@ struct sqlite3 {
|
|||
#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
|
||||
#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
|
||||
#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
|
||||
#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
|
@ -1069,6 +1064,7 @@ struct SrcList {
|
|||
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
||||
Table *pTab; /* An SQL table corresponding to zName */
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
u8 isPopulated; /* Temporary table associated with SELECT is populated */
|
||||
u8 jointype; /* Type of join between this table and the next */
|
||||
i16 iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
|
@ -1481,8 +1477,8 @@ int sqlite3Compare(const char *, const char *);
|
|||
int sqlite3SortCompare(const char *, const char *);
|
||||
void sqlite3RealToSortable(double r, char *);
|
||||
|
||||
void *sqlite3Malloc(int);
|
||||
void *sqlite3MallocRaw(int);
|
||||
void *sqlite3Malloc(int,int);
|
||||
void *sqlite3MallocRaw(int,int);
|
||||
void sqlite3Free(void*);
|
||||
void *sqlite3Realloc(void*,int);
|
||||
char *sqlite3StrDup(const char*);
|
||||
|
@ -1748,6 +1744,7 @@ int sqlite3ApiExit(sqlite3 *db, int);
|
|||
int sqlite3MallocFailed(void);
|
||||
void sqlite3FailedMalloc(void);
|
||||
void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
|
||||
int sqlite3OpenTempDatabase(Parse *);
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
void sqlite3TableLock(Parse *, int, int, u8, const char *);
|
||||
|
@ -1765,6 +1762,14 @@ void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
|
|||
#define sqlite3MallocAllow()
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
void *sqlite3ThreadSafeMalloc(int);
|
||||
void sqlite3ThreadSafeFree(void *);
|
||||
#else
|
||||
#define sqlite3ThreadSafeMalloc sqlite3MallocX
|
||||
#define sqlite3ThreadSafeFree sqlite3FreeX
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
#include "sseInt.h"
|
||||
#endif
|
||||
|
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the sqlite3_get_table() and sqlite3_free_table()
|
||||
** interface routines. These are just wrappers around the main
|
||||
** interface routine of sqlite3_exec().
|
||||
**
|
||||
** These routines are in a separate files so that they will not be linked
|
||||
** if they are not used.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_GET_TABLE
|
||||
|
||||
/*
|
||||
** This structure is used to pass data from sqlite3_get_table() through
|
||||
** to the callback function is uses to build the result.
|
||||
*/
|
||||
typedef struct TabResult {
|
||||
char **azResult;
|
||||
char *zErrMsg;
|
||||
int nResult;
|
||||
int nAlloc;
|
||||
int nRow;
|
||||
int nColumn;
|
||||
int nData;
|
||||
int rc;
|
||||
} TabResult;
|
||||
|
||||
/*
|
||||
** This routine is called once for each row in the result table. Its job
|
||||
** is to fill in the TabResult structure appropriately, allocating new
|
||||
** memory as necessary.
|
||||
*/
|
||||
static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
TabResult *p = (TabResult*)pArg;
|
||||
int need;
|
||||
int i;
|
||||
char *z;
|
||||
|
||||
/* Make sure there is enough space in p->azResult to hold everything
|
||||
** we need to remember from this invocation of the callback.
|
||||
*/
|
||||
if( p->nRow==0 && argv!=0 ){
|
||||
need = nCol*2;
|
||||
}else{
|
||||
need = nCol;
|
||||
}
|
||||
if( p->nData + need >= p->nAlloc ){
|
||||
char **azNew;
|
||||
p->nAlloc = p->nAlloc*2 + need + 1;
|
||||
azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
if( azNew==0 ) goto malloc_failed;
|
||||
p->azResult = azNew;
|
||||
}
|
||||
|
||||
/* If this is the first row, then generate an extra row containing
|
||||
** the names of all columns.
|
||||
*/
|
||||
if( p->nRow==0 ){
|
||||
p->nColumn = nCol;
|
||||
for(i=0; i<nCol; i++){
|
||||
if( colv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
z = malloc( strlen(colv[i])+1 );
|
||||
if( z==0 ) goto malloc_failed;
|
||||
strcpy(z, colv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
}else if( p->nColumn!=nCol ){
|
||||
sqlite3SetString(&p->zErrMsg,
|
||||
"sqlite3_get_table() called with two or more incompatible queries",
|
||||
(char*)0);
|
||||
p->rc = SQLITE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy over the row data
|
||||
*/
|
||||
if( argv!=0 ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( argv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
z = malloc( strlen(argv[i])+1 );
|
||||
if( z==0 ) goto malloc_failed;
|
||||
strcpy(z, argv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
malloc_failed:
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the database. But instead of invoking a callback for each row,
|
||||
** malloc() for space to hold the result and return the entire results
|
||||
** at the conclusion of the call.
|
||||
**
|
||||
** The result that is written to ***pazResult is held in memory obtained
|
||||
** from malloc(). But the caller cannot free this memory directly.
|
||||
** Instead, the entire table should be passed to sqlite3_free_table() when
|
||||
** the calling procedure is finished using it.
|
||||
*/
|
||||
int sqlite3_get_table(
|
||||
sqlite3 *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
char ***pazResult, /* Write the result table here */
|
||||
int *pnRow, /* Write the number of rows in the result here */
|
||||
int *pnColumn, /* Write the number of columns of result here */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc;
|
||||
TabResult res;
|
||||
if( pazResult==0 ){ return SQLITE_ERROR; }
|
||||
*pazResult = 0;
|
||||
if( pnColumn ) *pnColumn = 0;
|
||||
if( pnRow ) *pnRow = 0;
|
||||
res.zErrMsg = 0;
|
||||
res.nResult = 0;
|
||||
res.nRow = 0;
|
||||
res.nColumn = 0;
|
||||
res.nData = 1;
|
||||
res.nAlloc = 20;
|
||||
res.rc = SQLITE_OK;
|
||||
res.azResult = malloc( sizeof(char*)*res.nAlloc );
|
||||
if( res.azResult==0 ) return SQLITE_NOMEM;
|
||||
res.azResult[0] = 0;
|
||||
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
|
||||
if( res.azResult ){
|
||||
res.azResult[0] = (char*)res.nData;
|
||||
}
|
||||
if( rc==SQLITE_ABORT ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
if( res.zErrMsg ){
|
||||
if( pzErrMsg ){
|
||||
free(*pzErrMsg);
|
||||
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
|
||||
}
|
||||
sqliteFree(res.zErrMsg);
|
||||
}
|
||||
db->errCode = res.rc;
|
||||
return res.rc;
|
||||
}
|
||||
sqliteFree(res.zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
return rc;
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
char **azNew;
|
||||
azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
|
||||
if( azNew==0 ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
res.nAlloc = res.nData+1;
|
||||
res.azResult = azNew;
|
||||
}
|
||||
*pazResult = &res.azResult[1];
|
||||
if( pnColumn ) *pnColumn = res.nColumn;
|
||||
if( pnRow ) *pnRow = res.nRow;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine frees the space the sqlite3_get_table() malloced.
|
||||
*/
|
||||
void sqlite3_free_table(
|
||||
char **azResult /* Result returned from from sqlite3_get_table() */
|
||||
){
|
||||
if( azResult ){
|
||||
int i, n;
|
||||
azResult--;
|
||||
if( azResult==0 ) return;
|
||||
n = (int)azResult[0];
|
||||
for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
|
||||
free(azResult);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_GET_TABLE */
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.150 2006/01/23 13:00:38 drh Exp $
|
||||
** $Id: tclsqlite.c,v 1.151 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
|
@ -1116,7 +1116,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
if( i+1!=nCol ){
|
||||
char *zErr;
|
||||
zErr = malloc(200 + strlen(zFile));
|
||||
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
|
||||
sprintf(zErr,
|
||||
"Error: %s line %d: expected %d columns of data but found %d",
|
||||
zFile, lineno, nCol, i+1);
|
||||
Tcl_AppendResult(interp, zErr, 0);
|
||||
free(zErr);
|
||||
|
|
|
@ -0,0 +1,485 @@
|
|||
/*
|
||||
** 2006 January 07
|
||||
**
|
||||
** 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 contains demonstration code. Nothing in this file gets compiled
|
||||
** or linked into the SQLite library unless you use a non-standard option:
|
||||
**
|
||||
** -DSQLITE_SERVER=1
|
||||
**
|
||||
** The configure script will never generate a Makefile with the option
|
||||
** above. You will need to manually modify the Makefile if you want to
|
||||
** include any of the code from this file in your project. Or, at your
|
||||
** option, you may copy and paste the code from this file and
|
||||
** thereby avoiding a recompile of SQLite.
|
||||
**
|
||||
**
|
||||
** This source file demonstrates how to use SQLite to create an SQL database
|
||||
** server thread in a multiple-threaded program. One or more client threads
|
||||
** send messages to the server thread and the server thread processes those
|
||||
** messages in the order received and returns the results to the client.
|
||||
**
|
||||
** One might ask: "Why bother? Why not just let each thread connect
|
||||
** to the database directly?" There are a several of reasons to
|
||||
** prefer the client/server approach.
|
||||
**
|
||||
** (1) Some systems (ex: Redhat9) have broken threading implementations
|
||||
** that prevent SQLite database connections from being used in
|
||||
** a thread different from the one where they were created. With
|
||||
** the client/server approach, all database connections are created
|
||||
** and used within the server thread. Client calls to the database
|
||||
** can be made from multiple threads (though not at the same time!)
|
||||
**
|
||||
** (2) Beginning with SQLite version 3.3.0, when two or more
|
||||
** connections to the same database occur within the same thread,
|
||||
** they can optionally share their database cache. This reduces
|
||||
** I/O and memory requirements. Cache shared is controlled using
|
||||
** the sqlite3_enable_shared_cache() API.
|
||||
**
|
||||
** (3) Database connections on a shared cache use table-level locking
|
||||
** instead of file-level locking for improved concurrency.
|
||||
**
|
||||
** (4) Database connections on a shared cache can by optionally
|
||||
** set to READ UNCOMMITTED isolation. (The default isolation for
|
||||
** SQLite is SERIALIZABLE.) When this occurs, readers will
|
||||
** never be blocked by a writer and writers will not be
|
||||
** blocked by readers. There can still only be a single writer
|
||||
** at a time, but multiple readers can simultaneously exist with
|
||||
** that writer. This is a huge increase in concurrency.
|
||||
**
|
||||
** To summarize the rational for using a client/server approach: prior
|
||||
** to SQLite version 3.3.0 it probably was not worth the trouble. But
|
||||
** with SQLite version 3.3.0 and beyond you can get significant performance
|
||||
** and concurrency improvements and memory usage reductions by going
|
||||
** client/server.
|
||||
**
|
||||
** Note: The extra features of version 3.3.0 described by points (2)
|
||||
** through (4) above are only available if you compile without the
|
||||
** option -DSQLITE_OMIT_SHARED_CACHE.
|
||||
**
|
||||
** Here is how the client/server approach works: The database server
|
||||
** thread is started on this procedure:
|
||||
**
|
||||
** void *sqlite3_server(void *NotUsed);
|
||||
**
|
||||
** The sqlite_server procedure runs as long as the g.serverHalt variable
|
||||
** is false. A mutex is used to make sure no more than one server runs
|
||||
** at a time. The server waits for messages to arrive on a message
|
||||
** queue and processes the messages in order.
|
||||
**
|
||||
** Two convenience routines are provided for starting and stopping the
|
||||
** server thread:
|
||||
**
|
||||
** void sqlite3_server_start(void);
|
||||
** void sqlite3_server_stop(void);
|
||||
**
|
||||
** Both of the convenience routines return immediately. Neither will
|
||||
** ever give an error. If a server is already started or already halted,
|
||||
** then the routines are effectively no-ops.
|
||||
**
|
||||
** Clients use the following interfaces:
|
||||
**
|
||||
** sqlite3_client_open
|
||||
** sqlite3_client_prepare
|
||||
** sqlite3_client_step
|
||||
** sqlite3_client_reset
|
||||
** sqlite3_client_finalize
|
||||
** sqlite3_client_close
|
||||
**
|
||||
** These interfaces work exactly like the standard core SQLite interfaces
|
||||
** having the same names without the "_client_" infix. Many other SQLite
|
||||
** interfaces can be used directly without having to send messages to the
|
||||
** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined.
|
||||
** The following interfaces fall into this second category:
|
||||
**
|
||||
** sqlite3_bind_*
|
||||
** sqlite3_changes
|
||||
** sqlite3_clear_bindings
|
||||
** sqlite3_column_*
|
||||
** sqlite3_complete
|
||||
** sqlite3_create_collation
|
||||
** sqlite3_create_function
|
||||
** sqlite3_data_count
|
||||
** sqlite3_db_handle
|
||||
** sqlite3_errcode
|
||||
** sqlite3_errmsg
|
||||
** sqlite3_last_insert_rowid
|
||||
** sqlite3_total_changes
|
||||
** sqlite3_transfer_bindings
|
||||
**
|
||||
** A single SQLite connection (an sqlite3* object) or an SQLite statement
|
||||
** (an sqlite3_stmt* object) should only be passed to a single interface
|
||||
** function at a time. The connections and statements can be passed from
|
||||
** any thread to any of the functions listed in the second group above as
|
||||
** long as the same connection is not in use by two threads at once and
|
||||
** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional
|
||||
** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is
|
||||
** below.
|
||||
**
|
||||
** The busy handler for all database connections should remain turned
|
||||
** off. That means that any lock contention will cause the associated
|
||||
** sqlite3_client_step() call to return immediately with an SQLITE_BUSY
|
||||
** error code. If a busy handler is enabled and lock contention occurs,
|
||||
** then the entire server thread will block. This will cause not only
|
||||
** the requesting client to block but every other database client as
|
||||
** well. It is possible to enhance the code below so that lock
|
||||
** contention will cause the message to be placed back on the top of
|
||||
** the queue to be tried again later. But such enhanced processing is
|
||||
** not included here, in order to keep the example simple.
|
||||
**
|
||||
** This example code assumes the use of pthreads. Pthreads
|
||||
** implementations are available for windows. (See, for example
|
||||
** http://sourceware.org/pthreads-win32/announcement.html.) Or, you
|
||||
** can translate the locking and thread synchronization code to use
|
||||
** windows primitives easily enough. The details are left as an
|
||||
** exercise to the reader.
|
||||
**
|
||||
**** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT ****
|
||||
**
|
||||
** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then
|
||||
** SQLite includes code that tracks how much memory is being used by
|
||||
** each thread. These memory counts can become confused if memory
|
||||
** is allocated by one thread and then freed by another. For that
|
||||
** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations
|
||||
** that might allocate or free memory should be performanced in the same
|
||||
** thread that originally created the database connection. In that case,
|
||||
** many of the operations that are listed above as safe to be performed
|
||||
** in separate threads would need to be sent over to the server to be
|
||||
** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then
|
||||
** the following functions can be used safely from different threads
|
||||
** without messing up the allocation counts:
|
||||
**
|
||||
** sqlite3_bind_parameter_name
|
||||
** sqlite3_bind_parameter_index
|
||||
** sqlite3_changes
|
||||
** sqlite3_column_blob
|
||||
** sqlite3_column_count
|
||||
** sqlite3_complete
|
||||
** sqlite3_data_count
|
||||
** sqlite3_db_handle
|
||||
** sqlite3_errcode
|
||||
** sqlite3_errmsg
|
||||
** sqlite3_last_insert_rowid
|
||||
** sqlite3_total_changes
|
||||
**
|
||||
** The remaining functions are not thread-safe when memory management
|
||||
** is enabled. So one would have to define some new interface routines
|
||||
** along the following lines:
|
||||
**
|
||||
** sqlite3_client_bind_*
|
||||
** sqlite3_client_clear_bindings
|
||||
** sqlite3_client_column_*
|
||||
** sqlite3_client_create_collation
|
||||
** sqlite3_client_create_function
|
||||
** sqlite3_client_transfer_bindings
|
||||
**
|
||||
** The example code in this file is intended for use with memory
|
||||
** management turned off. So the implementation of these additional
|
||||
** client interfaces is left as an exercise to the reader.
|
||||
**
|
||||
** It may seem surprising to the reader that the list of safe functions
|
||||
** above does not include things like sqlite3_bind_int() or
|
||||
** sqlite3_column_int(). But those routines might, in fact, allocate
|
||||
** or deallocate memory. In the case of sqlite3_bind_int(), if the
|
||||
** parameter was previously bound to a string that string might need
|
||||
** to be deallocated before the new integer value is inserted. In
|
||||
** the case of sqlite3_column_int(), the value of the column might be
|
||||
** a UTF-16 string which will need to be converted to UTF-8 then into
|
||||
** an integer.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Only compile the code in this file on UNIX with a THREADSAFE build
|
||||
** and only if the SQLITE_SERVER macro is defined.
|
||||
*/
|
||||
#ifdef SQLITE_SERVER
|
||||
#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE
|
||||
|
||||
/*
|
||||
** We require only pthreads and the public interface of SQLite.
|
||||
*/
|
||||
#include <pthread.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Messages are passed from client to server and back again as
|
||||
** instances of the following structure.
|
||||
*/
|
||||
typedef struct SqlMessage SqlMessage;
|
||||
struct SqlMessage {
|
||||
int op; /* Opcode for the message */
|
||||
sqlite3 *pDb; /* The SQLite connection */
|
||||
sqlite3_stmt *pStmt; /* A specific statement */
|
||||
int errCode; /* Error code returned */
|
||||
const char *zIn; /* Input filename or SQL statement */
|
||||
int nByte; /* Size of the zIn parameter for prepare() */
|
||||
const char *zOut; /* Tail of the SQL statement */
|
||||
SqlMessage *pNext; /* Next message in the queue */
|
||||
SqlMessage *pPrev; /* Previous message in the queue */
|
||||
pthread_mutex_t clientMutex; /* Hold this mutex to access the message */
|
||||
pthread_cond_t clientWakeup; /* Signal to wake up the client */
|
||||
};
|
||||
|
||||
/*
|
||||
** Legal values for SqlMessage.op
|
||||
*/
|
||||
#define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */
|
||||
#define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */
|
||||
#define MSG_Step 3 /* sqlite3_step(pStmt) */
|
||||
#define MSG_Reset 4 /* sqlite3_reset(pStmt) */
|
||||
#define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */
|
||||
#define MSG_Close 6 /* sqlite3_close(pDb) */
|
||||
#define MSG_Done 7 /* Server has finished with this message */
|
||||
|
||||
|
||||
/*
|
||||
** State information about the server is stored in a static variable
|
||||
** named "g" as follows:
|
||||
*/
|
||||
static struct ServerState {
|
||||
pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */
|
||||
pthread_mutex_t serverMutex; /* Held by the server while it is running */
|
||||
pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */
|
||||
volatile int serverHalt; /* Server halts itself when true */
|
||||
SqlMessage *pQueueHead; /* Head of the message queue */
|
||||
SqlMessage *pQueueTail; /* Tail of the message queue */
|
||||
} g = {
|
||||
PTHREAD_MUTEX_INITIALIZER,
|
||||
PTHREAD_MUTEX_INITIALIZER,
|
||||
PTHREAD_COND_INITIALIZER,
|
||||
};
|
||||
|
||||
/*
|
||||
** Send a message to the server. Block until we get a reply.
|
||||
**
|
||||
** The mutex and condition variable in the message are uninitialized
|
||||
** when this routine is called. This routine takes care of
|
||||
** initializing them and destroying them when it has finished.
|
||||
*/
|
||||
static void sendToServer(SqlMessage *pMsg){
|
||||
/* Initialize the mutex and condition variable on the message
|
||||
*/
|
||||
pthread_mutex_init(&pMsg->clientMutex, 0);
|
||||
pthread_cond_init(&pMsg->clientWakeup, 0);
|
||||
|
||||
/* Add the message to the head of the server's message queue.
|
||||
*/
|
||||
pthread_mutex_lock(&g.queueMutex);
|
||||
pMsg->pNext = g.pQueueHead;
|
||||
if( g.pQueueHead==0 ){
|
||||
g.pQueueTail = pMsg;
|
||||
}else{
|
||||
g.pQueueHead->pPrev = pMsg;
|
||||
}
|
||||
pMsg->pPrev = 0;
|
||||
g.pQueueHead = pMsg;
|
||||
pthread_mutex_unlock(&g.queueMutex);
|
||||
|
||||
/* Signal the server that the new message has be queued, then
|
||||
** block waiting for the server to process the message.
|
||||
*/
|
||||
pthread_mutex_lock(&pMsg->clientMutex);
|
||||
pthread_cond_signal(&g.serverWakeup);
|
||||
while( pMsg->op!=MSG_Done ){
|
||||
pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex);
|
||||
}
|
||||
pthread_mutex_unlock(&pMsg->clientMutex);
|
||||
|
||||
/* Destroy the mutex and condition variable of the message.
|
||||
*/
|
||||
pthread_mutex_destroy(&pMsg->clientMutex);
|
||||
pthread_cond_destroy(&pMsg->clientWakeup);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following 6 routines are client-side implementations of the
|
||||
** core SQLite interfaces:
|
||||
**
|
||||
** sqlite3_open
|
||||
** sqlite3_prepare
|
||||
** sqlite3_step
|
||||
** sqlite3_reset
|
||||
** sqlite3_finalize
|
||||
** sqlite3_close
|
||||
**
|
||||
** Clients should use the following client-side routines instead of
|
||||
** the core routines above.
|
||||
**
|
||||
** sqlite3_client_open
|
||||
** sqlite3_client_prepare
|
||||
** sqlite3_client_step
|
||||
** sqlite3_client_reset
|
||||
** sqlite3_client_finalize
|
||||
** sqlite3_client_close
|
||||
**
|
||||
** Each of these routines creates a message for the desired operation,
|
||||
** sends that message to the server, waits for the server to process
|
||||
** then message and return a response.
|
||||
*/
|
||||
int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){
|
||||
SqlMessage msg;
|
||||
msg.op = MSG_Open;
|
||||
msg.zIn = zDatabaseName;
|
||||
sendToServer(&msg);
|
||||
*ppDb = msg.pDb;
|
||||
return msg.errCode;
|
||||
}
|
||||
int sqlite3_client_prepare(
|
||||
sqlite3 *pDb,
|
||||
const char *zSql,
|
||||
int nByte,
|
||||
sqlite3_stmt **ppStmt,
|
||||
const char **pzTail
|
||||
){
|
||||
SqlMessage msg;
|
||||
msg.op = MSG_Prepare;
|
||||
msg.pDb = pDb;
|
||||
msg.zIn = zSql;
|
||||
msg.nByte = nByte;
|
||||
sendToServer(&msg);
|
||||
*ppStmt = msg.pStmt;
|
||||
if( pzTail ) *pzTail = msg.zOut;
|
||||
return msg.errCode;
|
||||
}
|
||||
int sqlite3_client_step(sqlite3_stmt *pStmt){
|
||||
SqlMessage msg;
|
||||
msg.op = MSG_Step;
|
||||
msg.pStmt = pStmt;
|
||||
sendToServer(&msg);
|
||||
return msg.errCode;
|
||||
}
|
||||
int sqlite3_client_reset(sqlite3_stmt *pStmt){
|
||||
SqlMessage msg;
|
||||
msg.op = MSG_Reset;
|
||||
msg.pStmt = pStmt;
|
||||
sendToServer(&msg);
|
||||
return msg.errCode;
|
||||
}
|
||||
int sqlite3_client_finalize(sqlite3_stmt *pStmt){
|
||||
SqlMessage msg;
|
||||
msg.op = MSG_Finalize;
|
||||
msg.pStmt = pStmt;
|
||||
sendToServer(&msg);
|
||||
return msg.errCode;
|
||||
}
|
||||
int sqlite3_client_close(sqlite3 *pDb){
|
||||
SqlMessage msg;
|
||||
msg.op = MSG_Close;
|
||||
msg.pDb = pDb;
|
||||
sendToServer(&msg);
|
||||
return msg.errCode;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine implements the server. To start the server, first
|
||||
** make sure g.serverHalt is false, then create a new detached thread
|
||||
** on this procedure. See the sqlite3_server_start() routine below
|
||||
** for an example. This procedure loops until g.serverHalt becomes
|
||||
** true.
|
||||
*/
|
||||
void *sqlite3_server(void *NotUsed){
|
||||
sqlite3_enable_shared_cache(1);
|
||||
if( pthread_mutex_trylock(&g.serverMutex) ){
|
||||
sqlite3_enable_shared_cache(0);
|
||||
return 0; /* Another server is already running */
|
||||
}
|
||||
while( !g.serverHalt ){
|
||||
SqlMessage *pMsg;
|
||||
|
||||
/* Remove the last message from the message queue.
|
||||
*/
|
||||
pthread_mutex_lock(&g.queueMutex);
|
||||
while( g.pQueueTail==0 && g.serverHalt==0 ){
|
||||
pthread_cond_wait(&g.serverWakeup, &g.queueMutex);
|
||||
}
|
||||
pMsg = g.pQueueTail;
|
||||
if( pMsg ){
|
||||
if( pMsg->pPrev ){
|
||||
pMsg->pPrev->pNext = 0;
|
||||
}else{
|
||||
g.pQueueHead = 0;
|
||||
}
|
||||
g.pQueueTail = pMsg->pPrev;
|
||||
}
|
||||
pthread_mutex_unlock(&g.queueMutex);
|
||||
if( pMsg==0 ) break;
|
||||
|
||||
/* Process the message just removed
|
||||
*/
|
||||
pthread_mutex_lock(&pMsg->clientMutex);
|
||||
switch( pMsg->op ){
|
||||
case MSG_Open: {
|
||||
pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb);
|
||||
break;
|
||||
}
|
||||
case MSG_Prepare: {
|
||||
pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte,
|
||||
&pMsg->pStmt, &pMsg->zOut);
|
||||
break;
|
||||
}
|
||||
case MSG_Step: {
|
||||
pMsg->errCode = sqlite3_step(pMsg->pStmt);
|
||||
break;
|
||||
}
|
||||
case MSG_Reset: {
|
||||
pMsg->errCode = sqlite3_reset(pMsg->pStmt);
|
||||
break;
|
||||
}
|
||||
case MSG_Finalize: {
|
||||
pMsg->errCode = sqlite3_finalize(pMsg->pStmt);
|
||||
break;
|
||||
}
|
||||
case MSG_Close: {
|
||||
pMsg->errCode = sqlite3_close(pMsg->pDb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal the client that the message has been processed.
|
||||
*/
|
||||
pMsg->op = MSG_Done;
|
||||
pthread_mutex_unlock(&pMsg->clientMutex);
|
||||
pthread_cond_signal(&pMsg->clientWakeup);
|
||||
}
|
||||
pthread_mutex_unlock(&g.serverMutex);
|
||||
sqlite3_thread_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Start a server thread if one is not already running. If there
|
||||
** is aleady a server thread running, the new thread will quickly
|
||||
** die and this routine is effectively a no-op.
|
||||
*/
|
||||
void sqlite3_server_start(void){
|
||||
pthread_t x;
|
||||
int rc;
|
||||
g.serverHalt = 0;
|
||||
rc = pthread_create(&x, 0, sqlite3_server, 0);
|
||||
if( rc==0 ){
|
||||
pthread_detach(x);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If a server thread is running, then stop it. If no server is
|
||||
** running, this routine is effectively a no-op.
|
||||
**
|
||||
** This routine returns immediately without waiting for the server
|
||||
** thread to stop. But be assured that the server will eventually stop.
|
||||
*/
|
||||
void sqlite3_server_stop(void){
|
||||
g.serverHalt = 1;
|
||||
pthread_cond_broadcast(&g.serverWakeup);
|
||||
}
|
||||
|
||||
#endif /* defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE */
|
||||
#endif /* defined(SQLITE_SERVER) */
|
|
@ -15,7 +15,7 @@
|
|||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.116 2006/01/20 17:56:33 drh Exp $
|
||||
** $Id: tokenize.c,v 1.117 2006/02/09 22:24:41 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -261,6 +261,7 @@ static int getToken(const unsigned char *z, int *tokenType){
|
|||
#ifndef SQLITE_OMIT_TCL_VARIABLE
|
||||
case '$':
|
||||
#endif
|
||||
case '@': /* For compatibility with MS SQL Server */
|
||||
case ':': {
|
||||
int n = 0;
|
||||
*tokenType = TK_VARIABLE;
|
||||
|
|
|
@ -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.121 2006/01/18 16:51:36 danielk1977 Exp $
|
||||
** $Id: update.c,v 1.122 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -494,7 +494,7 @@ void sqlite3Update(
|
|||
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
|
||||
}
|
||||
|
||||
update_cleanup:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.182 2006/01/23 15:39:59 drh Exp $
|
||||
** $Id: util.c,v 1.185 2006/02/14 10:48:39 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -443,6 +443,7 @@ int sqlite3OutstandingMallocs(Tcl_Interp *interp){
|
|||
** This is the test layer's wrapper around sqlite3OsMalloc().
|
||||
*/
|
||||
static void * OSMALLOC(int n){
|
||||
sqlite3OsEnterMutex();
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
sqlite3_nMaxAlloc =
|
||||
MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
|
||||
|
@ -455,8 +456,10 @@ static void * OSMALLOC(int n){
|
|||
sqlite3_nMalloc++;
|
||||
applyGuards(p);
|
||||
linkAlloc(p);
|
||||
sqlite3OsLeaveMutex();
|
||||
return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
|
||||
}
|
||||
sqlite3OsLeaveMutex();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -473,12 +476,14 @@ static int OSSIZEOF(void *p){
|
|||
** pointer to the space allocated for the application to use.
|
||||
*/
|
||||
static void OSFREE(void *pFree){
|
||||
sqlite3OsEnterMutex();
|
||||
u32 *p = (u32 *)getOsPointer(pFree); /* p points to Os level allocation */
|
||||
checkGuards(p);
|
||||
unlinkAlloc(p);
|
||||
memset(pFree, 0x55, OSSIZEOF(pFree));
|
||||
sqlite3OsFree(p);
|
||||
sqlite3_nFree++;
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -521,34 +526,56 @@ static void OSMALLOC_FAILED(){
|
|||
**--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
** The handleSoftLimit() function is called before each call to
|
||||
** sqlite3OsMalloc() or xRealloc(). The parameter 'n' is the number of
|
||||
** extra bytes about to be allocated (for Realloc() this means the size of the
|
||||
** new allocation less the size of the old allocation). If the extra allocation
|
||||
** means that the total memory allocated to SQLite in this thread would exceed
|
||||
** the limit set by sqlite3_soft_heap_limit(), then sqlite3_release_memory() is
|
||||
** called to try to avoid this. No indication of whether or not this is
|
||||
** successful is returned to the caller.
|
||||
** This routine is called when we are about to allocate n additional bytes
|
||||
** of memory. If the new allocation will put is over the soft allocation
|
||||
** limit, then invoke sqlite3_release_memory() to try to release some
|
||||
** memory before continuing with the allocation.
|
||||
**
|
||||
** This routine also makes sure that the thread-specific-data (TSD) has
|
||||
** be allocated. If it has not and can not be allocated, then return
|
||||
** false. The updateMemoryUsedCount() routine below will deallocate
|
||||
** the TSD if it ought to be.
|
||||
**
|
||||
** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
|
||||
** a no-op
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
static int enforceSoftLimit(int n){
|
||||
ThreadData *pTsd = sqlite3ThreadData();
|
||||
if( pTsd==0 ){
|
||||
return 0;
|
||||
}
|
||||
assert( pTsd->nAlloc>=0 );
|
||||
if( n>0 && pTsd->nSoftHeapLimit>0 ){
|
||||
while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
# define enforceSoftLimit(X) 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Update the count of total outstanding memory that is held in
|
||||
** thread-specific-data (TSD). If after this update the TSD is
|
||||
** no longer being used, then deallocate it.
|
||||
**
|
||||
** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
|
||||
** a no-op
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
static int handleSoftLimit(int n){
|
||||
static void updateMemoryUsedCount(int n){
|
||||
ThreadData *pTsd = sqlite3ThreadData();
|
||||
if( pTsd ){
|
||||
pTsd->nAlloc += n;
|
||||
assert( pTsd->nAlloc>=0 );
|
||||
if( n>0 && pTsd->nSoftHeapLimit>0 ){
|
||||
while( pTsd->nAlloc>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) );
|
||||
}else if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){
|
||||
if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){
|
||||
sqlite3ReleaseThreadData();
|
||||
}
|
||||
}
|
||||
return (pTsd ? 0 : 1);
|
||||
}
|
||||
#else
|
||||
#define handleSoftLimit(x) 0
|
||||
#define updateMemoryUsedCount(x) /* no-op */
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -556,19 +583,15 @@ static int handleSoftLimit(int n){
|
|||
** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory
|
||||
** by calling sqlite3_release_memory().
|
||||
*/
|
||||
void *sqlite3MallocRaw(int n){
|
||||
void *sqlite3MallocRaw(int n, int doMemManage){
|
||||
void *p = 0;
|
||||
if( n>0 && !sqlite3MallocFailed() && !handleSoftLimit(n) ){
|
||||
if( n>0 && !sqlite3MallocFailed() && (!doMemManage || enforceSoftLimit(n)) ){
|
||||
while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) );
|
||||
if( !p ){
|
||||
/* If the allocation failed, call handleSoftLimit() again, this time
|
||||
** with the additive inverse of the argument passed to
|
||||
** handleSoftLimit() above. This is so the ThreadData.nAlloc variable is
|
||||
** still correct after a malloc() failure.
|
||||
*/
|
||||
(void)handleSoftLimit(n * -1);
|
||||
sqlite3FailedMalloc();
|
||||
OSMALLOC_FAILED();
|
||||
}else if( doMemManage ){
|
||||
updateMemoryUsedCount(OSSIZEOF(p));
|
||||
}
|
||||
}
|
||||
return p;
|
||||
|
@ -585,20 +608,19 @@ void *sqlite3Realloc(void *p, int n){
|
|||
}
|
||||
|
||||
if( !p ){
|
||||
return sqlite3Malloc(n);
|
||||
return sqlite3Malloc(n, 1);
|
||||
}else{
|
||||
void *np = 0;
|
||||
if( !handleSoftLimit(n - OSSIZEOF(p)) ){
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
int origSize = OSSIZEOF(p);
|
||||
#endif
|
||||
if( enforceSoftLimit(n - origSize) ){
|
||||
while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) );
|
||||
if( !np ){
|
||||
/* If the allocation failed, call handleSoftLimit() again, this time
|
||||
** with the additive inverse of the argument passed to
|
||||
** handleSoftLimit() above. This is so the ThreadData.nAlloc variable is
|
||||
** still correct after a malloc() failure.
|
||||
*/
|
||||
(void)handleSoftLimit(OSSIZEOF(p) - n);
|
||||
sqlite3FailedMalloc();
|
||||
OSMALLOC_FAILED();
|
||||
}else{
|
||||
updateMemoryUsedCount(OSSIZEOF(np) - origSize);
|
||||
}
|
||||
}
|
||||
return np;
|
||||
|
@ -610,8 +632,8 @@ void *sqlite3Realloc(void *p, int n){
|
|||
** value returned by a previous call to sqlite3Malloc() or sqlite3Realloc().
|
||||
*/
|
||||
void sqlite3FreeX(void *p){
|
||||
(void)handleSoftLimit(0 - OSSIZEOF(p));
|
||||
if( p ){
|
||||
updateMemoryUsedCount(0 - OSSIZEOF(p));
|
||||
OSFREE(p);
|
||||
}
|
||||
}
|
||||
|
@ -631,8 +653,8 @@ void *sqlite3MallocX(int n){
|
|||
** These two are implemented as wrappers around sqlite3MallocRaw(),
|
||||
** sqlite3Realloc() and sqlite3Free().
|
||||
*/
|
||||
void *sqlite3Malloc(int n){
|
||||
void *p = sqlite3MallocRaw(n);
|
||||
void *sqlite3Malloc(int n, int doMemManage){
|
||||
void *p = sqlite3MallocRaw(n, doMemManage);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
}
|
||||
|
@ -646,6 +668,33 @@ void sqlite3ReallocOrFree(void **pp, int n){
|
|||
*pp = p;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3ThreadSafeMalloc() and sqlite3ThreadSafeFree() are used in those
|
||||
** rare scenarios where sqlite may allocate memory in one thread and free
|
||||
** it in another. They are exactly the same as sqlite3Malloc() and
|
||||
** sqlite3Free() except that:
|
||||
**
|
||||
** * The allocated memory is not included in any calculations with
|
||||
** respect to the soft-heap-limit, and
|
||||
**
|
||||
** * sqlite3ThreadSafeMalloc() must be matched with ThreadSafeFree(),
|
||||
** not sqlite3Free(). Calling sqlite3Free() on memory obtained from
|
||||
** ThreadSafeMalloc() will cause an error somewhere down the line.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
void *sqlite3ThreadSafeMalloc(int n){
|
||||
ENTER_MALLOC;
|
||||
return sqlite3Malloc(n, 0);
|
||||
}
|
||||
void sqlite3ThreadSafeFree(void *p){
|
||||
ENTER_MALLOC;
|
||||
if( p ){
|
||||
OSFREE(p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Return the number of bytes allocated at location p. p must be either
|
||||
** a NULL pointer (in which case 0 is returned) or a pointer returned by
|
||||
|
@ -672,14 +721,14 @@ int sqlite3AllocSize(void *p){
|
|||
char *sqlite3StrDup(const char *z){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqlite3MallocRaw(strlen(z)+1);
|
||||
zNew = sqlite3MallocRaw(strlen(z)+1, 1);
|
||||
if( zNew ) strcpy(zNew, z);
|
||||
return zNew;
|
||||
}
|
||||
char *sqlite3StrNDup(const char *z, int n){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqlite3MallocRaw(n+1);
|
||||
zNew = sqlite3MallocRaw(n+1, 1);
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, n);
|
||||
zNew[n] = 0;
|
||||
|
|
|
@ -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.540 2006/01/30 15:34:23 drh Exp $
|
||||
** $Id: vdbe.c,v 1.543 2006/02/10 14:02:07 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -189,6 +189,31 @@ static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
|
|||
return pCx;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to convert a value into a numeric representation if we can
|
||||
** do so without loss of information. In other words, if the string
|
||||
** looks like a number, convert it into a number. If it does not
|
||||
** look like a number, leave it alone.
|
||||
*/
|
||||
static void applyNumericAffinity(Mem *pRec){
|
||||
if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
|
||||
int realnum;
|
||||
sqlite3VdbeMemNulTerminate(pRec);
|
||||
if( (pRec->flags&MEM_Str)
|
||||
&& sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
|
||||
i64 value;
|
||||
sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
|
||||
if( !realnum && sqlite3atoi64(pRec->z, &value) ){
|
||||
sqlite3VdbeMemRelease(pRec);
|
||||
pRec->i = value;
|
||||
pRec->flags = MEM_Int;
|
||||
}else{
|
||||
sqlite3VdbeMemRealify(pRec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Processing is determine by the affinity parameter:
|
||||
**
|
||||
|
@ -220,31 +245,28 @@ static void applyAffinity(Mem *pRec, char affinity, u8 enc){
|
|||
}else if( affinity!=SQLITE_AFF_NONE ){
|
||||
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|
||||
|| affinity==SQLITE_AFF_NUMERIC );
|
||||
if( 0==(pRec->flags&(MEM_Real|MEM_Int)) ){
|
||||
/* pRec does not have a valid integer or real representation.
|
||||
** Attempt a conversion if pRec has a string representation and
|
||||
** it looks like a number.
|
||||
*/
|
||||
int realnum;
|
||||
sqlite3VdbeMemNulTerminate(pRec);
|
||||
if( (pRec->flags&MEM_Str)
|
||||
&& sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
|
||||
i64 value;
|
||||
sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
|
||||
if( !realnum && sqlite3atoi64(pRec->z, &value) ){
|
||||
sqlite3VdbeMemRelease(pRec);
|
||||
pRec->i = value;
|
||||
pRec->flags = MEM_Int;
|
||||
}else{
|
||||
sqlite3VdbeMemNumerify(pRec);
|
||||
}
|
||||
}
|
||||
}else if( pRec->flags & MEM_Real ){
|
||||
applyNumericAffinity(pRec);
|
||||
if( pRec->flags & MEM_Real ){
|
||||
sqlite3VdbeIntegerAffinity(pRec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to convert the type of a function argument or a result column
|
||||
** into a numeric representation. Use either INTEGER or REAL whichever
|
||||
** is appropriate. But only do the conversion if it is possible without
|
||||
** loss of information and return the revised type of the argument.
|
||||
**
|
||||
** This is an EXPERIMENTAL api and is subject to change or removal.
|
||||
*/
|
||||
int sqlite3_value_numeric_type(sqlite3_value *pVal){
|
||||
Mem *pMem = (Mem*)pVal;
|
||||
applyNumericAffinity(pMem);
|
||||
storeTypeInfo(pMem, 0);
|
||||
return pMem->type;
|
||||
}
|
||||
|
||||
/*
|
||||
** Exported version of applyAffinity(). This one works on sqlite3_value*,
|
||||
** not the internal Mem* type.
|
||||
|
@ -1965,6 +1987,7 @@ case OP_Column: {
|
|||
u8 *zIdx; /* Index into header */
|
||||
u8 *zEndHdr; /* Pointer to first byte after the header */
|
||||
u32 offset; /* Offset into the data */
|
||||
int szHdrSz; /* Size of the header size field at start of record */
|
||||
int avail; /* Number of bytes of available data */
|
||||
if( pC && pC->aType ){
|
||||
aType = pC->aType;
|
||||
|
@ -1997,7 +2020,8 @@ case OP_Column: {
|
|||
pC->aRow = 0;
|
||||
}
|
||||
}
|
||||
zIdx = (u8 *)GetVarint((u8*)zData, offset);
|
||||
assert( zRec!=0 || avail>=payloadSize || avail>=9 );
|
||||
szHdrSz = GetVarint((u8*)zData, offset);
|
||||
|
||||
/* The KeyFetch() or DataFetch() above are fast and will get the entire
|
||||
** record header in most cases. But they will fail to get the complete
|
||||
|
@ -2012,8 +2036,8 @@ case OP_Column: {
|
|||
}
|
||||
zData = sMem.z;
|
||||
}
|
||||
zEndHdr = (u8 *)zData + offset;
|
||||
zIdx = (u8 *)zData + (int)zIdx;
|
||||
zEndHdr = (u8 *)&zData[offset];
|
||||
zIdx = (u8 *)&zData[szHdrSz];
|
||||
|
||||
/* Scan the header and use it to fill in the aType[] and aOffset[]
|
||||
** arrays. aType[i] will contain the type integer for the i-th
|
||||
|
@ -3815,7 +3839,7 @@ case OP_IdxGE: { /* no-push */
|
|||
assert( p->apCsr[i]!=0 );
|
||||
assert( pTos>=p->aStack );
|
||||
if( (pC = p->apCsr[i])->pCursor!=0 ){
|
||||
int res, rc;
|
||||
int res;
|
||||
|
||||
assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
|
||||
Stringify(pTos, encoding);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
** 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.99 2005/09/20 17:42:23 drh Exp $
|
||||
** $Id: vdbe.h,v 1.101 2006/02/10 03:06:10 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
|
@ -69,6 +69,7 @@ typedef struct VdbeOpList VdbeOpList;
|
|||
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
|
||||
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
|
||||
#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */
|
||||
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
|
||||
|
||||
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
|
||||
** is made. That copy is freed when the Vdbe is finalized. But if the
|
||||
|
@ -79,6 +80,17 @@ typedef struct VdbeOpList VdbeOpList;
|
|||
*/
|
||||
#define P3_KEYINFO_HANDOFF (-9)
|
||||
|
||||
/*
|
||||
** The Vdbe.aColName array contains 5n Mem structures, where n is the
|
||||
** number of columns of data returned by the statement.
|
||||
*/
|
||||
#define COLNAME_NAME 0
|
||||
#define COLNAME_DECLTYPE 1
|
||||
#define COLNAME_DATABASE 2
|
||||
#define COLNAME_TABLE 3
|
||||
#define COLNAME_COLUMN 4
|
||||
#define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
|
||||
|
||||
/*
|
||||
** The following macro converts a relative address in the p2 field
|
||||
** of a VdbeOp structure into a negative number so that
|
||||
|
@ -117,7 +129,7 @@ void sqlite3VdbeTrace(Vdbe*,FILE*);
|
|||
int sqlite3VdbeReset(Vdbe*);
|
||||
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
|
||||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
|
||||
void sqlite3VdbeCountChanges(Vdbe*);
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){
|
|||
int sqlite3_value_type(sqlite3_value* pVal){
|
||||
return pVal->type;
|
||||
}
|
||||
/* sqlite3_value_numeric_type() defined in vdbe.c */
|
||||
|
||||
/**************************** sqlite3_result_ *******************************
|
||||
** The following routines are used by user-defined functions to specify
|
||||
|
@ -335,9 +336,10 @@ void sqlite3_set_auxdata(
|
|||
** Return the number of times the Step function of a aggregate has been
|
||||
** called.
|
||||
**
|
||||
** This routine is defined here in vdbe.c because it depends on knowing
|
||||
** the internals of the sqlite3_context structure which is only defined in
|
||||
** this source file.
|
||||
** This function is deprecated. Do not use it for new code. It is
|
||||
** provide only to avoid breaking legacy code. New aggregate function
|
||||
** implementations should keep their own counts within their aggregate
|
||||
** context.
|
||||
*/
|
||||
int sqlite3_aggregate_count(sqlite3_context *p){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
|
@ -468,6 +470,13 @@ int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
|
|||
return sqlite3_value_type( columnMem(pStmt,i) );
|
||||
}
|
||||
|
||||
/* The following function is experimental and subject to change or
|
||||
** removal */
|
||||
/*int sqlite3_column_numeric_type(sqlite3_stmt *pStmt, int i){
|
||||
** return sqlite3_value_numeric_type( columnMem(pStmt,i) );
|
||||
**}
|
||||
*/
|
||||
|
||||
/*
|
||||
** Convert the N-th element of pStmt->pColName[] into a string using
|
||||
** xFunc() then return that string. If N is out of range, return 0.
|
||||
|
@ -512,11 +521,13 @@ static const void *columnName(
|
|||
** statement pStmt.
|
||||
*/
|
||||
const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -525,26 +536,30 @@ const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
|
|||
** of the result set of SQL statement pStmt.
|
||||
*/
|
||||
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
#if !defined(SQLITE_OMIT_ORIGIN_NAMES) && 0
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
/*
|
||||
** Return the name of the database from which a result column derives.
|
||||
** NULL is returned if the result column is an expression or constant or
|
||||
** anything else which is not an unabiguous reference to a database column.
|
||||
*/
|
||||
const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 2);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 2);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
|
@ -554,11 +569,13 @@ const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
|
|||
** anything else which is not an unabiguous reference to a database column.
|
||||
*/
|
||||
const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 3);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 3);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
|
@ -568,16 +585,16 @@ const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
|
|||
** anything else which is not an unabiguous reference to a database column.
|
||||
*/
|
||||
const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 4);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 4);
|
||||
return columnName(
|
||||
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
#endif /* SQLITE_OMIT_ORIGIN_NAMES */
|
||||
|
||||
|
||||
#endif /* SQLITE_ENABLE_COLUMN_METADATA */
|
||||
|
||||
|
||||
/******************************* sqlite3_bind_ ***************************
|
||||
|
@ -800,12 +817,12 @@ int sqlite3_bind_parameter_indexes(
|
|||
}
|
||||
*pIndexes = indexes;
|
||||
return nVars;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sqlite3_free_parameter_indexes(int *pIndexes)
|
||||
{
|
||||
{
|
||||
sqliteFree( pIndexes );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer all bindings from the first statement over to the second.
|
||||
|
|
|
@ -871,9 +871,9 @@ static void Cleanup(Vdbe *p){
|
|||
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
|
||||
Mem *pColName;
|
||||
int n;
|
||||
releaseMemArray(p->aColName, p->nResColumn*2);
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
sqliteFree(p->aColName);
|
||||
n = nResColumn*2;
|
||||
n = nResColumn*COLNAME_N;
|
||||
p->nResColumn = nResColumn;
|
||||
p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );
|
||||
if( p->aColName==0 ) return;
|
||||
|
@ -893,13 +893,14 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
|
|||
** the string is freed using sqliteFree() when the vdbe is finished with
|
||||
** it. Otherwise, N bytes of zName are copied.
|
||||
*/
|
||||
int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
|
||||
int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
|
||||
int rc;
|
||||
Mem *pColName;
|
||||
assert( idx<(2*p->nResColumn) );
|
||||
assert( idx<p->nResColumn );
|
||||
assert( var<COLNAME_N );
|
||||
if( sqlite3MallocFailed() ) return SQLITE_NOMEM;
|
||||
assert( p->aColName!=0 );
|
||||
pColName = &(p->aColName[idx]);
|
||||
pColName = &(p->aColName[idx+var*p->nResColumn]);
|
||||
if( N==P3_DYNAMIC || N==P3_STATIC ){
|
||||
rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
|
||||
}else{
|
||||
|
@ -1481,7 +1482,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
|||
releaseMemArray(p->aVar, p->nVar);
|
||||
sqliteFree(p->aLabel);
|
||||
sqliteFree(p->aStack);
|
||||
releaseMemArray(p->aColName, p->nResColumn*2);
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
sqliteFree(p->aColName);
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
sqliteFree(p);
|
||||
|
|
|
@ -42,6 +42,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
|||
return SQLITE_ERROR;
|
||||
#else
|
||||
|
||||
|
||||
/* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
|
||||
** then the encoding of the value may not have changed.
|
||||
*/
|
||||
|
@ -118,6 +119,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
|||
z[n+1] = 0;
|
||||
pMem->z = (char*)z;
|
||||
pMem->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
assert(0==(1&(int)pMem->z));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -596,19 +598,25 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
|||
|
||||
if( pColl ){
|
||||
if( pMem1->enc==pColl->enc ){
|
||||
/* The strings are already in the correct encoding. Call the
|
||||
** comparison function directly */
|
||||
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
|
||||
}else{
|
||||
u8 origEnc = pMem1->enc;
|
||||
rc = pColl->xCmp(
|
||||
pColl->pUser,
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc),
|
||||
sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc),
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc),
|
||||
sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc)
|
||||
);
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem1, origEnc);
|
||||
const void *v1, *v2;
|
||||
int n1, n2;
|
||||
/* Convert the strings into the encoding that the comparison
|
||||
** function expects */
|
||||
v1 = sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc);
|
||||
n1 = v1==0 ? 0 : pMem1->n;
|
||||
assert( n1==sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc) );
|
||||
v2 = sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc);
|
||||
n2 = v2==0 ? 0 : pMem2->n;
|
||||
assert( n2==sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc) );
|
||||
/* Do the comparison */
|
||||
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
|
||||
/* Convert the strings back into the database encoding */
|
||||
sqlite3ValueText((sqlite3_value*)pMem1, origEnc);
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem2, origEnc);
|
||||
sqlite3ValueText((sqlite3_value*)pMem2, origEnc);
|
||||
return rc;
|
||||
}
|
||||
|
@ -752,10 +760,14 @@ void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
|
|||
** except the data returned is in the encoding specified by the second
|
||||
** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
|
||||
** SQLITE_UTF8.
|
||||
**
|
||||
** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
|
||||
** If that is the case, then the result must be aligned on an even byte
|
||||
** boundary.
|
||||
*/
|
||||
const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
||||
if( !pVal ) return 0;
|
||||
assert( enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE || enc==SQLITE_UTF8);
|
||||
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
|
||||
|
||||
if( pVal->flags&MEM_Null ){
|
||||
return 0;
|
||||
|
@ -763,12 +775,23 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
|||
assert( (MEM_Blob>>3) == MEM_Str );
|
||||
pVal->flags |= (pVal->flags & MEM_Blob)>>3;
|
||||
if( pVal->flags&MEM_Str ){
|
||||
sqlite3VdbeChangeEncoding(pVal, enc);
|
||||
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
|
||||
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
|
||||
assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
|
||||
if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}else if( !(pVal->flags&MEM_Blob) ){
|
||||
sqlite3VdbeMemStringify(pVal, enc);
|
||||
assert( 0==(1&(int)pVal->z) );
|
||||
}
|
||||
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
|
||||
if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
|
||||
return pVal->z;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
assert(pVal->enc==enc || sqlite3MallocFailed() );
|
||||
return (const void *)(pVal->enc==enc ? (pVal->z) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
** so is applicable. Because this module is responsible for selecting
|
||||
** indices, you might also think of this module as the "query optimizer".
|
||||
**
|
||||
** $Id: where.c,v 1.203 2006/01/24 12:09:20 danielk1977 Exp $
|
||||
** $Id: where.c,v 1.204 2006/02/01 02:45:02 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -1500,9 +1500,16 @@ WhereInfo *sqlite3WhereBegin(
|
|||
double lowestCost; /* Cost of the pBest */
|
||||
int bestJ = 0; /* The value of j */
|
||||
Bitmask m; /* Bitmask value for j or bestJ */
|
||||
int once = 0; /* True when first table is seen */
|
||||
|
||||
lowestCost = SQLITE_BIG_DBL;
|
||||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
|
||||
if( once &&
|
||||
((pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
|
||||
|| (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0))
|
||||
){
|
||||
break;
|
||||
}
|
||||
m = getMask(&maskSet, pTabItem->iCursor);
|
||||
if( (m & notReady)==0 ){
|
||||
if( j==iFrom ) iFrom++;
|
||||
|
@ -1512,17 +1519,13 @@ WhereInfo *sqlite3WhereBegin(
|
|||
(i==0 && ppOrderBy) ? *ppOrderBy : 0,
|
||||
&pIdx, &flags, &nEq);
|
||||
if( cost<lowestCost ){
|
||||
once = 1;
|
||||
lowestCost = cost;
|
||||
pBest = pIdx;
|
||||
bestFlags = flags;
|
||||
bestNEq = nEq;
|
||||
bestJ = j;
|
||||
}
|
||||
if( (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
|
||||
|| (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0)
|
||||
){
|
||||
break;
|
||||
}
|
||||
}
|
||||
TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
|
||||
pLevel-pWInfo->a));
|
||||
|
|
Загрузка…
Ссылка в новой задаче