SQLite Forum

Wishing CLI could be usefully embedded
Login
Hi,

Having recently integrated shell.c into an application, I can provide some feedback on the subject.

Starting with sqlite-amalgamation-3360000/shell.c, this is what I changed:

- Added a line at the top of the file to prevent the language-supplied build tool from building it (Golang wants to build all .c files itself, but it was better to have the project Makefile handle it).
- Change the include of sqlite3.h to match the project-specific rename of the header (trying to prevent accidentally using the system copy).
- Add some extern definitions for callbacks into the host program.
- Change any of the functions that print output (e.g. utf8_printf(), output_c_string()) to instead call into the host program so output can be redirected from there.
- Crossing the language barrier from the host program to C is relatively expensive in this case, so the output functions that printed lots of single characters were changed to buffer the output with sqlite3_str.  Trading potential memory use for speed is ok in this application's case.
- Combined the Windows and unix utf8_printf() versions into a single one.
- Modified needCsvQuote[] to change which characters required quoting.
- Changed some of the BOX_$N defines so box output looks slightly different.
- Replaced fputs() calls with utf8_printf() in various places (e.g. print_box_row_separator()) to route all output to a single function.
- Changed exec_prepared_stmt_columnar() and exec_prepared_stmt() to return a row count.
- Changed box output content/header alignment from center to left.
- Changed open_db() to set globalDb=p->db and set up a few sqlite3_create_function(p->db, "shell_add_schema") type calls that weren't being initialized.
- Renamed the call to sqlite3_fileio_init() to sqlite3_fileio_init1() because it was conflicting with the same name from integrating fileio.c elsewhere in the application.
- Created a wrapper version of exec_prepared_stmt() that initializes a ShellState and some other global type stuff needed in order for the host application to send a prepared query into shell.c and get formatted output back out.
- Renamed main() to sqlite_shell_main() so it won't conflict with the host application and so that it takes an optional sqlite3* that the host application controls.
- Removed calls to close_db() and session_close_all() since the sqlite3* is managed by the host application.

There's of course different ways some of these things could be done, but this is how they ended up in this case.  The goal with embedding the shell was to gain access to custom virtual tables, to provide a REPL, and to re-use the box/csv/etc output routines.

'Hope this is useful.

Thanks.