Feature request: optional argument "off" to ".output" dot-command
(1) By wdixon on 2025-03-27 14:54:09 [source]
REQUEST:
I am requesting an optional parameter "off
" to the .output
command. If there, it would turn off all output. In other words, instead of output going to stdout or a designated file, it would not go anywhere.
REASON:
If you include a PRAGMA
command in your SQL commands, its output is included in everything else. Specifically, in my case, I have PRAGMA busy_timeout=5000;
above my INSERTs and UPDATEs. No problem, they do not generate any output, so I can throw everything away, and generally I don't need that PRAGMA statement with my SELECTs. But I have one case that looks like
PRAGMA busy_timeout=5000;
INSERT INTO Table (column) VALUES ('value');
SELECT last_insert_rowid();
So, what I get is the last rowid, along with '5000'! And now I have to deal with ignoring the extra output.
What I think would be very beneficial would be to be able to do this:
.output off
PRAGMA busy_timeout=5000;
.output
INSERT INTO Table (column) VALUES ('value');
SELECT last_insert_rowid();
This would let you throw away the output of the PRAGMA
command, and keep the "real" output that you are requesting. It would also let you include a timeout value in all of your SQL commands in a way that you didn't have to explicitly exclude a portion of the output you receive.
NOTE:
I am aware that this can currently be simulated somewhat by specifying .output /dev/null
if you are running on a Linux OS, or.output null
if running under Windows. But in my case, my code will be running in both environments. In order to use the null device, I would have to test for OS version, and duplicate all of my SQL commands. This enhancement would make SQLite more platform independent.
(2) By Richard Hipp (drh) on 2025-03-27 15:55:20 in reply to 1 [link] [source]
You can use the (undocumented) ".mode off
" command to get the same effect, I think.
(3) By wdixon on 2025-03-27 16:59:47 in reply to 2 [link] [source]
Almost!
I should be able to put .mode off
before my PRAGMA
statement, and mode list
after it.
But, I build a variable containing all my lines of SQL code (using a "here" document), and then pipe it to the sqlite3 command. If I do that within a bash accept, it works perfectly.
> cat test2c.sh
#! /bin/bash
cat << EOF | sqlite3 test.db
.mode off
PRAGMA busy_timeout=5000;
.mode list
INSERT INTO TestTable (col1, col2)
VALUES (123, $$);
SELECT * FROM TestTable
WHERE col2 = $$;
EOF
> ./test2c.sh
123|3549946
>
But if I do that within a perl script, it complains.
> cat test2d.pl
#! /usr/bin/perl
my $sqlcmd = << "END_OF_SQL";
.mode off
PRAGMA busy_timeout=5000;
.mode list
INSERT INTO TestTable (col1, col2)
VALUES (123, $$);
SELECT * FROM TestTable
WHERE col2 = $$;
END_OF_SQL
`sqlite3 test.db "$sqlcmd"`;
> ./test2d.pl
extra argument: "busy_timeout=5000;"
>
I think it is combining the .mode off
and the PRAGMA
statements into a single line. I tried adding a semi-colon after the .mode line, doesn't make any difference.
I will be running this on both a Linux machine and my Windows laptop, so I can't use bash (or I would).
Any ideas?
(4) By RandomCoder on 2025-03-27 17:45:48 in reply to 3 [link] [source]
If you want to replicate piping the script into SQLite in Perl like you did in Bash, you can do something like this:
#!/usr/bin/perl
my $sqlcmd = << "END_OF_SQL";
.mode off
PRAGMA busy_timeout=5000;
.mode list
INSERT INTO TestTable (col1, col2)
VALUES (123, $$);
SELECT * FROM TestTable
WHERE col2 = $$;
END_OF_SQL
open SQLITE, "|sqlite3 test.db > temp_output";
print SQLITE $sqlcmd;
close SQLITE;
open OUTPUT, "temp_output";
$results = <OUTPUT>;
close OUTPUT;
unlink("temp_output");
print "Results = [" . $results . "]\n";
It's possible to also pipe the output so you don't need the temporary file, but that's an exercise for you, as it's a Perl specific feature, not anything to do with SQLite. Or, I'd very much suggest using DBD::SQLite
to avoid this rather fragile way of interacting with a SQLite database.
(5) By wdixon on 2025-03-27 20:13:21 in reply to 4 [link] [source]
Thanks, but if I'm going to have to jump through hoops for each and every SQL command I use in my code, I'll grep out the PRAGMA output in a subroutine:
> cat test2d.pl
#! /usr/bin/perl
sub sql_cmd {
my ($dbname, $cmd) = @_;
$timeout = 5135; # a pseudo-unique number around 5000
$cmd = "PRAGMA busy_timeout=$timeout;\n$cmd";
chomp (@rows = `sqlite3 $dbname "$cmd"`);
@rows = grep (!/^$timeout$/, @rows);
return @rows;
}
my $sqlcmd = << "END_OF_SQL";
INSERT INTO TestTable (col1, col2)
VALUES (123, $$);
SELECT * FROM TestTable;
END_OF_SQL
@lines = sql_cmd ("test.db", "$sqlcmd");
foreach $line (@lines) {
print "$line\n";
}
> ./test2d.pl
123|3572361
>
I'll just make sure I put that subroutine in every perl script I write.
I still think it should be part of the SQLite package to suppress PRAGMA output, but if I have to go the long way around, I guess I'll have to.
(And there are complicated reasons why I'm not using DBD::SQLite
, that are too long to go into here, and aren't really part of this issue. The product should work as-is, without expecting you to use a specific perl module.)
(6) By mgr (mgrmgr) on 2025-03-28 12:02:42 in reply to 3 [link] [source]
you could factor out your PRAGMA-part to a file and load that with the -init
option
sqlite3 -init file_with_modeoff_pragma_modelist.sql test.db "$sqlcmd_without_the_pragmastuff"
or daisy-chain them up with -cmd
options
sqlite3 -cmd '.mode off' -cmd 'PRAGMA busy_timeout=5000' -cmd '.mode list' test.db "$sqlcmd_without_the_pragmastuff"
or use the variant with multiple SQL arguments as recently (re)discovered and documented 82fc67070f9aff00 / cli extra command line arguments
sqlite3 test.db '.mode off' 'PRAGMA busy_timeout=5000' '.mode list' "$sqlcmd_without_the_pragmastuff"
(7) By Stephan Beal (stephan) on 2025-03-28 14:38:26 in reply to 1 [link] [source]
I am aware that this can currently be simulated somewhat by specifying .output /dev/null if you are running on a Linux OS, or.output null if running under Windows. But in my case, my code will be running in both environments.
What if:
sqlite> .once off
was simply an alias for one of:
sqlite> .once /dev/null sqlite> .once nul
depending on whether it's built for Windows? Would that solve your problem?
i've got a local patch for that, drh's approval to make it so, and it seems to work on Linux and Windows, but i'd like confirmation that that is functionally what you're looking for before committing it:
$ f diff Index: src/shell.c.in ================================================================== --- src/shell.c.in +++ src/shell.c.in @@ -10269,11 +10269,19 @@ showHelp(p->out, azArg[0]); rc = 1; goto meta_command_exit; } }else if( zFile==0 && eMode==0 ){ - zFile = sqlite3_mprintf("%s", z); + if( cli_strcmp(z, "off")==0 ){ +#ifdef _WIN32 + zFile = sqlite3_mprintf("nul"); +#else + zFile = sqlite3_mprintf("/dev/null"); +#endif + }else{ + zFile = sqlite3_mprintf("%s", z); + } if( zFile && zFile[0]=='|' ){ while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]); break; } }else{
(8) By wdixon on 2025-03-28 15:10:05 in reply to 7 [link] [source]
That looks like it would work for me.
(9) By Stephan Beal (stephan) on 2025-03-28 15:40:47 in reply to 8 [link] [source]
That looks like it would work for me.
That's now in the trunk.
(10) By mgr (mgrmgr) on 2025-03-28 20:12:38 in reply to 9 [link] [source]
though neither
.once off
PRAGMA busy_timeout=5000;
SELECT ... ;
nor
.output off
PRAGMA busy_timeout=5000;
.output
SELECT ... ;
is any better than
.mode off
PRAGMA busy_timeout=5000;
.mode list
SELECT ... ;
if the linebreak gets lost between the .xxx
commands, as wdixon showed.
On the contrary, '.once' behaves strangely (also before that change ) when used with -cmd
or as "one of many" argument, it changes output not only for one statement but for all of them:
sqlite3 :memory: ".once test.txt" "PRAGMA busy_timeout=5000;" "SELECT 88;" "SELECT 99;"
sqlite3 -cmd ".once test2.txt" :memory: "PRAGMA busy_timeout=5000; SELECT 88; SELECT 99;"
Both do not output anything but write 3 lines to test.txt/test2.txt :
5000
88
99