mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Merge updates from trunk.
FossilOrigin-Name: 8dc0cdf652f099d464d3de416dffd83efb895009
This commit is contained in:
@@ -1109,7 +1109,7 @@ static void analyzeOneTable(
|
||||
** goto chng_addr_N
|
||||
*/
|
||||
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
||||
for(i=0; i<nCol; i++){
|
||||
for(i=0; i<nCol-1; i++){
|
||||
char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
|
||||
@@ -1118,7 +1118,7 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regChng);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol-1, regChng);
|
||||
aGotoChng[nCol] = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
|
||||
/*
|
||||
@@ -1129,7 +1129,7 @@ static void analyzeOneTable(
|
||||
** ...
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, addrGotoChng0);
|
||||
for(i=0; i<nCol; i++){
|
||||
for(i=0; i<nCol-1; i++){
|
||||
sqlite3VdbeJumpHere(v, aGotoChng[i]);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
|
||||
}
|
||||
@@ -1320,6 +1320,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
|
||||
Table *pTab;
|
||||
Index *pIdx;
|
||||
Token *pTableName;
|
||||
Vdbe *v;
|
||||
|
||||
/* Read the database schema. If an error occurs, leave an error message
|
||||
** and code in pParse and return NULL. */
|
||||
@@ -1367,6 +1368,8 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
|
||||
}
|
||||
}
|
||||
}
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1425,14 +1428,19 @@ static void decodeIntArray(
|
||||
#else
|
||||
if( pIndex )
|
||||
#endif
|
||||
{
|
||||
if( strcmp(z, "unordered")==0 ){
|
||||
while( z[0] ){
|
||||
if( sqlite3_strglob("unordered*", z)==0 ){
|
||||
pIndex->bUnordered = 1;
|
||||
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
|
||||
int v32 = 0;
|
||||
sqlite3GetInt32(z+3, &v32);
|
||||
pIndex->szIdxRow = sqlite3LogEst(v32);
|
||||
pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_COSTMULT
|
||||
else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
|
||||
pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
|
||||
}
|
||||
#endif
|
||||
while( z[0]!=0 && z[0]!=' ' ) z++;
|
||||
while( z[0]==' ' ) z++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1473,11 +1481,15 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
z = argv[2];
|
||||
|
||||
if( pIndex ){
|
||||
pIndex->bUnordered = 0;
|
||||
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
|
||||
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
|
||||
}else{
|
||||
Index fakeIdx;
|
||||
fakeIdx.szIdxRow = pTable->szTabRow;
|
||||
#ifdef SQLITE_ENABLE_COSTMULT
|
||||
fakeIdx.pTable = pTable;
|
||||
#endif
|
||||
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
|
||||
pTable->szTabRow = fakeIdx.szIdxRow;
|
||||
}
|
||||
|
||||
34
src/build.c
34
src/build.c
@@ -113,6 +113,19 @@ static void codeTableLocks(Parse *pParse){
|
||||
#define codeTableLocks(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return TRUE if the given yDbMask object is empty - if it contains no
|
||||
** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero()
|
||||
** macros when SQLITE_MAX_ATTACHED is greater than 30.
|
||||
*/
|
||||
#if SQLITE_MAX_ATTACHED>30
|
||||
int sqlite3DbMaskAllZero(yDbMask m){
|
||||
int i;
|
||||
for(i=0; i<sizeof(yDbMask); i++) if( m[i] ) return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine is called after a single SQL statement has been
|
||||
** parsed and a VDBE program to execute that statement has been
|
||||
@@ -149,18 +162,19 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
** transaction on each used database and to verify the schema cookie
|
||||
** on each used database.
|
||||
*/
|
||||
if( db->mallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){
|
||||
yDbMask mask;
|
||||
if( db->mallocFailed==0
|
||||
&& (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
|
||||
){
|
||||
int iDb, i;
|
||||
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
||||
sqlite3VdbeJumpHere(v, 0);
|
||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||
for(iDb=0; iDb<db->nDb; iDb++){
|
||||
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp4Int(v,
|
||||
OP_Transaction, /* Opcode */
|
||||
iDb, /* P1 */
|
||||
(mask & pParse->writeMask)!=0, /* P2 */
|
||||
DbMaskTest(pParse->writeMask,iDb), /* P2 */
|
||||
pParse->cookieValue[iDb], /* P3 */
|
||||
db->aDb[iDb].pSchema->iGeneration /* P4 */
|
||||
);
|
||||
@@ -216,7 +230,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
pParse->nMem = 0;
|
||||
pParse->nSet = 0;
|
||||
pParse->nVar = 0;
|
||||
pParse->cookieMask = 0;
|
||||
DbMaskZero(pParse->cookieMask);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3843,15 +3857,13 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
sqlite3 *db = pToplevel->db;
|
||||
yDbMask mask;
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
mask = ((yDbMask)1)<<iDb;
|
||||
if( (pToplevel->cookieMask & mask)==0 ){
|
||||
pToplevel->cookieMask |= mask;
|
||||
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
|
||||
DbMaskSet(pToplevel->cookieMask, iDb);
|
||||
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
sqlite3OpenTempDatabase(pToplevel);
|
||||
@@ -3890,7 +3902,7 @@ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
|
||||
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
pToplevel->writeMask |= ((yDbMask)1)<<iDb;
|
||||
DbMaskSet(pToplevel->writeMask, iDb);
|
||||
pToplevel->isMultiWrite |= setStatement;
|
||||
}
|
||||
|
||||
|
||||
11
src/expr.c
11
src/expr.c
@@ -2075,7 +2075,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
i64 value;
|
||||
const char *z = pExpr->u.zToken;
|
||||
assert( z!=0 );
|
||||
c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
c = sqlite3DecOrHexToI64(z, &value);
|
||||
if( c==0 || (c==2 && negFlag) ){
|
||||
char *zV;
|
||||
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
|
||||
@@ -2085,7 +2085,14 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
|
||||
#else
|
||||
codeReal(v, z, negFlag, iMem);
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
if( sqlite3_strnicmp(z,"0x",2)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
codeReal(v, z, negFlag, iMem);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2101,8 +2101,8 @@ static const int aHardLimit[] = {
|
||||
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
|
||||
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
|
||||
#endif
|
||||
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>62
|
||||
# error SQLITE_MAX_ATTACHED must be between 0 and 62
|
||||
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
|
||||
# error SQLITE_MAX_ATTACHED must be between 0 and 125
|
||||
#endif
|
||||
#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1
|
||||
# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1
|
||||
@@ -3409,7 +3409,7 @@ sqlite3_int64 sqlite3_uri_int64(
|
||||
){
|
||||
const char *z = sqlite3_uri_parameter(zFilename, zParam);
|
||||
sqlite3_int64 v;
|
||||
if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){
|
||||
if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
|
||||
bDflt = v;
|
||||
}
|
||||
return bDflt;
|
||||
|
||||
@@ -1048,7 +1048,7 @@ void sqlite3Pragma(
|
||||
Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
||||
i64 iLimit = -2;
|
||||
if( zRight ){
|
||||
sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8);
|
||||
sqlite3DecOrHexToI64(zRight, &iLimit);
|
||||
if( iLimit<-1 ) iLimit = -1;
|
||||
}
|
||||
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
|
||||
@@ -1176,7 +1176,7 @@ void sqlite3Pragma(
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( zRight ){
|
||||
int ii;
|
||||
sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8);
|
||||
sqlite3DecOrHexToI64(zRight, &sz);
|
||||
if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
|
||||
if( pId2->n==0 ) db->szMmap = sz;
|
||||
for(ii=db->nDb-1; ii>=0; ii--){
|
||||
@@ -2219,7 +2219,7 @@ void sqlite3Pragma(
|
||||
*/
|
||||
case PragTyp_SOFT_HEAP_LIMIT: {
|
||||
sqlite3_int64 N;
|
||||
if( zRight && sqlite3Atoi64(zRight, &N, 1000000, SQLITE_UTF8)==SQLITE_OK ){
|
||||
if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
|
||||
sqlite3_soft_heap_limit64(N);
|
||||
}
|
||||
returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
|
||||
|
||||
155
src/shell.c
155
src/shell.c
@@ -64,6 +64,7 @@
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
#define isatty(h) _isatty(h)
|
||||
#ifndef access
|
||||
# define access(f,m) _access((f),(m))
|
||||
@@ -459,6 +460,7 @@ struct callback_data {
|
||||
char *zDestTable; /* Name of destination table when MODE_Insert */
|
||||
char colSeparator[20]; /* Column separator character for several modes */
|
||||
char rowSeparator[20]; /* Row separator character for MODE_Ascii */
|
||||
char newline[20]; /* Record separator in MODE_Csv */
|
||||
int colWidth[100]; /* Requested width of each column when in column mode*/
|
||||
int actualWidth[100]; /* Actual width of each column */
|
||||
char nullvalue[20]; /* The text to print when a NULL comes back from
|
||||
@@ -505,11 +507,17 @@ static const char *modeDescr[] = {
|
||||
};
|
||||
|
||||
/*
|
||||
** These are the column/row separators used by the ASCII mode.
|
||||
** These are the column/row/line separators used by the various
|
||||
** import/export modes.
|
||||
*/
|
||||
#define SEP_Line "\n"
|
||||
#define SEP_Column "\x1F"
|
||||
#define SEP_Row "\x1E"
|
||||
#define SEP_Column "|"
|
||||
#define SEP_Row "\n"
|
||||
#define SEP_Tab "\t"
|
||||
#define SEP_Space " "
|
||||
#define SEP_Comma ","
|
||||
#define SEP_CrLf "\r\n"
|
||||
#define SEP_Unit "\x1F"
|
||||
#define SEP_Record "\x1E"
|
||||
|
||||
/*
|
||||
** Number of elements in an array
|
||||
@@ -669,7 +677,8 @@ static const char needCsvQuote[] = {
|
||||
/*
|
||||
** Output a single term of CSV. Actually, p->separator is used for
|
||||
** the separator, which may or may not be a comma. p->nullvalue is
|
||||
** the null value. Strings are quoted if necessary.
|
||||
** the null value. Strings are quoted if necessary. The separator
|
||||
** is only issued if bSep is true.
|
||||
*/
|
||||
static void output_csv(struct callback_data *p, const char *z, int bSep){
|
||||
FILE *out = p->out;
|
||||
@@ -870,17 +879,26 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
|
||||
break;
|
||||
}
|
||||
case MODE_Csv: {
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
fflush(p->out);
|
||||
_setmode(_fileno(p->out), _O_BINARY);
|
||||
#endif
|
||||
if( p->cnt++==0 && p->showHeader ){
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
|
||||
}
|
||||
fprintf(p->out, "%s", p->rowSeparator);
|
||||
fprintf(p->out, "%s", p->newline);
|
||||
}
|
||||
if( azArg==0 ) break;
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azArg[i], i<nArg-1);
|
||||
if( azArg>0 ){
|
||||
for(i=0; i<nArg; i++){
|
||||
output_csv(p, azArg[i], i<nArg-1);
|
||||
}
|
||||
fprintf(p->out, "%s", p->newline);
|
||||
}
|
||||
fprintf(p->out, "%s", p->rowSeparator);
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
fflush(p->out);
|
||||
_setmode(_fileno(p->out), _O_TEXT);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case MODE_Insert: {
|
||||
@@ -1653,7 +1671,8 @@ static char zHelp[] =
|
||||
".schema ?TABLE? Show the CREATE statements\n"
|
||||
" If TABLE specified, only show tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
".separator STRING Change column separator for output mode and .import\n"
|
||||
".separator STRING ?NL? Change column separator for output mode and .import\n"
|
||||
" NL is the end-of-line mark for CSV\n"
|
||||
".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
|
||||
".show Show the current values for various settings\n"
|
||||
".stats on|off Turn stats on or off\n"
|
||||
@@ -1671,6 +1690,69 @@ static char zHelp[] =
|
||||
|
||||
/* Forward reference */
|
||||
static int process_input(struct callback_data *p, FILE *in);
|
||||
/*
|
||||
** Implementation of the "readfile(X)" SQL function. The entire content
|
||||
** of the file named X is read and returned as a BLOB. NULL is returned
|
||||
** if the file does not exist or is unreadable.
|
||||
*/
|
||||
static void readfileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zName;
|
||||
FILE *in;
|
||||
long nIn;
|
||||
void *pBuf;
|
||||
|
||||
zName = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zName==0 ) return;
|
||||
in = fopen(zName, "rb");
|
||||
if( in==0 ) return;
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
pBuf = sqlite3_malloc( nIn );
|
||||
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "writefile(X,Y)" SQL function. The argument Y
|
||||
** is written into file X. The number of bytes written is returned. Or
|
||||
** NULL is returned if something goes wrong, such as being unable to open
|
||||
** file X for writing.
|
||||
*/
|
||||
static void writefileFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
FILE *out;
|
||||
const char *z;
|
||||
int n;
|
||||
sqlite3_int64 rc;
|
||||
const char *zFile;
|
||||
|
||||
zFile = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zFile==0 ) return;
|
||||
out = fopen(zFile, "wb");
|
||||
if( out==0 ) return;
|
||||
z = (const char*)sqlite3_value_blob(argv[1]);
|
||||
if( z==0 ){
|
||||
n = 0;
|
||||
rc = 0;
|
||||
}else{
|
||||
n = sqlite3_value_bytes(argv[1]);
|
||||
rc = fwrite(z, 1, n, out);
|
||||
}
|
||||
fclose(out);
|
||||
sqlite3_result_int64(context, rc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure the database is open. If it is not, then open it. If
|
||||
@@ -1694,6 +1776,10 @@ static void open_db(struct callback_data *p, int keepAlive){
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
sqlite3_enable_load_extension(p->db, 1);
|
||||
#endif
|
||||
sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
readfileFunc, 0, 0);
|
||||
sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
|
||||
writefileFunc, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2846,23 +2932,24 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
p->mode = MODE_Html;
|
||||
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
|
||||
p->mode = MODE_Tcl;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, " ");
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Line);
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
|
||||
p->mode = MODE_Csv;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, ",");
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Line);
|
||||
sqlite3_snprintf(sizeof(p->newline), p->newline, SEP_CrLf);
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
|
||||
p->mode = MODE_List;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, "\t");
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Line);
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
|
||||
p->mode = MODE_Insert;
|
||||
set_table_name(p, nArg>=3 ? azArg[2] : "table");
|
||||
}else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
|
||||
p->mode = MODE_Ascii;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
|
||||
}else {
|
||||
fprintf(stderr,"Error: mode should be one of: "
|
||||
"ascii column csv html insert line list tabs tcl\n");
|
||||
@@ -3155,12 +3242,17 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}else
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
if( nArg<2 || nArg>3 ){
|
||||
fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
|
||||
rc = 1;
|
||||
}
|
||||
if( nArg>=2 ){
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
|
||||
"%.*s", (int)sizeof(p->colSeparator)-1, azArg[1]);
|
||||
}else{
|
||||
fprintf(stderr, "Usage: .separator STRING\n");
|
||||
rc = 1;
|
||||
}
|
||||
if( nArg>=3 ){
|
||||
sqlite3_snprintf(sizeof(p->newline), p->newline,
|
||||
"%.*s", (int)sizeof(p->newline)-1, azArg[2]);
|
||||
}
|
||||
}else
|
||||
|
||||
@@ -3206,6 +3298,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
fprintf(p->out,"%12.12s: ", "rowseparator");
|
||||
output_c_string(p->out, p->rowSeparator);
|
||||
fprintf(p->out, "\n");
|
||||
fprintf(p->out,"%12.12s: ", "newline");
|
||||
output_c_string(p->out, p->newline);
|
||||
fprintf(p->out, "\n");
|
||||
fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
|
||||
fprintf(p->out,"%12.12s: ","width");
|
||||
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
|
||||
@@ -3823,6 +3918,7 @@ static const char zOptions[] =
|
||||
#ifdef SQLITE_ENABLE_MULTIPLEX
|
||||
" -multiplex enable the multiplexor VFS\n"
|
||||
#endif
|
||||
" -newline SEP set newline character(s) for CSV\n"
|
||||
" -nullvalue TEXT set text string for NULL values. Default ''\n"
|
||||
" -rowseparator SEP set output line separator. Default: '\\n'\n"
|
||||
" -separator SEP set output field separator. Default: '|'\n"
|
||||
@@ -3852,8 +3948,9 @@ static void usage(int showDetail){
|
||||
static void main_init(struct callback_data *data) {
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->mode = MODE_List;
|
||||
memcpy(data->colSeparator,"|", 2);
|
||||
memcpy(data->rowSeparator,"\n", 2);
|
||||
memcpy(data->colSeparator,SEP_Column, 2);
|
||||
memcpy(data->rowSeparator,SEP_Row, 2);
|
||||
memcpy(data->newline,SEP_CrLf, 3);
|
||||
data->showHeader = 0;
|
||||
sqlite3_config(SQLITE_CONFIG_URI, 1);
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
|
||||
@@ -3946,6 +4043,7 @@ int main(int argc, char **argv){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-separator")==0
|
||||
|| strcmp(z,"-nullvalue")==0
|
||||
|| strcmp(z,"-newline")==0
|
||||
|| strcmp(z,"-cmd")==0
|
||||
){
|
||||
(void)cmdline_option_value(argc, argv, ++i);
|
||||
@@ -4055,15 +4153,18 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-ascii")==0 ){
|
||||
data.mode = MODE_Ascii;
|
||||
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
|
||||
SEP_Column);
|
||||
SEP_Unit);
|
||||
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
|
||||
SEP_Row);
|
||||
SEP_Record);
|
||||
}else if( strcmp(z,"-separator")==0 || strcmp(z,"-colseparator")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
}else if( strcmp(z,"-rowseparator")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
}else if( strcmp(z,"-newline")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.newline), data.newline,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
}else if( strcmp(z,"-nullvalue")==0 ){
|
||||
sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
|
||||
"%s",cmdline_option_value(argc,argv,++i));
|
||||
|
||||
@@ -4711,6 +4711,13 @@ int sqlite3_sleep(int);
|
||||
** is a NULL pointer, then SQLite performs a search for an appropriate
|
||||
** temporary file directory.
|
||||
**
|
||||
** Applications are strongly discouraged from using this global variable.
|
||||
** It is required to set a temporary folder on Windows Runtime (WinRT).
|
||||
** But for all other platforms, it is highly recommended that applications
|
||||
** neither read nor write this variable. This global variable is a relic
|
||||
** that exists for backwards compatibility of legacy applications and should
|
||||
** be avoided in new projects.
|
||||
**
|
||||
** It is not safe to read or modify this variable in more than one
|
||||
** thread at a time. It is not safe to read or modify this variable
|
||||
** if a [database connection] is being used at the same time in a separate
|
||||
@@ -4729,6 +4736,11 @@ int sqlite3_sleep(int);
|
||||
** Hence, if this variable is modified directly, either it should be
|
||||
** made NULL or made to point to memory obtained from [sqlite3_malloc]
|
||||
** or else the use of the [temp_store_directory pragma] should be avoided.
|
||||
** Except when requested by the [temp_store_directory pragma], SQLite
|
||||
** does not free the memory that sqlite3_temp_directory points to. If
|
||||
** the application wants that memory to be freed, it must do
|
||||
** so itself, taking care to only do so after all [database connection]
|
||||
** objects have been destroyed.
|
||||
**
|
||||
** <b>Note to Windows Runtime users:</b> The temporary directory must be set
|
||||
** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various
|
||||
|
||||
@@ -1477,6 +1477,9 @@ struct Table {
|
||||
i16 nCol; /* Number of columns in this table */
|
||||
u16 nRef; /* Number of pointers to this Table */
|
||||
LogEst szTabRow; /* Estimated size of each table row in bytes */
|
||||
#ifdef SQLITE_ENABLE_COSTMULT
|
||||
LogEst costMult; /* Cost multiplier for using this table */
|
||||
#endif
|
||||
u8 tabFlags; /* Mask of TF_* values */
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
@@ -2136,6 +2139,7 @@ struct SrcList {
|
||||
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
|
||||
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
|
||||
#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
|
||||
#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */
|
||||
|
||||
/* Allowed return values from sqlite3WhereIsDistinct()
|
||||
*/
|
||||
@@ -2392,9 +2396,19 @@ struct TriggerPrg {
|
||||
** The yDbMask datatype for the bitmask of all attached databases.
|
||||
*/
|
||||
#if SQLITE_MAX_ATTACHED>30
|
||||
typedef sqlite3_uint64 yDbMask;
|
||||
typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8];
|
||||
# define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0)
|
||||
# define DbMaskZero(M) memset((M),0,sizeof(M))
|
||||
# define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7))
|
||||
# define DbMaskAllZero(M) sqlite3DbMaskAllZero(M)
|
||||
# define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0)
|
||||
#else
|
||||
typedef unsigned int yDbMask;
|
||||
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
|
||||
# define DbMaskZero(M) (M)=0
|
||||
# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
|
||||
# define DbMaskAllZero(M) (M)==0
|
||||
# define DbMaskNonZero(M) (M)!=0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -3067,6 +3081,9 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
||||
# define sqlite3ViewGetColumnNames(A,B) 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_MAX_ATTACHED>30
|
||||
int sqlite3DbMaskAllZero(yDbMask);
|
||||
#endif
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
@@ -3317,6 +3334,7 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2);
|
||||
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
|
||||
char sqlite3ExprAffinity(Expr *pExpr);
|
||||
int sqlite3Atoi64(const char*, i64*, int, u8);
|
||||
int sqlite3DecOrHexToI64(const char*, i64*);
|
||||
void sqlite3Error(sqlite3*, int, const char*,...);
|
||||
void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
|
||||
u8 sqlite3HexToInt(int h);
|
||||
|
||||
@@ -270,6 +270,12 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
|
||||
testcase( z[0]=='9' );
|
||||
*tokenType = TK_INTEGER;
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
|
||||
for(i=3; sqlite3Isxdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
for(i=0; sqlite3Isdigit(z[i]); i++){}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( z[i]=='.' ){
|
||||
|
||||
58
src/util.c
58
src/util.c
@@ -475,9 +475,9 @@ static int compare2pow63(const char *zNum, int incr){
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert zNum to a 64-bit signed integer.
|
||||
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
|
||||
** routine does *not* accept hexadecimal notation.
|
||||
**
|
||||
** If the zNum value is representable as a 64-bit twos-complement
|
||||
** integer, then write that value into *pNum and return 0.
|
||||
@@ -565,10 +565,44 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Transform a UTF-8 integer literal, in either decimal or hexadecimal,
|
||||
** into a 64-bit signed integer. This routine accepts hexadecimal literals,
|
||||
** whereas sqlite3Atoi64() does not.
|
||||
**
|
||||
** Returns:
|
||||
**
|
||||
** 0 Successful transformation. Fits in a 64-bit signed integer.
|
||||
** 1 Integer too large for a 64-bit signed integer or is malformed
|
||||
** 2 Special case of 9223372036854775808
|
||||
*/
|
||||
int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
if( z[0]=='0'
|
||||
&& (z[1]=='x' || z[1]=='X')
|
||||
&& sqlite3Isxdigit(z[2])
|
||||
){
|
||||
u64 u = 0;
|
||||
int i, k;
|
||||
for(i=2; z[i]=='0'; i++){}
|
||||
for(k=i; sqlite3Isxdigit(z[k]); k++){
|
||||
u = u*16 + sqlite3HexToInt(z[k]);
|
||||
}
|
||||
memcpy(pOut, &u, 8);
|
||||
return (z[k]==0 && k-i<=16) ? 0 : 1;
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_HEX_INTEGER */
|
||||
{
|
||||
return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If zNum represents an integer that will fit in 32-bits, then set
|
||||
** *pValue to that integer and return true. Otherwise return false.
|
||||
**
|
||||
** This routine accepts both decimal and hexadecimal notation for integers.
|
||||
**
|
||||
** Any non-numeric characters that following zNum are ignored.
|
||||
** This is different from sqlite3Atoi64() which requires the
|
||||
** input number to be zero-terminated.
|
||||
@@ -583,7 +617,25 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
}else if( zNum[0]=='+' ){
|
||||
zNum++;
|
||||
}
|
||||
while( zNum[0]=='0' ) zNum++;
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
else if( zNum[0]=='0'
|
||||
&& (zNum[1]=='x' || zNum[1]=='X')
|
||||
&& sqlite3Isxdigit(zNum[2])
|
||||
){
|
||||
u32 u = 0;
|
||||
zNum += 2;
|
||||
while( zNum[0]=='0' ) zNum++;
|
||||
for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){
|
||||
u = u*16 + sqlite3HexToInt(zNum[i]);
|
||||
}
|
||||
if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){
|
||||
memcpy(pValue, &u, 4);
|
||||
return 1;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
|
||||
v = v*10 + c;
|
||||
}
|
||||
|
||||
64
src/vdbe.c
64
src/vdbe.c
@@ -3034,7 +3034,7 @@ case OP_Transaction: {
|
||||
assert( p->bIsReader );
|
||||
assert( p->readOnly==0 || pOp->p2==0 );
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p1) );
|
||||
if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
|
||||
rc = SQLITE_READONLY;
|
||||
goto abort_due_to_error;
|
||||
@@ -3129,7 +3129,7 @@ case OP_ReadCookie: { /* out2-prerelease */
|
||||
assert( pOp->p3<SQLITE_N_BTREE_META );
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, iDb) );
|
||||
|
||||
sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta);
|
||||
pOut->u.i = iMeta;
|
||||
@@ -3150,7 +3150,7 @@ case OP_SetCookie: { /* in3 */
|
||||
Db *pDb;
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p1) );
|
||||
assert( p->readOnly==0 );
|
||||
pDb = &db->aDb[pOp->p1];
|
||||
assert( pDb->pBt!=0 );
|
||||
@@ -3205,7 +3205,21 @@ case OP_SetCookie: { /* in3 */
|
||||
** sequence of the index being opened. Otherwise, if P4 is an integer
|
||||
** value, it is set to the number of columns in the table.
|
||||
**
|
||||
** See also OpenWrite.
|
||||
** See also: OpenWrite, ReopenIdx
|
||||
*/
|
||||
/* Opcode: ReopenIdx P1 P2 P3 P4 P5
|
||||
** Synopsis: root=P2 iDb=P3
|
||||
**
|
||||
** The ReopenIdx opcode works exactly like ReadOpen except that it first
|
||||
** checks to see if the cursor on P1 is already open with a root page
|
||||
** number of P2 and if it is this opcode becomes a no-op. In other words,
|
||||
** if the cursor is already open, do not reopen it.
|
||||
**
|
||||
** The ReopenIdx opcode may only be used with P5==0 and with P4 being
|
||||
** a P4_KEYINFO object. Furthermore, the P3 value must be the same as
|
||||
** every other ReopenIdx or OpenRead for the same cursor number.
|
||||
**
|
||||
** See the OpenRead opcode documentation for additional information.
|
||||
*/
|
||||
/* Opcode: OpenWrite P1 P2 P3 P4 P5
|
||||
** Synopsis: root=P2 iDb=P3
|
||||
@@ -3227,6 +3241,19 @@ case OP_SetCookie: { /* in3 */
|
||||
**
|
||||
** See also OpenRead.
|
||||
*/
|
||||
case OP_ReopenIdx: {
|
||||
VdbeCursor *pCur;
|
||||
|
||||
assert( pOp->p5==0 );
|
||||
assert( pOp->p4type==P4_KEYINFO );
|
||||
pCur = p->apCsr[pOp->p1];
|
||||
if( pCur && pCur->pgnoRoot==pOp->p2 ){
|
||||
assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
|
||||
break;
|
||||
}
|
||||
/* If the cursor is not currently open or is open on a different
|
||||
** index, then fall through into OP_OpenRead to force a reopen */
|
||||
}
|
||||
case OP_OpenRead:
|
||||
case OP_OpenWrite: {
|
||||
int nField;
|
||||
@@ -3241,7 +3268,8 @@ case OP_OpenWrite: {
|
||||
assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
|
||||
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
|
||||
assert( p->bIsReader );
|
||||
assert( pOp->opcode==OP_OpenRead || p->readOnly==0 );
|
||||
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
|
||||
|| p->readOnly==0 );
|
||||
|
||||
if( p->expired ){
|
||||
rc = SQLITE_ABORT;
|
||||
@@ -3253,7 +3281,7 @@ case OP_OpenWrite: {
|
||||
p2 = pOp->p2;
|
||||
iDb = pOp->p3;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, iDb) );
|
||||
pDb = &db->aDb[iDb];
|
||||
pX = pDb->pBt;
|
||||
assert( pX!=0 );
|
||||
@@ -3298,6 +3326,7 @@ case OP_OpenWrite: {
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->nullRow = 1;
|
||||
pCur->isOrdered = 1;
|
||||
pCur->pgnoRoot = p2;
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
|
||||
pCur->pKeyInfo = pKeyInfo;
|
||||
assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
|
||||
@@ -4844,7 +4873,7 @@ case OP_Destroy: { /* out2-prerelease */
|
||||
}else{
|
||||
iDb = pOp->p3;
|
||||
assert( iCnt==1 );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<iDb))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, iDb) );
|
||||
iMoved = 0; /* Not needed. Only to silence a warning. */
|
||||
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
|
||||
pOut->flags = MEM_Int;
|
||||
@@ -4884,7 +4913,7 @@ case OP_Clear: {
|
||||
|
||||
nChange = 0;
|
||||
assert( p->readOnly==0 );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p2) );
|
||||
rc = sqlite3BtreeClearTable(
|
||||
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
|
||||
);
|
||||
@@ -4954,7 +4983,7 @@ case OP_CreateTable: { /* out2-prerelease */
|
||||
|
||||
pgno = 0;
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p1) );
|
||||
assert( p->readOnly==0 );
|
||||
pDb = &db->aDb[pOp->p1];
|
||||
assert( pDb->pBt!=0 );
|
||||
@@ -5119,7 +5148,7 @@ case OP_IntegrityCk: {
|
||||
}
|
||||
aRoot[j] = 0;
|
||||
assert( pOp->p5<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p5) );
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
|
||||
(int)pnErr->u.i, &nErr);
|
||||
sqlite3DbFree(db, aRoot);
|
||||
@@ -5779,7 +5808,7 @@ case OP_IncrVacuum: { /* jump */
|
||||
Btree *pBt;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p1) );
|
||||
assert( p->readOnly==0 );
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
rc = sqlite3BtreeIncrVacuum(pBt);
|
||||
@@ -5794,12 +5823,13 @@ case OP_IncrVacuum: { /* jump */
|
||||
|
||||
/* Opcode: Expire P1 * * * *
|
||||
**
|
||||
** Cause precompiled statements to become expired. An expired statement
|
||||
** fails with an error code of SQLITE_SCHEMA if it is ever executed
|
||||
** (via sqlite3_step()).
|
||||
** Cause precompiled statements to expire. When an expired statement
|
||||
** is executed using sqlite3_step() it will either automatically
|
||||
** reprepare itself (if it was originally created using sqlite3_prepare_v2())
|
||||
** or it will fail with SQLITE_SCHEMA.
|
||||
**
|
||||
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
|
||||
** then only the currently executing statement is affected.
|
||||
** then only the currently executing statement is expired.
|
||||
*/
|
||||
case OP_Expire: {
|
||||
if( !pOp->p1 ){
|
||||
@@ -5831,7 +5861,7 @@ case OP_TableLock: {
|
||||
if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
|
||||
int p1 = pOp->p1;
|
||||
assert( p1>=0 && p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<p1))!=0 );
|
||||
assert( DbMaskTest(p->btreeMask, p1) );
|
||||
assert( isWriteLock==0 || isWriteLock==1 );
|
||||
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
|
||||
if( (rc&0xFF)==SQLITE_LOCKED ){
|
||||
@@ -6281,7 +6311,7 @@ case OP_Init: { /* jump */
|
||||
if( zTrace ){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( (MASKBIT(i) & p->btreeMask)==0 ) continue;
|
||||
if( DbMaskTest(p->btreeMask, i)==0 ) continue;
|
||||
sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ struct VdbeCursor {
|
||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
Bool isTable:1; /* True if a table requiring integer keys */
|
||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||
Pgno pgnoRoot; /* Root page of the open btree cursor */
|
||||
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
|
||||
@@ -499,7 +499,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
pParse->aLabel = 0;
|
||||
pParse->nLabel = 0;
|
||||
*pMaxFuncArgs = nMaxArgs;
|
||||
assert( p->bIsReader!=0 || p->btreeMask==0 );
|
||||
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -526,7 +526,7 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
|
||||
assert( aOp && !p->db->mallocFailed );
|
||||
|
||||
/* Check that sqlite3VdbeUsesBtree() was not called on this VM */
|
||||
assert( p->btreeMask==0 );
|
||||
assert( DbMaskAllZero(p->btreeMask) );
|
||||
|
||||
resolveP2Values(p, pnMaxArg);
|
||||
*pnOp = p->nOp;
|
||||
@@ -1111,9 +1111,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
void sqlite3VdbeUsesBtree(Vdbe *p, int i){
|
||||
assert( i>=0 && i<p->db->nDb && i<(int)sizeof(yDbMask)*8 );
|
||||
assert( i<(int)sizeof(p->btreeMask)*8 );
|
||||
p->btreeMask |= ((yDbMask)1)<<i;
|
||||
DbMaskSet(p->btreeMask, i);
|
||||
if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
|
||||
p->lockMask |= ((yDbMask)1)<<i;
|
||||
DbMaskSet(p->lockMask, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1141,16 +1141,15 @@ void sqlite3VdbeUsesBtree(Vdbe *p, int i){
|
||||
*/
|
||||
void sqlite3VdbeEnter(Vdbe *p){
|
||||
int i;
|
||||
yDbMask mask;
|
||||
sqlite3 *db;
|
||||
Db *aDb;
|
||||
int nDb;
|
||||
if( p->lockMask==0 ) return; /* The common case */
|
||||
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
|
||||
db = p->db;
|
||||
aDb = db->aDb;
|
||||
nDb = db->nDb;
|
||||
for(i=0, mask=1; i<nDb; i++, mask += mask){
|
||||
if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
|
||||
for(i=0; i<nDb; i++){
|
||||
if( i!=1 && DbMaskTest(p->lockMask,i) && ALWAYS(aDb[i].pBt!=0) ){
|
||||
sqlite3BtreeEnter(aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
@@ -1163,16 +1162,15 @@ void sqlite3VdbeEnter(Vdbe *p){
|
||||
*/
|
||||
void sqlite3VdbeLeave(Vdbe *p){
|
||||
int i;
|
||||
yDbMask mask;
|
||||
sqlite3 *db;
|
||||
Db *aDb;
|
||||
int nDb;
|
||||
if( p->lockMask==0 ) return; /* The common case */
|
||||
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
|
||||
db = p->db;
|
||||
aDb = db->aDb;
|
||||
nDb = db->nDb;
|
||||
for(i=0, mask=1; i<nDb; i++, mask += mask){
|
||||
if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
|
||||
for(i=0; i<nDb; i++){
|
||||
if( i!=1 && DbMaskTest(p->lockMask,i) && ALWAYS(aDb[i].pBt!=0) ){
|
||||
sqlite3BtreeLeave(aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
|
||||
32
src/where.c
32
src/where.c
@@ -3422,6 +3422,7 @@ static Bitmask codeOneLoopStart(
|
||||
int iRetInit; /* Address of regReturn init */
|
||||
int untestedTerms = 0; /* Some terms not completely tested */
|
||||
int ii; /* Loop counter */
|
||||
u16 wctrlFlags; /* Flags for sub-WHERE clause */
|
||||
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
|
||||
Table *pTab = pTabItem->pTab;
|
||||
|
||||
@@ -3517,6 +3518,8 @@ static Bitmask codeOneLoopStart(
|
||||
** eliminating duplicates from other WHERE clauses, the action for each
|
||||
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
|
||||
*/
|
||||
wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
|
||||
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY;
|
||||
for(ii=0; ii<pOrWc->nTerm; ii++){
|
||||
WhereTerm *pOrTerm = &pOrWc->a[ii];
|
||||
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
|
||||
@@ -3529,8 +3532,7 @@ static Bitmask codeOneLoopStart(
|
||||
}
|
||||
/* Loop through table entries that match term pOrTerm. */
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
|
||||
WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
|
||||
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
|
||||
wctrlFlags, iCovCur);
|
||||
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
|
||||
if( pSubWInfo ){
|
||||
WhereLoop *pSubLoop;
|
||||
@@ -3621,6 +3623,7 @@ static Bitmask codeOneLoopStart(
|
||||
){
|
||||
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
|
||||
pCov = pSubLoop->u.btree.pIndex;
|
||||
wctrlFlags |= WHERE_REOPEN_IDX;
|
||||
}else{
|
||||
pCov = 0;
|
||||
}
|
||||
@@ -4227,6 +4230,16 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust the cost C by the costMult facter T. This only occurs if
|
||||
** compiled with -DSQLITE_ENABLE_COSTMULT
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_COSTMULT
|
||||
# define ApplyCostMultiplier(C,T) C += T
|
||||
#else
|
||||
# define ApplyCostMultiplier(C,T)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
|
||||
** index pIndex. Try to match one more.
|
||||
@@ -4423,7 +4436,6 @@ static int whereLoopAddBtreeIndex(
|
||||
}else{
|
||||
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
|
||||
}
|
||||
assert( rc!=SQLITE_OK || nOut>0 );
|
||||
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
|
||||
if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */
|
||||
if( nOut ){
|
||||
@@ -4455,6 +4467,7 @@ static int whereLoopAddBtreeIndex(
|
||||
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
|
||||
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
|
||||
}
|
||||
ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult);
|
||||
|
||||
nOutUnadjusted = pNew->nOut;
|
||||
pNew->rRun += nInMul + nIn;
|
||||
@@ -4574,6 +4587,14 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
|
||||
** Normally, nSeek is 1. nSeek values greater than 1 come about if the
|
||||
** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
|
||||
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
|
||||
**
|
||||
** The estimated values (nRow, nVisit, nSeek) often contain a large amount
|
||||
** of uncertainty. For this reason, scoring is designed to pick plans that
|
||||
** "do the least harm" if the estimates are inaccurate. For example, a
|
||||
** log(nRow) factor is omitted from a non-covering index scan in order to
|
||||
** bias the scoring in favor of using an index, since the worst-case
|
||||
** performance of using an index is far better than the worst-case performance
|
||||
** of a full table scan.
|
||||
*/
|
||||
static int whereLoopAddBtree(
|
||||
WhereLoopBuilder *pBuilder, /* WHERE clause information */
|
||||
@@ -4661,6 +4682,7 @@ static int whereLoopAddBtree(
|
||||
** approximately 7*N*log2(N) where N is the number of rows in
|
||||
** the table being indexed. */
|
||||
pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
|
||||
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
|
||||
/* TUNING: Each index lookup yields 20 rows in the table. This
|
||||
** is more than the usual guess of 10 rows, since we have no way
|
||||
** of knowning how selective the index will ultimately be. It would
|
||||
@@ -4702,6 +4724,7 @@ static int whereLoopAddBtree(
|
||||
pNew->iSortIdx = b ? iSortIdx : 0;
|
||||
/* TUNING: Cost of full table scan is (N*3.0). */
|
||||
pNew->rRun = rSize + 16;
|
||||
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
|
||||
whereLoopOutputAdjust(pWC, pNew);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
@@ -4737,7 +4760,7 @@ static int whereLoopAddBtree(
|
||||
if( m!=0 ){
|
||||
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
|
||||
}
|
||||
|
||||
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
|
||||
whereLoopOutputAdjust(pWC, pNew);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
@@ -6212,6 +6235,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pWInfo->aiCurOnePass[1] = iIndexCur;
|
||||
}else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
|
||||
iIndexCur = iIdxCur;
|
||||
if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
|
||||
}else{
|
||||
iIndexCur = pParse->nTab++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user