/ Check-in [51f515f2]
Login

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

Overview
Comment:More testing of ATTACH and DETACH. (CVS 899)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 51f515f28cb1cc3e8f0c3531724dc8876b25f18e
User & Date: drh 2003-04-05 16:56:29
Context
2003-04-06
20:44
Simplify the BTree interface by shortening names. Added two new methods for accessing the current filename and for changing the name of the database file. (CVS 900) check-in: 185d8dc8 user: drh tags: trunk
2003-04-05
16:56
More testing of ATTACH and DETACH. (CVS 899) check-in: 51f515f2 user: drh tags: trunk
03:42
Begin testing the new ATTACH and DETACH commands. (CVS 898) check-in: 7a0f8024 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
2608
2609
2610
2611
2612
2613
2614


















2615
2616
2617
2618
2619
2620
2621
....
2669
2670
2671
2672
2673
2674
2675

2676
2677
2678
2679
2680

2681
2682
2683
2684
2685
2686
2687
....
2699
2700
2701
2702
2703
2704
2705


2706
2707
2708
2709
2710
2711
2712
....
2718
2719
2720
2721
2722
2723
2724

2725
2726
2727
2728
2729
2730
2731
....
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756





2757

**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.140 2003/04/05 03:42:27 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
................................................................................
        sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
        ++i;
        pIdx = pIdx->pNext;
      }
    }
  }else



















#ifndef NDEBUG
  if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
    extern void sqliteParserTrace(FILE*, char *);
    if( getBoolean(zRight) ){
      sqliteParserTrace(stdout, "parser: ");
    }else{
................................................................................
  sqlite *db;

  if( pParse->explain ) return;
  db = pParse->db;
  if( db->file_format<4 ){
    sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
       "older format master database", 0);

    return;
  }
  if( db->nDb>=MAX_ATTACHED ){
    sqliteErrorMsg(pParse, "too many attached databases - max %d", 
       MAX_ATTACHED);

    return;
  }
  if( db->aDb==db->aDbStatic ){
    aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
    if( aNew==0 ) return;
    memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
  }else{
................................................................................
  zName = 0;
  sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
  if( zName==0 ) return;
  sqliteDequote(zName);
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
      sqliteErrorMsg(pParse, "database %z is already in use", zName);


      return;
    }
  }
  aNew->zName = zName;
  zFile = 0;
  sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
  if( zFile==0 ) return;
................................................................................
  sqliteFree(zFile);
  db->flags &= ~SQLITE_Initialized;
  if( pParse->nErr ) return;
  rc = sqliteInit(pParse->db, &pParse->zErrMsg);
  if( rc ){
    sqliteResetInternalSchema(db, 0);
    pParse->nErr++;

  }
}

