-C Back\sout\sthe\s--compat\soption\sfrom\sthe\sCLI.
-D 2025-12-13T00:13:40.858
+C In\sthe\sCLI,\sif\sa\scommand-line\sargument\snames\sa\sfile\sand\sthe\sfilename\sends\nwith\s.sql\sor\s.txt,\sthen\sprocess\sthat\sfile\sas\san\sSQL\sscript.\s\sUse\sthis\nfeature\sfor\sbetter\stesting.
+D 2025-12-13T21:11:49.724
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/resolve.c 8d53771eb51a4ab5f970150c3a70969d8db79cd04a8774c2d296bbcf471a0dd0
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 344518c1bba9c4636bf651b7642304abd2e7075ba35feb4bae42a51e5efe991f
-F src/shell.c.in 000a5c12e353b59b0a9276a7ff577804ba98f663528f818b91f8d25ea639fdee
+F src/shell.c.in e885e048418c366c5aa3252bb83bb0a61297054fdf829bc2283fb4fdd0e9bebb
F src/sqlite.h.in 706cacea5308b0244fb6cec92e08310fb427a125375c64137cc1f878ae4cf5c0
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
F test/dbfuzz001.test 6c9a4622029d69dc38926f115864b055cb2f39badd25ec22cbfb130c8ba8e9c3
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
F test/dbfuzz2.c 4b3c12de4d98b1b2d908ab03d217d4619e47c8b23d5e67f8a6f2b1bdee7cae23
-F test/dblwidth-a.sql eb4141518610e52f931a55a984310075e98dc31eee5a28ae806b1e35377be85a
+F test/dblwidth-a.sql 59dd59aa78ce8fd8ab631a3816516831f4e947b143039257e6fe132c3cea4171
F test/dbpage.test 63fab1eb026bada121107e53436fa749bbf83281dc9dea17af422f7a5c0f289f
F test/dbpagefault.test ea39de2ca86041a9c6df1135645180a76d0a8da93ac159e2fafe38e39636530b
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
F test/mmapcorrupt.test 470fb44fe92e99c1d23701d156f8c17865f5b027063c9119dcfdb842791f4465
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
F test/mmapwarm.test 2272005969cd17a910077bd5082f70bc1fefad9a875afec7fc9af483898ecaf3
-F test/modeA.clitest 2db42f2814ba45d5e886fead881360e689bc27346cfc37e6bb46f63334bebc61
+F test/modeA.sql a804e7db0f672007a54f5b890737de7376ac4d08c6e309347e1c93be5d533c5c w test/modeA.clitest
F test/multiplex.test d74c034e52805f6de8cc5432cef8c9eb774bb64ec29b83a22effc8ca4dac1f08
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test fac575e0b1b852025575a6a8357701d80933e98b5d2fe6d35ddaa68f92f6a1f7
F test/shell8.test 641cf21a99c59404c24e3062923734951c4099a6b6b6520de00cf7a1249ee871
F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209
F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480
-F test/shellB.test de879b1ea7c25daf1a06b2c882b45a5d002e6580c81c57169ce47084cc6afb6b
+F test/shellB.test 41730c85658e1caa7e421454deefb3837fbfcd68be13a2a2f3a1ed92342fb0a4
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 1ca31e1a297c0d53d068afb658ce6602887cda0f3eaf42cd629c4d1b7204f0b0
-R cf0d7b71ff1f31fdee2bbe0931020fd5
+P 850d5dbfb0f1eacd1e5213759810ec7e5eba4fcc0b2718dabccd5b269b126f1c
+R 7d316ab9e616e989cd7843c90446decc
U drh
-Z b8e82ce5183ee7bea000d8d3bf76900c
+Z 1fff9a15000a4bc11ad069c242a3fa0b
# Remove this line to create a well-formed Fossil manifest.
}
#endif
+/*
+** Return the size of the named file in bytes. Or return a negative
+** number if the file does not exist.
+*/
+static sqlite3_int64 fileSize(const char *zFile){
+#if defined(_WIN32) || defined(WIN32)
+ struct _stat64 x;
+ if( _stat64(zFile, &x)!=0 ) return -1;
+ return (sqlite3_int64)x.st_size;
+#else
+ struct stat x;
+ if( stat(zFile, &x)!=0 ) return -1;
+ return (sqlite3_int64)x.st_size;
+#endif
+}
+
+/*
+** Return true if zFile is an SQLite database.
+**
+** Algorithm:
+** * If the file does not exist -> return false
+** * If the size of the file is not a multiple of 512 -> return false
+** * If sqlite3_open() fails -> return false
+** * if sqlite3_prepare() or sqlite3_step() fails -> return false
+** * Otherwise -> return true
+*/
+static int isDatabaseFile(const char *zFile, int openFlags){
+ sqlite3 *db = 0;
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ sqlite3_int64 sz = fileSize(zFile);
+ if( sz<512 || (sz%512)!=0 ) return 0;
+ if( sqlite3_open_v2(zFile, &db, openFlags, 0)==SQLITE_OK
+ && sqlite3_prepare_v2(db,"SELECT count(*) FROM sqlite_schema",-1,&pStmt,0)
+ ==SQLITE_OK
+ && sqlite3_step(pStmt)==SQLITE_ROW
+ ){
+ rc = 1;
+ }else{
+ rc = 0;
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_close(db);
+ return rc;
+}
+
/*
** Try to deduce the type of file for zName based on its content. Return
** one of the SHELL_OPEN_* constants.
int deduceDatabaseType(const char *zName, int dfltZip, int openFlags){
FILE *f;
size_t n;
- sqlite3 *db = 0;
- sqlite3_stmt *pStmt = 0;
int rc = SHELL_OPEN_UNSPEC;
char zBuf[100];
if( access(zName,0)!=0 ) goto database_type_by_name;
- if( sqlite3_open_v2(zName, &db, openFlags, 0)==SQLITE_OK
- && sqlite3_prepare_v2(db,"SELECT count(*) FROM sqlite_schema",-1,&pStmt,0)
- ==SQLITE_OK
- && sqlite3_step(pStmt)==SQLITE_ROW
- ){
+ if( isDatabaseFile(zName, openFlags) ){
rc = SHELL_OPEN_NORMAL;
}
- sqlite3_finalize(pStmt);
- sqlite3_close(db);
if( rc==SHELL_OPEN_NORMAL ) return SHELL_OPEN_NORMAL;
f = sqlite3_fopen(zName, "rb");
if( f==0 ) goto database_type_by_name;
return rc;
}
+/*
+** If the text in z[] is the name of a readable file and that file appears
+** to contain SQL text and/or dot-commands, then return true. If z[] is
+** not a file, or if the file is unreadable, or if the file is a database
+** or anything else that is not SQL text and dot-commands, then return false.
+**
+** If the bLeaveUninit flag is set, then be sure to leave SQLite in an
+** uninitialized state. This means invoking sqlite3_shutdown() after any
+** SQLite API is used.
+**
+** Some amount of guesswork is involved in this decision.
+*/
+static int isScriptFile(const char *z, int bLeaveUninit){
+ sqlite3_int64 sz = fileSize(z);
+ if( sz<=0 ) return 0;
+ if( (sz%512)==0 ){
+ int rc = isDatabaseFile(z, SQLITE_OPEN_READONLY);
+ if( bLeaveUninit ){
+ sqlite3_shutdown();
+ }
+ if( rc ) return 0; /* Is a database */
+ }
+ if( sqlite3_strlike("*.sql",z,0)==0 ) return 1;
+ if( sqlite3_strlike("*.txt",z,0)==0 ) return 1;
+ return 0;
+}
+
#ifndef SQLITE_OMIT_DESERIALIZE
/*
** Reconstruct an in-memory database using the output from the "dbtotxt"
}
#endif
- /* Do an initial pass through the command-line argument to locate
+ /* Do an initial pass through the command-line arguments to locate
** the name of the database file, the name of the initialization file,
** the size of the alternative malloc heap, options affecting commands
** or SQL run from the command line, and the first command to execute.
char *z;
z = argv[i];
if( z[0]!='-' || i>nOptsEnd ){
- if( data.aAuxDb->zDbFilename==0 ){
+ if( data.aAuxDb->zDbFilename==0 && !isScriptFile(z,1) ){
data.aAuxDb->zDbFilename = z;
}else{
/* Excess arguments are interpreted as SQL (or dot-commands) and
*/
if( !noInit ) process_sqliterc(&data,zInitFile);
- /* Make a second pass through the command-line argument and set
+ /* Make a second pass through the command-line arguments 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.
*/
for(i=0; i<nCmd; i++){
echo_group_input(&data, azCmd[i]);
- if( azCmd[i][0]=='.' ){
+ if( isScriptFile(azCmd[i],0) ){
+ FILE *inSaved = data.in;
+ i64 savedLineno = data.lineno;
+ int res = 1;
+ if( (data.in = openChrSource(azCmd[i]))!=0 ){
+ res = process_input(&data, azCmd[i]);
+ }
+ data.in = inSaved;
+ data.lineno = savedLineno;
+ if( res ) i = nCmd;
+ }else if( azCmd[i][0]=='.' ){
char *zErrCtx = malloc( 64 );
shell_check_oom(zErrCtx);
sqlite3_snprintf(64,zErrCtx,"argv[%i]:",aiCmd[i]);
+#!sqlite3
/*
** Run this script using "sqlite3" to confirm that the command-line
** shell properly handles the output of double-width characters.
**
** https://sqlite.org/forum/forumpost/008ac80276
*/
+.testcase 100
.mode box
CREATE TABLE data(word TEXT, description TEXT);
INSERT INTO data VALUES('〈οὐκέτι〉','Greek without dblwidth <...>');
-.print .mode box
SELECT * FROM data;
+.check <<END
+╭────────────┬──────────────────────────────╮
+│ word │ description │
+╞════════════╪══════════════════════════════╡
+│ 〈οὐκέτι〉 │ Greek without dblwidth <...> │
+╰────────────┴──────────────────────────────╯
+END
+
+.testcase 200
.mode table
-.print .mode table
SELECT * FROM data;
+.check <<END
++------------+------------------------------+
+| word | description |
++------------+------------------------------+
+| 〈οὐκέτι〉 | Greek without dblwidth <...> |
++------------+------------------------------+
+END
+
+.testcase 300
.mode qbox
-.print .mode qbox
SELECT * FROM data;
+.check <<END
+╭──────────────┬────────────────────────────────╮
+│ word │ description │
+╞══════════════╪════════════════════════════════╡
+│ '〈οὐκέτι〉' │ 'Greek without dblwidth <...>' │
+╰──────────────┴────────────────────────────────╯
+END
+
+.testcase 400
.mode column
-.print .mode column
SELECT * FROM data;
+.check <<END
+ word description
+---------- ----------------------------
+〈οὐκέτι〉 Greek without dblwidth <...>
+END