diff --git a/ext/qrf/README.md b/ext/qrf/README.md index fce24c4e30..d7fd0e4742 100644 --- a/ext/qrf/README.md +++ b/ext/qrf/README.md @@ -75,6 +75,7 @@ struct sqlite3_qrf_spec { unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */ unsigned char eTitleAlign; /* Alignment for column headers */ unsigned char bSplitColumn; /* Wrap single-column output into many columns */ + unsigned char bBorder; /* Show outer border in Box and Table styles */ short int nWrap; /* Wrap columns wider than this */ short int nScreenWidth; /* Maximum overall table width */ short int nLineLimit; /* Maximum number of lines for any row */ @@ -587,8 +588,12 @@ to draw the grid. The **Column** arranges the results in neat columns but does not draw in column or row separator, except that it does draw lines horizontal lines using "`-`" characters to separate the column names from the data below. This is very similar to default output styling in -psql. The **Markdown** renders its result in the -Markdown table format. +psql. The **Markdown** renders its result in the Markdown table format. + +The **Box** and **Table** styles normally have a border that surrounds +the entire result. However, if sqlite3_qrf_spec.bBorder is QRF_No, then +that border is omitted, saving a little space both horizontally and +vertically. #### 4.2.1 Split Column Mode diff --git a/ext/qrf/qrf.c b/ext/qrf/qrf.c index 24a19f6633..cc73a5f039 100644 --- a/ext/qrf/qrf.c +++ b/ext/qrf/qrf.c @@ -1370,13 +1370,24 @@ static int qrfColDataEnlarge(qrfColData *p){ static void qrfRowSeparator(sqlite3_str *pOut, qrfColData *p, char cSep){ int i; if( p->nCol>0 ){ - sqlite3_str_append(pOut, &cSep, 1); - sqlite3_str_appendchar(pOut, p->a[0].w+p->nMargin, '-'); - for(i=1; inCol; i++){ + int endMargin; + int useBorder = p->p->spec.bBorder!=QRF_No; + if( useBorder ){ + sqlite3_str_append(pOut, &cSep, 1); + endMargin = p->nMargin; + }else{ + endMargin = p->nCol>1 ? p->nMargin/2 : 0; + } + sqlite3_str_appendchar(pOut, p->a[0].w+endMargin, '-'); + for(i=1; inCol; i++){ + int w = p->a[i].w; + w += (i+1)==p->nCol ? endMargin : p->nMargin; + sqlite3_str_append(pOut, &cSep, 1); + sqlite3_str_appendchar(pOut, w, '-'); + } + if( useBorder ){ sqlite3_str_append(pOut, &cSep, 1); - sqlite3_str_appendchar(pOut, p->a[i].w+p->nMargin, '-'); } - sqlite3_str_append(pOut, &cSep, 1); } sqlite3_str_append(pOut, "\n", 1); } @@ -1434,13 +1445,24 @@ static void qrfBoxSeparator( ){ int i; if( p->nCol>0 ){ - sqlite3_str_appendall(pOut, zSep1); - qrfBoxLine(pOut, p->a[0].w+p->nMargin); - for(i=1; inCol; i++){ - sqlite3_str_appendall(pOut, zSep2); - qrfBoxLine(pOut, p->a[i].w+p->nMargin); + int endMargin; + int useBorder = p->p->spec.bBorder!=QRF_No; + if( useBorder ){ + sqlite3_str_appendall(pOut, zSep1); + endMargin = p->nMargin; + }else{ + endMargin = p->nCol>1 ? p->nMargin/2 : 0; + } + qrfBoxLine(pOut, p->a[0].w+endMargin); + for(i=1; inCol; i++){ + int w = p->a[i].w; + w += i==p->nCol-1 ? endMargin : p->nMargin; + sqlite3_str_appendall(pOut, zSep2); + qrfBoxLine(pOut, w); + } + if( useBorder ){ + sqlite3_str_appendall(pOut, zSep3); } - sqlite3_str_appendall(pOut, zSep3); } sqlite3_str_append(pOut, "\n", 1); } @@ -1608,6 +1630,7 @@ static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){ sepW = pData->nCol*2 - 2; }else{ sepW = pData->nCol*3 + 1; + if( p->spec.bBorder==QRF_No ) sepW -= 4; } nCol = pData->nCol; for(i=sumW=0; ia[i].w; @@ -1619,6 +1642,7 @@ static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){ sepW = pData->nCol - 1; }else{ sepW = pData->nCol + 1; + if( p->spec.bBorder==QRF_No ) sepW -= 2; } targetW = p->spec.nScreenWidth - sepW; @@ -1691,6 +1715,7 @@ static void qrfColumnar(Qrf *p){ /* Initialize the data container */ memset(&data, 0, sizeof(data)); data.nCol = p->nCol; + data.p = p; data.a = sqlite3_malloc64( nColumn*sizeof(struct qrfPerCol) ); if( data.a==0 ){ qrfOom(p); @@ -1821,7 +1846,12 @@ static void qrfColumnar(Qrf *p){ colSep = BOX_13; rowSep = BOX_13 "\n"; } - qrfBoxSeparator(p->pOut, &data, BOX_23, BOX_234, BOX_34); + if( p->spec.bBorder==QRF_No){ + rowStart = ""; + rowSep = "\n"; + }else{ + qrfBoxSeparator(p->pOut, &data, BOX_23, BOX_234, BOX_34); + } break; case QRF_STYLE_Table: if( data.nMargin ){ @@ -1833,7 +1863,12 @@ static void qrfColumnar(Qrf *p){ colSep = "|"; rowSep = "|\n"; } - qrfRowSeparator(p->pOut, &data, '+'); + if( p->spec.bBorder==QRF_No ){ + rowStart = ""; + rowSep = "\n"; + }else{ + qrfRowSeparator(p->pOut, &data, '+'); + } break; case QRF_STYLE_Column: { static const char zSpace[] = " "; @@ -1865,7 +1900,15 @@ static void qrfColumnar(Qrf *p){ szColSep = (int)strlen(colSep); bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow); - bRTrim = (p->spec.eStyle==QRF_STYLE_Column); + if( p->spec.eStyle==QRF_STYLE_Column + || (p->spec.bBorder==QRF_No + && (p->spec.eStyle==QRF_STYLE_Box || p->spec.eStyle==QRF_STYLE_Table) + ) + ){ + bRTrim = 1; + }else{ + bRTrim = 0; + } for(i=0; ispec.eStyle ){ - case QRF_STYLE_Box: - qrfBoxSeparator(p->pOut, &data, BOX_12, BOX_124, BOX_14); - break; - case QRF_STYLE_Table: - qrfRowSeparator(p->pOut, &data, '+'); - break; + if( p->spec.bBorder!=QRF_No ){ + switch( p->spec.eStyle ){ + case QRF_STYLE_Box: + qrfBoxSeparator(p->pOut, &data, BOX_12, BOX_124, BOX_14); + break; + case QRF_STYLE_Table: + qrfRowSeparator(p->pOut, &data, '+'); + break; + } } qrfWrite(p); diff --git a/ext/qrf/qrf.h b/ext/qrf/qrf.h index ddce3d1e79..baaeb4b18d 100644 --- a/ext/qrf/qrf.h +++ b/ext/qrf/qrf.h @@ -37,6 +37,7 @@ struct sqlite3_qrf_spec { unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */ unsigned char eTitleAlign; /* Alignment for column headers */ unsigned char bSplitColumn; /* Wrap single-column output into many columns */ + unsigned char bBorder; /* Show outer border in Box and Table styles */ short int nWrap; /* Wrap columns wider than this */ short int nScreenWidth; /* Maximum overall table width */ short int nLineLimit; /* Maximum number of lines for any row */ diff --git a/manifest b/manifest index 7c5ffd931a..0dd1cc4ff2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbuffer\soverread\sin\sfts5\sthat\smight\soccur\swhile\sprocessing\sa\scorrupt\sdb. -D 2025-11-26T13:58:53.816 +C Add\sthe\sbBorder\soption\sto\sthe\sQRF\sspec.\s\sReflect\sthis\sin\sthe\s-border\noption\son\sthe\sTCL\sformat\smethod,\sand\sthe\s--border\soption\sto\s".mode"\nin\sthe\sCLI.\s\sAlso\sadd\sthe\s"psql"\smode\sto\sthe\sCLI. +D 2025-11-26T16:21:56.554 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -416,9 +416,9 @@ F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f6 F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee -F ext/qrf/README.md c4ee554743fa61858e5685a90689c011adb549a4e5467d3c639c9bc57ba00bb0 -F ext/qrf/qrf.c 838c5af2b59b88640b1fd3665396ce15b1c6ed93612bdbc18e142a81d321e097 -F ext/qrf/qrf.h fe677b8564dd8feaff6d2876a0e06c2e1d8ceaa6f00acd179da92a9e87c2955a +F ext/qrf/README.md c63030fbaf2f5ceedc574749a0630da14bdac4f4ffe70415ddb0e64fc9876aa2 +F ext/qrf/qrf.c b134a3d07cea77d27301dca44bcd8d3cd1551cbed7e51c21854bb6fe570995fa +F ext/qrf/qrf.h 322d48537a5aa39c206c2ec0764a7938ea7662a8c25be1c4e9d742789609ba1e F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8 F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255 F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363 @@ -736,7 +736,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 6a509cddd815d64f6141e539fff633a518a393772a44dffb4490f7fc3f0d83a9 -F src/shell.c.in 990817862286db8f05d2274c20a730d27218c7bb1aa79da3c7c796a3d5f137b2 +F src/shell.c.in d139d8f1fe138235be68da9183fea6d2bceac642e2c3432ddebd7b8a100a46c8 F src/sqlite.h.in f1363321ca55cc2feaa289e9fe6dfb08102a28c54edf005564711a2348b06eef F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998 @@ -744,7 +744,7 @@ F src/sqliteInt.h a89c3a9296928dffcb4c287df176a739f9cf620c7c9d33aec59e8efb9b39cb F src/sqliteLimit.h 0a5516b4ec192a205c541e05f67009028a9451dc6678aae4cf8e68596903c246 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 -F src/tclsqlite.c d0afbb037e9c6e505312eb811fd7ee7ce28328d57bb8c46312fd676ca4e30318 +F src/tclsqlite.c ec2ad3fbf5390c3d4307bc9d1f2a37a9c5d726b5309769dc770ab37f6812152d F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a F src/test1.c 0e71fbcb484a271564e98e0158192c28c24f5521594218c3ba48bcb4cf634f91 F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff @@ -1510,7 +1510,7 @@ F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224c F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/pushdown.test 46a626ef1c0ca79b85296ff2e078b9da20a50e9b804b38f441590c3987580ddd -F test/qrf01.test 1cd0ef5c758dca528f01e47504f3b3181463a29919de06a9dffa7fe174575ead +F test/qrf01.test 6cef9377ad7defbb9dce75e022304807b75b5f1a7e17d1cafdea05bf076cc7f9 F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92 F test/qrf03.test 9de53aea459f5a127283db03cbb6011500757685646d21aa3c29c44c6ef23e86 F test/qrf04.test 0894692c998d2401dcc33449c02051b503ecce0c94217be54fb007c82d2d1379 @@ -1607,7 +1607,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21 F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707 F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test 9438957ab1c0d4c4622b98a11648999a86b6184c8317a87d3c5cb760d2f7bca9 +F test/shell1.test 5c46dd31357c3cc23a225ea8728563059db0f457c7569624a5f6a8fe44baa671 F test/shell2.test 103140814bdc7508aa41dd3462413cbc4aa84b4261112cb8d501d74275cb7d48 F test/shell3.test 840192774cc4edf7653520c0434a311c7477b9bc324abbc7bd2887915792fa8c F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db @@ -1616,7 +1616,7 @@ F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bd F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3 F test/shell8.test 641cf21a99c59404c24e3062923734951c4099a6b6b6520de00cf7a1249ee871 F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209 -F test/shellA.test 4b8983a40703b5550f691592b6c5bc64886c26755eeb7a474af849d1e39b51f2 +F test/shellA.test 3ee819f0e681e649b51c906a29d59abb10215c44e070d18500032f94bbc3fd3a F test/shellB.test de879b1ea7c25daf1a06b2c882b45a5d002e6580c81c57169ce47084cc6afb6b F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 @@ -2180,8 +2180,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P aa9d7365bb8d8a9d44388dc89dea09428d7cea2f9fba482cb56980b51b16b143 -R 5e44b544504a3631820cb0247deb77ab -U dan -Z 9f53e54c4bd9a5cb67f11a90d3e4df95 +P 8b0cbc18be3c6f2501b102757af6be98c48044a296104cca7bce822ac2304515 +R 8945f4ddcddcd63749e20ffed7b156be +U drh +Z 40eaa1e5fedbd407b6fc2b7e3ad849db # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3d1e57cd6e..8990fd26e9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8b0cbc18be3c6f2501b102757af6be98c48044a296104cca7bce822ac2304515 +02cbeb69884cd884d9b1b5f59c4168a3dc24b1a5aecc6967586c0be350b10574 diff --git a/src/shell.c.in b/src/shell.c.in index ca76c40652..c1012a7d76 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1428,15 +1428,16 @@ static const char *qrfQuoteNames[] = #define MODE_List 12 /* One record per line with a separator */ #define MODE_Markdown 13 /* Markdown formatting */ #define MODE_Off 14 /* No query output shown */ -#define MODE_QBox 15 /* BOX with SQL-quoted content */ -#define MODE_Quote 16 /* Quote values as for SQL */ -#define MODE_Split 17 /* Split-column mode */ -#define MODE_Table 18 /* MySQL-style table formatting */ -#define MODE_Tabs 19 /* Tab-separated values */ -#define MODE_Tcl 20 /* Space-separated list of TCL strings */ -#define MODE_Www 21 /* Full web-page output */ +#define MODE_Psql 15 /* Similar to psql */ +#define MODE_QBox 16 /* BOX with SQL-quoted content */ +#define MODE_Quote 17 /* Quote values as for SQL */ +#define MODE_Split 18 /* Split-column mode */ +#define MODE_Table 19 /* MySQL-style table formatting */ +#define MODE_Tabs 20 /* Tab-separated values */ +#define MODE_Tcl 21 /* Space-separated list of TCL strings */ +#define MODE_Www 22 /* Full web-page output */ -#define MODE_BUILTIN 21 /* Maximum built-in mode */ +#define MODE_BUILTIN 22 /* Maximum built-in mode */ #define MODE_BATCH 50 /* Default mode for batch processing */ #define MODE_TTY 51 /* Default mode for interactive processing */ #define MODE_USER 75 /* First user-defined mode */ @@ -1457,6 +1458,7 @@ struct ModeInfo { unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ unsigned char eStyle; /* Underlying QRF style */ unsigned char eCx; /* 0: other, 1: line, 2: columnar */ + unsigned char mFlg; /* Flags. 1=border-off 2=split-column */ }; /* String constants used by built-in modes */ @@ -1467,29 +1469,30 @@ static const char *aModeStr[] = /* 9 10 11 12 */ static const ModeInfo aModeInfo[] = { -/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx */ - { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0 }, - { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2 }, - { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0 }, - { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2 }, - { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0 }, - { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0 }, - { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0 }, - { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0 }, - { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0 }, - { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0 }, - { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0 }, - { "line", 0, 1, 9, 1, 1, 0, 0, 11, 1 }, - { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0 }, - { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2 }, - { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0 }, - { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2 }, - { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0 }, - { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2 }, - { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2 }, - { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0 }, - { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0 }, - { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0 } +/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ + { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, + { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 }, + { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, + { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 }, + { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, + { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, + { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }, + { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, + { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, + { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, + { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, + { "line", 0, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, + { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, + { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 }, + { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, + { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 }, + { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 }, + { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, + { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, + { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 }, + { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, + { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, + { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 } }; /* | / / | / / | | \ ** | / / | / / | | \_ 2: columnar ** Index into aModeStr[] | / / | | 1: line @@ -1615,7 +1618,12 @@ static void modeChange(ShellState *p, unsigned char eMode){ pM->spec.eBlob = pI->eBlob; pM->spec.bTitles = pI->bHdr; pM->spec.eTitle = pI->eHdr; - if( eMode==MODE_Split ){ + if( pI->mFlg & 0x01 ){ + pM->spec.bBorder = QRF_No; + }else{ + pM->spec.bBorder = QRF_Auto; + } + if( pI->mFlg & 0x02 ){ pM->spec.bSplitColumn = QRF_Yes; pM->bAutoScreenWidth = 1; }else{ @@ -7675,6 +7683,7 @@ static int modeTitleDsply(ShellState *p, int bAll){ ** Unspecified alignment defaults to 'L'. ** --blob-quote ARG ARG can be "auto", "text", "sql", "hex", "tcl", ** "json", or "size". Default is "auto". +** --border on|off Show outer border on "box" and "table" modes. ** --charlimit N Set the maximum number of output characters to ** show for any single SQL value to N. Longer values ** truncated. Zero means "no limit". @@ -7793,6 +7802,16 @@ static int dotCmdMode(ShellState *p){ p->mode.spec.eBlob = k & 0xff; } chng = 1; + }else if( optionMatch(z,"border") ){ + if( (++i)>=nArg ){ + dotCmdError(p, i-1, "missing argument", 0); + return 1; + } + k = pickStr(azArg[i], 0, "auto", "off", "on", ""); + if( k>=0 ){ + p->mode.spec.bBorder = k & 0x3; + } + chng = 1; }else if( 0<=(k=pickStr(z,0,"-charlimit","-linelimit","")) ){ int w; /* 0 1 */ if( i+1>=nArg ){ @@ -8095,6 +8114,12 @@ static int dotCmdMode(ShellState *p){ } sqlite3_str_append(pDesc, "\"", 1); } + if( bAll + || (p->mode.spec.bBorder==QRF_No) != ((pI->mFlg&1)!=0) + ){ + sqlite3_str_appendf(pDesc," --border %s", + p->mode.spec.bBorder==QRF_No ? "off" : "on"); + } if( bAll || p->mode.spec.eBlob!=QRF_BLOB_Auto ){ const char *azBQuote[] = { "auto", "text", "sql", "hex", "tcl", "json", "size" }; @@ -12807,6 +12832,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ modeChange(&data, MODE_Markdown); }else if( cli_strcmp(z,"-table")==0 ){ modeChange(&data, MODE_Table); + }else if( cli_strcmp(z,"-psql")==0 ){ + modeChange(&data, MODE_Psql); }else if( cli_strcmp(z,"-box")==0 ){ modeChange(&data, MODE_Box); }else if( cli_strcmp(z,"-csv")==0 ){ diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 39b1782ae6..3cedbf9c30 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -2065,6 +2065,7 @@ static void DbHookCmd( ** -splitcolumn ("auto"|"off"|"on") Enable split-column mode ** -defaultalign ("auto"|"left"|...) Default alignment ** -titalalign ("auto"|"left"|"right"|...) Default column name alignment +** -border ("auto"|"off"|"on") Border for box and table styles ** -wrap NUMBER Max width of any single column ** -screenwidth NUMBER Width of the display TTY ** -linelimit NUMBER Max lines for any cell @@ -2091,6 +2092,7 @@ static void DbHookCmd( ** -splitcolumn bSplitColumn ** -defaultalign eDfltAlign ** -titlealign eTitleAlign +** -border bBorder ** -wrap nWrap ** -screenwidth nScreenWidth ** -linelimit nLineLimit @@ -2240,13 +2242,16 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){ i++; }else if( strcmp(zArg,"-textjsonb")==0 || strcmp(zArg,"-splitcolumn")==0 + || strcmp(zArg,"-border")==0 ){ int v = 0; rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool, zArg, 0, &v); if( rc ) goto format_failed; - if( zArg[5]=='j' ){ + if( zArg[1]=='t' ){ qrf.bTextJsonb = aBoolMap[v]; + }else if( zArg[1]=='b' ){ + qrf.bBorder = aBoolMap[v]; }else{ qrf.bSplitColumn = aBoolMap[v]; } diff --git a/test/qrf01.test b/test/qrf01.test index 3dffa74d82..6ef8acf6c8 100644 --- a/test/qrf01.test +++ b/test/qrf01.test @@ -49,6 +49,14 @@ do_test 1.11b { │ x'424c4f42' │ │ 'Ἀμήν' │ └─────────────┴─────┴─────────┘ } +do_test 1.11c { + set result "\n[db format -text sql -border off {SELECT * FROM t1}]" +} { + a │ b │ c +────────────┼─────┼──────── +1 │ 2.5 │ 'three' +x'424c4f42' │ │ 'Ἀμήν' +} do_test 1.12 { set result "\n[db format -text csv {SELECT * FROM t1}]" } { @@ -112,6 +120,15 @@ do_test 1.31 { | BLOB | | Ἀμήν | +------+-----+-------+ } +do_test 1.32 { + set result "\n[db format -style table -border off {SELECT * FROM t1}]" +} { + a | b | c +-----+-----+------ +1 | 2.5 | three +BLOB | | Ἀμήν +} + do_test 1.40 { set result "\n[db format -style column {SELECT * FROM t1}]" diff --git a/test/shell1.test b/test/shell1.test index 539d8ef830..a5bcd4cab1 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -1311,6 +1311,12 @@ do_test shell1-8.4 { +------------------+-----+ | 6683623321994527 | -47 | +------------------+-----+}} +do_test shell1-8.4b { + catchcmd ":memory: --psql" \ + {SELECT ieee754_mantissa(47.49) AS M, ieee754_exponent(47.49) AS E;} +} {0 { M | E +-----------------+---- +6683623321994527 | -47}} do_test_with_ansi_output shell1-8.5 { catchcmd ":memory: --box" { create table t(a text, b int); diff --git a/test/shellA.test b/test/shellA.test index e3d2e1b9d0..3f0647aa3d 100644 --- a/test/shellA.test +++ b/test/shellA.test @@ -197,6 +197,24 @@ do_test_with_ansi_output shellA-4.1 { │ 8 │ last line │ └───┴──────────────────────────┘ } +do_test_with_ansi_output shellA-4.1b { + exec {*}$CLI -noinit test.db --box --escape ascii \ + {.mode -border off} \ + {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)} +} { +a │ x +──┼───────────────────────── +1 │ line with ' single quote +──┼───────────────────────── +2 │ ^[[31mVT-100 codes^[[0m +──┼───────────────────────── +6 │ new + │ line +──┼───────────────────────── +7 │ carriage^Mreturn +──┼───────────────────────── +8 │ last line +} do_test_with_ansi_output shellA-4.2 { exec {*}$CLI -noinit test.db {.mode qbox} {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)} } { @@ -210,6 +228,18 @@ do_test_with_ansi_output shellA-4.2 { │ 8 │ 'last line' │ └───┴───────────────────────────────────────────┘ } +do_test_with_ansi_output shellA-4.2b { + exec {*}$CLI -noinit test.db {.mode qbox -border off} \ + {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)} +} { +a │ x +──┼────────────────────────────────────────── +1 │ 'line with '' single quote' +2 │ unistr('\u001b[31mVT-100 codes\u001b[0m') +6 │ unistr('new\u000aline') +7 │ unistr('carriage\u000dreturn') +8 │ 'last line' +} # ".mode insert" #