1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Fix the handling of -init option to the sqlite shell. Ticket #568.

Also add hooks for encrypting the database. (CVS 1206)

FossilOrigin-Name: 3c796de8d1af55944f396f08feaa9e69c1652896
This commit is contained in:
drh
2004-02-01 01:22:50 +00:00
parent 3914aed1de
commit 22fbcb8ddd
6 changed files with 226 additions and 130 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\sbug\sintroduced\sby\sthe\sprevious\scheck-in.\s(CVS\s1205) C Fix\sthe\shandling\sof\s-init\soption\sto\sthe\ssqlite\sshell.\sTicket\s#568.\nAlso\sadd\shooks\sfor\sencrypting\sthe\sdatabase.\s(CVS\s1206)
D 2004-01-31T20:40:42 D 2004-02-01T01:22:51
F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -47,11 +47,11 @@ F src/pragma.c 89d62c31c6f0a43376fe8d20549b87a6d30c467a
F src/printf.c 292a7bfc5a815cb6465e32b2d5c9fe9bd43b27f0 F src/printf.c 292a7bfc5a815cb6465e32b2d5c9fe9bd43b27f0
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c b7694067df8d57fd0c85ddcc0840532d181552ad F src/select.c b7694067df8d57fd0c85ddcc0840532d181552ad
F src/shell.c 3b067edc098c45caca164bcad1fa79192c3ec5ae F src/shell.c a069d35277983d54348105aa3c73be3c45eb9c38
F src/sqlite.h.in c70d8533cd5a5ae8af580597dbc726693ef82de9 F src/sqlite.h.in 1798588cab21ebf9fac3aad7fc1539b396c1f91d
F src/sqliteInt.h c5b727d5d07b88654c204c0fc1ae79c9f635a008 F src/sqliteInt.h c5b727d5d07b88654c204c0fc1ae79c9f635a008
F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895 F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895
F src/tclsqlite.c 85810fc4a850e2178d71aa5efe576dcd331db596 F src/tclsqlite.c 30afbb2e446d193d867e49fb0ca5ed84f1e0867f
F src/test1.c e8652055d04d241d4fb437b5c33ff07d9f13b4b4 F src/test1.c e8652055d04d241d4fb437b5c33ff07d9f13b4b4
F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700 F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
@ -127,7 +127,7 @@ F test/sort.test ba07b107c16070208e6aab3cadea66ba079d85ba
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4 F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
F test/tableapi.test d881e787779a175238b72f55b5e50d3a85ab47a6 F test/tableapi.test d881e787779a175238b72f55b5e50d3a85ab47a6
F test/tclsqlite.test 6921477a25aa630fd8d89b1ad231f80ef0dea88e F test/tclsqlite.test 97233f45db35a76ceae9e56d244af68fc8061ceb
F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692 F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692
F test/tester.tcl 2671536d3650c29e7c105219f277568b0884cb58 F test/tester.tcl 2671536d3650c29e7c105219f277568b0884cb58
F test/thread1.test 0c1fcc2f9bdd887225e56f48db8ddfbb3d0794ba F test/thread1.test 0c1fcc2f9bdd887225e56f48db8ddfbb3d0794ba
@ -182,7 +182,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 06e7ff4cb8c73fd690c6d5b5f530a30d83f4f10c P 04cf22785e68fcd4098e6c10a89386108cd0bf07
R ff7fd92d976b4f09b582d8f23eb657e9 R 6b544ab7468b55cbc9dfec6b7298d72d
U drh U drh
Z 2fd2d1288462765557d2cdab9570e192 Z e87a644a943e033216fc69c960947b44

View File

@ -1 +1 @@
04cf22785e68fcd4098e6c10a89386108cd0bf07 3c796de8d1af55944f396f08feaa9e69c1652896

View File

