SQLite

Check-in [3bb33cf59d]
Login

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

Overview
Comment:Change 'pragma foreign_key_list' to return some extra information. (CVS 5795)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3bb33cf59da49f13201c0226e964cda067a4e780
User & Date: danielk1977 2008-10-10 17:47:21.000
Context
2008-10-10
17:58
Add the genfkey program to the tool/ directory. (CVS 5796) (check-in: 84e73fe8a6 user: danielk1977 tags: trunk)
17:47
Change 'pragma foreign_key_list' to return some extra information. (CVS 5795) (check-in: 3bb33cf59d user: danielk1977 tags: trunk)
17:41
Simplify the symbol hash table to use only a single key class. Other changes to improve code coverage. (CVS 5794) (check-in: ff50a8a7e5 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/parse.y.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.257 2008/10/10 14:27:17 drh Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.258 2008/10/10 17:47:21 danielk1977 Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// The next group of rules parses the arguments to a REFERENCES clause
// that determine if the referential integrity checking is deferred or
// or immediate and which determine what action to take if a ref-integ
// check fails.
//
%type refargs {int}
refargs(A) ::= .                     { A = OE_Restrict * 0x010101; }
refargs(A) ::= refargs(X) refarg(Y). { A = (X & Y.mask) | Y.value; }
%type refarg {struct {int value; int mask;}}
refarg(A) ::= MATCH nm.              { A.value = 0;     A.mask = 0x000000; }
refarg(A) ::= ON DELETE refact(X).   { A.value = X;     A.mask = 0x0000ff; }
refarg(A) ::= ON UPDATE refact(X).   { A.value = X<<8;  A.mask = 0x00ff00; }
refarg(A) ::= ON INSERT refact(X).   { A.value = X<<16; A.mask = 0xff0000; }
%type refact {int}
refact(A) ::= SET NULL.              { A = OE_SetNull; }







|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// The next group of rules parses the arguments to a REFERENCES clause
// that determine if the referential integrity checking is deferred or
// or immediate and which determine what action to take if a ref-integ
// check fails.
//
%type refargs {int}
refargs(A) ::= .                     { A = OE_Restrict * 0x010101; }
refargs(A) ::= refargs(X) refarg(Y). { A = (X & ~Y.mask) | Y.value; }
%type refarg {struct {int value; int mask;}}
refarg(A) ::= MATCH nm.              { A.value = 0;     A.mask = 0x000000; }
refarg(A) ::= ON DELETE refact(X).   { A.value = X;     A.mask = 0x0000ff; }
refarg(A) ::= ON UPDATE refact(X).   { A.value = X<<8;  A.mask = 0x00ff00; }
refarg(A) ::= ON INSERT refact(X).   { A.value = X<<16; A.mask = 0xff0000; }
%type refact {int}
refact(A) ::= SET NULL.              { A = OE_SetNull; }
Changes to src/pragma.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2003 April 6
**
** 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.
**
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.188 2008/09/26 21:08:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/* Ignore this whole file if pragmas are disabled
*/
#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2003 April 6
**
** 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.
**
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.189 2008/10/10 17:47:21 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/* Ignore this whole file if pragmas are disabled
*/
#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)
216
217
218
219
220
221
222










223
224
225
226
227
228
229

      return 1;
    }
  }
  return 0;
}
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */











/*
** Process a pragma statement.  
**
** Pragmas are of this form:
**
**      PRAGMA [database.]id [= value]







>
>
>
>
>
>
>
>
>
>







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

      return 1;
    }
  }
  return 0;
}
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */

static const char *actionName(u8 action){
  switch( action ){
    case OE_SetNull:  return "SET NULL";
    case OE_SetDflt:  return "SET DEFAULT";
    case OE_Restrict: return "RESTRICT";
    case OE_Cascade:  return "CASCADE";
  }
  return "";
}

