aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-03-19 13:31:54 +0000
committerdrh <>2024-03-19 13:31:54 +0000
commit4b42b5259f151aad0ece49b7132a6bc2e40b262f (patch)
tree82fae5e75de8fe0e4627c5b8d2363095dac00a6d /src
parent108dd6a52d3679cc3a772600ac22de792f92c897 (diff)
downloadsqlite-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.c9
-rw-r--r--src/global.c3
-rw-r--r--src/main.c33
-rw-r--r--src/select.c22
-rw-r--r--src/shell.c.in15
-rw-r--r--src/sqlite.h.in1
-rw-r--r--src/sqliteInt.h14
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 */