|
From: <cre...@us...> - 2006-09-23 18:21:07
|
Revision: 1523
http://svn.sourceforge.net/frontierkernel/?rev=1523&view=rev
Author: creecode
Date: 2006-09-23 11:20:39 -0700 (Sat, 23 Sep 2006)
Log Message:
-----------
Importing SQLite v3.3.7 vendor drop
Modified Paths:
--------------
Frontier/vendor/sqlite3/current/alter.c
Frontier/vendor/sqlite3/current/attach.c
Frontier/vendor/sqlite3/current/auth.c
Frontier/vendor/sqlite3/current/btree.c
Frontier/vendor/sqlite3/current/btree.h
Frontier/vendor/sqlite3/current/build.c
Frontier/vendor/sqlite3/current/callback.c
Frontier/vendor/sqlite3/current/delete.c
Frontier/vendor/sqlite3/current/expr.c
Frontier/vendor/sqlite3/current/func.c
Frontier/vendor/sqlite3/current/hash.c
Frontier/vendor/sqlite3/current/hash.h
Frontier/vendor/sqlite3/current/insert.c
Frontier/vendor/sqlite3/current/legacy.c
Frontier/vendor/sqlite3/current/main.c
Frontier/vendor/sqlite3/current/os.h
Frontier/vendor/sqlite3/current/os_unix.c
Frontier/vendor/sqlite3/current/os_win.c
Frontier/vendor/sqlite3/current/pager.c
Frontier/vendor/sqlite3/current/pager.h
Frontier/vendor/sqlite3/current/pragma.c
Frontier/vendor/sqlite3/current/prepare.c
Frontier/vendor/sqlite3/current/printf.c
Frontier/vendor/sqlite3/current/select.c
Frontier/vendor/sqlite3/current/shell.c
Frontier/vendor/sqlite3/current/sqliteInt.h
Frontier/vendor/sqlite3/current/table.c
Frontier/vendor/sqlite3/current/tclsqlite.c
Frontier/vendor/sqlite3/current/tokenize.c
Frontier/vendor/sqlite3/current/trigger.c
Frontier/vendor/sqlite3/current/update.c
Frontier/vendor/sqlite3/current/utf.c
Frontier/vendor/sqlite3/current/util.c
Frontier/vendor/sqlite3/current/vacuum.c
Frontier/vendor/sqlite3/current/vdbe.c
Frontier/vendor/sqlite3/current/vdbe.h
Frontier/vendor/sqlite3/current/vdbeInt.h
Frontier/vendor/sqlite3/current/vdbeapi.c
Frontier/vendor/sqlite3/current/vdbeaux.c
Frontier/vendor/sqlite3/current/vdbemem.c
Frontier/vendor/sqlite3/current/where.c
Added Paths:
-----------
Frontier/vendor/sqlite3/current/loadext.c
Frontier/vendor/sqlite3/current/os_os2.c
Frontier/vendor/sqlite3/current/os_os2.h
Frontier/vendor/sqlite3/current/parse.y
Frontier/vendor/sqlite3/current/sqlite.h.in
Frontier/vendor/sqlite3/current/sqlite3ext.h
Frontier/vendor/sqlite3/current/test1.c
Frontier/vendor/sqlite3/current/test2.c
Frontier/vendor/sqlite3/current/test3.c
Frontier/vendor/sqlite3/current/test4.c
Frontier/vendor/sqlite3/current/test5.c
Frontier/vendor/sqlite3/current/test6.c
Frontier/vendor/sqlite3/current/test7.c
Frontier/vendor/sqlite3/current/test8.c
Frontier/vendor/sqlite3/current/test_async.c
Frontier/vendor/sqlite3/current/test_loadext.c
Frontier/vendor/sqlite3/current/test_md5.c
Frontier/vendor/sqlite3/current/test_schema.c
Frontier/vendor/sqlite3/current/test_server.c
Frontier/vendor/sqlite3/current/test_tclvar.c
Frontier/vendor/sqlite3/current/vtab.c
Modified: Frontier/vendor/sqlite3/current/alter.c
===================================================================
--- Frontier/vendor/sqlite3/current/alter.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/alter.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -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.20 2006/02/09 02:56:03 drh Exp $
+** $Id: alter.c,v 1.21 2006/06/21 12:36:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -272,6 +272,12 @@
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
+ goto exit_rename_table;
+ }
+#endif
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
@@ -512,6 +518,13 @@
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_begin_add_column;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
+ goto exit_begin_add_column;
+ }
+#endif
+
/* Make sure this is not an attempt to ALTER a view. */
if( pTab->pSelect ){
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
Modified: Frontier/vendor/sqlite3/current/attach.c
===================================================================
--- Frontier/vendor/sqlite3/current/attach.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/attach.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
-** $Id: attach.c,v 1.49 2006/01/24 12:09:18 danielk1977 Exp $
+** $Id: attach.c,v 1.53 2006/06/27 16:34:57 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -73,6 +73,8 @@
zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]);
+ if( zFile==0 ) zFile = "";
+ if( zName==0 ) zName = "";
/* Check for the following errors:
**
@@ -82,7 +84,7 @@
*/
if( db->nDb>=MAX_ATTACHED+2 ){
sqlite3_snprintf(
- 127, zErr, "too many attached databases - max %d", MAX_ATTACHED
+ sizeof(zErr), zErr, "too many attached databases - max %d", MAX_ATTACHED
);
goto attach_error;
}
@@ -92,8 +94,8 @@
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName;
- if( z && sqlite3StrICmp(z, zName)==0 ){
- sqlite3_snprintf(127, zErr, "database %s is already in use", zName);
+ if( z && zName && sqlite3StrICmp(z, zName)==0 ){
+ sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName);
goto attach_error;
}
}
@@ -185,7 +187,12 @@
}
sqlite3ResetInternalSchema(db, 0);
db->nDb = iDb;
- sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
+ if( rc==SQLITE_NOMEM ){
+ if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
+ sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
+ }else{
+ sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
+ }
goto attach_error;
}
@@ -221,7 +228,7 @@
Db *pDb = 0;
char zErr[128];
- assert(zName);
+ if( zName==0 ) zName = "";
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
@@ -229,17 +236,21 @@
}
if( i>=db->nDb ){
- sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName);
+ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
goto detach_error;
}
if( i<2 ){
- sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName);
+ sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
if( !db->autoCommit ){
strcpy(zErr, "cannot DETACH database within transaction");
goto detach_error;
}
+ if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){
+ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
+ goto detach_error;
+ }
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
Modified: Frontier/vendor/sqlite3/current/auth.c
===================================================================
--- Frontier/vendor/sqlite3/current/auth.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/auth.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -14,7 +14,7 @@
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
**
-** $Id: auth.c,v 1.24 2006/01/13 13:55:45 drh Exp $
+** $Id: auth.c,v 1.25 2006/06/16 08:01:03 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -182,8 +182,10 @@
sqlite3 *db = pParse->db;
int rc;
- /* Don't do any authorization checks if the database is initialising. */
- if( db->init.busy ){
+ /* Don't do any authorization checks if the database is initialising
+ ** or if the parser is being invoked from within sqlite3_declare_vtab.
+ */
+ if( db->init.busy || IN_DECLARE_VTAB ){
return SQLITE_OK;
}
Modified: Frontier/vendor/sqlite3/current/btree.c
===================================================================
--- Frontier/vendor/sqlite3/current/btree.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/btree.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.314 2006/02/11 01:25:51 drh Exp $
+** $Id: btree.c,v 1.326 2006/08/08 13:51:43 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -388,8 +388,8 @@
u8 wrFlag; /* True if writable */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_SHARED_CACHE
- void *pKey;
- i64 nKey;
+ void *pKey; /* Saved key that was cursor's last known position */
+ i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#endif
};
@@ -426,10 +426,10 @@
#if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace )\
{ sqlite3DebugPrintf X; fflush(stdout); }
+int sqlite3_btree_trace=0; /* True to enable tracing */
#else
# define TRACE(X)
#endif
-int sqlite3_btree_trace=0; /* True to enable tracing */
/*
** Forward declaration
@@ -469,8 +469,15 @@
/* The database page the PENDING_BYTE occupies. This page is never used.
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
** should possibly be consolidated (presumably in pager.h).
+**
+** If disk I/O is omitted (meaning that the database is stored purely
+** in memory) then there is no pending byte.
*/
-#define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+#ifdef SQLITE_OMIT_DISKIO
+# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
+#else
+# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+#endif
/*
** A linked list of the following structures is stored at BtShared.pLock.
@@ -867,7 +874,8 @@
}
offset = PTRMAP_PTROFFSET(pBt, key);
- if( pEType ) *pEType = pPtrmap[offset];
+ assert( pEType!=0 );
+ *pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3pager_unref(pPtrmap);
@@ -1273,6 +1281,12 @@
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;
@@ -1618,8 +1632,8 @@
** the right size. This is to guard against size changes that result
** when compiling on a different architecture.
*/
- assert( sizeof(i64)==8 );
- assert( sizeof(u64)==8 );
+ assert( sizeof(i64)==8 || sizeof(i64)==4 );
+ assert( sizeof(u64)==8 || sizeof(u64)==4 );
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
@@ -1679,7 +1693,7 @@
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
-#ifndef SQLITE_OMIT_SHARED_CACHE
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
/* Add the new btree to the linked list starting at ThreadData.pBtree.
** There is no chance that a malloc() may fail inside of the
** sqlite3ThreadData() call, as the ThreadData structure must have already
@@ -1744,7 +1758,7 @@
pTsd->pBtree = pBt->pNext;
}else{
BtShared *pPrev;
- for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext);
+ for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){}
if( pPrev ){
assert( pTsd==sqlite3ThreadData() );
pPrev->pNext = pBt->pNext;
@@ -2353,7 +2367,7 @@
MemPage *pFreeMemPage = 0; /* "" */
#ifndef NDEBUG
- int nRef = *sqlite3pager_stats(pPager);
+ int nRef = sqlite3pager_refcount(pPager);
#endif
assert( pBt->autoVacuum );
@@ -2457,12 +2471,11 @@
if( rc!=SQLITE_OK ) goto autovacuum_out;
put4byte(&pBt->pPage1->aData[32], 0);
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) );
+ assert( nRef==sqlite3pager_refcount(pPager) );
if( rc!=SQLITE_OK ){
sqlite3pager_rollback(pPager);
}
@@ -3879,6 +3892,15 @@
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.
@@ -3919,7 +3941,9 @@
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);
@@ -4052,6 +4076,7 @@
n = nPayload;
if( n>spaceLeft ) n = spaceLeft;
if( n>nSrc ) n = nSrc;
+ assert( pSrc );
memcpy(pPayload, pSrc, n);
nPayload -= n;
pPayload += n;
@@ -4076,6 +4101,7 @@
MemPage *pThis;
unsigned char *aData;
+ assert( pNewParent!=0 );
if( pgno==0 ) return SQLITE_OK;
assert( pBt->pPager!=0 );
aData = sqlite3pager_lookup(pBt->pPager, pgno);
@@ -4086,7 +4112,7 @@
if( pThis->pParent!=pNewParent ){
if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
pThis->pParent = pNewParent;
- if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
+ sqlite3pager_ref(pNewParent->aData);
}
pThis->idxParent = idx;
}
@@ -4799,6 +4825,7 @@
rc = sqlite3pager_write(pNew->aData);
if( rc ) goto balance_cleanup;
}else{
+ assert( i>0 );
rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
if( rc ) goto balance_cleanup;
apNew[i] = pNew;
@@ -4950,6 +4977,8 @@
}
}
assert( j==nCell );
+ assert( nOld>0 );
+ assert( nNew>0 );
if( (pageFlags & PTF_LEAF)==0 ){
memcpy(&apNew[nNew-1]->aData[8], &apCopy[nOld-1]->aData[8], 4);
}
@@ -6204,11 +6233,7 @@
IntegrityCk *pCheck, /* Context for the sanity check */
int iPage, /* Page number of the page to check */
MemPage *pParent, /* Parent page */
- char *zParentContext, /* Parent context */
- char *zLowerBound, /* All keys should be greater than this, if not NULL */
- int nLower, /* Number of characters in zLowerBound */
- char *zUpperBound, /* All keys should be less than this, if not NULL */
- int nUpper /* Number of characters in zUpperBound */
+ char *zParentContext /* Parent context */
){
MemPage *pPage;
int i, rc, depth, d2, pgno, cnt;
@@ -6274,7 +6299,7 @@
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
}
#endif
- d2 = checkTreePage(pCheck,pgno,pPage,zContext,0,0,0,0);
+ d2 = checkTreePage(pCheck,pgno,pPage,zContext);
if( i>0 && d2!=depth ){
checkAppendMsg(pCheck, zContext, "Child page depth differs");
}
@@ -6289,7 +6314,7 @@
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0);
}
#endif
- checkTreePage(pCheck, pgno, pPage, zContext,0,0,0,0);
+ checkTreePage(pCheck, pgno, pPage, zContext);
}
/* Check for complete coverage of the page
@@ -6363,7 +6388,7 @@
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
- nRef = *sqlite3pager_stats(pBt->pPager);
+ nRef = sqlite3pager_refcount(pBt->pPager);
if( lockBtreeWithRetry(p)!=SQLITE_OK ){
return sqliteStrDup("Unable to acquire a read lock on the database");
}
@@ -6401,7 +6426,7 @@
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
}
#endif
- checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0);
+ checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ");
}
/* Make sure every page in the file is referenced
@@ -6429,10 +6454,10 @@
/* Make sure this analysis did not leave any unref() pages
*/
unlockBtreeIfUnused(pBt);
- if( nRef != *sqlite3pager_stats(pBt->pPager) ){
+ if( nRef != sqlite3pager_refcount(pBt->pPager) ){
checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
- nRef, *sqlite3pager_stats(pBt->pPager)
+ nRef, sqlite3pager_refcount(pBt->pPager)
);
}
@@ -6534,6 +6559,13 @@
}
/*
+** Return non-zero if a read (or write) transaction is active.
+*/
+int sqlite3BtreeIsInReadTrans(Btree *p){
+ return (p && (p->inTrans!=TRANS_NONE));
+}
+
+/*
** This call is a no-op if no write-transaction is currently active on pBt.
**
** Otherwise, sync the database file for the btree pBt. zMaster points to
@@ -6598,17 +6630,23 @@
return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
}
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** Obtain a lock on the table whose root page is iTab. The
+** lock is a write lock if isWritelock is true or a read lock
+** if it is false.
+*/
int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
int rc = SQLITE_OK;
-#ifndef SQLITE_OMIT_SHARED_CACHE
u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK);
rc = queryTableLock(p, iTab, lockType);
if( rc==SQLITE_OK ){
rc = lockTable(p, iTab, lockType);
}
-#endif
return rc;
}
+#endif
/*
** The following debugging interface has to be in this file (rather
@@ -6623,6 +6661,7 @@
int objc,
Tcl_Obj *CONST objv[]
){
+#ifndef SQLITE_OMIT_SHARED_CACHE
const ThreadData *pTd = sqlite3ThreadDataReadOnly();
if( pTd->useSharedData ){
BtShared *pBt;
@@ -6634,6 +6673,7 @@
}
Tcl_SetObjResult(interp, pRet);
}
+#endif
return TCL_OK;
}
#endif
Modified: Frontier/vendor/sqlite3/current/btree.h
===================================================================
--- Frontier/vendor/sqlite3/current/btree.h 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/btree.h 2006-09-23 18:20:39 UTC (rev 1523)
@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
-** @(#) $Id: btree.h,v 1.70 2006/02/11 01:25:51 drh Exp $
+** @(#) $Id: btree.h,v 1.71 2006/06/27 16:34:57 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@@ -75,6 +75,7 @@
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
+int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeSync(Btree*, const char *zMaster);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *);
Modified: Frontier/vendor/sqlite3/current/build.c
===================================================================
--- Frontier/vendor/sqlite3/current/build.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/build.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.386 2006/02/10 18:08:09 drh Exp $
+** $Id: build.c,v 1.409 2006/07/26 16:22:15 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -42,26 +42,28 @@
** codeTableLocks() functions.
*/
struct TableLock {
- int iDb;
- int iTab;
- u8 isWriteLock;
- const char *zName;
+ int iDb; /* The database containing the table to be locked */
+ int iTab; /* The root page of the table to be locked */
+ u8 isWriteLock; /* True for write lock. False for a read lock */
+ const char *zName; /* Name of the table */
};
/*
-** Have the compiled statement lock the table with rootpage iTab in database
-** iDb at the shared-cache level when executed. The isWriteLock argument
-** is zero for a read-lock, or non-zero for a write-lock.
+** Record the fact that we want to lock a table at run-time.
**
-** The zName parameter should point to the unqualified table name. This is
-** used to provide a more informative error message should the lock fail.
+** The table to be locked has root page iTab and is found in database iDb.
+** A read or a write lock can be taken depending on isWritelock.
+**
+** This routine just records the fact that the lock is desired. The
+** code to make the lock occur is generated by a later call to
+** codeTableLocks() which occurs during sqlite3FinishCoding().
*/
void sqlite3TableLock(
- Parse *pParse,
- int iDb,
- int iTab,
- u8 isWriteLock,
- const char *zName
+ Parse *pParse, /* Parsing context */
+ int iDb, /* Index of the database containing the table to lock */
+ int iTab, /* Root page number of the table to be locked */
+ u8 isWriteLock, /* True for a write lock */
+ const char *zName /* Name of the table to be locked */
){
int i;
int nBytes;
@@ -135,8 +137,8 @@
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
@@ -162,6 +164,12 @@
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pParse->pVirtualLock ){
+ char *vtab = (char *)pParse->pVirtualLock->pVtab;
+ sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB);
+ }
+#endif
/* Once all the cookies have been verified and transactions opened,
** obtain the required table-locks. This is a no-op unless the
@@ -185,7 +193,7 @@
/* 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,
@@ -338,7 +346,7 @@
** it is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function.
*/
-static void sqliteDeleteIndex(sqlite3 *db, Index *p){
+static void sqliteDeleteIndex(Index *p){
Index *pOld;
const char *zName = p->zName;
@@ -507,7 +515,7 @@
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema );
- sqliteDeleteIndex(db, pIndex);
+ sqliteDeleteIndex(pIndex);
}
#ifndef SQLITE_OMIT_FOREIGN_KEY
@@ -531,6 +539,7 @@
#ifndef SQLITE_OMIT_CHECK
sqlite3ExprDelete(pTable->pCheck);
#endif
+ sqlite3VtabClear(pTable);
sqliteFree(pTable);
}
@@ -690,8 +699,7 @@
** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response
** to a CREATE TABLE statement. In particular, this routine is called
-** after seeing tokens "CREATE" and "TABLE" and the table name. The
-** pStart token is the CREATE and pName is the table name. The isTemp
+** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp
** flag is true if the table should be stored in the auxiliary database
** file instead of in the main database file. This is normally the case
** when the "TEMP" or "TEMPORARY" keyword occurs in between
@@ -705,11 +713,11 @@
*/
void sqlite3StartTable(
Parse *pParse, /* Parser context */
- Token *pStart, /* The "CREATE" token */
Token *pName1, /* First part of the name of the table or view */
Token *pName2, /* Second part of the name of the table or view */
int isTemp, /* True if this is a TEMP table */
int isView, /* True if this is a VIEW */
+ int isVirtual, /* True if this is a VIRTUAL table */
int noErr /* Do nothing if table already exists */
){
Table *pTable;
@@ -773,7 +781,7 @@
code = SQLITE_CREATE_TABLE;
}
}
- if( sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
+ if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
goto begin_table_error;
}
}
@@ -781,22 +789,28 @@
/* Make sure the new table name does not collide with an existing
** index or table name in the same database. Issue an error message if
- ** it does.
+ ** it does. The exception is if the statement being parsed was passed
+ ** to an sqlite3_declare_vtab() call. In that case only the column names
+ ** and types will be used, so there is no need to test for namespace
+ ** collisions.
*/
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
- goto begin_table_error;
- }
- pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
- if( pTable ){
- if( !noErr ){
- sqlite3ErrorMsg(pParse, "table %T already exists", pName);
+ if( !IN_DECLARE_VTAB ){
+ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
+ goto begin_table_error;
}
- goto begin_table_error;
+ pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
+ if( pTable ){
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "table %T already exists", pName);
+ }
+ goto begin_table_error;
+ }
+ if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
+ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
+ goto begin_table_error;
+ }
}
- if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
- sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
- goto begin_table_error;
- }
+
pTable = sqliteMalloc( sizeof(Table) );
if( pTable==0 ){
pParse->rc = SQLITE_NOMEM;
@@ -804,10 +818,7 @@
goto begin_table_error;
}
pTable->zName = zName;
- pTable->nCol = 0;
- pTable->aCol = 0;
pTable->iPKey = -1;
- pTable->pIndex = 0;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
@@ -836,6 +847,12 @@
int fileFormat;
sqlite3BeginWriteOperation(pParse, 0, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( isVirtual ){
+ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ }
+#endif
+
/* If the file format and encoding in the database have not been set,
** set them now.
*/
@@ -843,7 +860,7 @@
lbl = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_If, 0, lbl);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
- 1 : SQLITE_DEFAULT_FILE_FORMAT;
+ 1 : SQLITE_MAX_FILE_FORMAT;
sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0);
@@ -858,8 +875,8 @@
** The rowid value is needed by the code that sqlite3EndTable will
** generate.
*/
-#ifndef SQLITE_OMIT_VIEW
- if( isView ){
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
+ if( isView || isVirtual ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}else
#endif
@@ -1095,7 +1112,7 @@
Table *pTab = pParse->pNewTable;
char *zType = 0;
int iCol = -1, i;
- if( pTab==0 ) goto primary_key_exit;
+ if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
if( pTab->hasPrimKey ){
sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
@@ -1150,7 +1167,7 @@
){
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
- if( pTab ){
+ if( pTab && !IN_DECLARE_VTAB ){
/* The CHECK expression must be duplicated so that tokens refer
** to malloced space and not the (ephemeral) text of the CREATE TABLE
** statement */
@@ -1372,7 +1389,7 @@
assert( !db->init.busy || !pSelect );
- iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ iDb = sqlite3SchemaToIndex(db, p->pSchema);
#ifndef SQLITE_OMIT_CHECK
/* Resolve names in all CHECK constraint expressions.
@@ -1584,7 +1601,7 @@
sqlite3SelectDelete(pSelect);
return;
}
- sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1, 0);
+ sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect);
@@ -1633,7 +1650,7 @@
}
#endif /* SQLITE_OMIT_VIEW */
-#ifndef SQLITE_OMIT_VIEW
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number
@@ -1647,6 +1664,14 @@
assert( pTable );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( sqlite3VtabCallConnect(pParse, pTable) ){
+ return SQLITE_ERROR;
+ }
+ if( IsVirtual(pTable) ) return 0;
+#endif
+
+#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
** already known.
*/
@@ -1699,9 +1724,10 @@
} else {
nErr++;
}
+#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
-#endif /* SQLITE_OMIT_VIEW */
+#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
/*
@@ -1727,6 +1753,17 @@
** used by SQLite when the btree layer moves a table root page. The
** root-page of a table or index in database iDb has changed from iFrom
** to iTo.
+**
+** Ticket #1728: The symbol table might still contain information
+** on tables and/or indices that are the process of being deleted.
+** If you are unlucky, one of those deleted indices or tables might
+** have the same rootpage number as the real table or index that is
+** being moved. So we cannot stop searching after the first match
+** because the first match might be for one of the deleted indices
+** or tables and not the table/index that is actually being moved.
+** We must continue looping until all tables and indices with
+** rootpage==iFrom have been converted to have a rootpage of iTo
+** in order to be certain that we got the right one.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
@@ -1738,7 +1775,6 @@
Table *pTab = sqliteHashData(pElem);
if( pTab->tnum==iFrom ){
pTab->tnum = iTo;
- return;
}
}
pHash = &pDb->pSchema->idxHash;
@@ -1746,10 +1782,8 @@
Index *pIdx = sqliteHashData(pElem);
if( pIdx->tnum==iFrom ){
pIdx->tnum = iTo;
- return;
}
}
- assert(0);
}
#endif
@@ -1865,6 +1899,7 @@
int code;
const char *zTab = SCHEMA_TABLE(iDb);
const char *zDb = db->aDb[iDb].zName;
+ const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table;
}
@@ -1874,6 +1909,14 @@
}else{
code = SQLITE_DROP_VIEW;
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ }else if( IsVirtual(pTab) ){
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
+ goto exit_drop_table;
+ }
+ code = SQLITE_DROP_VTABLE;
+ zArg2 = pTab->pMod->zName;
+#endif
}else{
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE;
@@ -1881,7 +1924,7 @@
code = SQLITE_DROP_TABLE;
}
}
- if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){
+ if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
goto exit_drop_table;
}
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
@@ -1917,6 +1960,15 @@
Db *pDb = &db->aDb[iDb];
sqlite3BeginWriteOperation(pParse, 0, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ }
+ }
+#endif
+
/* Drop all triggers associated with the table being dropped. Code
** is generated to remove entries from sqlite_master and/or
** sqlite_temp_master if required.
@@ -1925,7 +1977,7 @@
while( pTrigger ){
assert( pTrigger->pSchema==pTab->pSchema ||
pTrigger->pSchema==db->aDb[1].pSchema );
- sqlite3DropTriggerPtr(pParse, pTrigger, 1);
+ sqlite3DropTriggerPtr(pParse, pTrigger);
pTrigger = pTrigger->pNext;
}
@@ -1953,13 +2005,16 @@
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
- if( !isView ){
+ if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
/* Remove the table entry from SQLite's internal schema and modify
** the schema cookie.
*/
+ if( IsVirtual(pTab) ){
+ sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0);
+ }
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
sqlite3ChangeCookie(db, v, iDb);
}
@@ -2003,7 +2058,7 @@
char *z;
assert( pTo!=0 );
- if( p==0 || pParse->nErr ) goto fk_end;
+ if( p==0 || pParse->nErr || IN_DECLARE_VTAB ) goto fk_end;
if( pFromCol==0 ){
int iCol = p->nCol-1;
if( iCol<0 ) goto fk_end;
@@ -2207,7 +2262,7 @@
int nExtra = 0;
char *zExtra;
- if( pParse->nErr || sqlite3MallocFailed() ){
+ if( pParse->nErr || sqlite3MallocFailed() || IN_DECLARE_VTAB ){
goto exit_create_index;
}
@@ -2264,6 +2319,12 @@
goto exit_create_index;
}
#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be indexed");
+ goto exit_create_index;
+ }
+#endif
/*
** Find the name of the index. Make sure there is not already another
@@ -2630,9 +2691,13 @@
int i;
assert( a!=0 );
a[0] = 1000000;
- for(i=pIdx->nColumn; i>=1; i--){
- a[i] = 10;
+ for(i=pIdx->nColumn; i>=5; i--){
+ a[i] = 5;
}
+ while( i>=1 ){
+ a[i] = 11 - i;
+ i--;
+ }
if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1;
}
@@ -2958,7 +3023,7 @@
** 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);
@@ -3018,7 +3083,7 @@
if( iDb>=0 ){
assert( iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
- assert( iDb<32 );
+ assert( iDb<MAX_ATTACHED+2 );
mask = 1<<iDb;
if( (pParse->cookieMask & mask)==0 ){
pParse->cookieMask |= mask;
@@ -3110,7 +3175,7 @@
Table *pTab; /* A table in the database */
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
- if( pDb==0 ) continue;
+ assert( pDb!=0 );
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
reindexTable(pParse, pTab, zColl);
Modified: Frontier/vendor/sqlite3/current/callback.c
===================================================================
--- Frontier/vendor/sqlite3/current/callback.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/callback.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
-** $Id: callback.c,v 1.12 2006/01/18 16:51:35 danielk1977 Exp $
+** $Id: callback.c,v 1.15 2006/05/24 12:43:27 drh Exp $
*/
#include "sqliteInt.h"
@@ -178,9 +178,11 @@
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
- assert( !pDel ||
- (sqlite3MallocFailed() && pDel==pColl) );
- sqliteFree(pDel);
+ assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) );
+ if( pDel ){
+ sqliteFree(pDel);
+ pColl = 0;
+ }
}
}
return pColl;
@@ -312,3 +314,55 @@
}
return 0;
}
+
+/*
+** Free all resources held by the schema structure. The void* argument points
+** at a Schema struct. This function does not call sqliteFree() on the
+** pointer itself, it just cleans up subsiduary resources (i.e. the contents
+** of the schema hash tables).
+*/
+void sqlite3SchemaFree(void *p){
+ Hash temp1;
+ Hash temp2;
+ HashElem *pElem;
+ Schema *pSchema = (Schema *)p;
+
+ temp1 = pSchema->tblHash;
+ temp2 = pSchema->trigHash;
+ sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashClear(&pSchema->aFKey);
+ sqlite3HashClear(&pSchema->idxHash);
+ for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
+ sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
+ }
+ sqlite3HashClear(&temp2);
+ sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
+ for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
+ Table *pTab = sqliteHashData(pElem);
+ sqlite3DeleteTable(0, pTab);
+ }
+ sqlite3HashClear(&temp1);
+ pSchema->pSeqTab = 0;
+ pSchema->flags &= ~DB_SchemaLoaded;
+}
+
+/*
+** Find and return the schema associated with a BTree. Create
+** a new one if necessary.
+*/
+Schema *sqlite3SchemaGet(Btree *pBt){
+ Schema * p;
+ if( pBt ){
+ p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
+ }else{
+ p = (Schema *)sqliteMalloc(sizeof(Schema));
+ }
+ if( p && 0==p->file_format ){
+ sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
+ p->enc = SQLITE_UTF8;
+ }
+ return p;
+}
Modified: Frontier/vendor/sqlite3/current/delete.c
===================================================================
--- Frontier/vendor/sqlite3/current/delete.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/delete.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -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.121 2006/02/10 02:27:43 danielk1977 Exp $
+** $Id: delete.c,v 1.127 2006/06/19 03:05:10 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -42,8 +42,12 @@
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
- if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
- && pParse->nested==0 ){
+ if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
+ && pParse->nested==0)
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ || (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
+#endif
+ ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
@@ -66,7 +70,9 @@
Table *pTab, /* The table to be opened */
int opcode /* OP_OpenRead or OP_OpenWrite */
){
- Vdbe *v = sqlite3GetVdbe(p);
+ Vdbe *v;
+ if( IsVirtual(pTab) ) return;
+ v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
@@ -149,7 +155,7 @@
/* If pTab is really a view, make sure it has been initialized.
*/
- if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
@@ -190,7 +196,7 @@
*/
if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
@@ -205,7 +211,7 @@
** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect.
*/
- if( pWhere==0 && !triggers_exist ){
+ if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of
** entries in the table. */
@@ -230,8 +236,7 @@
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
}
}
- }
-
+ }
/* The usual case: There is a WHERE clause so we have to scan through
** the table and pick which records to delete.
*/
@@ -243,7 +248,7 @@
/* Remember the rowid of every item to be deleted.
*/
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+ sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
@@ -304,7 +309,15 @@
}
/* Delete the row */
- sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ pParse->pVirtualLock = pTab;
+ sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
+ }else
+#endif
+ {
+ sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
+ }
}
/* If there are row triggers, close all cursors then invoke
@@ -327,7 +340,7 @@
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
- if( !triggers_exist ){
+ if( !triggers_exist && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
@@ -382,7 +395,7 @@
){
int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
- sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
+ sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
if( count ){
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
@@ -407,7 +420,6 @@
** deleted.
*/
void sqlite3GenerateRowIndexDelete(
- sqlite3 *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
Modified: Frontier/vendor/sqlite3/current/expr.c
===================================================================
--- Frontier/vendor/sqlite3/current/expr.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/expr.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -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.254 2006/02/10 07:07:15 danielk1977 Exp $
+** $Id: expr.c,v 1.266 2006/07/11 13:15:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -212,6 +212,19 @@
}
/*
+** Works like sqlite3Expr() but frees its pLeft and pRight arguments
+** if it fails due to a malloc problem.
+*/
+Expr *sqlite3ExprOrFree(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
+ Expr *pNew = sqlite3Expr(op, pLeft, pRight, pToken);
+ if( pNew==0 ){
+ sqlite3ExprDelete(pLeft);
+ sqlite3ExprDelete(pRight);
+ }
+ return pNew;
+}
+
+/*
** When doing a nested parse, you can include terms in an expression
** that look like this: #0 #1 #2 ... These terms refer to elements
** on the stack. "#0" means the top of the stack.
@@ -547,12 +560,12 @@
pNew->iOffset = -1;
pNew->isResolved = p->isResolved;
pNew->isAgg = p->isAgg;
- pNew->usesVirt = 0;
+ pNew->usesEphm = 0;
pNew->disallowOrderBy = 0;
pNew->pRightmost = 0;
- pNew->addrOpenVirt[0] = -1;
- pNew->addrOpenVirt[1] = -1;
- pNew->addrOpenVirt[2] = -1;
+ pNew->addrOpenEphm[0] = -1;
+ pNew->addrOpenEphm[1] = -1;
+ pNew->addrOpenEphm[2] = -1;
return pNew;
}
#else
@@ -841,11 +854,13 @@
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
- Table *pTab = pItem->pTab;
- int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ Table *pTab;
+ int iDb;
Column *pCol;
- if( pTab==0 ) continue;
+ pTab = pItem->pTab;
+ assert( pTab!=0 );
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( pTab->nCol>0 );
if( zTab ){
if( pItem->zAlias ){
@@ -1314,7 +1329,7 @@
case TK_IN: {
char affinity;
KeyInfo keyInfo;
- int addr; /* Address of OP_OpenVirtual instruction */
+ int addr; /* Address of OP_OpenEphemeral instruction */
affinity = sqlite3ExprAffinity(pExpr->pLeft);
@@ -1332,7 +1347,7 @@
** is used.
*/
pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0);
+ addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
@@ -1365,7 +1380,7 @@
struct ExprList_item *pItem;
if( !affinity ){
- affinity = SQLITE_AFF_NUMERIC;
+ affinity = SQLITE_AFF_NONE;
}
keyInfo.aColl[0] = pExpr->pLeft->pColl;
@@ -1379,11 +1394,7 @@
** expression we need to rerun this code each time.
*/
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
- VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
- int j;
- for(j=0; j<3; j++){
- aOp[j].opcode = OP_Noop;
- }
+ sqlite3VdbeChangeToNoop(v, testAddr-1, 3);
testAddr = 0;
}
@@ -1491,7 +1502,8 @@
}else if( pExpr->iColumn>=0 ){
Table *pTab = pExpr->pTab;
int iCol = pExpr->iColumn;
- sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol);
+ int op = (pTab && IsVirtual(pTab)) ? OP_VColumn : OP_Column;
+ sqlite3VdbeAddOp(v, op, pExpr->iTable, iCol);
sqlite3ColumnDefault(v, pTab, iCol);
#ifndef SQLITE_OMIT_FLOATING_POINT
if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
@@ -1499,7 +1511,9 @@
}
#endif
}else{
- sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0);
+ Table *pTab = pExpr->pTab;
+ int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
+ sqlite3VdbeAddOp(v, op, pExpr->iTable, 0);
}
break;
}
@@ -1673,6 +1687,25 @@
pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
assert( pDef!=0 );
nExpr = sqlite3ExprCodeExprList(pParse, pList);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Possibly overload the function if the first argument is
+ ** a virtual table column.
+ **
+ ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the
+ ** second argument, not the first, as the argument to test to
+ ** see if it is a column in a virtual table. This is done because
+ ** the left operand of infix functions (the operand we want to
+ ** control overloading) ends up as the second argument to the
+ ** function. The expression "A glob B" is equivalent to
+ ** "glob(B,A). We want to use the A in "A glob B" to test
+ ** for function overloading. But we use the B term in "glob(B,A)".
+ */
+ if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){
+ pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[1].pExpr);
+ }else if( nExpr>0 ){
+ pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[0].pExpr);
+ }
+#endif
for(i=0; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
constMask |= (1<<i);
@@ -1692,7 +1725,9 @@
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS:
case TK_SELECT: {
- sqlite3CodeSubselect(pParse, pExpr);
+ if( pExpr->iColumn==0 ){
+ sqlite3CodeSubselect(pParse, pExpr);
+ }
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
VdbeComment((v, "# load subquery result"));
break;
Modified: Frontier/vendor/sqlite3/current/func.c
===================================================================
--- Frontier/vendor/sqlite3/current/func.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/func.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.121 2006/02/09 22:13:42 drh Exp $
+** $Id: func.c,v 1.132 2006/06/24 11:51:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -121,7 +121,13 @@
switch( sqlite3_value_type(argv[0]) ){
case SQLITE_INTEGER: {
i64 iVal = sqlite3_value_int64(argv[0]);
- if( iVal<0 ) iVal = iVal * -1;
+ if( iVal<0 ){
+ if( (iVal<<1)==0 ){
+ sqlite3_result_error(context, "integer overflow", -1);
+ return;
+ }
+ iVal = -iVal;
+ }
sqlite3_result_int64(context, iVal);
break;
}
@@ -131,7 +137,7 @@
}
default: {
double rVal = sqlite3_value_double(argv[0]);
- if( rVal<0 ) rVal = rVal * -1.0;
+ if( rVal<0 ) rVal = -rVal;
sqlite3_result_double(context, rVal);
break;
}
@@ -195,10 +201,11 @@
if( n>30 ) n = 30;
if( n<0 ) n = 0;
}
- if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
r = sqlite3_value_double(argv[0]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+ sqlite3AtoF(zBuf, &r);
+ sqlite3_result_double(context, r);
}
/*
@@ -258,9 +265,11 @@
int argc,
sqlite3_value **argv
){
- int r;
+ sqlite_int64 r;
sqlite3Randomness(sizeof(r), &r);
- sqlite3_result_int(context, r);
+ if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */
+ /* can always do abs() of the result */
+ sqlite3_result_int64(context, r);
}
/*
@@ -539,7 +548,20 @@
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
}
+/*
+** The MATCH() function is unimplemented. If anybody tries to use it,
+** return an error.
+*/
+static void matchStub(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ static const char zErr[] = "MATCH is not implemented";
+ sqlite3_result_error(context, zErr, sizeof(zErr)-1);
+}
+
/*
** EXPERIMENTAL - This is not an official function. The interface may
** change. This function may disappear. Do not write code that depends
@@ -633,6 +655,7 @@
};
assert( argc==1 );
zIn = (u8*)sqlite3_value_text(argv[0]);
+ if( zIn==0 ) zIn = "";
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
if( zIn[i] ){
zResult[0] = toupper(zIn[i]);
@@ -653,6 +676,26 @@
}
#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** A function that loads a shared-library extension then returns NULL.
+*/
+static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
+ const char *zFile = (const char *)sqlite3_value_text(argv[0]);
+ const char *zProc = 0;
+ sqlite3 *db = sqlite3_user_data(context);
+ char *zErrMsg = 0;
+
+ if( argc==2 ){
+ zProc = (const char *)sqlite3_value_text(argv[1]);
+ }
+ if( sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
+ sqlite3_result_error(context, zErrMsg, -1);
+ sqlite3_free(zErrMsg);
+ }
+}
+#endif
+
#ifdef SQLITE_TEST
/*
** This function generates a string of random characters. Used for
@@ -817,9 +860,11 @@
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
- LONGDOUBLE_TYPE sum; /* Sum of terms */
- i64 cnt; /* Number of elements summed */
- u8 approx; /* True if sum is approximate */
+ 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 */
};
/*
@@ -829,16 +874,8 @@
** that it returns NULL if it sums over no inputs. TOTAL returns
** 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.
+** value. TOTAL never fails, but SUM might through an exception if
+** it overflows an integer.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
SumCtx *p;
@@ -849,13 +886,18 @@
if( p && type!=SQLITE_NULL ){
p->cnt++;
if( type==SQLITE_INTEGER ){
- p->sum += sqlite3_value_int64(argv[0]);
- if( !p->approx ){
- i64 iVal;
- p->approx = p->sum!=(LONGDOUBLE_TYPE)(iVal = (i64)p->sum);
+ 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->sum += sqlite3_value_double(argv[0]);
+ p->rSum += sqlite3_value_double(argv[0]);
p->approx = 1;
}
}
@@ -864,10 +906,12 @@
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- if( p->approx ){
- 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);
}
}
}
@@ -875,13 +919,13 @@
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);
}
/*
@@ -993,9 +1037,14 @@
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
{ "changes", 0, 1, SQLITE_UTF8, 0, changes },
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
+ { "match", 2, 0, SQLITE_UTF8, 0, matchStub },
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ { "load_extension", 1, 1, SQLITE_UTF8, 0, loadExt },
+ { "load_extension", 2, 1, SQLITE_UTF8, 0, loadExt },
+#endif
#ifdef SQLITE_TEST
{ "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
{ "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
@@ -1062,7 +1111,7 @@
}
sqlite3RegisterDateTimeFunctions(db);
#ifdef SQLITE_SSE
- sqlite3SseFunctions(db);
+ (void)sqlite3SseFunctions(db);
#endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
sqlite3RegisterLikeFunctions(db, 1);
Modified: Frontier/vendor/sqlite3/current/hash.c
===================================================================
--- Frontier/vendor/sqlite3/current/hash.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/hash.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -12,7 +12,7 @@
** 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 $
+** $Id: hash.c,v 1.18 2006/02/14 10:48:39 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <assert.h>
@@ -41,6 +41,8 @@
pNew->count = 0;
pNew->htsize = 0;
pNew->ht = 0;
+ pNew->xMalloc = sqlite3MallocX;
+ pNew->xFree = sqlite3FreeX;
}
/* Remove all entries from a hash table. Reclaim all memory.
@@ -53,15 +55,15 @@
assert( pH!=0 );
elem = pH->first;
pH->first = 0;
- if( pH->ht ) sqliteFree(pH->ht);
+ if( pH->ht ) pH->xFree(pH->ht);
pH->ht = 0;
pH->htsize = 0;
while( elem ){
HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){
- sqliteFree(elem->pKey);
+ pH->xFree(elem->pKey);
}
- sqliteFree(elem);
+ pH->xFree(elem);
elem = next_elem;
}
pH->count = 0;
@@ -222,9 +224,9 @@
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) );
+ new_ht = (struct _ht *)pH->xMalloc( new_size*sizeof(struct _ht) );
if( new_ht==0 ) return;
- if( pH->ht ) sqliteFree(pH->ht);
+ if( pH->ht ) pH->xFree(pH->ht);
pH->ht = new_ht;
pH->htsize = new_size;
xHash = hashFunction(pH->keyClass);
@@ -290,9 +292,9 @@
pEntry->chain = 0;
}
if( pH->copyKey && elem->pKey ){
- sqliteFree(elem->pKey);
+ pH->xFree(elem->pKey);
}
- sqliteFree( elem );
+ pH->xFree( elem );
pH->count--;
if( pH->count<=0 ){
assert( pH->first==0 );
@@ -358,12 +360,12 @@
return old_data;
}
if( data==0 ) return 0;
- new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
+ new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){
- new_elem->pKey = sqliteMallocRaw( nKey );
+ new_elem->pKey = pH->xMalloc( nKey );
if( new_elem->pKey==0 ){
- sqliteFree(new_elem);
+ pH->xFree(new_elem);
return data;
}
memcpy((void*)new_elem->pKey, pKey, nKey);
@@ -376,7 +378,7 @@
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
- sqliteFree(new_elem);
+ pH->xFree(new_elem);
return data;
}
}
Modified: Frontier/vendor/sqlite3/current/hash.h
===================================================================
--- Frontier/vendor/sqlite3/current/hash.h 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/hash.h 2006-09-23 18:20:39 UTC (rev 1523)
@@ -12,7 +12,7 @@
** 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 $
+** $Id: hash.h,v 1.9 2006/02/14 10:48:39 danielk1977 Exp $
*/
#ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_
@@ -34,6 +34,8 @@
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 */
+ void *(*xMalloc)(int); /* malloc() function to use */
+ void (*xFree)(void *); /* free() function to use */
int htsize; /* Number of buckets in the hash table */
struct _ht { /* the hash table */
int count; /* Number of entries with this hash */
Modified: Frontier/vendor/sqlite3/current/insert.c
===================================================================
--- Frontier/vendor/sqlite3/current/insert.c 2006-09-18 21:43:27 UTC (rev 1522)
+++ Frontier/vendor/sqlite3/current/insert.c 2006-09-23 18:20:39 UTC (rev 1523)
@@ -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.161 2006/02/10 02:27:43 danielk1977 Exp $
+** $Id: insert.c,v 1.170 2006/06/19 03:05:10 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -269,11 +269,13 @@
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto insert_cleanup;
}
- if( pTab==0 ) goto insert_cleanup;
+ assert( pTab!=0 );
/* If pTab is really a view, make sure it has been initialized.
+ **...
[truncated message content] |