Fix bugs associated with the codec. (CVS 1846)

FossilOrigin-Name: b0a3becd82b9a4203c23f35dc5a5fd725e046f21
diff --git a/src/attach.c b/src/attach.c
index cd36936..4fa8447 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the ATTACH and DETACH commands.
 **
-** $Id: attach.c,v 1.24 2004/07/22 02:40:38 drh Exp $
+** $Id: attach.c,v 1.25 2004/07/22 15:02:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -23,7 +23,13 @@
 ** The pFilename and pDbname arguments are the tokens that define the
 ** filename and dbname in the ATTACH statement.
 */
-void sqlite3Attach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){
+void sqlite3Attach(
+  Parse *pParse,       /* The parser context */
+  Token *pFilename,    /* Name of database file */
+  Token *pDbname,      /* Name of the database to use internally */
+  int keyType,         /* 0: no key.  1: TEXT,  2: BLOB */
+  Token *pKey          /* Text of the key for keytype 2 and 3 */
+){
   Db *aNew;
   int rc, i;
   char *zFile, *zName;
@@ -91,14 +97,32 @@
     sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
   }
 #if SQLITE_HAS_CODEC
-  assert( pKey!=0 );
-  if( pKey->n>0 ){
-    extern int sqlite3CodecAttach(sqlite*, int, void*, int);
-    char *zKey = 0;
+  {
+    extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
+    char *zKey;
     int nKey;
+    if( keyType==0 ){
+      /* No key specified.  Use the key from the main database */
+      extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
+      sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
+    }else if( keyType==1 ){
+      /* Key specified as text */
+      zKey = sqlite3NameFromToken(pKey);
+      nKey = strlen(zKey);
+    }else{
+      /* Key specified as a BLOB */
+      char *zTemp;
+      assert( keyType==2 );
+      pKey->z++;
+      pKey->n--;
+      zTemp = sqlite3NameFromToken(pKey);
+      zKey = sqlite3HexToBlob(zTemp);
+      sqliteFree(zTemp);
+    }
     sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
-    zKey = sqlite3NameFromToken(pKey);
-    nKey = strlen(zKey);
+    if( keyType ){
+      sqliteFree(zKey);
+    }
   }
 #endif
   sqliteFree(zFile);
diff --git a/src/pager.c b/src/pager.c
index fc7bce9..36445b4 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.152 2004/07/22 01:19:35 drh Exp $
+** @(#) $Id: pager.c,v 1.153 2004/07/22 15:02:25 drh Exp $
 */
 #include "os.h"         /* Must be first to enable large file support */
 #include "sqliteInt.h"
@@ -1001,8 +1001,8 @@
       sqlite3OsSeek(&pPager->fd, pPager->pageSize*(off_t)(pPg->pgno-1));
       rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
       TRACE2("REFETCH page %d\n", pPg->pgno);
-      CODEC(pPager, zBuf, pPg->pgno, 2);
       if( rc ) break;
+      CODEC(pPager, zBuf, pPg->pgno, 2);
     }else{
       memset(zBuf, 0, pPager->pageSize);
     }
@@ -2516,12 +2516,13 @@
         }
         pPg->inJournal = 1;
       }else{
-        u32 cksum = pager_cksum(pPager, pPg->pgno, pData);
+        u32 cksum;
+        CODEC(pPager, pData, pPg->pgno, 7);
+        cksum = pager_cksum(pPager, pPg->pgno, pData);
         saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
         store32bits(cksum, pPg, pPager->pageSize);
         szPg = pPager->pageSize+8;
         store32bits(pPg->pgno, pPg, -4);
-        CODEC(pPager, pData, pPg->pgno, 7);
         rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
         pPager->journalOff += szPg;
         TRACE3("JOURNAL page %d needSync=%d\n", pPg->pgno, pPg->needSync);
diff --git a/src/parse.y b/src/parse.y
index 260e0f2..efb2420 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.130 2004/07/20 14:06:52 drh Exp $
+** @(#) $Id: parse.y,v 1.131 2004/07/22 15:02:25 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -54,6 +54,11 @@
 */
 struct TrigEvent { int a; IdList * b; };
 
+/*
+** An instance of this structure holds the ATTACH key and the key type.
+*/
+struct AttachKey { int type;  Token key; };
+
 } // end %include
 
 // These are extra tokens used by the lexer but never seen by the
@@ -893,11 +898,14 @@
 
 //////////////////////// ATTACH DATABASE file AS name /////////////////////////
 cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
-  sqlite3Attach(pParse, &F, &D, &K);
+  sqlite3Attach(pParse, &F, &D, K.type, &K.key);
 }