/*
** Process a pragma statement.  
**
** Pragmas are of this form:
**
**      PRAGMA [database.]id [= value]
869
870
871
872
873
874
875
876
877
878
879
880
881
882



883
884
885
886


887
888
889
890
891
892



893
894
895
896
897
898
899
900
    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    pTab = sqlite3FindTable(db, zRight, zDb);
    if( pTab ){
      v = sqlite3GetVdbe(pParse);
      pFK = pTab->pFKey;
      if( pFK ){
        int i = 0; 
        sqlite3VdbeSetNumCols(v, 5);
        pParse->nMem = 5;
        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC);
        sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC);
        sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC);
        sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P4_STATIC);
        sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P4_STATIC);



        while(pFK){
          int j;
          for(j=0; j<pFK->nCol; j++){
            char *zCol = pFK->aCol[j].zCol;


            sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
            sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
                              pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
            sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);



            sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
          }
          ++i;
          pFK = pFK->pNextFrom;
        }
      }
    }
  }else







|
|





>
>
>




>
>






>
>
>
|







879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    pTab = sqlite3FindTable(db, zRight, zDb);
    if( pTab ){
      v = sqlite3GetVdbe(pParse);
      pFK = pTab->pFKey;
      if( pFK ){
        int i = 0; 
        sqlite3VdbeSetNumCols(v, 8);
        pParse->nMem = 8;
        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC);
        sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC);
        sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC);
        sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P4_STATIC);
        sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P4_STATIC);
        sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", P4_STATIC);
        sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", P4_STATIC);
        sqlite3VdbeSetColName(v, 7, COLNAME_NAME, "match", P4_STATIC);
        while(pFK){
          int j;
          for(j=0; j<pFK->nCol; j++){
            char *zCol = pFK->aCol[j].zCol;
            char *zOnUpdate = (char *)actionName(pFK->updateConf);
            char *zOnDelete = (char *)actionName(pFK->deleteConf);
            sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
            sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
                              pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
            sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 6, 0, zOnUpdate, 0);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 7, 0, zOnDelete, 0);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 8, 0, "NONE", 0);
            sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
          }
          ++i;
          pFK = pFK->pNextFrom;
        }
      }
    }
  }else
Changes to test/fkey1.test.
67
68
69
70
71
72
73








74



75






















76
77
    DROP TABLE t5;
    DROP TABLE t8;
    DROP TABLE t6;
    DROP TABLE t10;
  }
} {}









   



























finish_test







>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


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
    DROP TABLE t5;
    DROP TABLE t8;
    DROP TABLE t6;
    DROP TABLE t10;
  }
} {}

do_test fkey1-3.1 {
  execsql {
    CREATE TABLE t5(a PRIMARY KEY, b, c);
    CREATE TABLE t6(
      d REFERENCES t5,
      e REFERENCES t5(c)
    );
    PRAGMA foreign_key_list(t6);
  }
} [concat            \
  {0 0 t5 e c RESTRICT RESTRICT NONE}       \
  {1 0 t5 d {} RESTRICT RESTRICT NONE}      \
]
do_test fkey1-3.2 {
  execsql {
    CREATE TABLE t7(d, e, f,
      FOREIGN KEY (d, e) REFERENCES t5(a, b)
    );
    PRAGMA foreign_key_list(t7);
  }
} [concat                        \
  {0 0 t5 d a RESTRICT RESTRICT NONE} \
  {0 1 t5 e b RESTRICT RESTRICT NONE} \
]
do_test fkey1-3.3 {
  execsql {
    CREATE TABLE t8(d, e, f,
      FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET NULL
    );
    PRAGMA foreign_key_list(t8);
  }
} [concat                        \
  {0 0 t5 d {} {SET NULL} CASCADE NONE} \
  {0 1 t5 e {} {SET NULL} CASCADE NONE} \
]

finish_test
Changes to test/pragma.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the PRAGMA command.
#
# $Id: pragma.test,v 1.67 2008/09/16 15:50:12 danielk1977 Exp $

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

# Test organization:
#
# pragma-1.*: Test cache_size, default_cache_size and synchronous on main db.







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the PRAGMA command.
#
# $Id: pragma.test,v 1.68 2008/10/10 17:47:21 danielk1977 Exp $

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

# Test organization:
#
# pragma-1.*: Test cache_size, default_cache_size and synchronous on main db.
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
db nullvalue {}
ifcapable {foreignkey} {
  do_test pragma-6.3 {
    execsql {
      CREATE TABLE t3(a int references t2(b), b UNIQUE);
      pragma foreign_key_list(t3);
    }
  } {0 0 t2 a b}
  do_test pragma-6.4 {
    execsql {
      pragma index_list(t3);
    }
  } {0 sqlite_autoindex_t3_1 1}
}
ifcapable {!foreignkey} {







|







521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
db nullvalue {}
ifcapable {foreignkey} {
  do_test pragma-6.3 {
    execsql {
      CREATE TABLE t3(a int references t2(b), b UNIQUE);
      pragma foreign_key_list(t3);
    }
  } {0 0 t2 a b RESTRICT RESTRICT NONE}
  do_test pragma-6.4 {
    execsql {
      pragma index_list(t3);
    }
  } {0 sqlite_autoindex_t3_1 1}
}
ifcapable {!foreignkey} {