/ Check-in [edf45cd7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix spurious "no such table: x1" errors in shared-schema mode that could occur when a query that is a join across two or more databases needs to call the xConnect() methods of a virtual table.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema
Files: files | file ages | folders
SHA3-256: edf45cd7c6c1122db961ae66c21c7e974115e6048f1f5014015a5f693f1844bf
User & Date: dan 2019-08-08 15:47:32
Wiki:reuse-schema
Context
2019-08-09
14:54
In shared-schema mode, handle the case where a connection has created a virtual-table object, but is later assigned a different shared-schema object for which the virtual-table schema has not yet been initialized. check-in: e30c7414 user: dan tags: reuse-schema
2019-08-08
15:47
Fix spurious "no such table: x1" errors in shared-schema mode that could occur when a query that is a join across two or more databases needs to call the xConnect() methods of a virtual table. check-in: edf45cd7 user: dan tags: reuse-schema
11:44
Fix a bug causing "no such table" and other similar sqlite3_prepare*() errors to return SQLITE_SCHEMA instead of SQLITE_ERROR in shared-schema mode when there is an attached database for which the schema has never been loaded. check-in: 111e2c73 user: dan tags: reuse-schema
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/sqliteInt.h.

3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
  AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
  Parse *pToplevel;    /* Parse structure for main program (or NULL) */
  Table *pTriggerTab;  /* Table triggers are being coded for */
  Parse *pParentParse; /* Parent parser if this parser is nested */
  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
  u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
  u8 disableTriggers;  /* True to disable triggers */







<







3135
3136
3137
3138
3139
3140
3141

3142
3143
3144
3145
3146
3147
3148
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
  AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
  Parse *pToplevel;    /* Parse structure for main program (or NULL) */
  Table *pTriggerTab;  /* Table triggers are being coded for */

  int addrCrTab;       /* Address of OP_CreateBtree opcode on CREATE TABLE */
  u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
  u8 disableTriggers;  /* True to disable triggers */

Changes to src/tokenize.c.

556
557
558
559
560
561
562

563
564
565
566
567
568
569
...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
...
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  int nErr = 0;                   /* Number of errors encountered */
  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
  int n = 0;                      /* Length of the next token token */
  int tokenType;                  /* type of the next token */
  int lastTokenParsed = -1;       /* type of the previous token */
  sqlite3 *db = pParse->db;       /* The database connection */
  int mxSqlLen;                   /* Max length of an SQL string */

#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
#endif
  VVA_ONLY( u8 startedWithOom = db->mallocFailed );

  assert( zSql!=0 );
  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
................................................................................
    return SQLITE_NOMEM_BKPT;
  }
#endif
  assert( pParse->pNewTable==0 );
  assert( pParse->pNewTrigger==0 );
  assert( pParse->nVar==0 );
  assert( pParse->pVList==0 );
  pParse->pParentParse = db->pParse;
  db->pParse = pParse;
  while( 1 ){
    n = sqlite3GetToken((u8*)zSql, &tokenType);
    mxSqlLen -= n;
    if( mxSqlLen<0 ){
      pParse->rc = SQLITE_TOOBIG;
      break;
................................................................................
    sqlite3DbFreeNN(db, p);
  }
  while( pParse->pZombieTab ){
    Table *p = pParse->pZombieTab;
    pParse->pZombieTab = p->pNextZombie;
    sqlite3DeleteTable(db, p);
  }
  db->pParse = pParse->pParentParse;
  pParse->pParentParse = 0;
  assert( nErr==0 || pParse->rc!=SQLITE_OK );
  return nErr;
}


#ifdef SQLITE_ENABLE_NORMALIZE
/*







>







 







<







 







|
<







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
...
592
593
594
595
596
597
598

599
600
601
602
603
604
605
...
718
719
720
721
722
723
724
725

726
727
728
729
730
731
732
  int nErr = 0;                   /* Number of errors encountered */
  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
  int n = 0;                      /* Length of the next token token */
  int tokenType;                  /* type of the next token */
  int lastTokenParsed = -1;       /* type of the previous token */
  sqlite3 *db = pParse->db;       /* The database connection */
  int mxSqlLen;                   /* Max length of an SQL string */
  Parse *pParentParse = db->pParse;
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
  yyParser sEngine;    /* Space to hold the Lemon-generated Parser object */
#endif
  VVA_ONLY( u8 startedWithOom = db->mallocFailed );

  assert( zSql!=0 );
  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
................................................................................
    return SQLITE_NOMEM_BKPT;
  }
#endif
  assert( pParse->pNewTable==0 );
  assert( pParse->pNewTrigger==0 );
  assert( pParse->nVar==0 );
  assert( pParse->pVList==0 );

  db->pParse = pParse;
  while( 1 ){
    n = sqlite3GetToken((u8*)zSql, &tokenType);
    mxSqlLen -= n;
    if( mxSqlLen<0 ){
      pParse->rc = SQLITE_TOOBIG;
      break;
................................................................................
    sqlite3DbFreeNN(db, p);
  }
  while( pParse->pZombieTab ){
    Table *p = pParse->pZombieTab;
    pParse->pZombieTab = p->pNextZombie;
    sqlite3DeleteTable(db, p);
  }
  db->pParse = pParentParse;

  assert( nErr==0 || pParse->rc!=SQLITE_OK );
  return nErr;
}


