Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84c1079220 | |||
| c8d866294b | |||
| 9efde40a5d | |||
| 09f37099a7 | |||
| 526acc1834 | |||
| d962afef2d | |||
| 395ac6c1bc | |||
| e9d0bc6b68 | |||
| ab6a63ec67 | |||
| 57ed7f322f | |||
| 34c2c8dc47 | |||
| 3f9df1f5fb | |||
| 2eeac123c8 | |||
| 64a123a216 | |||
| a10e79d91a | |||
| d20673a95f | |||
| f02d100e08 | |||
| 4c8f0621fd | |||
| 6abc21cfb8 | |||
| 20079bb358 | |||
| 3d6fa49c54 | |||
| 4df365e5a7 | |||
| 9d8bf6f04a | |||
| c0026ff7a6 | |||
| 1e3f888acf | |||
| 2d4dfbccdc | |||
| 6142310e08 | |||
| 42ae7e7f34 | |||
| 57cf5c2dfc | |||
| a212476ad2 | |||
| 7a0a0a22e7 | |||
| b709ba8108 |
@@ -80,8 +80,8 @@ Then run commands like this:
|
||||
fossil open https://sqlite.org/src
|
||||
|
||||
The initial "fossil open" command will take two or three minutes. Afterwards,
|
||||
you can do fast, bandwidth-efficient updates to the whatever versions
|
||||
of SQLite you like. Some examples:
|
||||
you can do fast, bandwidth-efficient updates to whatever versions of SQLite you
|
||||
like. Some examples:
|
||||
|
||||
fossil update trunk ;# latest trunk check-in
|
||||
fossil update release ;# latest official release
|
||||
|
||||
+1657
-972
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,827 @@
|
||||
/*
|
||||
** 2026-04-13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** Partial reimplement of the sqlite3_analyzer utility program as
|
||||
** loadable SQL function.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
** State information for the analysis
|
||||
*/
|
||||
typedef struct Analysis Analysis;
|
||||
struct Analysis {
|
||||
sqlite3 *db; /* Database connection */
|
||||
sqlite3_context *context; /* SQL function context */
|
||||
sqlite3_str *pOut; /* Write output here */
|
||||
char *zSU; /* Name of the temp.space_used table */
|
||||
const char *zSchema; /* Schema to be analyzed */
|
||||
};
|
||||
|
||||
/*
|
||||
** Free all resources that the Analysis object references and
|
||||
** reset the Analysis object.
|
||||
**
|
||||
** Call this routine multiple times on the same Analysis object
|
||||
** is a harmless no-op, as long as the memory for the object itself
|
||||
** has not been freed.
|
||||
*/
|
||||
static void analysisReset(Analysis *p){
|
||||
if( p->zSU ){
|
||||
char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU);
|
||||
if( zSql ){
|
||||
sqlite3_exec(p->db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
}
|
||||
sqlite3_str_free(p->pOut);
|
||||
sqlite3_free(p->zSU);
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
|
||||
/*
|
||||
** Report an error using formatted text. If zFormat==NULL then report
|
||||
** an OOM error.
|
||||
*/
|
||||
static void analysisError(Analysis *p, const char *zFormat, ...){
|
||||
char *zErr;
|
||||
if( zFormat ){
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zErr = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
}else{
|
||||
zErr = 0;
|
||||
}
|
||||
if( zErr==0 ){
|
||||
sqlite3_result_error_nomem(p->context);
|
||||
}else{
|
||||
sqlite3_result_error(p->context, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
analysisReset(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare and return an SQL statement.
|
||||
*/
|
||||
static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
zSql = sqlite3_vmprintf(zFmt, ap);
|
||||
if( zSql==0 ){ analysisError(p,0); return 0; }
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
analysisError(p, "SQL parse error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), zSql);
|
||||
sqlite3_finalize(pStmt);
|
||||
analysisReset(p);
|
||||
pStmt = 0;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** If rc is something other than SQLITE_DONE or SQLITE_OK, then report
|
||||
** an error and return true.
|
||||
**
|
||||
** If rc is SQLITE_DONE or SQLITE_OK, then return false.
|
||||
**
|
||||
** The prepared statement is closed in either case.
|
||||
*/
|
||||
static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run SQL. Return the number of errors.
|
||||
*/
|
||||
static int analysisSql(Analysis *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ) return 1;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){}
|
||||
if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run an SQL query that returns an integer. Write that integer
|
||||
** into *piRes. Return the number of errors.
|
||||
*/
|
||||
static int analysisSqlInt(
|
||||
Analysis *p,
|
||||
sqlite3_int64 *piRes,
|
||||
const char *zFormat, ...
|
||||
){
|
||||
va_list ap;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = analysisVPrep(p,zFormat,ap);
|
||||
va_end(ap);
|
||||
if( pStmt==0 ) return 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
*piRes = sqlite3_column_int64(pStmt, 0);
|
||||
rc = SQLITE_OK;
|
||||
}else if( rc==SQLITE_DONE ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
if( p->db ){
|
||||
/* p->db is NULL if there was some prior error */
|
||||
analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s",
|
||||
sqlite3_errmsg(p->db), sqlite3_sql(pStmt));
|
||||
}
|
||||
analysisReset(p);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add to the output a title line that contains the text determined
|
||||
** by the format string. If the output is initially empty, begin
|
||||
** the title line with "/" so that it forms the beginning of a C-style
|
||||
** comment. Otherwise begin with a new-line. Always finish with a
|
||||
** newline.
|
||||
*/
|
||||
static void analysisTitle(Analysis *p, const char *zFormat, ...){
|
||||
char *zFirst;
|
||||
char *zTitle;
|
||||
size_t nTitle;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zTitle = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zTitle==0 ){
|
||||
analysisError(p, 0);
|
||||
return;
|
||||
}
|
||||
zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*";
|
||||
nTitle = strlen(zTitle);
|
||||
if( nTitle>=75 ){
|
||||
sqlite3_str_appendf(p->pOut, "%s** %z\n\n", zFirst, zTitle);
|
||||
}else{
|
||||
int nExtra = 74 - (int)nTitle;
|
||||
sqlite3_str_appendf(p->pOut, "%s** %z %.*c\n\n", zFirst, zTitle,
|
||||
nExtra, '*');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an output line that begins with the zDesc text extended out to
|
||||
** 50 columns with "." characters, and followed by whatever text is
|
||||
** described by zFormat.
|
||||
*/
|
||||
static void analysisLine(
|
||||
Analysis *p, /* Analysis context */
|
||||
const char *zDesc, /* Description */
|
||||
const char *zFormat, /* Argument to the description */
|
||||
...
|
||||
){
|
||||
char *zTxt;
|
||||
size_t nDesc;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
zTxt = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zTxt==0 ){
|
||||
analysisError(p, 0);
|
||||
return;
|
||||
}
|
||||
nDesc = strlen(zDesc);
|
||||
if( nDesc>=50 ){
|
||||
sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt);
|
||||
}else{
|
||||
int nExtra = 50 - (int)nDesc;
|
||||
sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a percentage into the output. The number written should show
|
||||
** two or three significant digits, with the decimal point being the fourth
|
||||
** character.
|
||||
*/
|
||||
static void analysisPercent(Analysis *p, double r){
|
||||
char zNum[100];
|
||||
char *zDP;
|
||||
int nLeadingDigit;
|
||||
int sz;
|
||||
sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r);
|
||||
sz = (int)strlen(zNum);
|
||||
zDP = strchr(zNum, '.');
|
||||
if( zDP==0 ){
|
||||
memcpy(zNum+sz,".0",3);
|
||||
nLeadingDigit = sz;
|
||||
sz += 2;
|
||||
}else{
|
||||
nLeadingDigit = (int)(zDP - zNum);
|
||||
}
|
||||
if( nLeadingDigit<3 ){
|
||||
sqlite3_str_appendchar(p->pOut, 3-nLeadingDigit, ' ');
|
||||
}
|
||||
sqlite3_str_append(p->pOut, zNum, sz);
|
||||
sqlite3_str_append(p->pOut, "%\n", 2);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a subreport on a subset of tables and/or indexes.
|
||||
**
|
||||
** The title if the subreport is given by zTitle. zWhere is
|
||||
** a boolean expression that can go in the WHERE clause to select
|
||||
** the relevant rows of the s.zSU table.
|
||||
*/
|
||||
static int analysisSubreport(
|
||||
Analysis *p, /* Analysis context */
|
||||
char *zTitle, /* Title for this subreport */
|
||||
char *zWhere, /* WHERE clause for this subreport */
|
||||
sqlite3_int64 pgsz, /* Database page size */
|
||||
sqlite3_int64 nPage /* Number of pages in entire database */
|
||||
){
|
||||
sqlite3_stmt *pStmt; /* Statement to query p->zSU */
|
||||
sqlite3_int64 nentry; /* Number of btree entires */
|
||||
sqlite3_int64 payload; /* Payload in bytes */
|
||||
sqlite3_int64 ovfl_payload; /* overflow payload in bytes */
|
||||
sqlite3_int64 mx_payload; /* largest individual payload */
|
||||
sqlite3_int64 ovfl_cnt; /* Number entries using overflow */
|
||||
sqlite3_int64 leaf_pages; /* Leaf pages */
|
||||
sqlite3_int64 int_pages; /* internal pages */
|
||||
sqlite3_int64 ovfl_pages; /* overflow pages */
|
||||
sqlite3_int64 leaf_unused; /* unused bytes on leaf pages */
|
||||
sqlite3_int64 int_unused; /* unused bytes on internal pages */
|
||||
sqlite3_int64 ovfl_unused; /* unused bytes on overflow pages */
|
||||
sqlite3_int64 int_cell; /* B-tree entries on internal pages */
|
||||
sqlite3_int64 depth; /* btree depth */
|
||||
sqlite3_int64 cnt; /* Number of s.zSU entries that match */
|
||||
sqlite3_int64 storage; /* Total bytes */
|
||||
sqlite3_int64 total_pages; /* Total page count */
|
||||
sqlite3_int64 total_unused; /* Total unused bytes */
|
||||
sqlite3_int64 total_meta; /* Total metadata */
|
||||
int rc;
|
||||
|
||||
if( zTitle==0 || zWhere==0 ){
|
||||
analysisError(p, 0);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pStmt = analysisPrepare(p,
|
||||
"SELECT\n"
|
||||
" sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */
|
||||
" sum(payload),\n" /* 1 */
|
||||
" sum(ovfl_payload),\n" /* 2 */
|
||||
" max(mx_payload),\n" /* 3 */
|
||||
" sum(ovfl_cnt),\n" /* 4 */
|
||||
" sum(leaf_pages),\n" /* 5 */
|
||||
" sum(int_pages),\n" /* 6 */
|
||||
" sum(ovfl_pages),\n" /* 7 */
|
||||
" sum(leaf_unused),\n" /* 8 */
|
||||
" sum(int_unused),\n" /* 9 */
|
||||
" sum(ovfl_unused),\n" /* 10 */
|
||||
" max(depth),\n" /* 11 */
|
||||
" count(*),\n" /* 12 */
|
||||
" sum(int_entries)\n" /* 13 */
|
||||
" FROM temp.%s WHERE %s",
|
||||
p->zSU, zWhere);
|
||||
if( pStmt==0 ) return 1;
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
analysisTitle(p, zTitle);
|
||||
|
||||
nentry = sqlite3_column_int64(pStmt, 0);
|
||||
payload = sqlite3_column_int64(pStmt, 1);
|
||||
ovfl_payload = sqlite3_column_int64(pStmt, 2);
|
||||
mx_payload = sqlite3_column_int64(pStmt, 3);
|
||||
ovfl_cnt = sqlite3_column_int64(pStmt, 4);
|
||||
leaf_pages = sqlite3_column_int64(pStmt, 5);
|
||||
int_pages = sqlite3_column_int64(pStmt, 6);
|
||||
ovfl_pages = sqlite3_column_int64(pStmt, 7);
|
||||
leaf_unused = sqlite3_column_int64(pStmt, 8);
|
||||
int_unused = sqlite3_column_int64(pStmt, 9);
|
||||
ovfl_unused = sqlite3_column_int64(pStmt, 10);
|
||||
depth = sqlite3_column_int64(pStmt, 11);
|
||||
cnt = sqlite3_column_int64(pStmt, 12);
|
||||
int_cell = sqlite3_column_int64(pStmt, 13);
|
||||
rc = SQLITE_DONE;
|
||||
|
||||
total_pages = leaf_pages + int_pages + ovfl_pages;
|
||||
analysisLine(p, "Percentage of total database", "%.3g%%\n",
|
||||
(total_pages*100.0)/(double)nPage);
|
||||
analysisLine(p, "Number of entries", "%lld\n", nentry);
|
||||
storage = total_pages*pgsz;
|
||||
analysisLine(p, "Bytes of storage consumed", "%lld\n", storage);
|
||||
analysisLine(p, "Bytes of payload", "%-11lld ", payload);
|
||||
analysisPercent(p, payload*100.0/(double)storage);
|
||||
if( ovfl_cnt>0 ){
|
||||
analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload);
|
||||
analysisPercent(p, ovfl_payload*100.0/(double)payload);
|
||||
}
|
||||
total_unused = leaf_unused + int_unused + ovfl_unused;
|
||||
total_meta = storage - payload - total_unused;
|
||||
analysisLine(p, "Bytes of metadata","%-11lld ", total_meta);
|
||||
analysisPercent(p, total_meta*100.0/(double)storage);
|
||||
if( cnt==1 ){
|
||||
analysisLine(p, "B-tree depth", "%lld\n", depth);
|
||||
if( int_cell>1 ){
|
||||
analysisLine(p, "Average fanout", "%.1f\n",
|
||||
(double)(int_cell+int_pages)/(double)int_pages);
|
||||
}
|
||||
}
|
||||
if( nentry>0 ){
|
||||
analysisLine(p, "Average payload per entry", "%.1f\n",
|
||||
(double)payload/(double)nentry);
|
||||
analysisLine(p, "Average unused bytes per entry", "%.1f\n",
|
||||
(double)total_unused/(double)nentry);
|
||||
analysisLine(p, "Average metadata per entry", "%.1f\n",
|
||||
(double)total_meta/(double)nentry);
|
||||
}
|
||||
analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload);
|
||||
if( nentry>0 ){
|
||||
analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt);
|
||||
analysisPercent(p, ovfl_cnt*100.0/(double)nentry);
|
||||
}
|
||||
if( int_pages>0 ){
|
||||
analysisLine(p, "Index pages used", "%lld\n", int_pages);
|
||||
}
|
||||
analysisLine(p, "Primary pages used", "%lld\n", leaf_pages);
|
||||
if( ovfl_cnt ){
|
||||
analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages);
|
||||
}
|
||||
analysisLine(p, "Total pages used", "%lld\n", total_pages);
|
||||
if( int_pages>0 ){
|
||||
analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused);
|
||||
}
|
||||
analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused);
|
||||
if( ovfl_cnt ){
|
||||
analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused);
|
||||
}
|
||||
analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused);
|
||||
analysisPercent(p, total_unused*100.0/(double)storage);
|
||||
}
|
||||
return analysisStmtFinish(p, rc, pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: analyze(SCHEMA)
|
||||
**
|
||||
** Analyze the database schema named in the argument. Return text
|
||||
** containing the analysis.
|
||||
*/
|
||||
static void analyzeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int n;
|
||||
sqlite3_int64 i64;
|
||||
sqlite3_int64 pgsz;
|
||||
sqlite3_int64 nPage;
|
||||
sqlite3_int64 nPageInUse;
|
||||
sqlite3_int64 nFreeList;
|
||||
sqlite3_int64 nIndex;
|
||||
sqlite3_int64 nWORowid;
|
||||
Analysis s;
|
||||
sqlite3_uint64 r[2];
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.db = sqlite3_context_db_handle(context);
|
||||
s.context = context;
|
||||
s.pOut = sqlite3_str_new(0);
|
||||
if( s.pOut==0 ){ analysisError(&s, 0); return; }
|
||||
s.zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( s.zSchema==0 ){
|
||||
s.zSchema = "main";
|
||||
}else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){
|
||||
/* Attempt to analyze "temp" returns NULL */
|
||||
analysisReset(&s);
|
||||
return;
|
||||
}
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s,&i64,"SELECT 1 FROM pragma_database_list"
|
||||
" WHERE name=%Q COLLATE nocase",s.zSchema);
|
||||
if( rc || i64==0 ){
|
||||
/* Return NULL the named schema does not exist */
|
||||
analysisReset(&s);
|
||||
return;
|
||||
}
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]);
|
||||
if( s.zSU==0 ){ analysisError(&s, 0); return; }
|
||||
|
||||
/* The s.zSU table contains the data used for the analysis.
|
||||
** The table name contains 128-bits of randomness to avoid
|
||||
** collisions with preexisting tables in temp.
|
||||
*/
|
||||
rc = analysisSql(&s,
|
||||
"CREATE TABLE temp.%s(\n"
|
||||
" name text, -- A table or index\n"
|
||||
" tblname text, -- Table that owns name\n"
|
||||
" is_index boolean, -- TRUE if it is an index\n"
|
||||
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n"
|
||||
" nentry int, -- Number of entries in the BTree\n"
|
||||
" leaf_entries int, -- Number of leaf entries\n"
|
||||
" depth int, -- Depth of the b-tree\n"
|
||||
" payload int, -- Total data stored in this table/index\n"
|
||||
" ovfl_payload int, -- Total data stored on overflow pages\n"
|
||||
" ovfl_cnt int, -- Number of entries that use overflow\n"
|
||||
" mx_payload int, -- Maximum payload size\n"
|
||||
" int_pages int, -- Interior pages used\n"
|
||||
" leaf_pages int, -- Leaf pages used\n"
|
||||
" ovfl_pages int, -- Overflow pages used\n"
|
||||
" int_unused int, -- Unused bytes on interior pages\n"
|
||||
" leaf_unused int, -- Unused bytes on primary pages\n"
|
||||
" ovfl_unused int, -- Unused bytes on overflow pages\n"
|
||||
" int_entries int -- Btree cells on internal pages\n"
|
||||
");",
|
||||
s.zSU
|
||||
);
|
||||
if( rc ) return;
|
||||
|
||||
/* Populate the s.zSU table
|
||||
*/
|
||||
rc = analysisSql(&s,
|
||||
"WITH\n"
|
||||
" allidx(idxname) AS (\n"
|
||||
" SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n"
|
||||
" ),\n"
|
||||
" allobj(allname,tblname,isidx,isworowid) AS (\n"
|
||||
" SELECT 'sqlite_schema',\n"
|
||||
" 'sqlite_schema',\n"
|
||||
" 0,\n"
|
||||
" 0\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT name,\n"
|
||||
" tbl_name,\n"
|
||||
" type='index',\n"
|
||||
" EXISTS(SELECT 1\n"
|
||||
" FROM pragma_index_list(sqlite_schema.name,%Q)\n"
|
||||
" WHERE pragma_index_list.origin='pk'\n"
|
||||
" AND pragma_index_list.name NOT IN allidx)\n"
|
||||
" FROM \"%w\".sqlite_schema\n"
|
||||
" )\n"
|
||||
"INSERT INTO temp.%s\n"
|
||||
" SELECT\n"
|
||||
" allname,\n"
|
||||
" tblname,\n"
|
||||
" isidx,\n"
|
||||
" isworowid,\n"
|
||||
" sum(ncell),\n"
|
||||
" sum((pagetype='leaf')*ncell),\n"
|
||||
" max((length(if(path GLOB '*+*','',path))+3)/4),\n"
|
||||
" sum(payload),\n"
|
||||
" sum((pagetype='overflow')*payload),\n"
|
||||
" sum(path GLOB '*+000000'),\n"
|
||||
" max(mx_payload),\n"
|
||||
" sum(pagetype='internal'),\n"
|
||||
" sum(pagetype='leaf'),\n"
|
||||
" sum(pagetype='overflow'),\n"
|
||||
" sum((pagetype='internal')*unused),\n"
|
||||
" sum((pagetype='leaf')*unused),\n"
|
||||
" sum((pagetype='overflow')*unused),\n"
|
||||
" sum(if(pagetype='internal',ncell))\n"
|
||||
" FROM allobj CROSS JOIN dbstat(%Q) \n"
|
||||
" WHERE dbstat.name=allobj.allname\n"
|
||||
" GROUP BY allname;\n",
|
||||
s.zSchema, /* %w.sqlite_schema -- in allidx */
|
||||
s.zSchema, /* pragma_index_list(...,%Q) */
|
||||
s.zSchema, /* %w.sqlite_schema */
|
||||
s.zSU, /* INTO temp.%s */
|
||||
s.zSchema /* JOIN dbstat(%Q) */
|
||||
);
|
||||
if( rc ) return;
|
||||
|
||||
/* Begin generating the report */
|
||||
analysisTitle(&s, "Database storage utilization report");
|
||||
pgsz = 0;
|
||||
rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Page size in bytes","%lld\n",pgsz);
|
||||
|
||||
nPage = 0;
|
||||
rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages in the database", "%lld\n", nPage);
|
||||
if( nPage<=0 ) nPage = 1;
|
||||
|
||||
nPageInUse = 0;
|
||||
rc = analysisSqlInt(&s, &nPageInUse,
|
||||
"SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse);
|
||||
analysisPercent(&s, (nPageInUse*100.0)/(double)nPage);
|
||||
|
||||
nFreeList = 0;
|
||||
rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList);
|
||||
analysisPercent(&s, (nFreeList*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64, "PRAGMA \"%w\".auto_vacuum", s.zSchema);
|
||||
if( rc ) return;
|
||||
if( i64==0 || nPage<=1 ){
|
||||
i64 = 0;
|
||||
}else{
|
||||
double rPtrsPerPage = pgsz/5;
|
||||
double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0);
|
||||
i64 = (sqlite3_int64)ceil(rAvPage);
|
||||
}
|
||||
analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", i64);
|
||||
analysisPercent(&s, (i64*100.0)/(double)nPage);
|
||||
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of tables", "%lld\n", i64);
|
||||
nWORowid = 0;
|
||||
rc = analysisSqlInt(&s, &nWORowid,
|
||||
"SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid);
|
||||
analysisLine(&s, "Number of rowid tables", "%lld\n", i64 - nWORowid);
|
||||
}
|
||||
nIndex = 0;
|
||||
rc = analysisSqlInt(&s, &nIndex,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of indexes", "%lld\n", nIndex);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT count(*) FROM \"%w\".sqlite_schema"
|
||||
" WHERE name GLOB 'sqlite_autoindex_*' AND type='index'",
|
||||
s.zSchema);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - i64);
|
||||
analysisLine(&s, "Number of implied indexes", "%lld\n", i64);
|
||||
analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage);
|
||||
i64 = 0;
|
||||
rc = analysisSqlInt(&s, &i64,
|
||||
"SELECT sum(payload) FROM temp.%s"
|
||||
" WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'",
|
||||
s.zSU);
|
||||
if( rc ) return;
|
||||
analysisLine(&s, "Bytes of payload", "%-11lld ", i64);
|
||||
analysisPercent(&s, i64*100.0/(double)(pgsz*nPage));
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables with their indexes");
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(tblname),\n"
|
||||
" sum(int_pages+leaf_pages+ovfl_pages)\n"
|
||||
" FROM temp.%s\n"
|
||||
" GROUP BY 1\n"
|
||||
" ORDER BY 2 DESC, 1;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
|
||||
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
|
||||
analysisPercent(&s, (n*100.0)/(double)nPage);
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
analysisTitle(&s, "Page counts for all tables and indexes separately");
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(name),\n"
|
||||
" sum(int_pages+leaf_pages+ovfl_pages)\n"
|
||||
" FROM temp.%s\n"
|
||||
" GROUP BY 1\n"
|
||||
" ORDER BY 2 DESC, 1;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
sqlite3_int64 n = sqlite3_column_int64(pStmt,1);
|
||||
analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", n);
|
||||
analysisPercent(&s, (n*100.0)/(double)nPage);
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
if( nWORowid>0 ){
|
||||
rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid",
|
||||
pgsz, nPage);
|
||||
if( rc ) return;
|
||||
rc = analysisSubreport(&s, "All rowid tables",
|
||||
"NOT is_without_rowid AND NOT is_index",
|
||||
pgsz, nPage);
|
||||
if( rc ) return;
|
||||
}
|
||||
rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage);
|
||||
if( rc ) return;
|
||||
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s"
|
||||
" GROUP BY 1 ORDER BY 1",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
const char *zUpper = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
|
||||
int nSubIndex = sqlite3_column_int(pStmt, 2);
|
||||
if( nSubIndex==0 ){
|
||||
char *zTitle = sqlite3_mprintf("Table %s", zUpper);
|
||||
char *zWhere = sqlite3_mprintf("name=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}else{
|
||||
sqlite3_stmt *pS2;
|
||||
char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper);
|
||||
char *zWhere = sqlite3_mprintf("tblname=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper);
|
||||
zWhere = sqlite3_mprintf("name=%Q", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
if( nSubIndex>1 ){
|
||||
zTitle = sqlite3_mprintf("All indexes of table %s", zUpper);
|
||||
zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}
|
||||
pS2 = analysisPrepare(&s,
|
||||
"SELECT name, upper(name) FROM temp.%s"
|
||||
" WHERE is_index AND tblname=%Q",
|
||||
s.zSU, zName);
|
||||
if( pS2==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){
|
||||
const char *zU = (const char*)sqlite3_column_text(pS2, 1);
|
||||
const char *zN = (const char*)sqlite3_column_text(pS2, 0);
|
||||
zTitle = sqlite3_mprintf("Index %s", zU);
|
||||
zWhere = sqlite3_mprintf("name=%Q", zN);
|
||||
rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage);
|
||||
sqlite3_free(zTitle);
|
||||
sqlite3_free(zWhere);
|
||||
if( rc ) break;
|
||||
}
|
||||
rc = analysisStmtFinish(&s, rc, pS2);
|
||||
if( rc ) break;
|
||||
}
|
||||
}
|
||||
if( analysisStmtFinish(&s, rc, pStmt) ) return;
|
||||
|
||||
/* Append SQL statements that will recreate the raw data used for
|
||||
** the analysis.
|
||||
*/
|
||||
analysisTitle(&s, "Raw data used to generate this report");
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
"The following SQL will create a table named \"space_used\" which\n"
|
||||
"contains most of the information used to generate the report above.\n"
|
||||
"*/\n"
|
||||
);
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
"BEGIN;\n"
|
||||
"CREATE TABLE space_used(\n"
|
||||
" name text, -- A table or index\n" /* 0 */
|
||||
" tblname text, -- Table that owns name\n" /* 1 */
|
||||
" is_index boolean, -- TRUE if it is an index\n" /* 2 */
|
||||
" is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" /* 3 */
|
||||
" nentry int, -- Number of entries in the BTree\n" /* 4 */
|
||||
" leaf_entries int, -- Number of leaf entries\n" /* 5 */
|
||||
" depth int, -- Depth of the b-tree\n" /* 6 */
|
||||
" payload int, -- Total data in this table/index\n" /* 7 */
|
||||
" ovfl_payload int, -- Total data on overflow pages\n" /* 8 */
|
||||
" ovfl_cnt int, -- Entries that use overflow\n" /* 9 */
|
||||
" mx_payload int, -- Maximum payload size\n" /* 10 */
|
||||
" int_pages int, -- Interior pages used\n" /* 11 */
|
||||
" leaf_pages int, -- Leaf pages used\n" /* 12 */
|
||||
" ovfl_pages int, -- Overflow pages used\n" /* 13 */
|
||||
" int_unused int, -- Unused bytes on interior pages\n" /* 14 */
|
||||
" leaf_unused int, -- Unused bytes on primary pages\n" /* 15 */
|
||||
" ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */
|
||||
" int_entries int -- B-tree entries on internal pages\n"/* 17 */
|
||||
");\n"
|
||||
"INSERT INTO space_used VALUES\n"
|
||||
);
|
||||
pStmt = analysisPrepare(&s,
|
||||
"SELECT quote(name), quote(tblname),\n" /* 0..1 */
|
||||
" is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */
|
||||
" depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */
|
||||
" int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */
|
||||
" leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */
|
||||
" FROM temp.%s;",
|
||||
s.zSU);
|
||||
if( pStmt==0 ) return;
|
||||
n = 0;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
if( n++ ) sqlite3_str_appendf(s.pOut,",\n");
|
||||
sqlite3_str_appendf(s.pOut,
|
||||
" (%s,%s,%lld,%lld,%lld,%lld,%lld,%lld,%lld,"
|
||||
"%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)",
|
||||
sqlite3_column_text(pStmt, 0),
|
||||
sqlite3_column_text(pStmt, 1),
|
||||
sqlite3_column_int64(pStmt, 2),
|
||||
sqlite3_column_int64(pStmt, 3),
|
||||
sqlite3_column_int64(pStmt, 4),
|
||||
sqlite3_column_int64(pStmt, 5),
|
||||
sqlite3_column_int64(pStmt, 6),
|
||||
sqlite3_column_int64(pStmt, 7),
|
||||
sqlite3_column_int64(pStmt, 8),
|
||||
sqlite3_column_int64(pStmt, 9),
|
||||
sqlite3_column_int64(pStmt, 10),
|
||||
sqlite3_column_int64(pStmt, 11),
|
||||
sqlite3_column_int64(pStmt, 12),
|
||||
sqlite3_column_int64(pStmt, 13),
|
||||
sqlite3_column_int64(pStmt, 14),
|
||||
sqlite3_column_int64(pStmt, 15),
|
||||
sqlite3_column_int64(pStmt, 16),
|
||||
sqlite3_column_int64(pStmt, 17));
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
analysisError(&s, "SQL run-time error: %s\nSQL: %s",
|
||||
sqlite3_errmsg(s.db), sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
return;
|
||||
}
|
||||
sqlite3_str_appendf(s.pOut,";\nCOMMIT;");
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
if( sqlite3_str_length(s.pOut) ){
|
||||
sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1,
|
||||
sqlite3_free);
|
||||
s.pOut = 0;
|
||||
}
|
||||
analysisReset(&s);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_analyze_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "analyze", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS,
|
||||
0, analyzeFunc, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
@@ -397,4 +397,65 @@ do_test 3.5 {
|
||||
} {0 SQLITE_DONE}
|
||||
|
||||
catch { db close }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a database that uses custom collation sequences can be RBU
|
||||
# vacuumed.
|
||||
#
|
||||
reset_db
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'i');
|
||||
INSERT INTO t1 VALUES(2, 'iiii');
|
||||
INSERT INTO t1 VALUES(3, 'ii');
|
||||
INSERT INTO t1 VALUES(4, 'iii');
|
||||
|
||||
PRAGMA writable_schema = ON;
|
||||
UPDATE sqlite_schema SET sql = sql || '; SELECT blow_up_the_world();';
|
||||
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b); SELECT blow_up_the_world();}}
|
||||
|
||||
set ::eof 0
|
||||
proc blowup {} {
|
||||
set ::eof 1
|
||||
}
|
||||
|
||||
|
||||
db close
|
||||
|
||||
do_test 4.1 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
set db1 [rbu db 0]
|
||||
set db2 [rbu db 1]
|
||||
|
||||
sqlite3_create_function_v2 $db1 blow_up_the_world -1 any -func blowup
|
||||
sqlite3_create_function_v2 $db2 blow_up_the_world -1 any -func blowup
|
||||
|
||||
while {[rbu step]=="SQLITE_OK"} {}
|
||||
list [catch { rbu close } msg] $msg
|
||||
} {0 SQLITE_DONE}
|
||||
|
||||
do_test 4.2 { set ::eof } 0
|
||||
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 4.3 {
|
||||
SELECT sql FROM sqlite_schema
|
||||
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b)}}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
PRAGMA writable_schema = ON;
|
||||
INSERT INTO sqlite_schema(sql) VALUES('SELECT blow_up_the_world()');
|
||||
}
|
||||
|
||||
do_test 4.5 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
while {[rbu step]=="SQLITE_OK"} {}
|
||||
list [catch { rbu close } msg] $msg
|
||||
} {1 {SQLITE_CORRUPT - malformed database schema (?)}}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -3655,7 +3655,12 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
|
||||
|
||||
while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
|
||||
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
|
||||
p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, zSql);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_step(pStmt);
|
||||
rbuFinalize(p, pStmt);
|
||||
}
|
||||
}
|
||||
rbuFinalize(p, pSql);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
if(capi.sqlite3_vfs_find("opfs")){
|
||||
stdout("\nOPFS is available. To open a persistent db, use:\n\n",
|
||||
" .open file:name?vfs=opfs\n\nbut note that some",
|
||||
"features (e.g. upload) do not yet work with OPFS.");
|
||||
"features (e.g. upload) do not work with OPFS.");
|
||||
}
|
||||
stdout('\nEnter ".help" for usage hints.');
|
||||
return true;
|
||||
|
||||
@@ -868,6 +868,12 @@
|
||||
prompt: 'sqlite> ',
|
||||
greetings: false /* the docs incorrectly call this 'greeting' */
|
||||
});
|
||||
/* Disable all special handling of the input:
|
||||
https://sqlite.org/forum/forumpost/c6665017c0dbba1f
|
||||
https://github.com/jcubic/jquery.terminal/issues/1044 */
|
||||
const no_formatting = (str)=>window.jQuery.terminal.escape_formatting(str);
|
||||
no_formatting.__meta__ = true;
|
||||
window.jQuery.terminal.new_formatter(no_formatting);
|
||||
EAll('.unhide-if-terminal-available').forEach(e=>{
|
||||
e.classList.remove('hidden');
|
||||
});
|
||||
@@ -891,5 +897,6 @@
|
||||
SF.dbExec(urlParams.get('sql') || null);
|
||||
delete SF.ForceResizeKludge.$disabled;
|
||||
SF.ForceResizeKludge();
|
||||
globalThis.fiddle = SF;
|
||||
}/*onSFLoaded()*/;
|
||||
})();
|
||||
|
||||
@@ -322,8 +322,9 @@
|
||||
<h1>Usage Summary</h1>
|
||||
|
||||
<ul>
|
||||
<li class='hidden unhide-if-terminal-available'>In "terminal
|
||||
mode" it accepts input just like the CLI shell does.</li>
|
||||
<li class='hidden unhide-if-terminal-available'>In
|
||||
<a href="https://github.com/jcubic/jquery.terminal">"terminal
|
||||
mode"</a> it accepts input just like the CLI shell does.</li>
|
||||
<li>In split-view mode:
|
||||
<ul>
|
||||
<li>Input can be executed with either the Run
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Fix\sharmless\scompiler\swarnings.
|
||||
D 2026-04-11T17:47:31.596
|
||||
C Add\sa\smissing\sopen_db()\scall\sin\sthe\snew\s".dbstat"\scommand\sof\sthe\sCLI.
|
||||
D 2026-04-15T11:58:54.973
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -7,7 +7,7 @@ F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d
|
||||
F Makefile.in 5fda086f33b144da08119255da1d2557f983d0764a13707f05acf0159fd89ba5
|
||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||
F Makefile.msc 06b757f8648f1d9dd9683dbd72350cf0cf20d6fe09168cac455569b81dd97ddc
|
||||
F README.md f49fbd826941842e348242f3ab62f240c985ceafdf8fbe576abf4eb75317468c
|
||||
F README.md e4f1a030f813c2fafc898c66d4f10bff2c75eb1a8f504eb9ad9a5ef80e3ff814
|
||||
F VERSION 99cf3be5f13d091183e4314b7fc2e0c0e69accfbe64608b45a313338bbdd7b62
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
|
||||
@@ -44,7 +44,7 @@ F autosetup/cc-lib.tcl 493c5935b5dd3bf9bd4eca89b07c8b1b1a9356d61783035144e21795f
|
||||
F autosetup/cc-shared.tcl 163eda58c14cd662fd8a504bd2ad8a716ef4db7015dc1de0095d5de8dd601a4b
|
||||
F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f
|
||||
F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e
|
||||
F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d
|
||||
F autosetup/jimsh0.c 740dc8cbfaedaff1f27b54b32e0015b22fa6c1a439492b9795968d61e56bab75
|
||||
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
|
||||
F autosetup/proj.tcl ce301197f364f7ce2acabbbd84b43d19e917ec73653157ca134a06f32d322712
|
||||
F autosetup/sqlite-config.tcl 8fecce2838b7e7d990d161d08998034f3e3b0b2ddf4d7a99dbfafba9c902e302
|
||||
@@ -358,6 +358,7 @@ F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b6
|
||||
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
|
||||
F ext/misc/README.md 6243cdc4d7eb791c41ef0716f3980b8b5f6aa8c61ff76a3958cbf0031c6ebfa7
|
||||
F ext/misc/amatch.c 8d237cc014b3736922c26a76a451050d244aa4980c47c531f368f817b1e77b49
|
||||
F ext/misc/analyze.c c329e7fdd23caebbe5362b25a416a7fda7e1524ddba03be12f1d2e4a903caa02
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
|
||||
F ext/misc/base64.c 1445761667c16356e827fc6418294c869468be934429aaa8315035e76dd58acf
|
||||
@@ -463,11 +464,11 @@ F ext/rbu/rburesume.test 1403752d152b55efb7fc25749c0fccc790061371ec9ffe428cc04f8
|
||||
F ext/rbu/rbusave.test 588b618dad9d65c4b13d03a79931de82213503fedc26bdf5789c996ecf427fba
|
||||
F ext/rbu/rbusplit.test a6dedd23cf37bcf2e8646d9d7139846e96d60d92f9bc6d6ba6ca8c24c0bd1f72
|
||||
F ext/rbu/rbutemplimit.test 4980df2d4b74f4dd982add8f78809106154ef5a3c4bdce747422ab0b0481e029
|
||||
F ext/rbu/rbuvacuum.test 542561741ff2b262e3694bc6012b44694ee62c545845319a06f323783b15311e
|
||||
F ext/rbu/rbuvacuum.test e3585cfda220038e8186c583e9bd2aaa9eccd0a5c2e40ed861de3c987c93f68c
|
||||
F ext/rbu/rbuvacuum2.test 1a9bd41f127be2826de2a65204df9118525a8af8d16e61e6bc63ba3ac0010a23
|
||||
F ext/rbu/rbuvacuum3.test 3ce42695fdf21aaa3499e857d7d4253bc499ad759bcd6c9362042c13cd37d8de
|
||||
F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69eefaebb205
|
||||
F ext/rbu/sqlite3rbu.c e99400d29d029936075e27495b269a2dcdceae3cf8c86b1d0869b4af487be3ab
|
||||
F ext/rbu/sqlite3rbu.c 28246b647831409e84dfb8286fbeda55f1de89e934571509a23a67ada572d0c0
|
||||
F ext/rbu/sqlite3rbu.h e3a5bf21e09ca93ce4e8740e00d6a853e90a697968ec0ea98f40826938bdb68e
|
||||
F ext/rbu/test_rbu.c 8b6e64e486c28c41ef29f6f4ea6be7b3091958987812784904f5e903f6b56418
|
||||
F ext/recover/dbdata.c 10d3c56968a9af6853722a47280805ad1564714d79ea45ac6f7da14bb57fd137
|
||||
@@ -621,9 +622,9 @@ F ext/wasm/demo-worker1-promiser.c-pp.js d210aa1e8a74ea6244fe2290de5710bb55b3a9e
|
||||
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
|
||||
F ext/wasm/demo-worker1.js fdfa90aa9d6b402bfed802cf1595fe4da6cc834ac38c8ff854bf1ee01f5ff9bb
|
||||
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
|
||||
F ext/wasm/fiddle/fiddle-worker.js 3cdd20c1e84494a1f28bd80265ae2a754764b08c67e146e61f99d864de4bf5f6
|
||||
F ext/wasm/fiddle/fiddle.js aa5df1e56f54d3ef8cf4ca6e58cc4977380297debcd4e39a9bda64ca50d7ebb2
|
||||
F ext/wasm/fiddle/index.c-pp.html 02f063ef30b8124f311029855c4439e77bc6505d1bf65a163d88c064a63ee9d9
|
||||
F ext/wasm/fiddle/fiddle-worker.js e45bfe9ce4cf0d0270ca0ed254af8deecc7d46c399db4a56fd1d0846d5e258ec
|
||||
F ext/wasm/fiddle/fiddle.js 2a0984cc4a35e6889c0d84ee9bf853317d5545ddb3966dfb995bbe589f923c4c
|
||||
F ext/wasm/fiddle/index.c-pp.html 5fd1f462864710d1b00d27fc4bc6190cb846cc865d7cc93b99644423f2c4cc84
|
||||
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
|
||||
F ext/wasm/index.html 5bf6cf1b0a3c8b9f5f54d77f2219d7ae87a15162055ce308109c49b1dcab4239
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b
|
||||
@@ -674,18 +675,18 @@ F src/auth.c ebec42df26b34a62b6750d30d9c2c03554a1c522020182476f7729a439fef04f
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
|
||||
F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
|
||||
F src/btree.c 216ffbe197e330118a2999adc7d3f09b0e2eeb163df8746ba9a2b27fed3d4335
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c 8581de0af3b6c448f5d64e2d18a91ac1e7057b3bcb8b8827e1240f80d87486a4
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
|
||||
F src/complete.c 9304071c5f2ddd040cd786ec5d157c6a5592561674816e4a9e74164a0ba40647
|
||||
F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9a
|
||||
F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
|
||||
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
|
||||
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
|
||||
F src/expr.c 51e9c77ff5d9a21439e611fe6571a3cd50387e526e13c5614fd407e5b8571930
|
||||
F src/expr.c 68400681c5f6e41231d2c85abf6bb432aeeb2e36c4abdf90eb7b78551a5ce0f3
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
|
||||
F src/func.c 706ac012bf87d8ad7416a56a1d2b1f19e5dea03506a4606a01aa9d3bacf392c7
|
||||
@@ -697,8 +698,8 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9
|
||||
F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0
|
||||
F src/loadext.c 78d5b06f18996ffa1203129b28fea043f63a87a4117539678f1d761c30b4ff65
|
||||
F src/main.c 6180079f53ccdd784df2eddc3751f49ea7153c5959bee792b19ad9f4bdbcf437
|
||||
F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -722,7 +723,7 @@ F src/os_setup.h 8efc64eda6a6c2f221387eefc2e7e45fd5a3d5c8337a7a83519ba4fbd2957ae
|
||||
F src/os_unix.c a07dce662f6c4e18098f6faa9f7ec7cf311f56ee9151bed2aad4dcd55852c9e2
|
||||
F src/os_win.c 0d553b6e8b92c8eb85e7f1b4a8036fe8638c8b32c9ad8d9d72a861c10f81b4c5
|
||||
F src/os_win.h 5e168adf482484327195d10f9c3bce3520f598e04e07ffe62c9c5a8067c1037b
|
||||
F src/pager.c fe34fd22ec251436985d7b6ebdd05bf238a17901c2cb23d3d28974dd2361a912
|
||||
F src/pager.c fbec9063ea139dfa5d94ce540671752b89f8e8dc38f8a1f614bab1aa04a2dd40
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y 3b784d6083380a950e3b1b32ce5ddd303e8c7c209d8ab788df2c62aaf9ee8eb3
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
@@ -735,10 +736,10 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
|
||||
F src/shell.c.in bed26ce3998b32fde83acbf7f4af3bd9e64902bec6bbfa1a834c9f30497b7231
|
||||
F src/sqlite.h.in a5605faa9479bbaac16c4ab43eb09ff50632004a8e05084d3fde56063ef73766
|
||||
F src/shell.c.in 4279e364fd909db808ab8fc46ed06f25e96aaa28726bf6342a9b74bde58bc813
|
||||
F src/sqlite.h.in 39d2e09114d2bdb7afd998f4a469c8f8cd065f8093835a7d0422f260fc78fb4f
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
|
||||
F src/sqlite3ext.h 9788c301f95370fa30e808861f1d2e6f022a816ddbe2a4f67486784c1b31db2e
|
||||
F src/sqliteInt.h bc1cbc0c23dba35b324ae85a7dbb5fb182321bbd30857fb21f3d0cba049001a5
|
||||
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
@@ -805,7 +806,7 @@ F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3
|
||||
F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
|
||||
F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
|
||||
F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
|
||||
F src/vdbeaux.c 5387185849ef00062a5e84af731704e4bf5ec156d82cf5e509a442e9c03e089b
|
||||
F src/vdbeaux.c 8749b5f4f6d65e048ba78143d2dfc6898f65010ecef213891094e8166d1557da
|
||||
F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
|
||||
F src/vdbemem.c efacb8f229422d2a4db0ed38e49b7f3897862a98d82b261aa3b43d7a2d98c6da
|
||||
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
|
||||
@@ -816,7 +817,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
|
||||
F src/wal.c 7340d4f9bb827bd349127cac6b2cf0cb7f76b9fda645f7b9b0bf7a6e0b1e2e7c
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
|
||||
F src/where.c bffca5e4ef20d0bfbdc24f1dc13fd3f955284225a8ad25a4454635f6be39aad0
|
||||
F src/where.c a00d35adeb2550249ba02f24e50eecfb99cba34c8d7d5299b295a591219a2e73
|
||||
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
|
||||
F src/wherecode.c 676cb6cb02878643e817d9917a2d3522b83a3736b2cedd3dc8a01d7bb92af6c2
|
||||
F src/whereexpr.c e9f7185fba366d9365aa7a97329609e4cf00b3dd0400d069fbaa5187350c17c6
|
||||
@@ -1619,8 +1620,8 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
|
||||
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell-prompt.sql c1437f778af91ae3dcb705225c09564a84197626f93de4725233c4ab6ac6daf0
|
||||
F test/shell1.test eda2e527435f139224dda67db6bbd2466597408d4fe5883d647d67fa32d88f7c
|
||||
F test/shell-prompt.sql 5c18599f2b7566172007005206471aefb7e0be593e8f52d37b9ab03a12aa84a6
|
||||
F test/shell1.test c84eff209f93ad17ccdf7e1634969fc8231684254edeb21d9b13d67c3179cdb5
|
||||
F test/shell2.test dc541d2681503e55466a24d35a4cbf8ca5b90b8fcdef37fc4db07373a67d31d3
|
||||
F test/shell3.test 91efdd545097a61a1f72cf79c9ad5b49da080f3f10282eaf4c3c272cd1012db2
|
||||
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
|
||||
@@ -1630,7 +1631,7 @@ F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d
|
||||
F test/shell8.test 38c9e4d7e85d2a3ecfacaa9f6cda4f7a81bf4fffb5f3f37f9cd76827c6883192
|
||||
F test/shell9.test c0e8871061a92151450b3332279a893b516fa73a6c46d4f51a0998407cbf8c89
|
||||
F test/shellA.test 05cdaafa1f79913654487ce3aefa038d4106245d58f52e02faf506140a76d480
|
||||
F test/shellB.test a42be39e2332877d8ee239e1ca2a78d0a1feda21d90f3dd50f32f26cc3b433de
|
||||
F test/shellB.test 82622da7783c32ce931138bec3d5016e802d70361b9f9364b5d49c1dfc2f5af9
|
||||
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -2198,8 +2199,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P b7ecc84735d41e9cdb498020b86d8219efa18ca5b40aef1031a14809f1ac2d38
|
||||
R 3f3e811020519b37271ba11ee0c7ac4e
|
||||
P fdba76df2b3a5b4d56ba79f80fd8b16d5faebca1fb07a266262be2ea635e6f94
|
||||
R 11ac4a0e6010f18fd1adc28138c24819
|
||||
U drh
|
||||
Z 2c87724d0b9b70070b616de7a4951a24
|
||||
Z 0f53747329f642cf306c269a12fd15f3
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch cli-prompt
|
||||
tag cli-prompt
|
||||
branch analyze-sql-func
|
||||
tag analyze-sql-func
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3b4cc8d3beab8c910dd954bf8093f7ab499e4690b9cf882f981c4415dd7a7540
|
||||
a138e44a243466f8679e9652421f8c893a4a1bc0addc86736588d9aee51cf090
|
||||
|
||||
+3
-3
@@ -5939,12 +5939,12 @@ moveto_table_finish:
|
||||
** zero if the cell is less than or equal pIdxKey. Return positive
|
||||
** if unknown.
|
||||
**
|
||||
** Return value negative: Cell at pCur[idx] less than pIdxKey
|
||||
** Return value negative: Cell at pPage[idx] less than pIdxKey
|
||||
**
|
||||
** Return value is zero: Cell at pCur[idx] equals pIdxKey
|
||||
** Return value is zero: Cell at pPage[idx] equals pIdxKey
|
||||
**
|
||||
** Return value positive: Nothing is known about the relationship
|
||||
** of the cell at pCur[idx] and pIdxKey.
|
||||
** of the cell at pPage[idx] and pIdxKey.
|
||||
**
|
||||
** This routine is part of an optimization. It is always safe to return
|
||||
** a positive value as that will cause the optimization to be skipped.
|
||||
|
||||
+4
-4
@@ -332,10 +332,10 @@ sqlite3_int64 sqlite3_incomplete(const char *zSql){
|
||||
}
|
||||
incomplete_finish:
|
||||
if( state==1 ) nParen = 0;
|
||||
return (((i64)nParen)<<32) |
|
||||
((i64)pending<<16) |
|
||||
((i64)statemap[state]<<8) |
|
||||
(state!=1);
|
||||
return (i64)((((u64)nParen)<<32) |
|
||||
((u64)pending<<16) |
|
||||
((u64)statemap[state]<<8) |
|
||||
(state!=1));
|
||||
}
|
||||
int sqlite3_complete(const char *zSql){
|
||||
return sqlite3_incomplete(zSql)==0;
|
||||
|
||||
+1
-1
@@ -2650,7 +2650,7 @@ int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
|
||||
** Walk an expression tree. Return non-zero if
|
||||
**
|
||||
** (1) the expression is constant, and
|
||||
** (2) the expression does originate in the ON or USING clause
|
||||
** (2) the expression does not originate in the ON or USING clause
|
||||
** of a LEFT JOIN, and
|
||||
** (3) the expression does not contain any EP_FixedCol TK_COLUMN
|
||||
** operands created by the constant propagation optimization.
|
||||
|
||||
+3
-2
@@ -528,11 +528,12 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_str_free,
|
||||
#ifdef SQLITE_ENABLE_CARRAY
|
||||
sqlite3_carray_bind,
|
||||
sqlite3_carray_bind_v2
|
||||
sqlite3_carray_bind_v2,
|
||||
#else
|
||||
0,
|
||||
0
|
||||
0,
|
||||
#endif
|
||||
sqlite3_incomplete
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
||||
+2
-1
@@ -1136,7 +1136,8 @@ void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of changes in the most recent call to sqlite3_exec().
|
||||
** Return the number of changes in the most recently executed DML
|
||||
** statement.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_changes64(sqlite3 *db){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
|
||||
+4
-4
@@ -1993,7 +1993,7 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
|
||||
** database transaction.
|
||||
**
|
||||
** This routine is never called in PAGER_ERROR state. If it is called
|
||||
** in PAGER_NONE or PAGER_SHARED state and the lock held is less
|
||||
** in PAGER_OPEN or PAGER_READER state and the lock held is less
|
||||
** exclusive than a RESERVED lock, it is a no-op.
|
||||
**
|
||||
** Otherwise, any active savepoints are released.
|
||||
@@ -3754,7 +3754,7 @@ void sqlite3PagerSetBusyHandler(
|
||||
**
|
||||
** then the pager object page size is set to *pPageSize.
|
||||
**
|
||||
** If the page size is changed, then this function uses sqlite3PagerMalloc()
|
||||
** If the page size is changed, then this function uses sqlite3PageMalloc()
|
||||
** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
|
||||
** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
|
||||
** In all other cases, SQLITE_OK is returned.
|
||||
@@ -5101,8 +5101,8 @@ sqlite3_file *sqlite3_database_file_object(const char *zName){
|
||||
|
||||
|
||||
/*
|
||||
** This function is called after transitioning from PAGER_UNLOCK to
|
||||
** PAGER_SHARED state. It tests if there is a hot journal present in
|
||||
** This function is called while transitioning from PAGER_OPEN to a
|
||||
** higher state. It tests if there is a hot journal present in
|
||||
** the file-system for the given pager. A hot journal is one that
|
||||
** needs to be played back. According to this function, a hot-journal
|
||||
** file exists if the following criteria are met:
|
||||
|
||||
+105
-33
@@ -299,6 +299,7 @@ INCLUDE ../ext/intck/sqlite3intck.h
|
||||
INCLUDE ../ext/intck/sqlite3intck.c
|
||||
INCLUDE ../ext/misc/stmtrand.c
|
||||
INCLUDE ../ext/misc/vfstrace.c
|
||||
INCLUDE ../ext/misc/analyze.c
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
#define SQLITE_SHELL_HAVE_RECOVER 1
|
||||
@@ -907,6 +908,16 @@ static char *local_getline(char *zLine, FILE *in){
|
||||
return zLine;
|
||||
}
|
||||
|
||||
/*
|
||||
** The default prompts.
|
||||
*/
|
||||
#ifndef SQLITE_PS1
|
||||
# define SQLITE_PS1 "SQLite /f> "
|
||||
#endif
|
||||
#ifndef SQLITE_PS2
|
||||
# define SQLITE_PS2 "/B.../H> "
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the raw (unexpanded) prompt string. This will be the
|
||||
** first of the following that exist:
|
||||
@@ -929,9 +940,9 @@ static const char *prompt_string(ShellState *p, int bContinue){
|
||||
if( zPS ) return zPS;
|
||||
#endif
|
||||
if( bContinue ){
|
||||
return "\\B...\\H> ";
|
||||
return SQLITE_PS2;
|
||||
}else{
|
||||
return "SQLite \\f> ";
|
||||
return SQLITE_PS1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -948,7 +959,10 @@ static const char *prompt_filename(ShellState *p){
|
||||
zFN = sqlite3_filename_database(pFN);
|
||||
}
|
||||
if( zFN==0 || zFN[0]==0 ){
|
||||
zFN = "in-memory";
|
||||
zFN = p->pAuxDb->zDbFilename;
|
||||
if( zFN==0 || zFN[0]==0 || cli_strcmp(zFN,":memory:")==0 ){
|
||||
zFN = "in-memory";
|
||||
}
|
||||
}
|
||||
return zFN;
|
||||
}
|
||||
@@ -957,6 +971,14 @@ static const char *prompt_filename(ShellState *p){
|
||||
** Expand escapes in the given input prompt string. Return the
|
||||
** expanded prompt in memory obtained from sqlite3_malloc(). The
|
||||
** caller is responsible for freeing the memory.
|
||||
**
|
||||
** Early prototypes use U+005c '\\' as the escape character. But
|
||||
** that is an escape character for shells and C and many other languages,
|
||||
** which can lead to nested quoting problems and confusion. The
|
||||
** U+0025 '%' character was also tried, and that works pretty well on
|
||||
** unix, but % is special to many formats on Windows. So now we
|
||||
** use a forward-slash, U+002f '/', which seems to pass through
|
||||
** every shell and "make" without issue.
|
||||
*/
|
||||
static char *expand_prompt(
|
||||
ShellState *p, /* The current shell state */
|
||||
@@ -969,27 +991,27 @@ static char *expand_prompt(
|
||||
int onoff = 1;
|
||||
int idxSpace = -1;
|
||||
for(i=0; zPrompt[i]; i++){
|
||||
if( zPrompt[i]!='\\' ) continue;
|
||||
if( zPrompt[i]!='/' ) continue;
|
||||
if( i>0 ){
|
||||
if( onoff ) sqlite3_str_append(pOut, zPrompt, i);
|
||||
zPrompt += i;
|
||||
i = 0;
|
||||
}
|
||||
/* At this point zPrompt[0] is a \ character and all prior
|
||||
/* At this point zPrompt[0] is a / character and all prior
|
||||
** characters have already been loaded into pOut. Process the
|
||||
** escape sequence that zPrompt points to. */
|
||||
c = zPrompt[1];
|
||||
if( c==0 ){
|
||||
/* \ at the end of a line is silently ignored */
|
||||
/* / at the end of a line is silently ignored */
|
||||
break;
|
||||
}
|
||||
if( c=='\\' ){
|
||||
/* \\ maps into a single \ */
|
||||
if( c=='/' ){
|
||||
/* // maps into a single / */
|
||||
zPrompt++;
|
||||
continue;
|
||||
}
|
||||
if( c>='0' && c<='7' ){
|
||||
/* \nnn becomes a single byte given by octal nnn */
|
||||
/* /nnn becomes a single byte given by octal nnn */
|
||||
int v = c - '0';
|
||||
while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){
|
||||
v = v*8 + zPrompt[++i] - '0';
|
||||
@@ -1000,7 +1022,7 @@ static char *expand_prompt(
|
||||
continue;
|
||||
}
|
||||
if( c=='e' ){
|
||||
/* \e is \033 "Escape" */
|
||||
/* /e is shorthand for /033 which is U+001B "Escape" */
|
||||
if( onoff ) sqlite3_str_append(pOut, "\033", 1);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
@@ -1010,14 +1032,15 @@ static char *expand_prompt(
|
||||
/* The intent of the following codes it to provide alternative
|
||||
** text displays depending on whether or not the connection is
|
||||
** currently in a transaction. Example 1: Show a "*" before the ">"
|
||||
** like psql:
|
||||
** like psql: (Note: We encode the "*" as /052 to avoid closing
|
||||
** out this comment.)
|
||||
**
|
||||
** .prompt 'sqlite\x*\;> '
|
||||
** .prompt 'sqlite/x/052/;> '
|
||||
**
|
||||
** Example 2: Show database filename is blue if not in a transaction,
|
||||
** or red if within a transaction:
|
||||
**
|
||||
** .prompt '\e[1;\x31\:34\;m\f>\e[0m '
|
||||
** .prompt '/e[1;/x31/:34/;m~f>/e[0m '
|
||||
*/
|
||||
if( c==':' ){
|
||||
/* toggle display on/off */
|
||||
@@ -1034,7 +1057,7 @@ static char *expand_prompt(
|
||||
continue;
|
||||
}
|
||||
if( c=='x' ){
|
||||
/* \x turns display off not in a transaction, on if in txn */
|
||||
/* /x turns display off not in a transaction, on if in txn */
|
||||
onoff = p->db && !sqlite3_get_autocommit(p->db);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
@@ -1042,9 +1065,9 @@ static char *expand_prompt(
|
||||
}
|
||||
|
||||
if( c=='f' || c=='F' || c=='~' ){
|
||||
/* \f becomes the tail of the database filename */
|
||||
/* \F becomes the full pathname */
|
||||
/* \~ becomes the full pathname relative to $HOME */
|
||||
/* /f becomes the tail of the database filename */
|
||||
/* /F becomes the full pathname */
|
||||
/* /~ becomes the full pathname relative to $HOME */
|
||||
if( onoff ){
|
||||
const char *zFN = prompt_filename(p);
|
||||
if( c=='f' ){
|
||||
@@ -1073,7 +1096,7 @@ static char *expand_prompt(
|
||||
}
|
||||
|
||||
if( c=='H' ){
|
||||
/* \H becomes text needed to terminate current input */
|
||||
/* /H becomes text needed to terminate current input */
|
||||
if( onoff ){
|
||||
sqlite3_int64 R = zPrior ? sqlite3_incomplete(zPrior) : 0;
|
||||
int cc = (R>>16)&0xff;
|
||||
@@ -1105,8 +1128,8 @@ static char *expand_prompt(
|
||||
}
|
||||
|
||||
if( c=='B' ){
|
||||
/* \B is a no-op for the main prompt. For the continuation prompt,
|
||||
** \B expands to zero or more spaces to make the continuation prompt
|
||||
/* /B is a no-op for the main prompt. For the continuation prompt,
|
||||
** /B expands to zero or more spaces to make the continuation prompt
|
||||
** at least as wide as the main prompt. */
|
||||
if( onoff ) idxSpace = sqlite3_str_length(pOut);
|
||||
zPrompt += 2;
|
||||
@@ -1115,7 +1138,7 @@ static char *expand_prompt(
|
||||
}
|
||||
|
||||
/* No match to a known escape. Generate an error. */
|
||||
if( onoff ) sqlite3_str_appendf(pOut,"UNKNOWN(\"\\%c\")",c);
|
||||
if( onoff ) sqlite3_str_appendf(pOut,"UNKNOWN(\"/%c\")",c);
|
||||
zPrompt += 2;
|
||||
i = -1;
|
||||
}
|
||||
@@ -1123,7 +1146,7 @@ static char *expand_prompt(
|
||||
sqlite3_str_append(pOut, zPrompt, i);
|
||||
}
|
||||
|
||||
/* Expand the \B, if there is one and if this is a continuation prompt */
|
||||
/* Expand the /B, if there is one and if this is a continuation prompt */
|
||||
if( idxSpace>=0 && zPrior!=0 && zPrior[0]!=0 ){
|
||||
char *zOther = expand_prompt(p, 0, prompt_string(p,0));
|
||||
size_t wOther = sqlite3_qrf_wcswidth(zOther);
|
||||
@@ -3933,6 +3956,7 @@ static const char *(azHelp[]) = {
|
||||
#if SQLITE_SHELL_HAVE_RECOVER
|
||||
".dbinfo ?DB? Show status information about the database",
|
||||
#endif
|
||||
".dbstat ?SCHEMA? Report database space and size stats",
|
||||
".dbtotxt Hex dump of the database file",
|
||||
".dump ?OBJECTS? Render database content as SQL",
|
||||
" Options:",
|
||||
@@ -3965,7 +3989,7 @@ static const char *(azHelp[]) = {
|
||||
" --schema SCHEMA Use SCHEMA instead of \"main\"",
|
||||
" --help Show CMD details",
|
||||
".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
|
||||
",headers on|off Turn display of headers on or off",
|
||||
".headers on|off Turn display of headers on or off",
|
||||
".help ?-all? ?PATTERN? Show help text for PATTERN",
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
".import FILE TABLE Import data from FILE into TABLE",
|
||||
@@ -4043,6 +4067,7 @@ static const char *(azHelp[]) = {
|
||||
" --timeout S Halt after running for S seconds",
|
||||
#endif
|
||||
".prompt MAIN CONTINUE Replace the standard prompts",
|
||||
" --hard-reset Unset SQLITE_PS1/2 and then --reset",
|
||||
" --reset Revert to default prompts",
|
||||
" --show Show the current prompt strings",
|
||||
" -- No more options. Subsequent args are prompts",
|
||||
@@ -4755,6 +4780,7 @@ static void open_db(ShellState *p, int openFlags){
|
||||
sqlite3_regexp_init(p->db, 0, 0);
|
||||
sqlite3_ieee_init(p->db, 0, 0);
|
||||
sqlite3_series_init(p->db, 0, 0);
|
||||
sqlite3_analyze_init(p->db, 0, 0);
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
sqlite3_fileio_init(p->db, 0, 0);
|
||||
sqlite3_completion_init(p->db, 0, 0);
|
||||
@@ -9548,13 +9574,44 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){
|
||||
rc = shell_dbinfo_command(p, nArg, azArg);
|
||||
}else
|
||||
|
||||
if( c=='r' && cli_strncmp(azArg[0], "recover", n)==0 ){
|
||||
open_db(p, 0);
|
||||
rc = recoverDatabaseCmd(p, nArg, azArg);
|
||||
}else
|
||||
#endif /* SQLITE_SHELL_HAVE_RECOVER */
|
||||
|
||||
if( c=='d' && n==6 && cli_strncmp(azArg[0], "dbstat", n)==0 ){
|
||||
const char *zSchema = 0;
|
||||
int ii;
|
||||
char *zSql;
|
||||
open_db(p, 0);
|
||||
for(ii=1; ii<nArg; ii++){
|
||||
const char *z = azArg[ii];
|
||||
if( z[0]=='-' ){
|
||||
dotCmdError(p, ii, "unknown option", 0);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
if( zSchema ){
|
||||
dotCmdError(p, ii, "unknown argument", 0);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
zSchema = z;
|
||||
}
|
||||
zSql = sqlite3_mprintf("SELECT analyze(%Q)", zSchema);
|
||||
shell_check_oom(zSql);
|
||||
modePush(p);
|
||||
modeChange(p, MODE_BATCH);
|
||||
p->mode.spec.nLineLimit = 0;
|
||||
p->mode.spec.nCharLimit = 0;
|
||||
p->mode.spec.nTitleLimit = 0;
|
||||
shell_exec(p, zSql, 0);
|
||||
modePop(p);
|
||||
sqlite3_free(zSql);
|
||||
}else
|
||||
|
||||
if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
|
||||
open_db(p, 0);
|
||||
rc = shell_dbtotxt_command(p, nArg, azArg);
|
||||
}else
|
||||
|
||||
if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){
|
||||
char *zLike = 0;
|
||||
char *zSql;
|
||||
@@ -9685,11 +9742,6 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
|
||||
open_db(p, 0);
|
||||
rc = shell_dbtotxt_command(p, nArg, azArg);
|
||||
}else
|
||||
|
||||
if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
if( p->mode.autoEQPtrace ){
|
||||
@@ -10657,6 +10709,16 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
const char *z = azArg[i];
|
||||
if( z[0]=='-' && !noOpt ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-hard-reset")==0 ){
|
||||
#ifdef _WIN32
|
||||
_putenv("SQLITE_PS1=");
|
||||
_putenv("SQLITE_PS2=");
|
||||
#else
|
||||
unsetenv("SQLITE_PS1");
|
||||
unsetenv("SQLITE_PS2");
|
||||
#endif
|
||||
z += 5;
|
||||
}
|
||||
if( strcmp(z,"-reset")==0 ){
|
||||
free(p->azPrompt[0]);
|
||||
free(p->azPrompt[1]);
|
||||
@@ -10678,9 +10740,12 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
dotCmdError(p, i, "extra argument", 0);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){
|
||||
dotCmdError(p, i, "use quotes around the prompt string", 0);
|
||||
}else{
|
||||
free(p->azPrompt[cnt]);
|
||||
p->azPrompt[cnt] = strdup(z);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}else
|
||||
@@ -10729,6 +10794,13 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
}else
|
||||
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
|
||||
|
||||
#if SQLITE_SHELL_HAVE_RECOVER
|
||||
if( c=='r' && cli_strncmp(azArg[0], "recover", n)==0 ){
|
||||
open_db(p, 0);
|
||||
rc = recoverDatabaseCmd(p, nArg, azArg);
|
||||
}else
|
||||
#endif /* SQLITE_SHELL_HAVE_RECOVER */
|
||||
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
if( c=='r' && n>=3 && cli_strncmp(azArg[0], "restore", n)==0 ){
|
||||
const char *zSrcFile;
|
||||
|
||||
+1
-1
@@ -2992,7 +2992,7 @@ int sqlite3_is_interrupted(sqlite3*);
|
||||
** then the return value from sqlite3_complete16() will be non-zero
|
||||
** regardless of whether or not the input SQL is complete.)^
|
||||
**
|
||||
** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)
|
||||
** The X input to [sqlite3_complete(X)] and [sqlite3_incomplete(X)]
|
||||
** must be a zero-terminated UTF-8 string.
|
||||
**
|
||||
** The input to [sqlite3_complete16()] must be a zero-terminated
|
||||
|
||||
@@ -376,6 +376,8 @@ struct sqlite3_api_routines {
|
||||
void (*str_free)(sqlite3_str*);
|
||||
int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*));
|
||||
int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*);
|
||||
/* Version 3.54.0 and later */
|
||||
sqlite3_int64 (*incomplete)(const char*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -719,6 +721,8 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_str_free sqlite3_api->str_free
|
||||
#define sqlite3_carray_bind sqlite3_api->carray_bind
|
||||
#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2
|
||||
/* Version 3.54.0 and later */
|
||||
#define sqlite3_incomplete sqlite3_api->incomplete
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
@@ -1900,7 +1900,6 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
|
||||
#if VDBE_DISPLAY_P4
|
||||
/*
|
||||
** Compute a string that describes the P4 parameter for an opcode.
|
||||
** Use zTemp for any required temporary buffer space.
|
||||
*/
|
||||
char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
|
||||
char *zP4 = 0;
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
|
||||
** If the ONEPASS optimization is used (if this routine returns true)
|
||||
** then also write the indices of open cursors used by ONEPASS
|
||||
** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data
|
||||
** table and iaCur[1] gets the cursor used by an auxiliary index.
|
||||
** table and aiCur[1] gets the cursor used by an auxiliary index.
|
||||
** Either value may be -1, indicating that cursor is not used.
|
||||
** Any cursors returned will have been opened for writing.
|
||||
**
|
||||
|
||||
+59
-3
@@ -19,6 +19,7 @@
|
||||
.testcase setup
|
||||
.open -new test.db
|
||||
.mode list -quote off -escape ascii
|
||||
.prompt --hard-reset
|
||||
.check ''
|
||||
|
||||
.testcase 100
|
||||
@@ -28,9 +29,64 @@
|
||||
.testcase 110
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: 'SQLite \f> '
|
||||
Continuation: '\B...\H> '
|
||||
Main prompt: 'SQLite /f> '
|
||||
Continuation: '/B.../H> '
|
||||
END
|
||||
.testcase 111
|
||||
.prompt 'abc> ' '123> ' -show
|
||||
.check <<END
|
||||
Main prompt: 'abc> '
|
||||
Continuation: '123> '
|
||||
END
|
||||
.testcase 112
|
||||
.prompt -- --first --second
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: '--first'
|
||||
Continuation: '--second'
|
||||
END
|
||||
.testcase 113
|
||||
.prompt --reset --show
|
||||
.check <<END
|
||||
Main prompt: 'SQLite /f> '
|
||||
Continuation: '/B.../H> '
|
||||
END
|
||||
|
||||
.testcase 120 --error-prefix ERROR:
|
||||
.prompt show
|
||||
.check <<END
|
||||
ERROR: .prompt show
|
||||
ERROR: ^--- use quotes around the prompt string
|
||||
END
|
||||
|
||||
.testcase 121
|
||||
.prompt 'show'
|
||||
.check ''
|
||||
.testcase 122
|
||||
.prompt --show
|
||||
.check <<END
|
||||
Main prompt: 'show'
|
||||
Continuation: '/B.../H> '
|
||||
END
|
||||
|
||||
.testcase 130
|
||||
.prompt --reset
|
||||
.help prompt
|
||||
.check <<END
|
||||
.prompt MAIN CONTINUE Replace the standard prompts
|
||||
--hard-reset Unset SQLITE_PS1/2 and then --reset
|
||||
--reset Revert to default prompts
|
||||
--show Show the current prompt strings
|
||||
-- No more options. Subsequent args are prompts
|
||||
END
|
||||
|
||||
.testcase 140 --error-prefix ERROR:
|
||||
.prompt --xyz
|
||||
.check <<END
|
||||
ERROR: .prompt --xyz
|
||||
ERROR: ^--- unknown option
|
||||
END
|
||||
|
||||
|
||||
.testcase 1000
|
||||
SELECT shell_prompt_test(NULL);
|
||||
@@ -61,7 +117,7 @@ SELECT shell_prompt_test(NULL,'CREATE TRIGGER t1 BEGIN SELECT 1;');
|
||||
.check " ...END;> ";
|
||||
|
||||
.testcase 2000
|
||||
.prompt 'SQLite\x-txn$\:>\; '
|
||||
.prompt 'SQLite/x-txn$/:>/; '
|
||||
SELECT shell_prompt_test(NULL);
|
||||
.check 'SQLite> ';
|
||||
.testcase 2001
|
||||
|
||||
+2
-1
@@ -548,7 +548,8 @@ do_test shell1-3.17.3 {
|
||||
do_test shell1-3.17.4 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".prompt FOO BAR BAD"
|
||||
} {0 {}}
|
||||
} {1 {line 1: .prompt FOO BAR BAD
|
||||
line 1: ^--- extra argument}}
|
||||
|
||||
# .quit Exit this program
|
||||
do_test shell1-3.18.1 {
|
||||
|
||||
@@ -49,6 +49,8 @@ ifcapable vtab {
|
||||
do_clitest intck01.sql
|
||||
}
|
||||
do_clitest fptest01.sql
|
||||
unset -nocomplain ::env(SQLITE_PS1)
|
||||
unset -nocomplain ::env(SQLITE_PS2)
|
||||
do_clitest shell-prompt.sql
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user