@ -12,7 +12,7 @@
** This file contains code to implement the "sqlite" command line ** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases. ** utility for accessing SQLite databases.
** **
** $Id: shell.c,v 1.83 2003/12/04 20:51:41 drh Exp $ ** $Id: shell.c,v 1.84 2004/02/01 01:22:51 drh Exp $
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -186,6 +186,7 @@ struct callback_data {
** .explain ON */ ** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */ char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */ const char *zDbFilename; /* name of the database file */
char *zKey; /* Encryption key */
}; };
/* /*
@ -489,6 +490,9 @@ static char zHelp[] =
".prompt MAIN CONTINUE Replace the standard prompts\n" ".prompt MAIN CONTINUE Replace the standard prompts\n"
".quit Exit this program\n" ".quit Exit this program\n"
".read FILENAME Execute SQL in FILENAME\n" ".read FILENAME Execute SQL in FILENAME\n"
#ifdef SQLITE_HAS_CRYPTO
".rekey OLD NEW NEW Change the encryption key\n"
#endif
".schema ?TABLE? Show the CREATE statements\n" ".schema ?TABLE? Show the CREATE statements\n"
".separator STRING Change separator string for \"list\" mode\n" ".separator STRING Change separator string for \"list\" mode\n"
".show Show the current values for various settings\n" ".show Show the current values for various settings\n"
@ -507,20 +511,21 @@ static void process_input(struct callback_data *p, FILE *in);
static void open_db(struct callback_data *p){ static void open_db(struct callback_data *p){
if( p->db==0 ){ if( p->db==0 ){
char *zErrMsg = 0; char *zErrMsg = 0;
p->db = db = sqlite_open(p->zDbFilename, 0666, &zErrMsg); #ifdef SQLITE_HAS_CRYPTO
if( db==0 ){ if( p->zKey && p->zKey[0] ){
p->db = db = sqlite_open(p->zDbFilename, 0444, &zErrMsg); int n = strlen(p->zKey);
if( db==0 ){ p->db = sqlite_open_encrypted(p->zDbFilename, p->zKey, n, &zErrMsg);
if( zErrMsg ){ }else
fprintf(stderr,"Unable to open database \"%s\": %s\n", #endif
p->zDbFilename, zErrMsg); p->db = sqlite_open(p->zDbFilename, 0, &zErrMsg);
}else{ if( p->db==0 ){
fprintf(stderr,"Unable to open database %s\n", p->zDbFilename); if( zErrMsg ){
} fprintf(stderr,"Unable to open database \"%s\": %s\n",
exit(1); p->zDbFilename, zErrMsg);
}else{ }else{
fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", p->zDbFilename); fprintf(stderr,"Unable to open database %s\n", p->zDbFilename);
} }
exit(1);
} }
} }
} }
@ -781,6 +786,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
} }
}else }else
#ifdef SQLITE_HAS_CRYPTO
if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){
char *zOld = p->zKey;
if( zOld==0 ) zOld = "";
if( strcmp(azArg[1],zOld) ){
fprintf(stderr,"old key is incorrect\n");
}else if( strcmp(azArg[2], azArg[3]) ){
fprintf(stderr,"2nd copy of new key does not match the 1st\n");
}else{
sqlite_freemem(p->zKey);
p->zKey = sqlite_mprintf("%s", azArg[2]);
sqlite_rekey(p->db, p->zKey, strlen(p->zKey));
}
}else
#endif
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
struct callback_data data; struct callback_data data;
char *zErrMsg = 0; char *zErrMsg = 0;
@ -1105,9 +1126,13 @@ static char *find_home_dir(void){
** Read input from the file given by sqliterc_override. Or if that ** Read input from the file given by sqliterc_override. Or if that
** parameter is NULL, take input from ~/.sqliterc ** parameter is NULL, take input from ~/.sqliterc
*/ */
static void process_sqliterc(struct callback_data *p, char *sqliterc_override){ static void process_sqliterc(
struct callback_data *p, /* Configuration data */
const char *sqliterc_override /* Name of config file. NULL to use default */
){
char *home_dir = NULL; char *home_dir = NULL;
char *sqliterc = sqliterc_override; const char *sqliterc = sqliterc_override;
char *zBuf;
FILE *in = NULL; FILE *in = NULL;
if (sqliterc == NULL) { if (sqliterc == NULL) {
@ -1116,17 +1141,20 @@ static void process_sqliterc(struct callback_data *p, char *sqliterc_override){
fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0); fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
return; return;
} }
sqliterc = malloc(strlen(home_dir) + 15); zBuf = malloc(strlen(home_dir) + 15);
if( sqliterc==0 ){ if( zBuf==0 ){
fprintf(stderr,"%s: out of memory!\n", Argv0); fprintf(stderr,"%s: out of memory!\n", Argv0);
exit(1); exit(1);
} }
sprintf(sqliterc,"%s/.sqliterc",home_dir); sprintf(zBuf,"%s/.sqliterc",home_dir);
free(home_dir); free(home_dir);
sqliterc = (const char*)zBuf;
} }
in = fopen(sqliterc,"r"); in = fopen(sqliterc,"r");
if(in && isatty(fileno(stdout))) { if( in ){
printf("Loading resources from %s\n",sqliterc); if( isatty(fileno(stdout)) ){
printf("Loading resources from %s\n",sqliterc);
}
process_input(p,in); process_input(p,in);
fclose(in); fclose(in);
} }
@ -1174,15 +1202,13 @@ void main_init(struct callback_data *data) {
int main(int argc, char **argv){ int main(int argc, char **argv){
char *zErrMsg = 0; char *zErrMsg = 0;
struct callback_data data; struct callback_data data;
int origArgc = argc; const char *zInitFile = 0;
char **origArgv = argv; char *zFirstCmd = 0;
int i; int i;
extern int sqliteOsFileExists(const char*); extern int sqliteOsFileExists(const char*);
#ifdef __MACOS__ #ifdef __MACOS__
argc = ccommand(&argv); argc = ccommand(&argv);
origArgc = argc;
origArgv = argv;
#endif #endif
Argv0 = argv[0]; Argv0 = argv[0];
@ -1195,15 +1221,30 @@ int main(int argc, char **argv){
signal(SIGINT, interrupt_handler); signal(SIGINT, interrupt_handler);
#endif #endif
/* Locate the name of the database file /* Do an initial pass through the command-line argument to locate
** the name of the database file, the name of the initialization file,
** and the first command to execute.
*/ */
for(i=1; i<argc; i++){ for(i=1; i<argc-1; i++){
if( argv[i][0]!='-' ) break; if( argv[i][0]!='-' ) break;
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){ if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
i++; i++;
}else if( strcmp(argv[i],"-init")==0 ){
i++;
zInitFile = argv[i];
}else if( strcmp(argv[i],"-key")==0 ){
i++;
data.zKey = sqlite_mprintf("%s",argv[i]);
} }
} }
data.zDbFilename = i<argc ? argv[i] : ":memory:"; if( i<argc ){
data.zDbFilename = argv[i++];
}else{
data.zDbFilename = ":memory:";
}
if( i<argc ){
zFirstCmd = argv[i++];
}
data.out = stdout; data.out = stdout;
/* Go ahead and open the database file if it already exists. If the /* Go ahead and open the database file if it already exists. If the
@ -1215,96 +1256,63 @@ int main(int argc, char **argv){
open_db(&data); open_db(&data);
} }
/* Process the ~/.sqliterc file, if there is one /* Process the initialization file if there is one. If no -init option
** is given on the command line, look for a file named ~/.sqliterc and
** try to process it.
*/ */
process_sqliterc(&data,NULL); process_sqliterc(&data,zInitFile);
/* Process command-line options /* Make a second pass through the command-line argument and set
** options. This second pass is delayed until after the initialization
** file is processed so that the command-line arguments will override
** settings in the initialization file.
*/ */
while( argc>=2 && argv[1][0]=='-' ){ for(i=1; i<argc && argv[i][0]=='-'; i++){
if( argc>=3 && strcmp(argv[1],"-init")==0 ){ char *z = argv[i];
/* If we get a -init to do, we have to pretend that if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
** it replaced the .sqliterc file. Soooo, in order to i++;
** do that we need to start from scratch...*/ }else if( strcmp(z,"-html")==0 ){
main_init(&data);
/* treat this file as the sqliterc... */
process_sqliterc(&data,argv[2]);
/* fix up the command line so we do not re-read
** the option next time around... */
{
int i = 1;
for(i=1;i<=argc-2;i++) {
argv[i] = argv[i+2];
}
}
origArgc-=2;
/* and reset the command line options to be re-read.*/
argv = origArgv;
argc = origArgc;
}else if( strcmp(argv[1],"-html")==0 ){
data.mode = MODE_Html; data.mode = MODE_Html;
argc--; }else if( strcmp(z,"-list")==0 ){
argv++;
}else if( strcmp(argv[1],"-list")==0 ){
data.mode = MODE_List; data.mode = MODE_List;
argc--; }else if( strcmp(z,"-line")==0 ){
argv++;
}else if( strcmp(argv[1],"-line")==0 ){
data.mode = MODE_Line; data.mode = MODE_Line;
argc--; }else if( strcmp(z,"-column")==0 ){
argv++;
}else if( strcmp(argv[1],"-column")==0 ){
data.mode = MODE_Column; data.mode = MODE_Column;
argc--; }else if( strcmp(z,"-separator")==0 ){
argv++; i++;
}else if( argc>=3 && strcmp(argv[1],"-separator")==0 ){ sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]); }else if( strcmp(z,"-nullvalue")==0 ){
argc -= 2; i++;
argv += 2; sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
}else if( argc>=3 && strcmp(argv[1],"-nullvalue")==0 ){ }else if( strcmp(z,"-header")==0 ){
sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[2]);
argc -= 2;
argv += 2;
}else if( strcmp(argv[1],"-header")==0 ){
data.showHeader = 1; data.showHeader = 1;
argc--; }else if( strcmp(z,"-noheader")==0 ){
argv++;
}else if( strcmp(argv[1],"-noheader")==0 ){
data.showHeader = 0; data.showHeader = 0;
argc--; }else if( strcmp(z,"-echo")==0 ){
argv++;
}else if( strcmp(argv[1],"-echo")==0 ){
data.echoOn = 1; data.echoOn = 1;
argc--; }else if( strcmp(z,"-version")==0 ){
argv++;
}else if( strcmp(argv[1],"-version")==0 ){
printf("%s\n", sqlite_version); printf("%s\n", sqlite_version);
return 1; return 1;
}else if( strcmp(argv[1],"-help")==0 ){ }else if( strcmp(z,"-help")==0 ){
usage(1); usage(1);
}else{ }else{
fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]); fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
fprintf(stderr,"Use -help for a list of options.\n"); fprintf(stderr,"Use -help for a list of options.\n");
return 1; return 1;
} }
} }
if( argc<2 ){ if( zFirstCmd ){
usage(0);
}else if( argc==3 ){
/* Run just the command that follows the database name /* Run just the command that follows the database name
*/ */
if( argv[2][0]=='.' ){ if( zFirstCmd[0]=='.' ){
do_meta_command(argv[2], &data); do_meta_command(zFirstCmd, &data);
exit(0); exit(0);
}else{ }else{
int rc; int rc;
open_db(&data); open_db(&data);
rc = sqlite_exec(db, argv[2], callback, &data, &zErrMsg); rc = sqlite_exec(db, zFirstCmd, callback, &data, &zErrMsg);
if( rc!=0 && zErrMsg!=0 ){ if( rc!=0 && zErrMsg!=0 ){
fprintf(stderr,"SQL error: %s\n", zErrMsg); fprintf(stderr,"SQL error: %s\n", zErrMsg);
exit(1); exit(1);

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** presents to client programs.
** **
** @(#) $Id: sqlite.h.in,v 1.54 2004/01/15 02:44:03 drh Exp $ ** @(#) $Id: sqlite.h.in,v 1.55 2004/02/01 01:22:52 drh Exp $
*/ */
#ifndef _SQLITE_H_ #ifndef _SQLITE_H_
#define _SQLITE_H_ #define _SQLITE_H_
@ -773,6 +773,33 @@ void sqlite_progress_handler(sqlite*, int, int(*)(void*), void*);
*/ */
void *sqlite_commit_hook(sqlite*, int(*)(void*), void*); void *sqlite_commit_hook(sqlite*, int(*)(void*), void*);
/*
** Open an encrypted SQLite database. If pKey==0 or nKey==0, this routine
** is the same as sqlite_open().
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
sqlite *sqlite_open_encrypted(
const char *zFilename, /* Name of the encrypted database */
const void *pKey, /* Pointer to the key */
int nKey, /* Number of bytes in the key */
char **pzErrmsg /* Write error message here */
);
/*
** Change the key on an open database. If the current database is not
** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
** database is decrypted.
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
int sqlite_rekey(
sqlite *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
#ifdef __cplusplus #ifdef __cplusplus
} /* End of the 'extern "C"' block */ } /* End of the 'extern "C"' block */
#endif #endif

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** A TCL Interface to SQLite ** A TCL Interface to SQLite
** **
** $Id: tclsqlite.c,v 1.54 2004/01/15 02:44:03 drh Exp $ ** $Id: tclsqlite.c,v 1.55 2004/02/01 01:22:52 drh Exp $
*/ */
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@ -486,19 +486,21 @@ static int auth_callback(
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
SqliteDb *pDb = (SqliteDb*)cd; SqliteDb *pDb = (SqliteDb*)cd;
int choice; int choice;
int rc = TCL_OK;
static const char *DB_strs[] = { static const char *DB_strs[] = {
"authorizer", "busy", "changes", "authorizer", "busy", "changes",
"close", "commit_hook", "complete", "close", "commit_hook", "complete",
"errorcode", "eval", "function", "errorcode", "eval", "function",
"last_insert_rowid", "onecolumn", "progress", "last_insert_rowid", "onecolumn", "progress",
"timeout", "trace", 0 "rekey", "timeout", "trace",
0
}; };
enum DB_enum { enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CHANGES, DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE, DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE,
DB_ERRORCODE, DB_EVAL, DB_FUNCTION, DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
DB_LAST_INSERT_ROWID, DB_ONECOLUMN, DB_PROGRESS, DB_LAST_INSERT_ROWID, DB_ONECOLUMN, DB_PROGRESS,
DB_TIMEOUT, DB_TRACE, DB_REKEY, DB_TIMEOUT, DB_TRACE,
}; };
if( objc<2 ){ if( objc<2 ){
@ -747,7 +749,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
CallbackData cbData; CallbackData cbData;
char *zErrMsg; char *zErrMsg;
char *zSql; char *zSql;
int rc;
#ifdef UTF_TRANSLATION_NEEDED #ifdef UTF_TRANSLATION_NEEDED
Tcl_DString dSql; Tcl_DString dSql;
int i; int i;
@ -865,7 +866,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** Return a single column from a single row of the given SQL query. ** Return a single column from a single row of the given SQL query.
*/ */
case DB_ONECOLUMN: { case DB_ONECOLUMN: {
int rc;
char *zSql; char *zSql;
char *zErrMsg = 0; char *zErrMsg = 0;
if( objc!=3 ){ if( objc!=3 ){
@ -875,7 +875,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zSql = Tcl_GetStringFromObj(objv[2], 0); zSql = Tcl_GetStringFromObj(objv[2], 0);
rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg); rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
if( rc==SQLITE_ABORT ){ if( rc==SQLITE_ABORT ){
/* Do nothing. This is normal. */ rc = SQLITE_OK;
}else if( zErrMsg ){ }else if( zErrMsg ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
free(zErrMsg); free(zErrMsg);
@ -887,6 +887,29 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/*
** $db rekey KEY
**
** Change the encryption key on the currently open database.
*/
case DB_REKEY: {
int nKey;
void *pKey;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "KEY");
return TCL_ERROR;
}
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
#ifdef SQLITE_HAS_CRYPTO
rc = sqlite_rekey(pDb->db, pKey, nKey);
if( rc ){
Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
rc = TCL_ERROR;
}
#endif
break;
}
/* /*
** $db timeout MILLESECONDS ** $db timeout MILLESECONDS
** **
@ -940,11 +963,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} }
} /* End of the SWITCH statement */ } /* End of the SWITCH statement */
return TCL_OK; return rc;
} }
/* /*
** sqlite DBNAME FILENAME ?MODE? ** sqlite DBNAME FILENAME ?MODE? ?-key KEY?
** **
** This is the main Tcl command. When the "sqlite" Tcl command is ** This is the main Tcl command. When the "sqlite" Tcl command is
** invoked, this routine runs to process that command. ** invoked, this routine runs to process that command.
@ -974,21 +997,34 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** not. Used by tests to make sure the library was compiled ** not. Used by tests to make sure the library was compiled
** correctly. ** correctly.
*/ */
static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int mode; int mode;
SqliteDb *p; SqliteDb *p;
void *pKey = 0;
int nKey = 0;
const char *zArg;
char *zErrMsg; char *zErrMsg;
const char *zFile;
char zBuf[80]; char zBuf[80];
if( argc==2 ){ if( objc==2 ){
if( strcmp(argv[1],"-encoding")==0 ){ zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-encoding")==0 ){
Tcl_AppendResult(interp,sqlite_encoding,0); Tcl_AppendResult(interp,sqlite_encoding,0);
return TCL_OK; return TCL_OK;
} }
if( strcmp(argv[1],"-version")==0 ){ if( strcmp(zArg,"-version")==0 ){
Tcl_AppendResult(interp,sqlite_version,0); Tcl_AppendResult(interp,sqlite_version,0);
return TCL_OK; return TCL_OK;
} }
if( strcmp(argv[1],"-tcl-uses-utf")==0 ){ if( strcmp(zArg,"-has-crypto")==0 ){
#ifdef SQLITE_HAS_CRYPTO
Tcl_AppendResult(interp,"1",0);
#else
Tcl_AppendResult(interp,"0",0);
#endif
return TCL_OK;
}
if( strcmp(zArg,"-tcl-uses-utf")==0 ){
#ifdef TCL_UTF_MAX #ifdef TCL_UTF_MAX
Tcl_AppendResult(interp,"1",0); Tcl_AppendResult(interp,"1",0);
#else #else
@ -997,14 +1033,26 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
return TCL_OK; return TCL_OK;
} }
} }
if( argc!=3 && argc!=4 ){ if( objc==5 || objc==6 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
" HANDLE FILENAME ?MODE?\"", 0); if( strcmp(zArg,"-key")==0 ){
pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
objc -= 2;
}
}
if( objc!=3 && objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv,
#ifdef SQLITE_HAS_CRYPTO
"HANDLE FILENAME ?-key CRYPTOKEY?"
#else
"HANDLE FILENAME ?MODE?"
#endif
);
return TCL_ERROR; return TCL_ERROR;
} }
if( argc==3 ){ if( objc==3 ){
mode = 0666; mode = 0666;
}else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){ }else if( Tcl_GetIntFromObj(interp, objv[3], &mode)!=TCL_OK ){
return TCL_ERROR; return TCL_ERROR;
} }
zErrMsg = 0; zErrMsg = 0;
@ -1014,14 +1062,21 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
return TCL_ERROR; return TCL_ERROR;
} }
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
p->db = sqlite_open(argv[2], mode, &zErrMsg); zFile = Tcl_GetStringFromObj(objv[2], 0);
#ifdef SQLITE_HAS_CRYPTO
if( nKey>0 ){
p->db = sqlite_open_encrypted(zFile, pKey, nKey, &zErrMsg);
}else
#endif
p->db = sqlite_open(zFile, mode, &zErrMsg);
if( p->db==0 ){ if( p->db==0 ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
Tcl_Free((char*)p); Tcl_Free((char*)p);
free(zErrMsg); free(zErrMsg);
return TCL_ERROR; return TCL_ERROR;
} }
Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd); zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
/* The return value is the value of the sqlite* pointer /* The return value is the value of the sqlite* pointer
*/ */
@ -1063,13 +1118,13 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
*/ */
int Sqlite_Init(Tcl_Interp *interp){ int Sqlite_Init(Tcl_Interp *interp){
Tcl_InitStubs(interp, "8.0", 0); Tcl_InitStubs(interp, "8.0", 0);
Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0); Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite", "2.0"); Tcl_PkgProvide(interp, "sqlite", "2.0");
return TCL_OK; return TCL_OK;
} }
int Tclsqlite_Init(Tcl_Interp *interp){ int Tclsqlite_Init(Tcl_Interp *interp){
Tcl_InitStubs(interp, "8.0", 0); Tcl_InitStubs(interp, "8.0", 0);
Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0); Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite", "2.0"); Tcl_PkgProvide(interp, "sqlite", "2.0");
return TCL_OK; return TCL_OK;
} }

