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
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users