Implement the ".ar --create" command using a single
"REPLACE INTO sqlar SELECT ... FROM fsdir();" statement. Add the shell_putsnl() SQL function for providing --verbose output. FossilOrigin-Name: 28ab930436fea33c79073e84f39d9e381fa60b4702a5dcbfaaed72baeeae8431
This commit is contained in:
+39
-65
@@ -1135,6 +1135,22 @@ static void shellLog(void *pArg, int iErrCode, const char *zMsg){
|
||||
fflush(p->pLog);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: shell_putsnl(X)
|
||||
**
|
||||
** Write the text X to the screen (or whatever output is being directed)
|
||||
** adding a newline at the end, and then return X.
|
||||
*/
|
||||
static void shellPutsFunc(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
|
||||
utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
|
||||
sqlite3_result_value(pCtx, apVal[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
** Output the given string as a hex-encoded blob (eg. X'1234' )
|
||||
*/
|
||||
@@ -3307,6 +3323,8 @@ static void open_db(ShellState *p, int keepAlive){
|
||||
shellAddSchemaName, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
|
||||
shellModuleSchema, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
|
||||
shellPutsFunc, 0, 0);
|
||||
if( p->openMode==SHELL_OPEN_ZIPFILE ){
|
||||
char *zSql = sqlite3_mprintf(
|
||||
"CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename);
|
||||
@@ -5008,7 +5026,6 @@ static int arCreateOrUpdateCommand(
|
||||
ArCommand *pAr, /* Command arguments and options */
|
||||
int bUpdate /* true for a --create. false for --update */
|
||||
){
|
||||
const char *zSql = "SELECT name, mode, mtime, data FROM fsdir($name, $dir)";
|
||||
const char *zCreate =
|
||||
"CREATE TABLE IF NOT EXISTS sqlar(\n"
|
||||
" name TEXT PRIMARY KEY, -- name of the file\n"
|
||||
@@ -5018,86 +5035,41 @@ static int arCreateOrUpdateCommand(
|
||||
" data BLOB -- compressed content\n"
|
||||
")";
|
||||
const char *zDrop = "DROP TABLE IF EXISTS sqlar";
|
||||
const char *zInsert = "REPLACE INTO sqlar VALUES(?,?,?,?,sqlar_compress(?))";
|
||||
|
||||
sqlite3_stmt *pStmt = 0; /* Directory traverser */
|
||||
sqlite3_stmt *pInsert = 0; /* Compilation of zInsert */
|
||||
const char *zInsertFmt =
|
||||
"REPLACE INTO sqlar(name,mode,mtime,sz,data)\n"
|
||||
" SELECT\n"
|
||||
" %s,\n"
|
||||
" mode,\n"
|
||||
" mtime,\n"
|
||||
" CASE filetype(mode)\n"
|
||||
" WHEN 'file' THEN length(data)\n"
|
||||
" WHEN 'directory' THEN 0\n"
|
||||
" ELSE -1 END,\n"
|
||||
" CASE WHEN filetype(mode)<>'directory' THEN data ELSE NULL END\n"
|
||||
" FROM fsdir(%Q,%Q)\n"
|
||||
" WHERE filetype(mode)<>'unknown'";
|
||||
int i; /* For iterating through azFile[] */
|
||||
int j; /* Parameter index */
|
||||
int rc; /* Return code */
|
||||
|
||||
assert( pAr->bZip==0 );
|
||||
|
||||
rc = arExecSql(pAr, "SAVEPOINT ar;");
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
if( bUpdate==0 ){
|
||||
rc = arExecSql(pAr, zDrop);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
rc = arExecSql(pAr, zCreate);
|
||||
if( !pAr->bDryRun ){
|
||||
shellPrepare(pAr->db, &rc, zInsert, &pInsert);
|
||||
}
|
||||
shellPrepare(pAr->db, &rc, zSql, &pStmt);
|
||||
j = sqlite3_bind_parameter_index(pStmt, "$dir");
|
||||
sqlite3_bind_text(pStmt, j, pAr->zDir, -1, SQLITE_STATIC);
|
||||
if( pAr->bDryRun ){
|
||||
utf8_printf(pAr->p->out, "%s;\n", sqlite3_sql(pStmt));
|
||||
}
|
||||
|
||||
for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
|
||||
j = sqlite3_bind_parameter_index(pStmt, "$name");
|
||||
sqlite3_bind_text(pStmt, j, pAr->azArg[i], -1, SQLITE_STATIC);
|
||||
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int sz;
|
||||
const char *zName = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
int mode = sqlite3_column_int(pStmt, 1);
|
||||
unsigned int mtime = sqlite3_column_int(pStmt, 2);
|
||||
|
||||
if( pAr->bVerbose ){
|
||||
utf8_printf(pAr->p->out, "%s\n", zName);
|
||||
}
|
||||
if( pAr->bDryRun ){
|
||||
utf8_printf(pAr->p->out, "%s;\n", zInsert);
|
||||
continue;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(pInsert, 1, zName, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int(pInsert, 2, mode);
|
||||
sqlite3_bind_int64(pInsert, 3, (sqlite3_int64)mtime);
|
||||
|
||||
if( S_ISDIR(mode) ){
|
||||
sz = 0;
|
||||
sqlite3_bind_null(pInsert, 5);
|
||||
}else{
|
||||
sqlite3_bind_value(pInsert, 5, sqlite3_column_value(pStmt, 3));
|
||||
if( S_ISLNK(mode) ){
|
||||
sz = -1;
|
||||
}else{
|
||||
sz = sqlite3_column_bytes(pStmt, 3);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_bind_int(pInsert, 4, sz);
|
||||
if( pAr->bDryRun ){
|
||||
utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pInsert));
|
||||
}else{
|
||||
sqlite3_step(pInsert);
|
||||
}
|
||||
rc = sqlite3_reset(pInsert);
|
||||
}
|
||||
shellReset(&rc, pStmt);
|
||||
char *zSql = sqlite3_mprintf(zInsertFmt,
|
||||
pAr->bVerbose ? "shell_putsnl(name)" : "name",
|
||||
pAr->azArg[i], pAr->zDir);
|
||||
rc = arExecSql(pAr, zSql);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
arExecSql(pAr, "ROLLBACK TO ar; RELEASE ar;");
|
||||
}else{
|
||||
rc = arExecSql(pAr, "RELEASE ar;");
|
||||
}
|
||||
shellFinalize(&rc, pStmt);
|
||||
shellFinalize(&rc, pInsert);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -5161,7 +5133,9 @@ static int arDotCommand(
|
||||
#endif
|
||||
}
|
||||
if( cmd.zSrcTable==0 ){
|
||||
if( sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) ){
|
||||
if( cmd.eCmd!=AR_CMD_CREATE
|
||||
&& sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
|
||||
){
|
||||
utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
|
||||
rc = SQLITE_ERROR;
|
||||
goto end_ar_command;
|
||||
|
||||
Reference in New Issue
Block a user