/ Check-in [011904ca]
Login

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

Overview
Comment:If compiled with SQLITE_ENABLE_HIDDEN_COLUMNS, then columns in ordinary tables and views that have names beginning with "__hidden__" are omitted from the "*" expansion in SELECT statements and from the automatic list of columns following the table name in an INSERT INTO statement.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 011904cad2be2ce34e2f37ffae8ff2f1044a2969
User & Date: drh 2015-11-19 14:11:58
Context
2015-11-19
16:33
Create the new TK_ASTERISK token to represent the "*" in "SELECT *". Formerly that operator was TK_ALL, which was also used for UNION ALL. Less confusion if they operator symbols are distinct. check-in: 201ac6d4 user: drh tags: trunk
14:11
If compiled with SQLITE_ENABLE_HIDDEN_COLUMNS, then columns in ordinary tables and views that have names beginning with "__hidden__" are omitted from the "*" expansion in SELECT statements and from the automatic list of columns following the table name in an INSERT INTO statement. check-in: 011904ca user: drh tags: trunk
13:53
Only support the magic "__hidden__" column name prefix interpretation when compiled with SQLITE_ENABLE_HIDDEN_COLUMNS. Closed-Leaf check-in: 5490646b user: drh tags: hidden-columns-in-tables
13:21
Fix a 10-year-old misguided attempt at parser performance improvement that actually made parsing slightly slower. check-in: 3833cbac user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

  1044   1044     return;
  1045   1045   
  1046   1046     /* If an error occurs, we jump here */
  1047   1047   begin_table_error:
  1048   1048     sqlite3DbFree(db, zName);
  1049   1049     return;
  1050   1050   }
         1051  +
         1052  +/* Set properties of a table column based on the (magical)
         1053  +** name of the column.
         1054  +*/
         1055  +void sqlite3ColumnPropertiesFromName(Column *pCol){
         1056  +#if SQLITE_ENABLE_HIDDEN_COLUMNS
         1057  +  if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
         1058  +    pCol->colFlags |= COLFLAG_HIDDEN;
         1059  +  }
         1060  +#endif
         1061  +}
         1062  +
  1051   1063   
  1052   1064   /*
  1053   1065   ** Add a new column to the table currently being constructed.
  1054   1066   **
  1055   1067   ** The parser calls this routine once for each column declaration
  1056   1068   ** in a CREATE TABLE statement.  sqlite3StartTable() gets called
  1057   1069   ** first to get things going.  Then this routine is called for each
................................................................................
  1087   1099         return;
  1088   1100       }
  1089   1101       p->aCol = aNew;
  1090   1102     }
  1091   1103     pCol = &p->aCol[p->nCol];
  1092   1104     memset(pCol, 0, sizeof(p->aCol[0]));
  1093   1105     pCol->zName = z;
         1106  +  sqlite3ColumnPropertiesFromName(pCol);
  1094   1107    
  1095   1108     /* If there is no type specified, columns have the default affinity
  1096   1109     ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
  1097   1110     ** be called next to set pCol->affinity correctly.
  1098   1111     */
  1099   1112     pCol->affinity = SQLITE_AFF_BLOB;
  1100   1113     pCol->szEst = 1;

Changes to src/insert.c.

   732    732     if( pColumn==0 && nColumn>0 ){
   733    733       ipkColumn = pTab->iPKey;
   734    734     }
   735    735   
   736    736     /* Make sure the number of columns in the source data matches the number
   737    737     ** of columns to be inserted into the table.
   738    738     */
   739         -  if( IsVirtual(pTab) ){
   740         -    for(i=0; i<pTab->nCol; i++){
   741         -      nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
   742         -    }
          739  +  for(i=0; i<pTab->nCol; i++){
          740  +    nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
   743    741     }
   744    742     if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
   745    743       sqlite3ErrorMsg(pParse, 
   746    744          "table %S has %d columns but %d values were supplied",
   747    745          pTabList, 0, pTab->nCol-nHidden, nColumn);
   748    746       goto insert_cleanup;
   749    747     }
