Sorry, the attachment got scrubbed I think.  Here it is again:

diff -U 3 -H -d -r -N -- sqlite-3.6.17/src/attach.c 
sqlite-3.6.17-mod/src/attach.c
--- sqlite-3.6.17/src/attach.c  2009-11-03 10:47:25.000000000 +0100
+++ sqlite-3.6.17-mod/src/attach.c      2009-11-03 10:47:25.000000000 
+0100
@@ -55,12 +55,14 @@
 ** An SQL user-function registered to do the work of an ATTACH statement. 
The
 ** three arguments to the function come directly from an attach 
statement:
 **
-**     ATTACH DATABASE x AS y KEY z
+**     ATTACH [READONLY] DATABASE x AS y KEY z
 **
-**     SELECT sqlite_attach(x, y, z)
+**     SELECT sqlite_attach(readonly, x, y, z)
+**
+** "readonly" is 0 or 1.
 **
 ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as 
the
-** third argument.
+** third argument.  Note: "z" must be last for detachFunc to work 
correctly.
 */
 static void attachFunc(
   sqlite3_context *context,
@@ -72,13 +74,17 @@
   sqlite3 *db = sqlite3_context_db_handle(context);
   const char *zName;
   const char *zFile;
+  int fReadOnly;
+  int fflags;
   Db *aNew;
   char *zErrDyn = 0;
 
   UNUSED_PARAMETER(NotUsed);
 
-  zFile = (const char *)sqlite3_value_text(argv[0]);
-  zName = (const char *)sqlite3_value_text(argv[1]);
+  fReadOnly = sqlite3_value_int(argv[0]);
+  zFile = (const char *)sqlite3_value_text(argv[1]);
+  zName = (const char *)sqlite3_value_text(argv[2]);
+
   if( zFile==0 ) zFile = "";
   if( zName==0 ) zName = "";
 
@@ -126,8 +132,12 @@
   ** it to obtain the database schema. At this point the schema may
   ** or may not be initialised.
   */
+
+  fflags = db->openFlags;
+  if (fReadOnly) fflags = (fflags & ~(SQLITE_OPEN_READWRITE | 
SQLITE_OPEN_CREATE)) | SQLITE_OPEN_READONLY;
+
   rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
-                           db->openFlags | SQLITE_OPEN_MAIN_DB,
+                           fflags | SQLITE_OPEN_MAIN_DB,
                            &aNew->pBt);
   db->nDb++;
   if( rc==SQLITE_CONSTRAINT ){
@@ -156,7 +166,7 @@
     extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
     int nKey;
     char *zKey;
-    int t = sqlite3_value_type(argv[2]);
+    int t = sqlite3_value_type(argv[3]);
     switch( t ){
       case SQLITE_INTEGER:
       case SQLITE_FLOAT:
@@ -166,8 +176,8 @@
 
       case SQLITE_TEXT:
       case SQLITE_BLOB:
-        nKey = sqlite3_value_bytes(argv[2]);
-        zKey = (char *)sqlite3_value_blob(argv[2]);
+        nKey = sqlite3_value_bytes(argv[3]);
+        zKey = (char *)sqlite3_value_blob(argv[3]);
         sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
         break;
 
@@ -290,7 +300,8 @@
   Expr *pAuthArg,      /* Expression to pass to authorization callback */
   Expr *pFilename,     /* Name of database file */
   Expr *pDbname,       /* Name of the database to use internally */
-  Expr *pKey           /* Database key for encryption extension */
+  Expr *pKey,          /* Database key for encryption extension */
+  int readonly         /* attach readonly flag */
 ){
   int rc;
   NameContext sName;
@@ -325,14 +336,15 @@
 
 
   v = sqlite3GetVdbe(pParse);
-  regArgs = sqlite3GetTempRange(pParse, 4);
-  sqlite3ExprCode(pParse, pFilename, regArgs);
-  sqlite3ExprCode(pParse, pDbname, regArgs+1);
-  sqlite3ExprCode(pParse, pKey, regArgs+2);
+  regArgs = sqlite3GetTempRange(pParse, 5);
+  sqlite3ExprCode(pParse, pFilename, regArgs+1);
+  sqlite3ExprCode(pParse, pDbname, regArgs+2);
+  sqlite3ExprCode(pParse, pKey, regArgs+3);
 
   assert( v || db->mallocFailed );
   if( v ){
-    sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-pFunc->nArg, 
regArgs+3);
+       sqlite3VdbeAddOp2(v, OP_Integer, readonly, regArgs);
+    sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+4-pFunc->nArg, 
regArgs+4);
     assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
     sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
     sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
@@ -368,7 +380,7 @@
     "sqlite_detach",  /* zName */
     0                 /* pHash */
   };