#ifdef SQLITE_ENABLE_NORMALIZE
/*

Changes to src/vdbeblob.c.

127
128
129
130
131
132
133

134
135
136
137
138
139
140
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
){
  int nAttempt = 0;
  int iCol;               /* Index of zColumn in row-record */
  int rc = SQLITE_OK;
  char *zErr = 0;
  Table *pTab;
  Incrblob *pBlob = 0;

  Parse sParse;
  int bUnlock;            /* True to unlock reusable schemas before returning */

#ifdef SQLITE_ENABLE_API_ARMOR
  if( ppBlob==0 ){
    return SQLITE_MISUSE_BKPT;
  }
................................................................................
  if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */

  sqlite3_mutex_enter(db->mutex);
  assert( db->pParse==0 );

  bUnlock = sqlite3LockReusableSchema(db);
  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
  do {
    memset(&sParse, 0, sizeof(Parse));
    if( !pBlob ) goto blob_open_out;
    sParse.db = db;
................................................................................
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

blob_open_out:
  db->pParse = 0;
  sqlite3UnlockReusableSchema(db, bUnlock);
  if( rc==SQLITE_OK && db->mallocFailed==0 ){
    *ppBlob = (sqlite3_blob *)pBlob;
  }else{
    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
    sqlite3DbFree(db, pBlob);
  }







>







 







<







 







|







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
...
145
146
147
148
149
150
151

152
153
154
155
156
157
158
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
){
  int nAttempt = 0;
  int iCol;               /* Index of zColumn in row-record */
  int rc = SQLITE_OK;
  char *zErr = 0;
  Table *pTab;
  Incrblob *pBlob = 0;
  Parse *pParentParse = db->pParse;
  Parse sParse;
  int bUnlock;            /* True to unlock reusable schemas before returning */

#ifdef SQLITE_ENABLE_API_ARMOR
  if( ppBlob==0 ){
    return SQLITE_MISUSE_BKPT;
  }
................................................................................
  if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  wrFlag = !!wrFlag;                /* wrFlag = (wrFlag ? 1 : 0); */

  sqlite3_mutex_enter(db->mutex);


  bUnlock = sqlite3LockReusableSchema(db);
  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
  do {
    memset(&sParse, 0, sizeof(Parse));
    if( !pBlob ) goto blob_open_out;
    sParse.db = db;
................................................................................
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

blob_open_out:
  db->pParse = pParentParse;
  sqlite3UnlockReusableSchema(db, bUnlock);
  if( rc==SQLITE_OK && db->mallocFailed==0 ){
    *ppBlob = (sqlite3_blob *)pBlob;
  }else{
    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
    sqlite3DbFree(db, pBlob);
  }

Added test/reuse6.test.























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# 2019 February 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix reuse6

ifcapable !sharedschema {
  finish_test
  return
}

do_execsql_test 1.0 {
  CREATE TABLE t1(x, y);
  CREATE TABLE t2(a, b, c);
  CREATE INDEX t1x ON t1(x);
  CREATE INDEX t1y ON t1(y);
  CREATE VIEW v1 AS SELECT * FROM t2;

  INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6);
  INSERT INTO t2 VALUES('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i');

  ATTACH 'test.db2' AS aux;
  CREATE TABLE t3(i, ii);
  INSERT INTO t3 VALUES(10, 20);
}

sqlite3 db1 test.db -shared-schema 1
sqlite3 db2 test.db -shared-schema 1

do_execsql_test -db db1 1.1 {
  ATTACH 'test.db2' AS aux;
}

do_test 1.2 {
  execsql {SELECT * FROM t3} db1
} {10 20}

do_execsql_test -db db2 1.3 {
  ATTACH 'test.db2' AS aux;
}

do_test 1.3 {
  execsql {SELECT * FROM t3} db1
} {10 20}

do_execsql_test -db db2 1.5 {
  SELECT * FROM t3;
} {10 20}

do_test 1.6 {
  execsql {SELECT * FROM t3} db1
} {10 20}

db1 close
db2 close

#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
forcedelete test.db3
do_execsql_test 2.0 {
  CREATE TABLE t1(x, y);
  ATTACH 'test.db2' AS aux2;
  CREATE TABLE aux2.t2(x, y);
  ATTACH 'test.db3' AS aux3;
  CREATE TABLE aux3.t3(x, y);
}

sqlite3 db1 test.db -shared-schema 1
do_execsql_test -db db1 2.1 {
  ATTACH 'test.db2' AS aux2;
  ATTACH 'test.db3' AS aux3;
}

do_test 2.2.1 {
  catchsql { SELECT * FROM aux2.nosuchtable } db1
} {1 {no such table: aux2.nosuchtable}}
do_test 2.2.2 {
  sqlite3_errcode db1
} {SQLITE_ERROR}
db1 close

#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
ifcapable fts5 {
  do_execsql_test 3.0 {
    CREATE VIRTUAL TABLE ft USING fts5(a, b);
    ATTACH 'test.db2' AS aux;
    CREATE TABLE aux.t1(x, y, z);
  }

  sqlite3 db1 test.db -shared-schema 1
  do_execsql_test -db db1 3.1 {
    ATTACH 'test.db2' AS aux;
  }

breakpoint
  do_execsql_test -db db1 3.2 {
    SELECT * FROM main.ft, aux.t1;
  }
}








finish_test