................................................................................
   831    829       /* Cannot have triggers on a virtual table. If it were possible,
   832    830       ** this block would have to account for hidden column.
   833    831       */
   834    832       assert( !IsVirtual(pTab) );
   835    833   
   836    834       /* Create the new column data
   837    835       */
   838         -    for(i=0; i<pTab->nCol; i++){
   839         -      if( pColumn==0 ){
   840         -        j = i;
   841         -      }else{
          836  +    for(i=j=0; i<pTab->nCol; i++){
          837  +      if( pColumn ){
   842    838           for(j=0; j<pColumn->nId; j++){
   843    839             if( pColumn->a[j].idx==i ) break;
   844    840           }
   845    841         }
   846         -      if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
          842  +      if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
          843  +            || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
   847    844           sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
   848    845         }else if( useTempTable ){
   849    846           sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); 
   850    847         }else{
   851    848           assert( pSelect==0 ); /* Otherwise useTempTable is true */
   852    849           sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
   853    850         }
          851  +      if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
   854    852       }
   855    853   
   856    854       /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
   857    855       ** do not attempt any conversions before assembling the record.
   858    856       ** If this is a real table, attempt conversions as required by the
   859    857       ** table column affinities.
   860    858       */
................................................................................
   930    928           ** taking up data space with information that will never be used.
   931    929           ** As there may be shallow copies of this value, make it a soft-NULL */
   932    930           sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
   933    931           continue;
   934    932         }
   935    933         if( pColumn==0 ){
   936    934           if( IsHiddenColumn(&pTab->aCol[i]) ){
   937         -          assert( IsVirtual(pTab) );
   938    935             j = -1;
   939    936             nHidden++;
   940    937           }else{
   941    938             j = i - nHidden;
   942    939           }
   943    940         }else{
   944    941           for(j=0; j<pColumn->nId; j++){

Changes to src/select.c.

  1655   1655           for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
  1656   1656           if( zName[j]==':' ) nName = j;
  1657   1657         }
  1658   1658         zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
  1659   1659         if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
  1660   1660       }
  1661   1661       pCol->zName = zName;
         1662  +    sqlite3ColumnPropertiesFromName(pCol);
  1662   1663       if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
  1663   1664         db->mallocFailed = 1;
  1664   1665       }
  1665   1666     }
  1666   1667     sqlite3HashClear(&ht);
  1667   1668     if( db->mallocFailed ){
  1668   1669       for(j=0; j<i; j++){
................................................................................
  4356   4357               assert( zName );
  4357   4358               if( zTName && pSub
  4358   4359                && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
  4359   4360               ){
  4360   4361                 continue;
  4361   4362               }
  4362   4363   
  4363         -            /* If a column is marked as 'hidden' (currently only possible
  4364         -            ** for virtual tables), do not include it in the expanded
  4365         -            ** result-set list.
         4364  +            /* If a column is marked as 'hidden', do not include it in
         4365  +            ** the expanded result-set list.
  4366   4366               */
  4367   4367               if( IsHiddenColumn(&pTab->aCol[j]) ){
  4368         -              assert(IsVirtual(pTab));
  4369   4368                 continue;
  4370   4369               }
  4371   4370               tableSeen = 1;
  4372   4371   
  4373   4372               if( i>0 && zTName==0 ){
  4374   4373                 if( (pFrom->fg.jointype & JT_NATURAL)!=0
  4375   4374                   && tableAndColumnIndex(pTabList, i, zName, 0, 0)

Changes to src/sqliteInt.h.

  1692   1692   /*
  1693   1693   ** Test to see whether or not a table is a virtual table.  This is
  1694   1694   ** done as a macro so that it will be optimized out when virtual
  1695   1695   ** table support is omitted from the build.
  1696   1696   */
  1697   1697   #ifndef SQLITE_OMIT_VIRTUALTABLE
  1698   1698   #  define IsVirtual(X)      (((X)->tabFlags & TF_Virtual)!=0)
  1699         -#  define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
  1700   1699   #else
  1701   1700   #  define IsVirtual(X)      0
  1702   1701   #  define IsHiddenColumn(X) 0
  1703   1702   #endif
         1703  +
         1704  +/*
         1705  +** Macros to determine if a column is hidden.  IsOrdinaryHiddenColumn()
         1706  +** only works for non-virtual tables (ordinary tables and views) and is
         1707  +** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined.  The
         1708  +** IsHiddenColumn() macro is general purpose.
         1709  +*/
         1710  +#if defined(SQLITE_ENABLE_HIDDEN_COLUMNS)
         1711  +#  define IsHiddenColumn(X)         (((X)->colFlags & COLFLAG_HIDDEN)!=0)
         1712  +#  define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
         1713  +#elif !defined(SQLITE_OMIT_VIRTUAL)
         1714  +#  define IsHiddenColumn(X)         (((X)->colFlags & COLFLAG_HIDDEN)!=0)
         1715  +#  define IsOrdinaryHiddenColumn(X) 0
         1716  +#else
         1717  +#  define IsHiddenColumn(X)         0
         1718  +#  define IsOrdinaryHiddenColumn(X) 0
         1719  +#endif
         1720  +
  1704   1721   
  1705   1722   /* Does the table have a rowid */
  1706   1723   #define HasRowid(X)     (((X)->tabFlags & TF_WithoutRowid)==0)
  1707   1724   #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
  1708   1725   
  1709   1726   /*
  1710   1727   ** Each foreign key constraint is an instance of the following structure.
................................................................................
  3310   3327   void sqlite3DeleteColumnNames(sqlite3*,Table*);
  3311   3328   int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
  3312   3329   Table *sqlite3ResultSetOfSelect(Parse*,Select*);
  3313   3330   void sqlite3OpenMasterTable(Parse *, int);
  3314   3331   Index *sqlite3PrimaryKeyIndex(Table*);
  3315   3332   i16 sqlite3ColumnOfIndex(Index*, i16);
  3316   3333   void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
         3334  +void sqlite3ColumnPropertiesFromName(Column*);
  3317   3335   void sqlite3AddColumn(Parse*,Token*);
  3318   3336   void sqlite3AddNotNull(Parse*, int);
  3319   3337   void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
  3320   3338   void sqlite3AddCheckConstraint(Parse*, Expr*);
  3321   3339   void sqlite3AddColumnType(Parse*,Token*);
  3322   3340   void sqlite3AddDefaultValue(Parse*,ExprSpan*);
  3323   3341   void sqlite3AddCollateType(Parse*, Token*);

Changes to src/test_config.c.

   120    120   #endif
   121    121   
   122    122   #ifdef SQLITE_ENABLE_CURSOR_HINTS
   123    123     Tcl_SetVar2(interp, "sqlite_options", "cursorhints", "1", TCL_GLOBAL_ONLY);
   124    124   #else
   125    125     Tcl_SetVar2(interp, "sqlite_options", "cursorhints", "0", TCL_GLOBAL_ONLY);
   126    126   #endif
          127  +
          128  +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
          129  +  Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "1", TCL_GLOBAL_ONLY);
          130  +#else
          131  +  Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY);
          132  +#endif
   127    133   
   128    134   #ifdef SQLITE_ENABLE_MEMSYS3
   129    135     Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY);
   130    136   #else
   131    137     Tcl_SetVar2(interp, "sqlite_options", "mem3", "0", TCL_GLOBAL_ONLY);
   132    138   #endif
   133    139   

Added test/hidden.test.

            1  +# 2015 November 18
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# Test the __hidden__ hack.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix hidden
           18  +
           19  +ifcapable !hiddencolumns {
           20  +  finish_test
           21  +  return
           22  +}
           23  +
           24  +do_execsql_test 1.1 {
           25  +  CREATE TABLE t1(__hidden__a, b);
           26  +  INSERT INTO t1 VALUES('1');
           27  +  INSERT INTO t1(__hidden__a, b) VALUES('x', 'y');
           28  +} {}
           29  +
           30  +do_execsql_test 1.2 {
           31  +  SELECT * FROM t1;
           32  +} {1 y}
           33  +
           34  +do_execsql_test 1.3 {
           35  +  SELECT __hidden__a, * FROM t1;
           36  +} {{} 1 x y}
           37  +
           38  +foreach {tn view} {
           39  +  1 { CREATE VIEW v1(a, b, __hidden__c) AS SELECT a, b, c FROM x1 }
           40  +  2 { CREATE VIEW v1 AS SELECT a, b, c AS __hidden__c FROM x1 }
           41  +} {
           42  +  do_execsql_test 2.$tn.1 {
           43  +    DROP TABLE IF EXISTS x1;
           44  +    CREATE TABLE x1(a, b, c);
           45  +    INSERT INTO x1 VALUES(1, 2, 3);
           46  +  }
           47  +
           48  +  catchsql { DROP VIEW v1 }
           49  +  execsql $view
           50  +
           51  +  do_execsql_test 2.$tn.2 {
           52  +    SELECT a, b, __hidden__c FROM v1;
           53  +  } {1 2 3}
           54  +  
           55  +  do_execsql_test 2.$tn.3 {
           56  +    SELECT * FROM v1;
           57  +  } {1 2}
           58  +  
           59  +  do_execsql_test 2.$tn.4 {
           60  +    CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN
           61  +      INSERT INTO x1 VALUES(new.a, new.b, new.__hidden__c);
           62  +    END;
           63  +  
           64  +    INSERT INTO v1 VALUES(4, 5);
           65  +    SELECT * FROM x1;
           66  +  } {1 2 3 4 5 {}}
           67  +  
           68  +  do_execsql_test 2.$tn.5 {
           69  +    INSERT INTO v1(a, b, __hidden__c) VALUES(7, 8, 9);
           70  +    SELECT * FROM x1;
           71  +  } {1 2 3 4 5 {} 7 8 9}
           72  +}
           73  +  
           74  +finish_test

Changes to test/releasetest.tcl.

   115    115       -DSQLITE_TCL_DEFAULT_FULLMUTEX=1
   116    116       -DSQLITE_ENABLE_FTS3=1
   117    117       -DSQLITE_ENABLE_RTREE=1
   118    118       -DSQLITE_ENABLE_MEMSYS5=1
   119    119       -DSQLITE_ENABLE_MEMSYS3=1
   120    120       -DSQLITE_ENABLE_COLUMN_METADATA=1
   121    121       -DSQLITE_ENABLE_STAT4
          122  +    -DSQLITE_ENABLE_HIDDEN_COLUMNS
   122    123       -DSQLITE_MAX_ATTACHED=125
   123    124     }
   124    125     "Fast-One" {
   125    126       -O6
   126    127       -DSQLITE_ENABLE_FTS4=1
   127    128       -DSQLITE_ENABLE_RTREE=1
   128    129       -DSQLITE_ENABLE_STAT4
................................................................................
   141    142       -DSQLITE_ENABLE_ATOMIC_WRITE=1
   142    143       -DSQLITE_ENABLE_IOTRACE=1
   143    144       -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
   144    145       -DSQLITE_MAX_PAGE_SIZE=4096
   145    146       -DSQLITE_OMIT_LOAD_EXTENSION=1
   146    147       -DSQLITE_OMIT_PROGRESS_CALLBACK=1
   147    148       -DSQLITE_OMIT_VIRTUALTABLE=1
          149  +    -DSQLITE_ENABLE_HIDDEN_COLUMNS
   148    150       -DSQLITE_TEMP_STORE=3
   149    151       --enable-json1
   150    152     }
   151    153     "Device-Two" {
   152    154       -DSQLITE_4_BYTE_ALIGNED_MALLOC=1
   153    155       -DSQLITE_DEFAULT_AUTOVACUUM=1
   154    156       -DSQLITE_DEFAULT_CACHE_SIZE=1000
................................................................................
   209    211       -DSQLITE_OMIT_LOOKASIDE=1
   210    212       -DHAVE_USLEEP=1
   211    213     }
   212    214     "Valgrind" {
   213    215       -DSQLITE_ENABLE_STAT4
   214    216       -DSQLITE_ENABLE_FTS4
   215    217       -DSQLITE_ENABLE_RTREE
          218  +    -DSQLITE_ENABLE_HIDDEN_COLUMNS
   216    219       --enable-json1
   217    220     }
   218    221   
   219    222     # The next group of configurations are used only by the
   220    223     # Failure-Detection platform.  They are all the same, but we need
   221    224     # different names for them all so that they results appear in separate
   222    225     # subdirectories.