diff options
author | drh <> | 2024-03-19 13:31:54 +0000 |
---|---|---|
committer | drh <> | 2024-03-19 13:31:54 +0000 |
commit | 4b42b5259f151aad0ece49b7132a6bc2e40b262f (patch) | |
tree | 82fae5e75de8fe0e4627c5b8d2363095dac00a6d /src | |
parent | 108dd6a52d3679cc3a772600ac22de792f92c897 (diff) | |
download | sqlite-4b42b5259f151aad0ece49b7132a6bc2e40b262f.tar.gz sqlite-4b42b5259f151aad0ece49b7132a6bc2e40b262f.zip |
When compiled with SQLITE_ALLOW_ROWID_IN_VIEW, rowid-in-view is on by default
but can now be turned off using SQLITE_TESTCTRL_ROWID_IN_VIEW. Without the
compile-time option, rowid-in-view is always off.
FossilOrigin-Name: 8a6196ab29052071be753c5c77ac945c2d62ecc8019c6160f954eafe34ab05a8
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 9 | ||||
-rw-r--r-- | src/global.c | 3 | ||||
-rw-r--r-- | src/main.c | 33 | ||||
-rw-r--r-- | src/select.c | 22 | ||||
-rw-r--r-- | src/shell.c.in | 15 | ||||
-rw-r--r-- | src/sqlite.h.in | 1 | ||||
-rw-r--r-- | src/sqliteInt.h | 14 |
7 files changed, 82 insertions, 15 deletions
diff --git a/src/build.c b/src/build.c index 15f8fe1d2..1bc6008ec 100644 --- a/src/build.c +++ b/src/build.c @@ -3006,9 +3006,12 @@ void sqlite3CreateView( ** on a view, even though views do not have rowids. The following flag ** setting fixes this problem. But the fix can be disabled by compiling ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that - ** depend upon the old buggy behavior. */ -#ifndef SQLITE_ALLOW_ROWID_IN_VIEW - p->tabFlags |= TF_NoVisibleRowid; + ** depend upon the old buggy behavior. The ability can also be toggled + ** using SQLITE_TESTCTRL_ROWID_IN_VIEW */ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + p->tabFlags |= sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */ +#else + p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */ #endif sqlite3TwoPartName(pParse, pName1, pName2, &pName); diff --git a/src/global.c b/src/global.c index 7f27d91d1..121b3f6d6 100644 --- a/src/global.c +++ b/src/global.c @@ -289,6 +289,9 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */ +#endif 0, /* bLocaltimeFault */ 0, /* xAltLocaltime */ 0x7ffffffe, /* iOnceResetThreshold */ diff --git a/src/main.c b/src/main.c index 03429983d..67191fb0f 100644 --- a/src/main.c +++ b/src/main.c @@ -4405,6 +4405,39 @@ int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_ROWID_IN_VIEW, int *pVal); + ** + ** Query or set the sqlite3Config.mNoVisibleRowid flag. Cases: + ** + ** *pVal==1 Allow ROWID in VIEWs + ** *pVal==0 Disallow ROWID in VIEWs + ** *pVal<0 No change + ** + ** In every case *pVal is written with 1 if ROWID is allowd in VIEWs and + ** 0 if not. Changes to the setting only occur if SQLite is compiled + ** with -DSQLITE_ALLOW_ROWID_IN_VIEW (hereafter: "SARIV"). With the + ** "SARIV" compile-time option the default value for this setting is 1. + ** Otherwise this setting defaults to 0. This setting may only be changed + ** if SQLite is compiled with "SARIV". Hence, in the normal case when + ** SQLite is compiled without "SARIV", this test-control is a no-op + ** that always leaves *pVal set to 0. + ** + ** IMPORTANT: If you change this setting while a database connection + ** is option, it is very important to run "PRAGMA writable_schema=RESET" + ** afterwards in order to reparse all VIEW definitions in the schema. + */ + case SQLITE_TESTCTRL_ROWID_IN_VIEW: { + int *pVal = va_arg(ap, int*); +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + if( *pVal==0 ) sqlite3Config.mNoVisibleRowid = TF_NoVisibleRowid; + if( *pVal==1 ) sqlite3Config.mNoVisibleRowid = 0; + *pVal = (sqlite3Config.mNoVisibleRowid==0); +#else + *pVal = 0; +#endif + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*); ** ** Toggle the ability to use internal functions on or off for diff --git a/src/select.c b/src/select.c index 5dfabb140..7f8a0f892 100644 --- a/src/select.c +++ b/src/select.c @@ -1953,11 +1953,7 @@ static const char *columnTypeImpl( ** data for the result-set column of the sub-select. */ if( iCol<pS->pEList->nExpr -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - && iCol>=0 -#else - && ALWAYS(iCol>=0) -#endif + && (!ViewCanHaveRowid || iCol>=0) ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see @@ -5874,7 +5870,8 @@ int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ /* The usual case - do not allow ROWID on a subquery */ pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; #else - pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ + /* Legacy compatibility mode */ + pTab->tabFlags |= TF_Ephemeral | sqlite3Config.mNoVisibleRowid; #endif return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } @@ -6142,9 +6139,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pNestedFrom = pFrom->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); -#ifndef SQLITE_ALLOW_ROWID_IN_VIEW - assert( VisibleRowid(pTab)==0 ); -#endif + assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); }else{ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; @@ -6177,9 +6172,12 @@ static int selectExpander(Walker *pWalker, Select *p){ } nAdd = pTab->nCol; -#ifndef SQLITE_ALLOW_ROWID_IN_VIEW - if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++; -#endif + if( VisibleRowid(pTab) + && !ViewCanHaveRowid + && (selFlags & SF_NestedFrom)!=0 + ){ + nAdd++; + } for(j=0; j<nAdd; j++){ const char *zName; struct ExprList_item *pX; /* Newly added ExprList term */ diff --git a/src/shell.c.in b/src/shell.c.in index 9fdf90952..fbec5a8c9 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -10893,6 +10893,7 @@ static int do_meta_command(char *zLine, ShellState *p){ {"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" }, {"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" }, {"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" }, + {"rowid_in_view", SQLITE_TESTCTRL_ROWID_IN_VIEW,0,"?BOOLEAN?" }, {"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" }, {"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" }, {"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" }, @@ -11067,6 +11068,20 @@ static int do_meta_command(char *zLine, ShellState *p){ break; } #endif + case SQLITE_TESTCTRL_ROWID_IN_VIEW: { + rc2 = -1; + if( nArg>=3 ){ + if( !ShellHasFlag(p,SHFLG_TestingMode) ){ + eputz("The --unsafe-testing option is required to change " + "this setting\n"); + }else{ + rc2 = booleanValue(azArg[2]); + } + } + sqlite3_test_control(testctrl, &rc2); + isOk = 1; + break; + } #ifdef SQLITE_DEBUG case SQLITE_TESTCTRL_TUNE: { if( nArg==4 ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e05d7b231..17a231860 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -8307,6 +8307,7 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ +#define SQLITE_TESTCTRL_ROWID_IN_VIEW 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8d18bfdfb..9fdc721e4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2535,6 +2535,15 @@ struct Table { #define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) +/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is +** available. By default, this macro is false +*/ +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW +# define ViewCanHaveRowid 0 +#else +# define ViewCanHaveRowid (sqlite3Config.mNoVisibleRowid==0) +#endif + /* ** Each foreign key constraint is an instance of the following structure. ** @@ -4254,6 +4263,11 @@ struct Sqlite3Config { #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + u32 mNoVisibleRowid; /* TF_NoVisibleRowid if the ROWID_IN_VIEW + ** feature is disabled. 0 if rowids can + ** occur in views. */ +#endif int bLocaltimeFault; /* True to fail localtime() calls */ int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */ int iOnceResetThreshold; /* When to reset OP_Once counters */ |