-  codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, 
pDbname);
+  codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname, 
0);
 }
 
 /*
@@ -376,9 +388,9 @@
 **
 **     ATTACH p AS pDbname KEY pKey
 */
-void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
+void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey, int 
readonly){
   static FuncDef attach_func = {
-    3,                /* nArg */
+    4,                /* nArg */
     SQLITE_UTF8,      /* iPrefEnc */
     0,                /* flags */
     0,                /* pUserData */
@@ -389,7 +401,7 @@
     "sqlite_attach",  /* zName */
     0                 /* pHash */
   };
-  codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
+  codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey, 
readonly);
 }
 #endif /* SQLITE_OMIT_ATTACH */
 
diff -U 3 -H -d -r -N -- sqlite-3.6.17/src/parse.y 
sqlite-3.6.17-mod/src/parse.y
--- sqlite-3.6.17/src/parse.y   2009-11-03 10:47:25.000000000 +0100
+++ sqlite-3.6.17-mod/src/parse.y       2009-11-03 10:47:25.000000000 
+0100
@@ -1266,13 +1266,17 @@
 
 //////////////////////// ATTACH DATABASE file AS name 
/////////////////////////
 %ifndef SQLITE_OMIT_ATTACH
-cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
-  sqlite3Attach(pParse, F.pExpr, D.pExpr, K);
+cmd ::= ATTACH readonly_opt(R) database_kw_opt expr(F) AS expr(D) 
key_opt(K). {
+  sqlite3Attach(pParse, F.pExpr, D.pExpr, K, R);
 }
 cmd ::= DETACH database_kw_opt expr(D). {
   sqlite3Detach(pParse, D.pExpr);
 }
 
+%type readonly_opt {int}
+readonly_opt(A) ::= .                { A = 0; }
+readonly_opt(A) ::= READONLY.        { A = 1; }
+
 %type key_opt {Expr*}
 %destructor key_opt {sqlite3ExprDelete(pParse->db, $$);}
 key_opt(A) ::= .                     { A = 0; }
diff -U 3 -H -d -r -N -- sqlite-3.6.17/src/sqliteInt.h 
sqlite-3.6.17-mod/src/sqliteInt.h
--- sqlite-3.6.17/src/sqliteInt.h       2009-11-03 10:47:25.000000000 
+0100
+++ sqlite-3.6.17-mod/src/sqliteInt.h   2009-11-03 10:47:25.000000000 
+0100
@@ -2702,7 +2702,7 @@
 # define sqlite3AuthContextPush(a,b,c)
 # define sqlite3AuthContextPop(a)  ((void)(a))
 #endif
-void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
+void sqlite3Attach(Parse*, Expr*, Expr*, Expr*, int);
 void sqlite3Detach(Parse*, Expr*);
 int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename,
                        int omitJournal, int nCache, int flags, Btree 
**ppBtree);
diff -U 3 -H -d -r -N -- sqlite-3.6.17/tool/mkkeywordhash.c 
sqlite-3.6.17-mod/tool/mkkeywordhash.c
--- sqlite-3.6.17/tool/mkkeywordhash.c  2009-11-03 10:47:25.000000000 
+0100
+++ sqlite-3.6.17-mod/tool/mkkeywordhash.c      2009-11-03 
10:47:25.000000000 +0100
@@ -232,6 +232,7 @@
   { "PRIMARY",          "TK_PRIMARY",      ALWAYS                 },
   { "QUERY",            "TK_QUERY",        EXPLAIN                },
   { "RAISE",            "TK_RAISE",        TRIGGER                },
+  { "READONLY",         "TK_READONLY",     ATTACH                 },
   { "REFERENCES",       "TK_REFERENCES",   FKEY                   },
   { "REGEXP",           "TK_LIKE_KW",      ALWAYS                 },
   { "REINDEX",          "TK_REINDEX",      REINDEX                },
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to