-%type key_opt {Token}
-key_opt(A) ::= USING ids(X).  { A = X; }
-key_opt(A) ::= .              { A.z = 0; A.n = 0; }
+%type key_opt {struct AttachKey}
+key_opt(A) ::= .                     { A.type = 0; }
+%ifdef SQLITE_HAS_CODEC
+key_opt(A) ::= KEY ids(X).           { A.type=1; A.key = X; }
+key_opt(A) ::= KEY BLOB(X).          { A.type=2; A.Key = X; }
+%endif
 
 database_kw_opt ::= DATABASE.
 database_kw_opt ::= .
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 1db96f2..d6cde4e 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.307 2004/07/22 01:19:35 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.308 2004/07/22 15:02:25 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1330,7 +1330,7 @@
 # define sqlite3AuthContextPush(a,b,c)
 # define sqlite3AuthContextPop(a)  ((void)(a))
 #endif
-void sqlite3Attach(Parse*, Token*, Token*, Token*);
+void sqlite3Attach(Parse*, Token*, Token*, int, Token*);
 void sqlite3Detach(Parse*, Token*);
 int sqlite3BtreeFactory(const sqlite *db, const char *zFilename,
                        int omitJournal, int nCache, Btree **ppBtree);
diff --git a/src/test1.c b/src/test1.c
index 852a164..61758fc 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.94 2004/07/17 21:56:10 drh Exp $
+** $Id: test1.c,v 1.95 2004/07/22 15:02:26 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -305,6 +305,62 @@
 }
 
 /*
+** Usage:  sqlite3_key DB KEY
+**
+** Set the codec key.
+*/
+static int test_key(
+  void *NotUsed,
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int argc,              /* Number of arguments */
+  char **argv            /* Text of each argument */
+){
+  sqlite *db;
+  const char *zKey;
+  int nKey;
+  if( argc!=3 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+       " FILENAME\"", 0);
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+  zKey = argv[2];
+  nKey = strlen(zKey);
+#ifdef SQLITE_HAS_CODEC
+  sqlite3_key(db, zKey, nKey);
+#endif
+  return TCL_OK;
+}
+
+/*
+** Usage:  sqlite3_rekey DB KEY
+**
+** Change the codec key.
+*/
+static int test_rekey(
+  void *NotUsed,
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int argc,              /* Number of arguments */
+  char **argv            /* Text of each argument */
+){
+  sqlite *db;
+  const char *zKey;
+  int nKey;
+  if( argc!=3 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+       " FILENAME\"", 0);
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+  zKey = argv[2];
+  nKey = strlen(zKey);
+#ifdef SQLITE_HAS_CODEC
+  sqlite3_rekey(db, zKey, nKey);
+#endif
+  return TCL_OK;
+}
+
+/*
 ** Usage:  sqlite3_close DB
 **
 ** Closes the database opened by sqlite3_open.
@@ -2328,8 +2384,10 @@
      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
 #endif
-     { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
-     { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
+     { "sqlite_bind",                   (Tcl_CmdProc*)test_bind             },
+     { "breakpoint",                    (Tcl_CmdProc*)test_breakpoint       },
+     { "sqlite3_key",                   (Tcl_CmdProc*)test_key              },
+     { "sqlite3_rekey",                 (Tcl_CmdProc*)test_rekey            },
   };
   static struct {
      char *zName;