View File

@ -15,21 +15,26 @@
# interface is pretty well tested. This file contains some addition # interface is pretty well tested. This file contains some addition
# tests for fringe issues that the main test suite does not cover. # tests for fringe issues that the main test suite does not cover.
# #
# $Id: tclsqlite.test,v 1.17 2004/01/15 02:44:04 drh Exp $ # $Id: tclsqlite.test,v 1.18 2004/02/01 01:22:52 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
# Check the error messages generated by tclsqlite # Check the error messages generated by tclsqlite
# #
if {[sqlite -has-crypto]} {
set r "sqlite HANDLE FILENAME ?-key CRYPTOKEY?"
} else {
set r "sqlite HANDLE FILENAME ?MODE?"
}
do_test tcl-1.1 { do_test tcl-1.1 {
set v [catch {sqlite bogus} msg] set v [catch {sqlite bogus} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}} } [list 1 "wrong # args: should be \"$r\""]
do_test tcl-1.2 { do_test tcl-1.2 {
set v [catch {db bogus} msg] set v [catch {db bogus} msg]
lappend v $msg lappend v $msg
} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, onecolumn, progress, timeout, or trace}} } {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, onecolumn, progress, rekey, timeout, or trace}}
do_test tcl-1.3 { do_test tcl-1.3 {
execsql {CREATE TABLE t1(a int, b int)} execsql {CREATE TABLE t1(a int, b int)}
execsql {INSERT INTO t1 VALUES(10,20)} execsql {INSERT INTO t1 VALUES(10,20)}
@ -98,8 +103,9 @@ do_test tcl-3.1 {
INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1; INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1;
INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1; INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1;
} }
db onecolumn {SELECT * FROM t1 ORDER BY a} set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg]
} {10} lappend rc $msg
} {0 10}
do_test tcl-3.2 { do_test tcl-3.2 {
db onecolumn {SELECT * FROM t1 WHERE a<0} db onecolumn {SELECT * FROM t1 WHERE a<0}
} {} } {}