| | @@ -704,10 +704,11 @@ |
| 704 | 704 | unsigned char bWordWrap; /* Try to wrap on word boundaries */ |
| 705 | 705 | unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */ |
| 706 | 706 | unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */ |
| 707 | 707 | unsigned char eTitleAlign; /* Alignment for column headers */ |
| 708 | 708 | unsigned char bSplitColumn; /* Wrap single-column output into many columns */ |
| 709 | + unsigned char bBorder; /* Show outer border in Box and Table styles */ |
| 709 | 710 | short int nWrap; /* Wrap columns wider than this */ |
| 710 | 711 | short int nScreenWidth; /* Maximum overall table width */ |
| 711 | 712 | short int nLineLimit; /* Maximum number of lines for any row */ |
| 712 | 713 | int nCharLimit; /* Maximum number of characters in a cell */ |
| 713 | 714 | int nWidth; /* Number of entries in aWidth[] */ |
| | @@ -1990,19 +1991,19 @@ |
| 1990 | 1991 | int k; /* Bytes in a VT100 code */ |
| 1991 | 1992 | int n; /* Output column number */ |
| 1992 | 1993 | const unsigned char *z = (const unsigned char*)zIn; |
| 1993 | 1994 | unsigned char c = 0; |
| 1994 | 1995 | |
| 1995 | | - if( zIn[0]==0 ){ |
| 1996 | + if( z[0]==0 ){ |
| 1996 | 1997 | *pnThis = 0; |
| 1997 | 1998 | *pnWide = 0; |
| 1998 | 1999 | *piNext = 0; |
| 1999 | 2000 | return; |
| 2000 | 2001 | } |
| 2001 | 2002 | n = 0; |
| 2002 | | - for(i=0; n<w; i++){ |
| 2003 | | - c = zIn[i]; |
| 2003 | + for(i=0; n<=w; i++){ |
| 2004 | + c = z[i]; |
| 2004 | 2005 | if( c>=0xc0 ){ |
| 2005 | 2006 | int u; |
| 2006 | 2007 | int len = sqlite3_qrf_decode_utf8(&z[i], &u); |
| 2007 | 2008 | int wcw = sqlite3_qrf_wcwidth(u); |
| 2008 | 2009 | if( wcw+n>w ) break; |
| | @@ -2009,23 +2010,26 @@ |
| 2009 | 2010 | i += len-1; |
| 2010 | 2011 | n += wcw; |
| 2011 | 2012 | continue; |
| 2012 | 2013 | } |
| 2013 | 2014 | if( c>=' ' ){ |
| 2015 | + if( n==w ) break; |
| 2014 | 2016 | n++; |
| 2015 | 2017 | continue; |
| 2016 | 2018 | } |
| 2017 | 2019 | if( c==0 || c=='\n' ) break; |
| 2018 | | - if( c=='\r' && zIn[i+1]=='\n' ){ c = zIn[++i]; break; } |
| 2020 | + if( c=='\r' && z[i+1]=='\n' ){ c = z[++i]; break; } |
| 2019 | 2021 | if( c=='\t' ){ |
| 2020 | 2022 | int wcw = 8 - (n&7); |
| 2021 | 2023 | if( n+wcw>w ) break; |
| 2022 | 2024 | n += wcw; |
| 2023 | 2025 | continue; |
| 2024 | 2026 | } |
| 2025 | 2027 | if( c==0x1b && (k = qrfIsVt100(&z[i]))>0 ){ |
| 2026 | 2028 | i += k-1; |
| 2029 | + }else if( n==w ){ |
| 2030 | + break; |
| 2027 | 2031 | }else{ |
| 2028 | 2032 | n++; |
| 2029 | 2033 | } |
| 2030 | 2034 | } |
| 2031 | 2035 | if( c==0 ){ |
| | @@ -2121,40 +2125,10 @@ |
| 2121 | 2125 | } |
| 2122 | 2126 | } |
| 2123 | 2127 | sqlite3_str_append(pOut, (const char*)z, i); |
| 2124 | 2128 | } |
| 2125 | 2129 | |
| 2126 | | -/* |
| 2127 | | -** Output horizontally justified text into pOut. The text is the |
| 2128 | | -** first nVal bytes of zVal. Include nWS bytes of whitespace, either |
| 2129 | | -** split between both sides, or on the left, or on the right, depending |
| 2130 | | -** on eAlign. |
| 2131 | | -*/ |
| 2132 | | -static void qrfPrintAligned( |
| 2133 | | - sqlite3_str *pOut, /* Append text here */ |
| 2134 | | - const char *zVal, /* Text to append */ |
| 2135 | | - int nVal, /* Use only the first nVal bytes of zVal[] */ |
| 2136 | | - int nWS, /* Whitespace for horizonal alignment */ |
| 2137 | | - unsigned char eAlign /* Alignment type */ |
| 2138 | | -){ |
| 2139 | | - eAlign &= QRF_ALIGN_HMASK; |
| 2140 | | - if( eAlign==QRF_ALIGN_Center ){ |
| 2141 | | - /* Center the text */ |
| 2142 | | - sqlite3_str_appendchar(pOut, nWS/2, ' '); |
| 2143 | | - qrfAppendWithTabs(pOut, zVal, nVal); |
| 2144 | | - sqlite3_str_appendchar(pOut, nWS - nWS/2, ' '); |
| 2145 | | - }else if( eAlign==QRF_ALIGN_Right){ |
| 2146 | | - /* Right justify the text */ |
| 2147 | | - sqlite3_str_appendchar(pOut, nWS, ' '); |
| 2148 | | - qrfAppendWithTabs(pOut, zVal, nVal); |
| 2149 | | - }else{ |
| 2150 | | - /* Left justify the next */ |
| 2151 | | - qrfAppendWithTabs(pOut, zVal, nVal); |
| 2152 | | - sqlite3_str_appendchar(pOut, nWS, ' '); |
| 2153 | | - } |
| 2154 | | -} |
| 2155 | | - |
| 2156 | 2130 | /* |
| 2157 | 2131 | ** GCC does not define the offsetof() macro so we'll have to do it |
| 2158 | 2132 | ** ourselves. |
| 2159 | 2133 | */ |
| 2160 | 2134 | #ifndef offsetof |
| | @@ -2174,27 +2148,60 @@ |
| 2174 | 2148 | sqlite3_int64 nRow; /* Number of rows */ |
| 2175 | 2149 | sqlite3_int64 nAlloc; /* Number of cells allocated */ |
| 2176 | 2150 | sqlite3_int64 n; /* Number of cells. nCol*nRow */ |
| 2177 | 2151 | char **az; /* Content of all cells */ |
| 2178 | 2152 | int *aiWth; /* Width of each cell */ |
| 2153 | + unsigned char *abNum; /* True for each numeric cell */ |
| 2179 | 2154 | struct qrfPerCol { /* Per-column data */ |
| 2180 | 2155 | char *z; /* Cache of text for current row */ |
| 2181 | 2156 | int w; /* Computed width of this column */ |
| 2182 | 2157 | int mxW; /* Maximum natural (unwrapped) width */ |
| 2183 | 2158 | unsigned char e; /* Alignment */ |
| 2184 | 2159 | unsigned char fx; /* Width is fixed */ |
| 2160 | + unsigned char bNum; /* True if is numeric */ |
| 2185 | 2161 | } *a; /* One per column */ |
| 2186 | 2162 | }; |
| 2163 | + |
| 2164 | +/* |
| 2165 | +** Output horizontally justified text into pOut. The text is the |
| 2166 | +** first nVal bytes of zVal. Include nWS bytes of whitespace, either |
| 2167 | +** split between both sides, or on the left, or on the right, depending |
| 2168 | +** on eAlign. |
| 2169 | +*/ |
| 2170 | +static void qrfPrintAligned( |
| 2171 | + sqlite3_str *pOut, /* Append text here */ |
| 2172 | + struct qrfPerCol *pCol, /* Information about the text to print */ |
| 2173 | + int nVal, /* Use only the first nVal bytes of zVal[] */ |
| 2174 | + int nWS /* Whitespace for horizonal alignment */ |
| 2175 | +){ |
| 2176 | + unsigned char eAlign = pCol->e & QRF_ALIGN_HMASK; |
| 2177 | + if( eAlign==QRF_Auto && pCol->bNum ) eAlign = QRF_ALIGN_Right; |
| 2178 | + if( eAlign==QRF_ALIGN_Center ){ |
| 2179 | + /* Center the text */ |
| 2180 | + sqlite3_str_appendchar(pOut, nWS/2, ' '); |
| 2181 | + qrfAppendWithTabs(pOut, pCol->z, nVal); |
| 2182 | + sqlite3_str_appendchar(pOut, nWS - nWS/2, ' '); |
| 2183 | + }else if( eAlign==QRF_ALIGN_Right ){ |
| 2184 | + /* Right justify the text */ |
| 2185 | + sqlite3_str_appendchar(pOut, nWS, ' '); |
| 2186 | + qrfAppendWithTabs(pOut, pCol->z, nVal); |
| 2187 | + }else{ |
| 2188 | + /* Left justify the text */ |
| 2189 | + qrfAppendWithTabs(pOut, pCol->z, nVal); |
| 2190 | + sqlite3_str_appendchar(pOut, nWS, ' '); |
| 2191 | + } |
| 2192 | +} |
| 2187 | 2193 | |
| 2188 | 2194 | /* |
| 2189 | 2195 | ** Free all the memory allocates in the qrfColData object |
| 2190 | 2196 | */ |
| 2191 | 2197 | static void qrfColDataFree(qrfColData *p){ |
| 2192 | 2198 | sqlite3_int64 i; |
| 2193 | 2199 | for(i=0; i<p->n; i++) sqlite3_free(p->az[i]); |
| 2194 | 2200 | sqlite3_free(p->az); |
| 2195 | 2201 | sqlite3_free(p->aiWth); |
| 2202 | + sqlite3_free(p->abNum); |
| 2196 | 2203 | sqlite3_free(p->a); |
| 2197 | 2204 | memset(p, 0, sizeof(*p)); |
| 2198 | 2205 | } |
| 2199 | 2206 | |
| 2200 | 2207 | /* |
| | @@ -2202,10 +2209,11 @@ |
| 2202 | 2209 | ** Return non-zero if a memory allocation fails. |
| 2203 | 2210 | */ |
| 2204 | 2211 | static int qrfColDataEnlarge(qrfColData *p){ |
| 2205 | 2212 | char **azData; |
| 2206 | 2213 | int *aiWth; |
| 2214 | + unsigned char *abNum; |
| 2207 | 2215 | p->nAlloc = 2*p->nAlloc + 10*p->nCol; |
| 2208 | 2216 | azData = sqlite3_realloc64(p->az, p->nAlloc*sizeof(char*)); |
| 2209 | 2217 | if( azData==0 ){ |
| 2210 | 2218 | qrfOom(p->p); |
| 2211 | 2219 | qrfColDataFree(p); |
| | @@ -2217,26 +2225,38 @@ |
| 2217 | 2225 | qrfOom(p->p); |
| 2218 | 2226 | qrfColDataFree(p); |
| 2219 | 2227 | return 1; |
| 2220 | 2228 | } |
| 2221 | 2229 | p->aiWth = aiWth; |
| 2230 | + abNum = sqlite3_realloc64(p->abNum, p->nAlloc); |
| 2231 | + if( abNum==0 ){ |
| 2232 | + qrfOom(p->p); |
| 2233 | + qrfColDataFree(p); |
| 2234 | + return 1; |
| 2235 | + } |
| 2236 | + p->abNum = abNum; |
| 2222 | 2237 | return 0; |
| 2223 | 2238 | } |
| 2224 | 2239 | |
| 2225 | 2240 | /* |
| 2226 | 2241 | ** Print a markdown or table-style row separator using ascii-art |
| 2227 | 2242 | */ |
| 2228 | 2243 | static void qrfRowSeparator(sqlite3_str *pOut, qrfColData *p, char cSep){ |
| 2229 | 2244 | int i; |
| 2230 | 2245 | if( p->nCol>0 ){ |
| 2231 | | - sqlite3_str_append(pOut, &cSep, 1); |
| 2246 | + int useBorder = p->p->spec.bBorder!=QRF_No; |
| 2247 | + if( useBorder ){ |
| 2248 | + sqlite3_str_append(pOut, &cSep, 1); |
| 2249 | + } |
| 2232 | 2250 | sqlite3_str_appendchar(pOut, p->a[0].w+p->nMargin, '-'); |
| 2233 | 2251 | for(i=1; i<p->nCol; i++){ |
| 2234 | 2252 | sqlite3_str_append(pOut, &cSep, 1); |
| 2235 | 2253 | sqlite3_str_appendchar(pOut, p->a[i].w+p->nMargin, '-'); |
| 2236 | 2254 | } |
| 2237 | | - sqlite3_str_append(pOut, &cSep, 1); |
| 2255 | + if( useBorder ){ |
| 2256 | + sqlite3_str_append(pOut, &cSep, 1); |
| 2257 | + } |
| 2238 | 2258 | } |
| 2239 | 2259 | sqlite3_str_append(pOut, "\n", 1); |
| 2240 | 2260 | } |
| 2241 | 2261 | |
| 2242 | 2262 | /* |
| | @@ -2290,17 +2310,22 @@ |
| 2290 | 2310 | const char *zSep2, |
| 2291 | 2311 | const char *zSep3 |
| 2292 | 2312 | ){ |
| 2293 | 2313 | int i; |
| 2294 | 2314 | if( p->nCol>0 ){ |
| 2295 | | - sqlite3_str_appendall(pOut, zSep1); |
| 2315 | + int useBorder = p->p->spec.bBorder!=QRF_No; |
| 2316 | + if( useBorder ){ |
| 2317 | + sqlite3_str_appendall(pOut, zSep1); |
| 2318 | + } |
| 2296 | 2319 | qrfBoxLine(pOut, p->a[0].w+p->nMargin); |
| 2297 | 2320 | for(i=1; i<p->nCol; i++){ |
| 2298 | 2321 | sqlite3_str_appendall(pOut, zSep2); |
| 2299 | 2322 | qrfBoxLine(pOut, p->a[i].w+p->nMargin); |
| 2300 | 2323 | } |
| 2301 | | - sqlite3_str_appendall(pOut, zSep3); |
| 2324 | + if( useBorder ){ |
| 2325 | + sqlite3_str_appendall(pOut, zSep3); |
| 2326 | + } |
| 2302 | 2327 | } |
| 2303 | 2328 | sqlite3_str_append(pOut, "\n", 1); |
| 2304 | 2329 | } |
| 2305 | 2330 | |
| 2306 | 2331 | /* |
| | @@ -2379,10 +2404,11 @@ |
| 2379 | 2404 | static void qrfSplitColumn(qrfColData *pData, Qrf *p){ |
| 2380 | 2405 | int nCol = 1; |
| 2381 | 2406 | int *aw = 0; |
| 2382 | 2407 | char **az = 0; |
| 2383 | 2408 | int *aiWth = 0; |
| 2409 | + unsigned char *abNum = 0; |
| 2384 | 2410 | int nColNext = 2; |
| 2385 | 2411 | int w; |
| 2386 | 2412 | struct qrfPerCol *a = 0; |
| 2387 | 2413 | sqlite3_int64 nRow = 1; |
| 2388 | 2414 | sqlite3_int64 i; |
| | @@ -2416,35 +2442,47 @@ |
| 2416 | 2442 | if( a==0 ){ |
| 2417 | 2443 | sqlite3_free(az); |
| 2418 | 2444 | sqlite3_free(aiWth); |
| 2419 | 2445 | qrfOom(p); |
| 2420 | 2446 | return; |
| 2447 | + } |
| 2448 | + abNum = sqlite3_malloc64( nRow*nCol ); |
| 2449 | + if( abNum==0 ){ |
| 2450 | + sqlite3_free(az); |
| 2451 | + sqlite3_free(aiWth); |
| 2452 | + sqlite3_free(a); |
| 2453 | + qrfOom(p); |
| 2454 | + return; |
| 2421 | 2455 | } |
| 2422 | 2456 | for(i=0; i<pData->n; i++){ |
| 2423 | 2457 | sqlite3_int64 j = (i%nRow)*nCol + (i/nRow); |
| 2424 | 2458 | az[j] = pData->az[i]; |
| 2459 | + abNum[j]= pData->abNum[i]; |
| 2425 | 2460 | pData->az[i] = 0; |
| 2426 | 2461 | aiWth[j] = pData->aiWth[i]; |
| 2427 | 2462 | } |
| 2428 | 2463 | while( i<nRow*nCol ){ |
| 2429 | 2464 | sqlite3_int64 j = (i%nRow)*nCol + (i/nRow); |
| 2430 | 2465 | az[j] = sqlite3_mprintf(""); |
| 2431 | 2466 | if( az[j]==0 ) qrfOom(p); |
| 2432 | 2467 | aiWth[j] = 0; |
| 2468 | + abNum[j] = 0; |
| 2433 | 2469 | i++; |
| 2434 | 2470 | } |
| 2435 | 2471 | for(i=0; i<nCol; i++){ |
| 2436 | 2472 | a[i].fx = a[i].mxW = a[i].w = aw[i]; |
| 2437 | 2473 | a[i].e = pData->a[0].e; |
| 2438 | 2474 | } |
| 2439 | 2475 | sqlite3_free(pData->az); |
| 2440 | 2476 | sqlite3_free(pData->aiWth); |
| 2441 | 2477 | sqlite3_free(pData->a); |
| 2478 | + sqlite3_free(pData->abNum); |
| 2442 | 2479 | sqlite3_free(aw); |
| 2443 | 2480 | pData->az = az; |
| 2444 | 2481 | pData->aiWth = aiWth; |
| 2445 | 2482 | pData->a = a; |
| 2483 | + pData->abNum = abNum; |
| 2446 | 2484 | pData->nCol = nCol; |
| 2447 | 2485 | pData->n = pData->nAlloc = nRow*nCol; |
| 2448 | 2486 | for(i=w=0; i<nCol; i++) w += a[i].w; |
| 2449 | 2487 | pData->nMargin = (p->spec.nScreenWidth - w)/(nCol - 1); |
| 2450 | 2488 | if( pData->nMargin>5 ) pData->nMargin = 5; |
| | @@ -2464,10 +2502,11 @@ |
| 2464 | 2502 | if( p->spec.nScreenWidth==0 ) return; |
| 2465 | 2503 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2466 | 2504 | sepW = pData->nCol*2 - 2; |
| 2467 | 2505 | }else{ |
| 2468 | 2506 | sepW = pData->nCol*3 + 1; |
| 2507 | + if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2469 | 2508 | } |
| 2470 | 2509 | nCol = pData->nCol; |
| 2471 | 2510 | for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w; |
| 2472 | 2511 | if( p->spec.nScreenWidth >= sumW+sepW ) return; |
| 2473 | 2512 | |
| | @@ -2475,10 +2514,11 @@ |
| 2475 | 2514 | pData->nMargin = 0; |
| 2476 | 2515 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2477 | 2516 | sepW = pData->nCol - 1; |
| 2478 | 2517 | }else{ |
| 2479 | 2518 | sepW = pData->nCol + 1; |
| 2519 | + if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2480 | 2520 | } |
| 2481 | 2521 | targetW = p->spec.nScreenWidth - sepW; |
| 2482 | 2522 | |
| 2483 | 2523 | #define MIN_SQUOZE 8 |
| 2484 | 2524 | #define MIN_EX_SQUOZE 16 |
| | @@ -2547,10 +2587,11 @@ |
| 2547 | 2587 | } |
| 2548 | 2588 | |
| 2549 | 2589 | /* Initialize the data container */ |
| 2550 | 2590 | memset(&data, 0, sizeof(data)); |
| 2551 | 2591 | data.nCol = p->nCol; |
| 2592 | + data.p = p; |
| 2552 | 2593 | data.a = sqlite3_malloc64( nColumn*sizeof(struct qrfPerCol) ); |
| 2553 | 2594 | if( data.a==0 ){ |
| 2554 | 2595 | qrfOom(p); |
| 2555 | 2596 | return; |
| 2556 | 2597 | } |
| | @@ -2560,10 +2601,11 @@ |
| 2560 | 2601 | |
| 2561 | 2602 | /* Load the column header names and all cell content into data */ |
| 2562 | 2603 | if( p->spec.bTitles==QRF_Yes ){ |
| 2563 | 2604 | unsigned char saved_eText = p->spec.eText; |
| 2564 | 2605 | p->spec.eText = p->spec.eTitle; |
| 2606 | + memset(data.abNum, 0, nColumn); |
| 2565 | 2607 | for(i=0; i<nColumn; i++){ |
| 2566 | 2608 | const char *z = (const char*)sqlite3_column_name(p->pStmt,i); |
| 2567 | 2609 | int nNL = 0; |
| 2568 | 2610 | int n, w; |
| 2569 | 2611 | pStr = sqlite3_str_new(p->db); |
| | @@ -2584,14 +2626,16 @@ |
| 2584 | 2626 | } |
| 2585 | 2627 | for(i=0; i<nColumn; i++){ |
| 2586 | 2628 | char *z; |
| 2587 | 2629 | int nNL = 0; |
| 2588 | 2630 | int n, w; |
| 2631 | + int eType = sqlite3_column_type(p->pStmt,i); |
| 2589 | 2632 | pStr = sqlite3_str_new(p->db); |
| 2590 | 2633 | qrfRenderValue(p, pStr, i); |
| 2591 | 2634 | n = sqlite3_str_length(pStr); |
| 2592 | 2635 | z = data.az[data.n] = sqlite3_str_finish(pStr); |
| 2636 | + data.abNum[data.n] = eType==SQLITE_INTEGER || eType==SQLITE_FLOAT; |
| 2593 | 2637 | data.aiWth[data.n] = w = qrfDisplayWidth(z, n, &nNL); |
| 2594 | 2638 | data.n++; |
| 2595 | 2639 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 2596 | 2640 | if( nNL ) data.bMultiRow = 1; |
| 2597 | 2641 | } |
| | @@ -2677,11 +2721,16 @@ |
| 2677 | 2721 | }else{ |
| 2678 | 2722 | rowStart = BOX_13; |
| 2679 | 2723 | colSep = BOX_13; |
| 2680 | 2724 | rowSep = BOX_13 "\n"; |
| 2681 | 2725 | } |
| 2682 | | - qrfBoxSeparator(p->pOut, &data, BOX_23, BOX_234, BOX_34); |
| 2726 | + if( p->spec.bBorder==QRF_No){ |
| 2727 | + rowStart += 3; |
| 2728 | + rowSep = "\n"; |
| 2729 | + }else{ |
| 2730 | + qrfBoxSeparator(p->pOut, &data, BOX_23, BOX_234, BOX_34); |
| 2731 | + } |
| 2683 | 2732 | break; |
| 2684 | 2733 | case QRF_STYLE_Table: |
| 2685 | 2734 | if( data.nMargin ){ |
| 2686 | 2735 | rowStart = "| "; |
| 2687 | 2736 | colSep = " | "; |
| | @@ -2689,11 +2738,16 @@ |
| 2689 | 2738 | }else{ |
| 2690 | 2739 | rowStart = "|"; |
| 2691 | 2740 | colSep = "|"; |
| 2692 | 2741 | rowSep = "|\n"; |
| 2693 | 2742 | } |
| 2694 | | - qrfRowSeparator(p->pOut, &data, '+'); |
| 2743 | + if( p->spec.bBorder==QRF_No ){ |
| 2744 | + rowStart += 1; |
| 2745 | + rowSep = "\n"; |
| 2746 | + }else{ |
| 2747 | + qrfRowSeparator(p->pOut, &data, '+'); |
| 2748 | + } |
| 2695 | 2749 | break; |
| 2696 | 2750 | case QRF_STYLE_Column: { |
| 2697 | 2751 | static const char zSpace[] = " "; |
| 2698 | 2752 | rowStart = ""; |
| 2699 | 2753 | if( data.nMargin<2 ){ |
| | @@ -2721,20 +2775,31 @@ |
| 2721 | 2775 | szRowStart = (int)strlen(rowStart); |
| 2722 | 2776 | szRowSep = (int)strlen(rowSep); |
| 2723 | 2777 | szColSep = (int)strlen(colSep); |
| 2724 | 2778 | |
| 2725 | 2779 | bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow); |
| 2726 | | - bRTrim = (p->spec.eStyle==QRF_STYLE_Column); |
| 2780 | + if( p->spec.eStyle==QRF_STYLE_Column |
| 2781 | + || (p->spec.bBorder==QRF_No |
| 2782 | + && (p->spec.eStyle==QRF_STYLE_Box || p->spec.eStyle==QRF_STYLE_Table) |
| 2783 | + ) |
| 2784 | + ){ |
| 2785 | + bRTrim = 1; |
| 2786 | + }else{ |
| 2787 | + bRTrim = 0; |
| 2788 | + } |
| 2727 | 2789 | for(i=0; i<data.n; i+=nColumn){ |
| 2728 | 2790 | int bMore; |
| 2729 | 2791 | int nRow = 0; |
| 2730 | 2792 | |
| 2731 | 2793 | /* Draw a single row of the table. This might be the title line |
| 2732 | 2794 | ** (if there is a title line) or a row in the body of the table. |
| 2733 | 2795 | ** The column number will be j. The row number is i/nColumn. |
| 2734 | 2796 | */ |
| 2735 | | - for(j=0; j<nColumn; j++){ data.a[j].z = data.az[i+j]; } |
| 2797 | + for(j=0; j<nColumn; j++){ |
| 2798 | + data.a[j].z = data.az[i+j]; |
| 2799 | + data.a[j].bNum = data.abNum[i+j]; |
| 2800 | + } |
| 2736 | 2801 | do{ |
| 2737 | 2802 | sqlite3_str_append(p->pOut, rowStart, szRowStart); |
| 2738 | 2803 | bMore = 0; |
| 2739 | 2804 | for(j=0; j<nColumn; j++){ |
| 2740 | 2805 | int nThis = 0; |
| | @@ -2741,11 +2806,11 @@ |
| 2741 | 2806 | int nWide = 0; |
| 2742 | 2807 | int iNext = 0; |
| 2743 | 2808 | int nWS; |
| 2744 | 2809 | qrfWrapLine(data.a[j].z, data.a[j].w, bWW, &nThis, &nWide, &iNext); |
| 2745 | 2810 | nWS = data.a[j].w - nWide; |
| 2746 | | - qrfPrintAligned(p->pOut, data.a[j].z, nThis, nWS, data.a[j].e); |
| 2811 | + qrfPrintAligned(p->pOut, &data.a[j], nThis, nWS); |
| 2747 | 2812 | data.a[j].z += iNext; |
| 2748 | 2813 | if( data.a[j].z[0]!=0 ){ |
| 2749 | 2814 | bMore = 1; |
| 2750 | 2815 | } |
| 2751 | 2816 | if( j<nColumn-1 ){ |
| | @@ -2763,11 +2828,12 @@ |
| 2763 | 2828 | if( data.a[j].z[0]==0 ){ |
| 2764 | 2829 | sqlite3_str_appendchar(p->pOut, data.a[j].w, ' '); |
| 2765 | 2830 | }else{ |
| 2766 | 2831 | int nE = 3; |
| 2767 | 2832 | if( nE>data.a[j].w ) nE = data.a[j].w; |
| 2768 | | - qrfPrintAligned(p->pOut, "...", nE, data.a[j].w-nE, data.a[j].e); |
| 2833 | + data.a[j].z = "..."; |
| 2834 | + qrfPrintAligned(p->pOut, &data.a[j], nE, data.a[j].w-nE); |
| 2769 | 2835 | } |
| 2770 | 2836 | if( j<nColumn-1 ){ |
| 2771 | 2837 | sqlite3_str_append(p->pOut, colSep, szColSep); |
| 2772 | 2838 | }else{ |
| 2773 | 2839 | if( bRTrim ) qrfRTrim(p->pOut); |
| | @@ -2824,17 +2890,19 @@ |
| 2824 | 2890 | } |
| 2825 | 2891 | } |
| 2826 | 2892 | } |
| 2827 | 2893 | |
| 2828 | 2894 | /* Draw the line across the bottom of the table */ |
| 2829 | | - switch( p->spec.eStyle ){ |
| 2830 | | - case QRF_STYLE_Box: |
| 2831 | | - qrfBoxSeparator(p->pOut, &data, BOX_12, BOX_124, BOX_14); |
| 2832 | | - break; |
| 2833 | | - case QRF_STYLE_Table: |
| 2834 | | - qrfRowSeparator(p->pOut, &data, '+'); |
| 2835 | | - break; |
| 2895 | + if( p->spec.bBorder!=QRF_No ){ |
| 2896 | + switch( p->spec.eStyle ){ |
| 2897 | + case QRF_STYLE_Box: |
| 2898 | + qrfBoxSeparator(p->pOut, &data, BOX_12, BOX_124, BOX_14); |
| 2899 | + break; |
| 2900 | + case QRF_STYLE_Table: |
| 2901 | + qrfRowSeparator(p->pOut, &data, '+'); |
| 2902 | + break; |
| 2903 | + } |
| 2836 | 2904 | } |
| 2837 | 2905 | qrfWrite(p); |
| 2838 | 2906 | |
| 2839 | 2907 | qrfColDataFree(&data); |
| 2840 | 2908 | return; |
| | @@ -6010,17 +6078,20 @@ |
| 6010 | 6078 | } |
| 6011 | 6079 | /* End of the hashing logic |
| 6012 | 6080 | *****************************************************************************/ |
| 6013 | 6081 | |
| 6014 | 6082 | /* |
| 6015 | | -** Implementation of the sha1(X) function. |
| 6083 | +** Two SQL functions: sha1(X) and sha1b(X). |
| 6016 | 6084 | ** |
| 6017 | | -** Return a lower-case hexadecimal rendering of the SHA1 hash of the |
| 6018 | | -** argument X. If X is a BLOB, it is hashed as is. For all other |
| 6085 | +** sha1(X) returns a lower-case hexadecimal rendering of the SHA1 hash |
| 6086 | +** of the argument X. If X is a BLOB, it is hashed as is. For all other |
| 6019 | 6087 | ** types of input, X is converted into a UTF-8 string and the string |
| 6020 | | -** is hash without the trailing 0x00 terminator. The hash of a NULL |
| 6088 | +** is hashed without the trailing 0x00 terminator. The hash of a NULL |
| 6021 | 6089 | ** value is NULL. |
| 6090 | +** |
| 6091 | +** sha1b(X) is the same except that it returns a 20-byte BLOB containing |
| 6092 | +** the binary hash instead of a hexadecimal string. |
| 6022 | 6093 | */ |
| 6023 | 6094 | static void sha1Func( |
| 6024 | 6095 | sqlite3_context *context, |
| 6025 | 6096 | int argc, |
| 6026 | 6097 | sqlite3_value **argv |
| | @@ -6037,15 +6108,17 @@ |
| 6037 | 6108 | hash_step(&cx, sqlite3_value_blob(argv[0]), nByte); |
| 6038 | 6109 | }else{ |
| 6039 | 6110 | hash_step(&cx, sqlite3_value_text(argv[0]), nByte); |
| 6040 | 6111 | } |
| 6041 | 6112 | if( sqlite3_user_data(context)!=0 ){ |
| 6113 | + /* sha1b() - binary result */ |
| 6042 | 6114 | hash_finish(&cx, zOut, 1); |
| 6043 | 6115 | sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT); |
| 6044 | 6116 | }else{ |
| 6117 | + /* sha1() - hexadecimal text result */ |
| 6045 | 6118 | hash_finish(&cx, zOut, 0); |
| 6046 | | - sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT); |
| 6119 | + sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); |
| 6047 | 6120 | } |
| 6048 | 6121 | } |
| 6049 | 6122 | |
| 6050 | 6123 | /* |
| 6051 | 6124 | ** Implementation of the sha1_query(SQL) function. |
| | @@ -24117,19 +24190,20 @@ |
| 24117 | 24190 | #define MODE_Json 10 /* Output JSON */ |
| 24118 | 24191 | #define MODE_Line 11 /* One column per line. Blank line between records */ |
| 24119 | 24192 | #define MODE_List 12 /* One record per line with a separator */ |
| 24120 | 24193 | #define MODE_Markdown 13 /* Markdown formatting */ |
| 24121 | 24194 | #define MODE_Off 14 /* No query output shown */ |
| 24122 | | -#define MODE_QBox 15 /* BOX with SQL-quoted content */ |
| 24123 | | -#define MODE_Quote 16 /* Quote values as for SQL */ |
| 24124 | | -#define MODE_Split 17 /* Split-column mode */ |
| 24125 | | -#define MODE_Table 18 /* MySQL-style table formatting */ |
| 24126 | | -#define MODE_Tabs 19 /* Tab-separated values */ |
| 24127 | | -#define MODE_Tcl 20 /* Space-separated list of TCL strings */ |
| 24128 | | -#define MODE_Www 21 /* Full web-page output */ |
| 24129 | | - |
| 24130 | | -#define MODE_BUILTIN 21 /* Maximum built-in mode */ |
| 24195 | +#define MODE_Psql 15 /* Similar to psql */ |
| 24196 | +#define MODE_QBox 16 /* BOX with SQL-quoted content */ |
| 24197 | +#define MODE_Quote 17 /* Quote values as for SQL */ |
| 24198 | +#define MODE_Split 18 /* Split-column mode */ |
| 24199 | +#define MODE_Table 19 /* MySQL-style table formatting */ |
| 24200 | +#define MODE_Tabs 20 /* Tab-separated values */ |
| 24201 | +#define MODE_Tcl 21 /* Space-separated list of TCL strings */ |
| 24202 | +#define MODE_Www 22 /* Full web-page output */ |
| 24203 | + |
| 24204 | +#define MODE_BUILTIN 22 /* Maximum built-in mode */ |
| 24131 | 24205 | #define MODE_BATCH 50 /* Default mode for batch processing */ |
| 24132 | 24206 | #define MODE_TTY 51 /* Default mode for interactive processing */ |
| 24133 | 24207 | #define MODE_USER 75 /* First user-defined mode */ |
| 24134 | 24208 | #define MODE_N_USER 25 /* Maximum number of user-defined modes */ |
| 24135 | 24209 | |
| | @@ -24146,10 +24220,11 @@ |
| 24146 | 24220 | unsigned char eHdr; /* Default header encoding. */ |
| 24147 | 24221 | unsigned char eBlob; /* Default blob encoding. */ |
| 24148 | 24222 | unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ |
| 24149 | 24223 | unsigned char eStyle; /* Underlying QRF style */ |
| 24150 | 24224 | unsigned char eCx; /* 0: other, 1: line, 2: columnar */ |
| 24225 | + unsigned char mFlg; /* Flags. 1=border-off 2=split-column */ |
| 24151 | 24226 | }; |
| 24152 | 24227 | |
| 24153 | 24228 | /* String constants used by built-in modes */ |
| 24154 | 24229 | static const char *aModeStr[] = |
| 24155 | 24230 | /* 0 1 2 3 4 5 6 7 8 */ |
| | @@ -24156,33 +24231,34 @@ |
| 24156 | 24231 | { 0, "\n", "|", " ", ",", "\r\n", "\036", "\037", "\t", |
| 24157 | 24232 | "", "NULL", "null", "\"\"" }; |
| 24158 | 24233 | /* 9 10 11 12 */ |
| 24159 | 24234 | |
| 24160 | 24235 | static const ModeInfo aModeInfo[] = { |
| 24161 | | -/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx */ |
| 24162 | | - { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0 }, |
| 24163 | | - { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2 }, |
| 24164 | | - { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0 }, |
| 24165 | | - { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2 }, |
| 24166 | | - { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0 }, |
| 24167 | | - { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0 }, |
| 24168 | | - { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0 }, |
| 24169 | | - { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0 }, |
| 24170 | | - { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0 }, |
| 24171 | | - { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0 }, |
| 24172 | | - { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0 }, |
| 24173 | | - { "line", 0, 1, 9, 1, 1, 0, 0, 11, 1 }, |
| 24174 | | - { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0 }, |
| 24175 | | - { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2 }, |
| 24176 | | - { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0 }, |
| 24177 | | - { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2 }, |
| 24178 | | - { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0 }, |
| 24179 | | - { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2 }, |
| 24180 | | - { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2 }, |
| 24181 | | - { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0 }, |
| 24182 | | - { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0 }, |
| 24183 | | - { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0 } |
| 24236 | +/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ |
| 24237 | + { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 24238 | + { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 }, |
| 24239 | + { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, |
| 24240 | + { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 }, |
| 24241 | + { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, |
| 24242 | + { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 24243 | + { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }, |
| 24244 | + { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, |
| 24245 | + { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, |
| 24246 | + { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, |
| 24247 | + { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, |
| 24248 | + { "line", 0, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, |
| 24249 | + { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 24250 | + { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 }, |
| 24251 | + { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, |
| 24252 | + { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 }, |
| 24253 | + { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 }, |
| 24254 | + { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, |
| 24255 | + { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, |
| 24256 | + { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 }, |
| 24257 | + { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 24258 | + { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, |
| 24259 | + { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 } |
| 24184 | 24260 | }; /* | / / | / / | | \ |
| 24185 | 24261 | ** | / / | / / | | \_ 2: columnar |
| 24186 | 24262 | ** Index into aModeStr[] | / / | | 1: line |
| 24187 | 24263 | ** | / / | | 0: other |
| 24188 | 24264 | ** | / / | \ |
| | @@ -24304,11 +24380,16 @@ |
| 24304 | 24380 | if( pI->eNull ) modeSetStr(&pM->spec.zNull, aModeStr[pI->eNull]); |
| 24305 | 24381 | pM->spec.eText = pI->eText; |
| 24306 | 24382 | pM->spec.eBlob = pI->eBlob; |
| 24307 | 24383 | pM->spec.bTitles = pI->bHdr; |
| 24308 | 24384 | pM->spec.eTitle = pI->eHdr; |
| 24309 | | - if( eMode==MODE_Split ){ |
| 24385 | + if( pI->mFlg & 0x01 ){ |
| 24386 | + pM->spec.bBorder = QRF_No; |
| 24387 | + }else{ |
| 24388 | + pM->spec.bBorder = QRF_Auto; |
| 24389 | + } |
| 24390 | + if( pI->mFlg & 0x02 ){ |
| 24310 | 24391 | pM->spec.bSplitColumn = QRF_Yes; |
| 24311 | 24392 | pM->bAutoScreenWidth = 1; |
| 24312 | 24393 | }else{ |
| 24313 | 24394 | pM->spec.bSplitColumn = QRF_No; |
| 24314 | 24395 | } |
| | @@ -26622,10 +26703,11 @@ |
| 26622 | 26703 | " meaning \"left\", \"centered\", and \"right\", with\n" |
| 26623 | 26704 | " one letter per column starting from the left.\n" |
| 26624 | 26705 | " Unspecified alignment defaults to 'L'.\n" |
| 26625 | 26706 | " --blob-quote ARG ARG can be \"auto\", \"text\", \"sql\", \"hex\", \"tcl\",\n" |
| 26626 | 26707 | " \"json\", or \"size\". Default is \"auto\".\n" |
| 26708 | +" --border on|off Show outer border on \"box\" and \"table\" modes.\n" |
| 26627 | 26709 | " --charlimit N Set the maximum number of output characters to\n" |
| 26628 | 26710 | " show for any single SQL value to N. Longer values\n" |
| 26629 | 26711 | " truncated. Zero means \"no limit\".\n" |
| 26630 | 26712 | " --colsep STRING Use STRING as the column separator\n" |
| 26631 | 26713 | " --escape ESC Enable/disable escaping of control characters\n" |
| | @@ -30505,10 +30587,11 @@ |
| 30505 | 30587 | ** meaning "left", "centered", and "right", with |
| 30506 | 30588 | ** one letter per column starting from the left. |
| 30507 | 30589 | ** Unspecified alignment defaults to 'L'. |
| 30508 | 30590 | ** --blob-quote ARG ARG can be "auto", "text", "sql", "hex", "tcl", |
| 30509 | 30591 | ** "json", or "size". Default is "auto". |
| 30592 | +** --border on|off Show outer border on "box" and "table" modes. |
| 30510 | 30593 | ** --charlimit N Set the maximum number of output characters to |
| 30511 | 30594 | ** show for any single SQL value to N. Longer values |
| 30512 | 30595 | ** truncated. Zero means "no limit". |
| 30513 | 30596 | ** --colsep STRING Use STRING as the column separator |
| 30514 | 30597 | ** --escape ESC Enable/disable escaping of control characters |
| | @@ -30622,10 +30705,20 @@ |
| 30622 | 30705 | /* 0 1 2 3 4 5 6 |
| 30623 | 30706 | ** Must match QRF_BLOB_xxxx values. See also tag-20251124a */ |
| 30624 | 30707 | if( k>=0 ){ |
| 30625 | 30708 | p->mode.spec.eBlob = k & 0xff; |
| 30626 | 30709 | } |
| 30710 | + chng = 1; |
| 30711 | + }else if( optionMatch(z,"border") ){ |
| 30712 | + if( (++i)>=nArg ){ |
| 30713 | + dotCmdError(p, i-1, "missing argument", 0); |
| 30714 | + return 1; |
| 30715 | + } |
| 30716 | + k = pickStr(azArg[i], 0, "auto", "off", "on", ""); |
| 30717 | + if( k>=0 ){ |
| 30718 | + p->mode.spec.bBorder = k & 0x3; |
| 30719 | + } |
| 30627 | 30720 | chng = 1; |
| 30628 | 30721 | }else if( 0<=(k=pickStr(z,0,"-charlimit","-linelimit","")) ){ |
| 30629 | 30722 | int w; /* 0 1 */ |
| 30630 | 30723 | if( i+1>=nArg ){ |
| 30631 | 30724 | dotCmdError(p, i, "missing argument", 0); |
| | @@ -30844,16 +30937,16 @@ |
| 30844 | 30937 | zW = azArg[++i]; |
| 30845 | 30938 | /* Every width value takes at least 2 bytes in the input string to |
| 30846 | 30939 | ** specify, so strlen(zW) bytes should be plenty of space to hold the |
| 30847 | 30940 | ** result. */ |
| 30848 | 30941 | aWidth = malloc( strlen(zW) ); |
| 30849 | | - while( isspace(zW[0]) ) zW++; |
| 30942 | + while( IsSpace(zW[0]) ) zW++; |
| 30850 | 30943 | while( zW[0] ){ |
| 30851 | 30944 | int w = 0; |
| 30852 | 30945 | int nDigit = 0; |
| 30853 | | - k = zW[0]=='-' && isdigit(zW[1]); |
| 30854 | | - while( isdigit(zW[k]) ){ |
| 30946 | + k = zW[0]=='-' && IsDigit(zW[1]); |
| 30947 | + while( IsDigit(zW[k]) ){ |
| 30855 | 30948 | w = w*10 + zW[k] - '0'; |
| 30856 | 30949 | if( w>QRF_MAX_WIDTH ){ |
| 30857 | 30950 | dotCmdError(p,i+1,"width too big", |
| 30858 | 30951 | "Maximum column width is %d", QRF_MAX_WIDTH); |
| 30859 | 30952 | free(aWidth); |
| | @@ -30870,11 +30963,11 @@ |
| 30870 | 30963 | } |
| 30871 | 30964 | if( zW[0]=='-' ) w = -w; |
| 30872 | 30965 | aWidth[nWidth++] = w; |
| 30873 | 30966 | zW += k; |
| 30874 | 30967 | if( zW[0]==',' ) zW++; |
| 30875 | | - while( isspace(zW[0]) ) zW++; |
| 30968 | + while( IsSpace(zW[0]) ) zW++; |
| 30876 | 30969 | } |
| 30877 | 30970 | free(p->mode.spec.aWidth); |
| 30878 | 30971 | p->mode.spec.aWidth = aWidth; |
| 30879 | 30972 | p->mode.spec.nWidth = nWidth; |
| 30880 | 30973 | chng = 1; |
| | @@ -30925,10 +31018,16 @@ |
| 30925 | 31018 | unsigned char a = p->mode.spec.aAlign[ii]; |
| 30926 | 31019 | sqlite3_str_appendchar(pDesc, 1, "LLCR"[a&3]); |
| 30927 | 31020 | } |
| 30928 | 31021 | sqlite3_str_append(pDesc, "\"", 1); |
| 30929 | 31022 | } |
| 31023 | + if( bAll |
| 31024 | + || (p->mode.spec.bBorder==QRF_No) != ((pI->mFlg&1)!=0) |
| 31025 | + ){ |
| 31026 | + sqlite3_str_appendf(pDesc," --border %s", |
| 31027 | + p->mode.spec.bBorder==QRF_No ? "off" : "on"); |
| 31028 | + } |
| 30930 | 31029 | if( bAll || p->mode.spec.eBlob!=QRF_BLOB_Auto ){ |
| 30931 | 31030 | const char *azBQuote[] = |
| 30932 | 31031 | { "auto", "text", "sql", "hex", "tcl", "json", "size" }; |
| 30933 | 31032 | /* 0 1 2 3 4 5 6 |
| 30934 | 31033 | ** Must match QRF_BLOB_xxxx values. See all instances of tag-20251124a */ |
| | @@ -33669,11 +33768,10 @@ |
| 33669 | 33768 | |
| 33670 | 33769 | if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0) |
| 33671 | 33770 | || (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0 |
| 33672 | 33771 | || cli_strncmp(azArg[0], "indexes", n)==0) ) |
| 33673 | 33772 | ){ |
| 33674 | | - int ii; |
| 33675 | 33773 | sqlite3_stmt *pStmt; |
| 33676 | 33774 | sqlite3_str *pSql; |
| 33677 | 33775 | const char *zPattern = nArg>1 ? azArg[1] : 0; |
| 33678 | 33776 | |
| 33679 | 33777 | open_db(p, 0); |
| | @@ -33691,11 +33789,11 @@ |
| 33691 | 33789 | rc = 1; |
| 33692 | 33790 | sqlite3_finalize(pStmt); |
| 33693 | 33791 | goto meta_command_exit; |
| 33694 | 33792 | } |
| 33695 | 33793 | pSql = sqlite3_str_new(p->db); |
| 33696 | | - for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ |
| 33794 | + while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 33697 | 33795 | const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); |
| 33698 | 33796 | if( zDbName==0 ) continue; |
| 33699 | 33797 | if( sqlite3_str_length(pSql) ){ |
| 33700 | 33798 | sqlite3_str_appendall(pSql, " UNION ALL "); |
| 33701 | 33799 | } |
| | @@ -35584,11 +35682,12 @@ |
| 35584 | 35682 | data.pAuxDb->zDbFilename = ":memory:"; |
| 35585 | 35683 | warnInmemoryDb = argc==1; |
| 35586 | 35684 | #else |
| 35587 | 35685 | cli_printf(stderr, |
| 35588 | 35686 | "%s: Error: no database filename specified\n", Argv0); |
| 35589 | | - return 1; |
| 35687 | + rc = 1; |
| 35688 | + goto shell_main_exit; |
| 35590 | 35689 | #endif |
| 35591 | 35690 | } |
| 35592 | 35691 | data.out = stdout; |
| 35593 | 35692 | if( bEnableVfstrace ){ |
| 35594 | 35693 | vfstrace_register("trace",0,vfstraceOut, &data, 1); |
| | @@ -35638,10 +35737,12 @@ |
| 35638 | 35737 | modeChange(&data, MODE_Json); |
| 35639 | 35738 | }else if( cli_strcmp(z,"-markdown")==0 ){ |
| 35640 | 35739 | modeChange(&data, MODE_Markdown); |
| 35641 | 35740 | }else if( cli_strcmp(z,"-table")==0 ){ |
| 35642 | 35741 | modeChange(&data, MODE_Table); |
| 35742 | + }else if( cli_strcmp(z,"-psql")==0 ){ |
| 35743 | + modeChange(&data, MODE_Psql); |
| 35643 | 35744 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 35644 | 35745 | modeChange(&data, MODE_Box); |
| 35645 | 35746 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 35646 | 35747 | modeChange(&data, MODE_Csv); |
| 35647 | 35748 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| | @@ -35724,11 +35825,12 @@ |
| 35724 | 35825 | }else if( cli_strcmp(z,"-bail")==0 ){ |
| 35725 | 35826 | /* No-op. The bail_on_error flag should already be set. */ |
| 35726 | 35827 | }else if( cli_strcmp(z,"-version")==0 ){ |
| 35727 | 35828 | cli_printf(stdout, "%s %s (%d-bit)\n", |
| 35728 | 35829 | sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*)); |
| 35729 | | - return 0; |
| 35830 | + rc = 0; |
| 35831 | + goto shell_main_exit; |
| 35730 | 35832 | }else if( cli_strcmp(z,"-interactive")==0 ){ |
| 35731 | 35833 | /* Need to check for interactive override here to so that it can |
| 35732 | 35834 | ** affect console setup (for Windows only) and testing thereof. |
| 35733 | 35835 | */ |
| 35734 | 35836 | stdin_is_interactive = 1; |
| | @@ -35781,29 +35883,33 @@ |
| 35781 | 35883 | ** we retain the goofy behavior for historical compatibility. */ |
| 35782 | 35884 | if( i==argc-1 ) break; |
| 35783 | 35885 | z = cmdline_option_value(argc,argv,++i); |
| 35784 | 35886 | if( z[0]=='.' ){ |
| 35785 | 35887 | rc = do_meta_command(z, &data); |
| 35786 | | - if( rc && bail_on_error ) return rc==2 ? 0 : rc; |
| 35888 | + if( rc && bail_on_error ){ |
| 35889 | + if( rc==2 ) rc = 0; |
| 35890 | + goto shell_main_exit; |
| 35891 | + } |
| 35787 | 35892 | }else{ |
| 35788 | 35893 | open_db(&data, 0); |
| 35789 | 35894 | rc = shell_exec(&data, z, &zErrMsg); |
| 35790 | 35895 | if( zErrMsg!=0 ){ |
| 35791 | 35896 | shellEmitError(zErrMsg); |
| 35792 | 35897 | sqlite3_free(zErrMsg); |
| 35793 | | - if( bail_on_error ) return rc!=0 ? rc : 1; |
| 35898 | + if( !rc ) rc = 1; |
| 35794 | 35899 | }else if( rc!=0 ){ |
| 35795 | 35900 | cli_printf(stderr,"Error: unable to process SQL \"%s\"\n", z); |
| 35796 | | - if( bail_on_error ) return rc; |
| 35797 | 35901 | } |
| 35902 | + if( bail_on_error ) goto shell_main_exit; |
| 35798 | 35903 | } |
| 35799 | 35904 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) |
| 35800 | 35905 | }else if( cli_strncmp(z, "-A", 2)==0 ){ |
| 35801 | 35906 | if( nCmd>0 ){ |
| 35802 | 35907 | cli_printf(stderr,"Error: cannot mix regular SQL or dot-commands" |
| 35803 | 35908 | " with \"%s\"\n", z); |
| 35804 | | - return 1; |
| 35909 | + rc = 1; |
| 35910 | + goto shell_main_exit; |
| 35805 | 35911 | } |
| 35806 | 35912 | open_db(&data, OPEN_DB_ZIPFILE); |
| 35807 | 35913 | if( z[2] ){ |
| 35808 | 35914 | argv[i] = &z[2]; |
| 35809 | 35915 | arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); |
| | @@ -35819,11 +35925,12 @@ |
| 35819 | 35925 | }else if( cli_strcmp(z,"-unsafe-testing")==0 ){ |
| 35820 | 35926 | /* Acted upon in first pass. */ |
| 35821 | 35927 | }else{ |
| 35822 | 35928 | cli_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); |
| 35823 | 35929 | eputz("Use -help for a list of options.\n"); |
| 35824 | | - return 1; |
| 35930 | + rc = 1; |
| 35931 | + goto shell_main_exit; |
| 35825 | 35932 | } |
| 35826 | 35933 | } |
| 35827 | 35934 | |
| 35828 | 35935 | if( !readStdin ){ |
| 35829 | 35936 | /* Run all arguments that do not begin with '-' as if they were separate |
| 35830 | 35937 | |