aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-11-11 19:07:58 +0000
committerdrh <>2024-11-11 19:07:58 +0000
commitbe46f935dc3d2e5a033d5427f636fa3c521e06d2 (patch)
tree8511424d9d1feadaae772332e473f0df449478b7 /src
parent074cad302637e991ef4f024303bed87340897b86 (diff)
downloadsqlite-be46f935dc3d2e5a033d5427f636fa3c521e06d2.tar.gz
sqlite-be46f935dc3d2e5a033d5427f636fa3c521e06d2.zip
Add the ".dbtotxt" command to the CLI.
FossilOrigin-Name: b43acf5a8cd4a5efbb90b71af7710084f49bb90ffe4f56de168e8c3a6b679124
Diffstat (limited to 'src')
-rw-r--r--src/shell.c.in100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/shell.c.in b/src/shell.c.in
index 874f448f6..3fb608ff7 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -4951,6 +4951,7 @@ static const char *(azHelp[]) = {
#if SQLITE_SHELL_HAVE_RECOVER
".dbinfo ?DB? Show status information about the database",
#endif
+ ".dbtotxt Hex dump of the database file",
".dump ?OBJECTS? Render database content as SQL",
" Options:",
" --data-only Output only INSERT statements",
@@ -6623,6 +6624,101 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
#endif /* SQLITE_SHELL_HAVE_RECOVER */
/*
+** Implementation of the ".dbtotxt" command.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
+ sqlite3_stmt *pStmt = 0;
+ sqlite3_int64 nPage = 0;
+ int pgSz = 0;
+ const char *zFilename;
+ const char *zTail;
+ char *zName = 0;
+ int rc, i, j;
+ unsigned char bShow[256]; /* Characters ok to display */
+
+ memset(bShow, '.', sizeof(bShow));
+ for(i=' '; i<='~'; i++){
+ if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
+ }
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_size", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
+ pgSz = sqlite3_column_int(pStmt, 0);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( pgSz<512 || pgSz>65536 || (pgSz&(pgSz-1))!=0 ) goto dbtotxt_error;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_count", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
+ nPage = sqlite3_column_int64(pStmt, 0);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( nPage<1 ) goto dbtotxt_error;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA databases", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ){
+ zTail = zFilename = "unk.db";
+ }else{
+ zFilename = (const char*)sqlite3_column_text(pStmt, 2);
+ if( zFilename==0 || zFilename[0]==0 ) zFilename = "unk.db";
+ zTail = strrchr(zFilename, '/');
+#if defined(_WIN32)
+ if( zTail==0 ) zTail = strrchr(zFilename, '\\');
+#endif
+ if( zTail ) zFilename = zTail;
+ }
+ zName = strdup(zTail);
+ shell_check_oom(zName);
+ sqlite3_fprintf(p->out, "| size %lld pagesize %d filename %s\n",
+ nPage*pgSz, pgSz, zName);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT pgno, data FROM sqlite_dbpage ORDER BY pgno", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ sqlite3_int64 pgno = sqlite3_column_int64(pStmt, 0);
+ const u8 *aData = sqlite3_column_blob(pStmt, 1);
+ int seenPageLabel = 0;
+ for(i=0; i<pgSz; i+=16){
+ const u8 *aLine = aData+i;
+ for(j=0; j<16 && aLine[j]==0; j++){}
+ if( j==16 ) continue;
+ if( !seenPageLabel ){
+ sqlite3_fprintf(p->out, "| page %lld offset %lld\n", pgno, pgno*pgSz);
+ seenPageLabel = 1;
+ }
+ sqlite3_fprintf(p->out, "| %5d:", i);
+ for(j=0; j<16; j++) sqlite3_fprintf(p->out, " %02x", aLine[j]);
+ sqlite3_fprintf(p->out, " ");
+ for(j=0; j<16; j++){
+ unsigned char c = (unsigned char)aLine[j];
+ sqlite3_fprintf(p->out, "%c", bShow[c]);
+ }
+ sqlite3_fprintf(p->out, "\n");
+ }
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_fprintf(p->out, "| end %s\n", zName);
+ free(zName);
+ return 0;
+
+dbtotxt_error:
+ if( rc ){
+ sqlite3_fprintf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
+ }
+ sqlite3_finalize(pStmt);
+ free(zName);
+ return 1;
+}
+
+/*
** Print the given string as an error message.
*/
static void shellEmitError(const char *zErr){
@@ -8799,6 +8895,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
+ rc = shell_dbtotxt_command(p, nArg, azArg);
+ }else
+
if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
p->autoEQPtest = 0;