/*
** This routine is called by the parser to process a DETACH statement:
**
**    DETACH DATABASE dbname
................................................................................
    if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
  }
  if( i>=db->nDb ){
    sqliteErrorMsg(pParse, "no such database: %T", pDbname);
    return;
  }
  if( i<2 ){
    sqliteErrorMsg(pParse, "cannot detached database %T", pDbname);
    return;
  }
  sqliteBtreeClose(db->aDb[i].pBt);
  db->aDb[i].pBt = 0;
  sqliteResetInternalSchema(db, 0);





}








|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>


|


>







 







>
>







 







>







 







|




|
>
>
>
>
>
|
>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
....
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
....
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
....
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
....
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.141 2003/04/05 16:56:29 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
................................................................................
        sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
        ++i;
        pIdx = pIdx->pNext;
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "database_list")==0 ){
    int i;
    static VdbeOp indexListPreface[] = {
      { OP_ColumnName,  0, 0,       "seq"},
      { OP_ColumnName,  1, 0,       "name"},
    };

    sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
    for(i=0; i<db->nDb; i++){
      if( db->aDb[i].pBt==0 ) continue;
      assert( db->aDb[i].zName!=0 );
      sqliteVdbeAddOp(v, OP_Integer, i, 0);
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      sqliteVdbeChangeP3(v, -1, db->aDb[i].zName, P3_STATIC);
      sqliteVdbeAddOp(v, OP_Callback, 2, 0);
    }
  }else

#ifndef NDEBUG
  if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
    extern void sqliteParserTrace(FILE*, char *);
    if( getBoolean(zRight) ){
      sqliteParserTrace(stdout, "parser: ");
    }else{
................................................................................
  sqlite *db;

  if( pParse->explain ) return;
  db = pParse->db;
  if( db->file_format<4 ){
    sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
       "older format master database", 0);
    pParse->rc = SQLITE_ERROR;
    return;
  }
  if( db->nDb>=MAX_ATTACHED+2 ){
    sqliteErrorMsg(pParse, "too many attached databases - max %d", 
       MAX_ATTACHED);
    pParse->rc = SQLITE_ERROR;
    return;
  }
  if( db->aDb==db->aDbStatic ){
    aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
    if( aNew==0 ) return;
    memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
  }else{
................................................................................
  zName = 0;
  sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
  if( zName==0 ) return;
  sqliteDequote(zName);
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
      sqliteErrorMsg(pParse, "database %z is already in use", zName);
      db->nDb--;
      pParse->rc = SQLITE_ERROR;
      return;
    }
  }
  aNew->zName = zName;
  zFile = 0;
  sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
  if( zFile==0 ) return;
................................................................................
  sqliteFree(zFile);
  db->flags &= ~SQLITE_Initialized;
  if( pParse->nErr ) return;
  rc = sqliteInit(pParse->db, &pParse->zErrMsg);
  if( rc ){
    sqliteResetInternalSchema(db, 0);
    pParse->nErr++;
    pParse->rc = SQLITE_ERROR;
  }
}

/*
** This routine is called by the parser to process a DETACH statement:
**
**    DETACH DATABASE dbname
................................................................................
    if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
  }
  if( i>=db->nDb ){
    sqliteErrorMsg(pParse, "no such database: %T", pDbname);
    return;
  }
  if( i<2 ){
    sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
    return;
  }
  sqliteBtreeClose(db->aDb[i].pBt);
  db->aDb[i].pBt = 0;
  sqliteResetInternalSchema(db, i);
  db->nDb--;
  if( i<db->nDb ){
    db->aDb[i] = db->aDb[db->nDb];
    memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
    sqliteResetInternalSchema(db, i);
  }
}

Changes to test/attach.test.

8
9
10
11
12
13
14
15
16
17
18
19
20

21
22

23
24
25
26
27
28
29
..
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
..
61
62
63
64
65
66
67



68
69





































































































































70
71
72
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach.test,v 1.1 2003/04/05 03:42:27 drh Exp $
#

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


file delete -force test2.db
file delete -force test2.db-journal


do_test attach-1.1 {
  execsql {
    CREATE TABLE t1(a,b);
    INSERT INTO t1 VALUES(1,2);
    INSERT INTO t1 VALUES(3,4);
    SELECT * FROM t1;
................................................................................
do_test attach-1.2 {
  sqlite db2 test2.db
  execsql {
    CREATE TABLE t2(x,y);
    INSERT INTO t2 VALUES(1,'x');
    INSERT INTO t2 VALUES(2,'y');
    SELECT * FROM t2;
  }
} {1 x 2 y}
do_test attach-1.3 {
  execsql {
    ATTACH DATABASE 'test2.db' AS two;
    SELECT * FROM two.t2;
  }
} {1 x 2 y}
................................................................................
  }
} {1 {no such table: t2}}
do_test attach-1.7 {
  catchsql {
    SELECT * FROM two.t2;
  }
} {1 {no such table: two.t2}}




db2 close







































































































































finish_test







|





>
|
|
>







 







|







 







>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
..
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach.test,v 1.2 2003/04/05 16:56:30 drh Exp $
#

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

for {set i 2} {$i<=15} {incr i} {
  file delete -force test$i.db
  file delete -force test$i.db-journal
}

do_test attach-1.1 {
  execsql {
    CREATE TABLE t1(a,b);
    INSERT INTO t1 VALUES(1,2);
    INSERT INTO t1 VALUES(3,4);
    SELECT * FROM t1;
................................................................................
do_test attach-1.2 {
  sqlite db2 test2.db
  execsql {
    CREATE TABLE t2(x,y);
    INSERT INTO t2 VALUES(1,'x');
    INSERT INTO t2 VALUES(2,'y');
    SELECT * FROM t2;
  } db2
} {1 x 2 y}
do_test attach-1.3 {
  execsql {
    ATTACH DATABASE 'test2.db' AS two;
    SELECT * FROM two.t2;
  }
} {1 x 2 y}
................................................................................
  }
} {1 {no such table: t2}}
do_test attach-1.7 {
  catchsql {
    SELECT * FROM two.t2;
  }
} {1 {no such table: two.t2}}
do_test attach-1.8 {
  catchsql {
    ATTACH DATABASE 'test3.db' AS three;
  }

} {1 {cannot attach empty database: three}}
do_test attach-1.9 {
  catchsql {
    SELECT * FROM three.sqlite_master;
  }
} {1 {no such table: three.sqlite_master}}
do_test attach-1.10 {
  catchsql {
    DETACH DATABASE three;
  }
} {1 {no such database: three}}
do_test attach-1.11 {
  execsql {
    ATTACH 'test.db' AS db2;
    ATTACH 'test.db' AS db3;
    ATTACH 'test.db' AS db4;
    ATTACH 'test.db' AS db5;
    ATTACH 'test.db' AS db6;
    ATTACH 'test.db' AS db7;
    ATTACH 'test.db' AS db8;
    ATTACH 'test.db' AS db9;
  }
} {}
do_test attach-1.11b {
  execsql {
    PRAGMA database_list;
  }
} {0 main 1 temp 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9}
do_test attach-1.12 {
  catchsql {
    ATTACH 'test.db' as db2;
  }
} {1 {database db2 is already in use}}
do_test attach-1.13 {
  catchsql {
    ATTACH 'test.db' as db5;
  }
} {1 {database db5 is already in use}}
do_test attach-1.14 {
  catchsql {
    ATTACH 'test.db' as db9;
  }
} {1 {database db9 is already in use}}
do_test attach-1.15 {
  catchsql {
    ATTACH 'test.db' as main;
  }
} {1 {database main is already in use}}
do_test attach-1.16 {
  catchsql {
    ATTACH 'test.db' as temp;
  }
} {1 {database temp is already in use}}
do_test attach-1.17 {
  catchsql {
    ATTACH 'test.db' as MAIN;
  }
} {1 {database MAIN is already in use}}
do_test attach-1.18 {
  catchsql {
    ATTACH 'test.db' as db10;
    ATTACH 'test.db' as db11;
  }
} {0 {}}
do_test attach-1.19 {
  catchsql {
    ATTACH 'test.db' as db12;
  }
} {1 {too many attached databases - max 10}}
do_test attach-1.20 {
  execsql {
    DETACH db5;
    PRAGMA database_list;
  }
} {0 main 1 temp 2 db2 3 db3 4 db4 5 db11 6 db6 7 db7 8 db8 9 db9 10 db10}
do_test attach-1.21 {
  catchsql {
    ATTACH 'test.db' as db12;
  }
} {0 {}}
do_test attach-1.22 {
  catchsql {
    ATTACH 'test.db' as db13;
  }
} {1 {too many attached databases - max 10}}
do_test attach-1.23 {
  catchsql {
    DETACH db14;
  }
} {1 {no such database: db14}}
do_test attach-1.24 {
  catchsql {
    DETACH db12;
  }
} {0 {}}
do_test attach-1.25 {
  catchsql {
    DETACH db12;
  }
} {1 {no such database: db12}}
do_test attach-1.26 {
  catchsql {
    DETACH main;
  }
} {1 {cannot detach database main}}
do_test attach-1.27 {
  catchsql {
    DETACH Temp;
  }
} {1 {cannot detach database Temp}}
do_test attach-1.28 {
  catchsql {
    DETACH db11;
    DETACH db10;
    DETACH db9;
    DETACH db8;
    DETACH db7;
    DETACH db6;
    DETACH db4;
    DETACH db3;
    DETACH db2;
  }
} {0 {}}
do_test attach-1.29 {
  execsql {
    PRAGMA database_list
  }
} {0 main 1 temp}


for {set i 2} {$i<=15} {incr i} {
  catch {db$i close}
}


finish_test