Fossil

Diff
Login

Diff

Differences From Artifact [62e4e4943e]:

To Artifact [63883c8ad2]:


679
680
681
682
683
684
685



686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705

706
707
708
709
710
711
712
**
*************************************************************************
** Header file for the Result-Format or "resfmt" utility library for SQLite.
** See the resfmt.md documentation for additional information.
*/
#ifndef SQLITE_QRF_H
#define SQLITE_QRF_H



#include <stdlib.h>
/* #include "sqlite3.h" */

/*
** Specification used by clients to define the output format they want
*/
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
struct sqlite3_qrf_spec {
  unsigned char iVersion;     /* Version number of this structure */
  unsigned char eStyle;       /* Formatting style.  "box", "csv", etc... */
  unsigned char eEsc;         /* How to escape control characters in text */
  unsigned char eText;        /* Quoting style for text */
  unsigned char eTitle;       /* Quating style for the text of column names */
  unsigned char eBlob;        /* Quoting style for BLOBs */
  unsigned char bTitles;      /* True to show column names */
  unsigned char bWordWrap;    /* Try to wrap on word boundaries */
  unsigned char bTextJsonb;   /* Render JSONB blobs as JSON text */
  unsigned char bTextNull;    /* Apply eText encoding to zNull[] */
  unsigned char eDfltAlign;   /* Default alignment, no covered by aAlignment */
  unsigned char eTitleAlign;  /* Alignment for column headers */

  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 */
  int nCharLimit;             /* Maximum number of characters in a cell */
  int nWidth;                 /* Number of entries in aWidth[] */
  int nAlign;                 /* Number of entries in aAlignment[] */
  short int *aWidth;          /* Column widths */







>
>
>




















>







679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
**
*************************************************************************
** Header file for the Result-Format or "resfmt" utility library for SQLite.
** See the resfmt.md documentation for additional information.
*/
#ifndef SQLITE_QRF_H
#define SQLITE_QRF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/* #include "sqlite3.h" */

/*
** Specification used by clients to define the output format they want
*/
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
struct sqlite3_qrf_spec {
  unsigned char iVersion;     /* Version number of this structure */
  unsigned char eStyle;       /* Formatting style.  "box", "csv", etc... */
  unsigned char eEsc;         /* How to escape control characters in text */
  unsigned char eText;        /* Quoting style for text */
  unsigned char eTitle;       /* Quating style for the text of column names */
  unsigned char eBlob;        /* Quoting style for BLOBs */
  unsigned char bTitles;      /* True to show column names */
  unsigned char bWordWrap;    /* Try to wrap on word boundaries */
  unsigned char bTextJsonb;   /* Render JSONB blobs as JSON text */
  unsigned char bTextNull;    /* Apply eText encoding to zNull[] */
  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 */
  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 */
  int nCharLimit;             /* Maximum number of characters in a cell */
  int nWidth;                 /* Number of entries in aWidth[] */
  int nAlign;                 /* Number of entries in aAlignment[] */
  short int *aWidth;          /* Column widths */
844
845
846
847
848
849
850
851
852

853
854
855
856
857
858
859
** it is impossible to know that true display width with 100% accuracy.
** Inaccuracies in the width estimates might cause columns to be misaligned.
** Unfortunately, there is nothing we can do about that.
*/
int sqlite3_qrf_wcwidth(int c);





#endif /* !defined(SQLITE_QRF_H) */

/************************* End ext/qrf/qrf.h ********************/
/************************* Begin ext/qrf/qrf.c ******************/
/*
** 2025-10-20
**







|
|
>







848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
** it is impossible to know that true display width with 100% accuracy.
** Inaccuracies in the width estimates might cause columns to be misaligned.
** Unfortunately, there is nothing we can do about that.
*/
int sqlite3_qrf_wcwidth(int c);


#ifdef __cplusplus
}
#endif
#endif /* !defined(SQLITE_QRF_H) */

/************************* End ext/qrf/qrf.h ********************/
/************************* Begin ext/qrf/qrf.c ******************/
/*
** 2025-10-20
**
1893
1894
1895
1896
1897
1898
1899











1900
1901
1902
1903
1904
1905
1906
    if( w>limit ){
      sqlite3_str_truncate(pOut, iStartLen+ii);
      sqlite3_str_append(pOut, "...", 3);
    }
  }
#endif
}












/*
** Store string zUtf to pOut as w characters.  If w is negative,
** then right-justify the text.  W is the width in display characters, not
** in bytes.  Double-width unicode characters count as two characters.
** VT100 escape sequences count as zero.  And so forth.
*/







>
>
>
>
>
>
>
>
>
>
>







1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
    if( w>limit ){
      sqlite3_str_truncate(pOut, iStartLen+ii);
      sqlite3_str_append(pOut, "...", 3);
    }
  }
#endif
}

/* Trim spaces of the end if pOut
*/
static void qrfRTrim(sqlite3_str *pOut){
#if SQLITE_VERSION_NUMBER>=3052000
  int nByte = sqlite3_str_length(pOut);
  const char *zOut = sqlite3_str_value(pOut);
  while( nByte>0 && zOut[nByte-1]==' ' ){ nByte--; }
  sqlite3_str_truncate(pOut, nByte);
#endif
}

/*
** Store string zUtf to pOut as w characters.  If w is negative,
** then right-justify the text.  W is the width in display characters, not
** in bytes.  Double-width unicode characters count as two characters.
** VT100 escape sequences count as zero.  And so forth.
*/
2303
2304
2305
2306
2307
2308
2309





























































































































2310
2311
2312
2313
2314
2315
2316
      if( p->spec.aWidth[i]<0 ){
         pData->a[i].e = QRF_ALIGN_Right |
                               (pData->a[i].e & QRF_ALIGN_VMASK);
      }
    }
  }
}






























































































































/*
** Adjust the layout for the screen width restriction
*/
static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){
  int sepW;             /* Width of all box separators and margins */
  int sumW;             /* Total width of data area over all columns */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
      if( p->spec.aWidth[i]<0 ){
         pData->a[i].e = QRF_ALIGN_Right |
                               (pData->a[i].e & QRF_ALIGN_VMASK);
      }
    }
  }
}

/*
** If the single column in pData->a[] with pData->n entries can be
** laid out as nCol columns with a 2-space gap between each such
** that all columns fit within nSW, then return a pointer to an array
** of integers which is the width of each column from left to right.
**
** If the layout is not possible, return a NULL pointer.
**
** Space to hold the returned array is from sqlite_malloc64().
*/
static int *qrfValidLayout(
  qrfColData *pData,   /* Collected query results */
  Qrf *p,              /* On which to report an OOM */
  int nCol,            /* Attempt this many columns */
  int nSW              /* Screen width */
){
  int i;        /* Loop counter */
  int nr;       /* Number of rows */
  int w = 0;    /* Width of the current column */
  int t;        /* Total width of all columns */
  int *aw;      /* Array of individual column widths */

  aw = sqlite3_malloc64( sizeof(int)*nCol );
  if( aw==0 ){
    qrfOom(p);
    return 0;
  }
  nr = (pData->n + nCol - 1)/nCol;
  for(i=0; i<pData->n; i++){
    if( (i%nr)==0 ){
      if( i>0 ) aw[i/nr-1] = w;
      w = pData->aiWth[i];
    }else if( pData->aiWth[i]>w ){
      w = pData->aiWth[i];
    }
  }
  aw[nCol-1] = w;
  for(t=i=0; i<nCol; i++) t += aw[i];
  t += 2*(nCol-1);
  if( t>nSW ){
    sqlite3_free(aw);
    return 0;
  }
  return aw;
}

/*
** The output is single-column and the bSplitColumn flag is set.
** Check to see if the single-column output can be split into multiple
** columns that appear side-by-side.  Adjust pData appropriately.
*/
static void qrfSplitColumn(qrfColData *pData, Qrf *p){
  int nCol = 1;
  int *aw = 0;
  char **az = 0;
  int *aiWth = 0;
  int nColNext = 2;
  int w;
  struct qrfPerCol *a = 0;
  sqlite3_int64 nRow = 1;
  sqlite3_int64 i;
  while( 1/*exit-by-break*/ ){
    int *awNew = qrfValidLayout(pData, p, nColNext, p->spec.nScreenWidth);
    if( awNew==0 ) break;
    sqlite3_free(aw);
    aw = awNew;
    nCol = nColNext;
    nRow = (pData->n + nCol - 1)/nCol;
    if( nRow==1 ) break;
    nColNext++;
    while( (pData->n + nColNext - 1)/nColNext == nRow ) nColNext++;
  }
  if( nCol==1 ){
    sqlite3_free(aw);
    return;  /* Cannot do better than 1 column */
  }
  az = sqlite3_malloc64( nRow*nCol*sizeof(char*) );
  if( az==0 ){
    qrfOom(p);
    return;
  }
  aiWth = sqlite3_malloc64( nRow*nCol*sizeof(int) );
  if( aiWth==0 ){
    sqlite3_free(az);
    qrfOom(p);
    return;
  }
  a = sqlite3_malloc64( nCol*sizeof(struct qrfPerCol) );
  if( a==0 ){
    sqlite3_free(az);
    sqlite3_free(aiWth);
    qrfOom(p);
    return;
  }
  for(i=0; i<pData->n; i++){
    sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
    az[j] = pData->az[i];
    pData->az[i] = 0;
    aiWth[j] = pData->aiWth[i];
  }
  while( i<nRow*nCol ){
    sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
    az[j] = sqlite3_mprintf("");
    if( az[j]==0 ) qrfOom(p);
    aiWth[j] = 0;
    i++;
  }
  for(i=0; i<nCol; i++){
    a[i].fx = a[i].mxW = a[i].w = aw[i];
    a[i].e = pData->a[0].e;
  }
  sqlite3_free(pData->az);
  sqlite3_free(pData->aiWth);
  sqlite3_free(pData->a);
  sqlite3_free(aw);
  pData->az = az;
  pData->aiWth = aiWth;
  pData->a = a;
  pData->nCol = nCol;
  pData->n = pData->nAlloc = nRow*nCol;
  for(i=w=0; i<nCol; i++) w += a[i].w;
  pData->nMargin = (p->spec.nScreenWidth - w)/(nCol - 1);
  if( pData->nMargin>5 ) pData->nMargin = 5;
}

/*
** Adjust the layout for the screen width restriction
*/
static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){
  int sepW;             /* Width of all box separators and margins */
  int sumW;             /* Total width of data area over all columns */
2393
2394
2395
2396
2397
2398
2399

2400
2401
2402
2403
2404
2405
2406
  const char *rowStart = 0;               /* Row start text */
  int szColSep, szRowSep, szRowStart;     /* Size in bytes of previous 3 */
  int rc;                                 /* Result code */
  int nColumn = p->nCol;                  /* Number of columns */
  int bWW;                                /* True to do word-wrap */
  sqlite3_str *pStr;                      /* Temporary rendering */
  qrfColData data;                        /* Columnar layout data */


  rc = sqlite3_step(p->pStmt);
  if( rc!=SQLITE_ROW || nColumn==0 ){
    return;   /* No output */
  }

  /* Initialize the data container */







>







2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
  const char *rowStart = 0;               /* Row start text */
  int szColSep, szRowSep, szRowStart;     /* Size in bytes of previous 3 */
  int rc;                                 /* Result code */
  int nColumn = p->nCol;                  /* Number of columns */
  int bWW;                                /* True to do word-wrap */
  sqlite3_str *pStr;                      /* Temporary rendering */
  qrfColData data;                        /* Columnar layout data */
  int bRTrim;                             /* Trim trailing space */

  rc = sqlite3_step(p->pStmt);
  if( rc!=SQLITE_ROW || nColumn==0 ){
    return;   /* No output */
  }

  /* Initialize the data container */
2502
2503
2504
2505
2506
2507
2508













2509
2510

2511
2512
2513
2514
2515
2516
2517
        ** character somewhere.  So make the column width at least 2. */
        w = 2;
      }
    }
    data.a[i].w = w;
  }














  /* Adjust the column widths due to screen width restrictions */
  qrfRestrictScreenWidth(&data, p);


  /* Draw the line across the top of the table.  Also initialize
  ** the row boundary and column separator texts. */
  switch( p->spec.eStyle ){
    case QRF_STYLE_Box:
      if( data.nMargin ){
        rowStart = BOX_13 " ";







>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>







2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
        ** character somewhere.  So make the column width at least 2. */
        w = 2;
      }
    }
    data.a[i].w = w;
  }

  if( nColumn==1
   && data.n>1
   && p->spec.bSplitColumn==QRF_Yes
   && p->spec.eStyle==QRF_STYLE_Column
   && p->spec.bTitles==QRF_No
   && p->spec.nScreenWidth>data.a[0].w+3
  ){
    /* Attempt to convert single-column tables into multi-column by
    ** verticle wrapping, if the screen is wide enough and if the
    ** bSplitColumn flag is set. */
    qrfSplitColumn(&data, p);
    nColumn = data.nCol;
  }else{
    /* Adjust the column widths due to screen width restrictions */
    qrfRestrictScreenWidth(&data, p);
  }

  /* Draw the line across the top of the table.  Also initialize
  ** the row boundary and column separator texts. */
  switch( p->spec.eStyle ){
    case QRF_STYLE_Box:
      if( data.nMargin ){
        rowStart = BOX_13 " ";
2534
2535
2536
2537
2538
2539
2540

2541





2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560

2561
2562
2563
2564
2565
2566
2567
        colSep = "|";
        rowSep = "|\n";
      }
      qrfRowSeparator(p->pOut, &data, '+');
      break;
    case QRF_STYLE_Column:
      rowStart = "";

      colSep = data.nMargin ? "  " : " ";





      rowSep = "\n";
      break;
    default:  /*case QRF_STYLE_Markdown:*/
      if( data.nMargin ){
        rowStart = "| ";
        colSep = " | ";
        rowSep = " |\n";
      }else{
        rowStart = "|";
        colSep = "|";
        rowSep = "|\n";
      }
      break;
  }
  szRowStart = (int)strlen(rowStart);
  szRowSep = (int)strlen(rowSep);
  szColSep = (int)strlen(colSep);

  bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow);

  for(i=0; i<data.n; i+=nColumn){
    int bMore;
    int nRow = 0;

    /* Draw a single row of the table.  This might be the title line
    ** (if there is a title line) or a row in the body of the table.
    ** The column number will be j.  The row number is i/nColumn.







>
|
>
>
>
>
>



















>







2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
        colSep = "|";
        rowSep = "|\n";
      }
      qrfRowSeparator(p->pOut, &data, '+');
      break;
    case QRF_STYLE_Column:
      rowStart = "";
      if( data.nMargin<2 ){
        colSep = " ";
      }else if( data.nMargin<=5 ){
        colSep = "     " + (5-data.nMargin);
      }else{
        colSep = "     ";
      }
      rowSep = "\n";
      break;
    default:  /*case QRF_STYLE_Markdown:*/
      if( data.nMargin ){
        rowStart = "| ";
        colSep = " | ";
        rowSep = " |\n";
      }else{
        rowStart = "|";
        colSep = "|";
        rowSep = "|\n";
      }
      break;
  }
  szRowStart = (int)strlen(rowStart);
  szRowSep = (int)strlen(rowSep);
  szColSep = (int)strlen(colSep);

  bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow);
  bRTrim = (p->spec.eStyle==QRF_STYLE_Column);
  for(i=0; i<data.n; i+=nColumn){
    int bMore;
    int nRow = 0;

    /* Draw a single row of the table.  This might be the title line
    ** (if there is a title line) or a row in the body of the table.
    ** The column number will be j.  The row number is i/nColumn.
2575
2576
2577
2578
2579
2580
2581
2582


2583
2584
2585

2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603

2604
2605
2606
2607
2608
2609
2610
        int nWide = 0;
        int iNext = 0;
        int nWS;
        qrfWrapLine(data.a[j].z, data.a[j].w, bWW, &nThis, &nWide, &iNext);
        nWS = data.a[j].w - nWide;
        qrfPrintAligned(p->pOut, data.a[j].z, nThis, nWS, data.a[j].e);
        data.a[j].z += iNext;
        if( data.a[j].z[0]!=0 ) bMore = 1;


        if( j<nColumn-1 ){
          sqlite3_str_append(p->pOut, colSep, szColSep);
        }else{

          sqlite3_str_append(p->pOut, rowSep, szRowSep);
        }
      }
    }while( bMore && ++nRow < p->mxHeight );
    if( bMore ){
      /* This row was terminated by nLineLimit.  Show ellipsis. */
      sqlite3_str_append(p->pOut, rowStart, szRowStart);
      for(j=0; j<nColumn; j++){
        if( data.a[j].z[0]==0 ){
          sqlite3_str_appendchar(p->pOut, data.a[j].w, ' ');
        }else{
          int nE = 3;
          if( nE>data.a[j].w ) nE = data.a[j].w;
          qrfPrintAligned(p->pOut, "...", nE, data.a[j].w-nE, data.a[j].e);
        }
        if( j<nColumn-1 ){
          sqlite3_str_append(p->pOut, colSep, szColSep);
        }else{

          sqlite3_str_append(p->pOut, rowSep, szRowSep);
        }
      }
    }

    /* Draw either (1) the separator between the title line and the body
    ** of the table, or (2) separators between individual rows of the table







|
>
>



>


















>







2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
        int nWide = 0;
        int iNext = 0;
        int nWS;
        qrfWrapLine(data.a[j].z, data.a[j].w, bWW, &nThis, &nWide, &iNext);
        nWS = data.a[j].w - nWide;
        qrfPrintAligned(p->pOut, data.a[j].z, nThis, nWS, data.a[j].e);
        data.a[j].z += iNext;
        if( data.a[j].z[0]!=0 ){
          bMore = 1;
        }
        if( j<nColumn-1 ){
          sqlite3_str_append(p->pOut, colSep, szColSep);
        }else{
          if( bRTrim ) qrfRTrim(p->pOut);
          sqlite3_str_append(p->pOut, rowSep, szRowSep);
        }
      }
    }while( bMore && ++nRow < p->mxHeight );
    if( bMore ){
      /* This row was terminated by nLineLimit.  Show ellipsis. */
      sqlite3_str_append(p->pOut, rowStart, szRowStart);
      for(j=0; j<nColumn; j++){
        if( data.a[j].z[0]==0 ){
          sqlite3_str_appendchar(p->pOut, data.a[j].w, ' ');
        }else{
          int nE = 3;
          if( nE>data.a[j].w ) nE = data.a[j].w;
          qrfPrintAligned(p->pOut, "...", nE, data.a[j].w-nE, data.a[j].e);
        }
        if( j<nColumn-1 ){
          sqlite3_str_append(p->pOut, colSep, szColSep);
        }else{
          if( bRTrim ) qrfRTrim(p->pOut);
          sqlite3_str_append(p->pOut, rowSep, szRowSep);
        }
      }
    }

    /* Draw either (1) the separator between the title line and the body
    ** of the table, or (2) separators between individual rows of the table
2637
2638
2639
2640
2641
2642
2643

2644
2645
2646
2647

2648
2649
2650
2651
2652
2653
2654
        case QRF_STYLE_Column: {
          if( isTitleDataSeparator ){
            for(j=0; j<nColumn; j++){
              sqlite3_str_appendchar(p->pOut, data.a[j].w, '-');
              if( j<nColumn-1 ){
                sqlite3_str_append(p->pOut, colSep, szColSep);
              }else{

                sqlite3_str_append(p->pOut, rowSep, szRowSep);
              }
            }
          }else if( data.bMultiRow ){

            sqlite3_str_append(p->pOut, "\n", 1);
          }
          break;
        }
      }
    }
  }







>




>







2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
        case QRF_STYLE_Column: {
          if( isTitleDataSeparator ){
            for(j=0; j<nColumn; j++){
              sqlite3_str_appendchar(p->pOut, data.a[j].w, '-');
              if( j<nColumn-1 ){
                sqlite3_str_append(p->pOut, colSep, szColSep);
              }else{
                qrfRTrim(p->pOut);
                sqlite3_str_append(p->pOut, rowSep, szRowSep);
              }
            }
          }else if( data.bMultiRow ){
            qrfRTrim(p->pOut);
            sqlite3_str_append(p->pOut, "\n", 1);
          }
          break;
        }
      }
    }
  }
23944
23945
23946
23947
23948
23949
23950

23951
23952
23953
23954
23955
23956
23957
23958
23959
23960
23961
23962
23963
#define MODE_Json     10  /* Output JSON */
#define MODE_Line     11  /* One column per line.  Blank line between records */
#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_Table    17  /* MySQL-style table formatting */
#define MODE_Tabs     18  /* Tab-separated values */
#define MODE_Tcl      19  /* Space-separated list of TCL strings */
#define MODE_Www      20  /* Full web-page output */

#define MODE_BUILTIN  20  /* 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 */
#define MODE_N_USER   25  /* Maximum number of user-defined modes */

/*
** Information about built-in display modes







>
|
|
|
|

|







24113
24114
24115
24116
24117
24118
24119
24120
24121
24122
24123
24124
24125
24126
24127
24128
24129
24130
24131
24132
24133
#define MODE_Json     10  /* Output JSON */
#define MODE_Line     11  /* One column per line.  Blank line between records */
#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_BUILTIN  21  /* 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 */
#define MODE_N_USER   25  /* Maximum number of user-defined modes */

/*
** Information about built-in display modes
23998
23999
24000
24001
24002
24003
24004

24005
24006
24007
24008
24009
24010
24011
  { "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,    1,   1,   12,    0 },
  { "markdown", 0,     0,    9,    1,    1,    1,   2,   13,    2 },
  { "off",      0,     0,    0,    0,    0,    0,   0,   14,    0 },
  { "qbox",     0,     0,    9,    2,    1,    2,   2,   1,     2 },
  { "quote",    4,     1,    10,   2,    2,    2,   1,   12,    0 },

  { "table",    0,     0,    9,    1,    1,    1,   2,   19,    2 },
  { "tabs",     8,     1,    9,    3,    3,    1,   1,   12,    0 },
  { "tcl",      3,     1,    12,   5,    5,    4,   1,   12,    0 },
  { "www",      0,     0,    9,    4,    4,    1,   2,   7,     0 }
};     /*       |     /     /      |     /    /     |    |       \
       **       |    /     /       |    /    /      |    |        \_ 2: columnar
       ** Index into aModeStr[]    |   /    /       |    |           1: line







>







24168
24169
24170
24171
24172
24173
24174
24175
24176
24177
24178
24179
24180
24181
24182
  { "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,    1,   1,   12,    0 },
  { "markdown", 0,     0,    9,    1,    1,    1,   2,   13,    2 },
  { "off",      0,     0,    0,    0,    0,    0,   0,   14,    0 },
  { "qbox",     0,     0,    9,    2,    1,    2,   2,   1,     2 },
  { "quote",    4,     1,    10,   2,    2,    2,   1,   12,    0 },
  { "split",    0,     0,    9,    1,    1,    1,   1,   2,     2 },
  { "table",    0,     0,    9,    1,    1,    1,   2,   19,    2 },
  { "tabs",     8,     1,    9,    3,    3,    1,   1,   12,    0 },
  { "tcl",      3,     1,    12,   5,    5,    4,   1,   12,    0 },
  { "www",      0,     0,    9,    4,    4,    1,   2,   7,     0 }
};     /*       |     /     /      |     /    /     |    |       \
       **       |    /     /       |    /    /      |    |        \_ 2: columnar
       ** Index into aModeStr[]    |   /    /       |    |           1: line
24126
24127
24128
24129
24130
24131
24132






24133
24134
24135
24136
24137
24138
24139
    if( pI->eCSep ) modeSetStr(&pM->spec.zColumnSep, aModeStr[pI->eCSep]);
    if( pI->eRSep ) modeSetStr(&pM->spec.zRowSep, aModeStr[pI->eRSep]);
    if( pI->eNull ) modeSetStr(&pM->spec.zNull, aModeStr[pI->eNull]);
    pM->spec.eText = pI->eText;
    pM->spec.eBlob = pI->eBlob;
    pM->spec.bTitles = pI->bHdr;
    pM->spec.eTitle = pI->eHdr;






  }else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){
    modeFree(&p->mode);
    modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode);
  }else if( eMode==MODE_BATCH ){
    u8 mFlags = p->mode.mFlags;
    modeFree(&p->mode);
    modeChange(p, MODE_List);







>
>
>
>
>
>







24297
24298
24299
24300
24301
24302
24303
24304
24305
24306
24307
24308
24309
24310
24311
24312
24313
24314
24315
24316
    if( pI->eCSep ) modeSetStr(&pM->spec.zColumnSep, aModeStr[pI->eCSep]);
    if( pI->eRSep ) modeSetStr(&pM->spec.zRowSep, aModeStr[pI->eRSep]);
    if( pI->eNull ) modeSetStr(&pM->spec.zNull, aModeStr[pI->eNull]);
    pM->spec.eText = pI->eText;
    pM->spec.eBlob = pI->eBlob;
    pM->spec.bTitles = pI->bHdr;
    pM->spec.eTitle = pI->eHdr;
    if( eMode==MODE_Split ){
      pM->spec.bSplitColumn = QRF_Yes;
      pM->bAutoScreenWidth = 1;
    }else{
      pM->spec.bSplitColumn = QRF_No;
    }
  }else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){
    modeFree(&p->mode);
    modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode);
  }else if( eMode==MODE_BATCH ){
    u8 mFlags = p->mode.mFlags;
    modeFree(&p->mode);
    modeChange(p, MODE_List);
26439
26440
26441
26442
26443
26444
26445


26446
26447
26448
26449
26450
26451
26452
"                           in output. ESC can be \"off\", \"ascii\", or\n"
"                           \"symbol\".\n"
"  --linelimit N            Set the maximum number of output lines to show for\n"
"                           any single SQL value to N. Longer values are\n"
"                           truncated. Zero means \"no limit\". Only works\n"
"                           in \"line\" mode and in columnar modes.\n"
"  --list                   List available modes\n"


"  --null STRING            Render SQL NULL values as the given string\n"
"  --once                   Setting changes to the right are reverted after\n"
"                           the next SQL command.\n"
"  --quote ARG              Enable/disable quoting of text. ARG can be\n"
"                           \"off\", \"on\", \"sql\", \"csv\", \"html\", \"tcl\",\n"
"                           or \"json\".  \"off\" means show the text as-is.\n"
"                           \"on and \"sql\" are synonyms.\n"







>
>







26616
26617
26618
26619
26620
26621
26622
26623
26624
26625
26626
26627
26628
26629
26630
26631
"                           in output. ESC can be \"off\", \"ascii\", or\n"
"                           \"symbol\".\n"
"  --linelimit N            Set the maximum number of output lines to show for\n"
"                           any single SQL value to N. Longer values are\n"
"                           truncated. Zero means \"no limit\". Only works\n"
"                           in \"line\" mode and in columnar modes.\n"
"  --list                   List available modes\n"
"  --no-limits              Shorthand to turn off --linelimit, --charlimit,\n"
"                           and --screenwidth.\n"
"  --null STRING            Render SQL NULL values as the given string\n"
"  --once                   Setting changes to the right are reverted after\n"
"                           the next SQL command.\n"
"  --quote ARG              Enable/disable quoting of text. ARG can be\n"
"                           \"off\", \"on\", \"sql\", \"csv\", \"html\", \"tcl\",\n"
"                           or \"json\".  \"off\" means show the text as-is.\n"
"                           \"on and \"sql\" are synonyms.\n"
30318
30319
30320
30321
30322
30323
30324


30325
30326
30327
30328
30329
30330
30331
**                            in output. ESC can be "off", "ascii", or
**                            "symbol".
**   --linelimit N            Set the maximum number of output lines to show for
**                            any single SQL value to N. Longer values are
**                            truncated. Zero means "no limit". Only works
**                            in "line" mode and in columnar modes.
**   --list                   List available modes


**   --null STRING            Render SQL NULL values as the given string
**   --once                   Setting changes to the right are reverted after
**                            the next SQL command.
**   --quote ARG              Enable/disable quoting of text. ARG can be
**                            "off", "on", "sql", "csv", "html", "tcl",
**                            or "json".  "off" means show the text as-is.
**                            "on and "sql" are synonyms.







>
>







30497
30498
30499
30500
30501
30502
30503
30504
30505
30506
30507
30508
30509
30510
30511
30512
**                            in output. ESC can be "off", "ascii", or
**                            "symbol".
**   --linelimit N            Set the maximum number of output lines to show for
**                            any single SQL value to N. Longer values are
**                            truncated. Zero means "no limit". Only works
**                            in "line" mode and in columnar modes.
**   --list                   List available modes
**   --no-limits              Shorthand to turn off --linelimit, --charlimit,
**                            and --screenwidth.
**   --null STRING            Render SQL NULL values as the given string
**   --once                   Setting changes to the right are reverted after
**                            the next SQL command.
**   --quote ARG              Enable/disable quoting of text. ARG can be
**                            "off", "on", "sql", "csv", "html", "tcl",
**                            or "json".  "off" means show the text as-is.
**                            "on and "sql" are synonyms.
30463
30464
30465
30466
30467
30468
30469















30470
30471
30472
30473
30474
30475
30476
        if( ii==MODE_Www ) continue;
        cli_printf(p->out, " %s", aModeInfo[ii].zName);
      }
      for(ii=0; ii<p->nSavedModes; ii++){
        cli_printf(p->out, " %s", p->aSavedModes[ii].zTag);
      }
      cli_puts(" batch tty\n", p->out);















    }else if( optionMatch(z,"quote") ){
      if( i+1<nArg
       && azArg[i+1][0]!='-'
       && (iMode>0 || strcmp(azArg[i+1],"off")==0 || modeFind(p, azArg[i+1])<0)
      ){
        /* --quote is followed by an argument other that is not an option
        ** or a mode name.  See it must be a boolean or a keyword to describe







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







30644
30645
30646
30647
30648
30649
30650
30651
30652
30653
30654
30655
30656
30657
30658
30659
30660
30661
30662
30663
30664
30665
30666
30667
30668
30669
30670
30671
30672
        if( ii==MODE_Www ) continue;
        cli_printf(p->out, " %s", aModeInfo[ii].zName);
      }
      for(ii=0; ii<p->nSavedModes; ii++){
        cli_printf(p->out, " %s", p->aSavedModes[ii].zTag);
      }
      cli_puts(" batch tty\n", p->out);
    }else if( optionMatch(z,"once") ){
      p->nPopMode = 0;
      modePush(p);
      p->nPopMode = 1;
    }else if( optionMatch(z,"noquote") ){
      /* (undocumented legacy) --noquote always turns quoting off */
      p->mode.spec.eText = QRF_TEXT_Plain;
      p->mode.spec.eBlob = QRF_BLOB_Text;
      chng = 1;
    }else if( optionMatch(z,"no-limits") ){
      p->mode.spec.nLineLimit = 0;
      p->mode.spec.nCharLimit = 0;
      p->mode.spec.nScreenWidth = 0;
      p->mode.bAutoScreenWidth = 0;
      chng = 1;
    }else if( optionMatch(z,"quote") ){
      if( i+1<nArg
       && azArg[i+1][0]!='-'
       && (iMode>0 || strcmp(azArg[i+1],"off")==0 || modeFind(p, azArg[i+1])<0)
      ){
        /* --quote is followed by an argument other that is not an option
        ** or a mode name.  See it must be a boolean or a keyword to describe
30515
30516
30517
30518
30519
30520
30521
30522
30523
30524
30525
30526
30527
30528
30529
30530
30531
30532
30533
30534
30535
30536
30537
          break;
        default:  /* off */
          p->mode.spec.eText = QRF_TEXT_Plain;
          p->mode.spec.eBlob = QRF_BLOB_Text;
          break;
      }
      chng = 1;
    }else if( optionMatch(z,"once") ){
      p->nPopMode = 0;
      modePush(p);
      p->nPopMode = 1;
    }else if( optionMatch(z,"noquote") ){
      /* (undocumented legacy) --noquote always turns quoting off */
      p->mode.spec.eText = QRF_TEXT_Plain;
      p->mode.spec.eBlob = QRF_BLOB_Text;
      chng = 1;
    }else if( optionMatch(z,"reset") ){
      int saved_eMode = p->mode.eMode;
      modeFree(&p->mode);
      modeChange(p, saved_eMode);
    }else if( optionMatch(z,"screenwidth") ){
      if( i+1>=nArg ){
        dotCmdError(p, i, "missing argument", 0);







<
<
<
<
<
<
<
<
<







30711
30712
30713
30714
30715
30716
30717









30718
30719
30720
30721
30722
30723
30724
          break;
        default:  /* off */
          p->mode.spec.eText = QRF_TEXT_Plain;
          p->mode.spec.eBlob = QRF_BLOB_Text;
          break;
      }
      chng = 1;









    }else if( optionMatch(z,"reset") ){
      int saved_eMode = p->mode.eMode;
      modeFree(&p->mode);
      modeChange(p, saved_eMode);
    }else if( optionMatch(z,"screenwidth") ){
      if( i+1>=nArg ){
        dotCmdError(p, i, "missing argument", 0);
31075
31076
31077
31078
31079
31080
31081

31082
31083
31084

31085
31086
31087
31088
31089
31090
31091
31092
31093
31094






31095
31096
31097
31098

31099
31100
31101
31102
31103







31104
31105
31106
31107
31108
31109
31110
  sqlite3_free(zFile);
  return 0;

dotCmdOutput_error:
  sqlite3_free(zFile);
  return 1;
}

/*
** Parse input line zLine up into individual arguments.  Retain the
** parse in the p->dot substructure.

*/
static void parseDotRealloc(ShellState *p, int nArg){
  p->dot.nAlloc = nArg+22;
  p->dot.azArg = realloc(p->dot.azArg,p->dot.nAlloc*sizeof(char*));
  shell_check_oom(p->dot.azArg);
  p->dot.aiOfst = realloc(p->dot.aiOfst,p->dot.nAlloc*sizeof(int));
  shell_check_oom(p->dot.aiOfst);
  p->dot.abQuot = realloc(p->dot.abQuot,p->dot.nAlloc);
  shell_check_oom(p->dot.abQuot);
}






static void parseDotCmdArgs(const char *zLine, ShellState *p){
  char *z;
  int h = 1;
  int nArg = 0;


  p->dot.zOrig = zLine;
  free(p->dot.zCopy);
  z = p->dot.zCopy = strdup(zLine);
  shell_check_oom(z);







  parseDotRealloc(p, 2);
  while( z[h] ){
    while( IsSpace(z[h]) ){ h++; }
    if( z[h]==0 ) break;
    if( nArg+2>p->dot.nAlloc ){
      parseDotRealloc(p, nArg);
    }







>

<
|
>










>
>
>
>
>
>




>





>
>
>
>
>
>
>







31262
31263
31264
31265
31266
31267
31268
31269
31270

31271
31272
31273
31274
31275
31276
31277
31278
31279
31280
31281
31282
31283
31284
31285
31286
31287
31288
31289
31290
31291
31292
31293
31294
31295
31296
31297
31298
31299
31300
31301
31302
31303
31304
31305
31306
31307
31308
31309
31310
31311
31312
  sqlite3_free(zFile);
  return 0;

dotCmdOutput_error:
  sqlite3_free(zFile);
  return 1;
}

/*

** Enlarge the space allocated in p->dot so that it can hold more
** than nArg parsed command-line arguments.
*/
static void parseDotRealloc(ShellState *p, int nArg){
  p->dot.nAlloc = nArg+22;
  p->dot.azArg = realloc(p->dot.azArg,p->dot.nAlloc*sizeof(char*));
  shell_check_oom(p->dot.azArg);
  p->dot.aiOfst = realloc(p->dot.aiOfst,p->dot.nAlloc*sizeof(int));
  shell_check_oom(p->dot.aiOfst);
  p->dot.abQuot = realloc(p->dot.abQuot,p->dot.nAlloc);
  shell_check_oom(p->dot.abQuot);
}


/*
** Parse input line zLine up into individual arguments.  Retain the
** parse in the p->dot substructure.
*/
static void parseDotCmdArgs(const char *zLine, ShellState *p){
  char *z;
  int h = 1;
  int nArg = 0;
  size_t szLine;

  p->dot.zOrig = zLine;
  free(p->dot.zCopy);
  z = p->dot.zCopy = strdup(zLine);
  shell_check_oom(z);
  szLine = strlen(z);
  while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--;
  if( szLine>0 && z[szLine-1]==';' && p->iCompat>=20251115 ){
    szLine--;
    while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--;
  }
  z[szLine] = 0;
  parseDotRealloc(p, 2);
  while( z[h] ){
    while( IsSpace(z[h]) ){ h++; }
    if( z[h]==0 ) break;
    if( nArg+2>p->dot.nAlloc ){
      parseDotRealloc(p, nArg);
    }
33404
33405
33406
33407
33408
33409
33410

33411
33412
33413
33414
33415
33416
33417
33418
33419
33420
33421
33422
33423
33424
33425
33426
33427
33428
33429
33430
33431
33432

33433
33434
33435

33436

33437
33438
33439
33440
33441
33442
33443
33444
33445
33446

33447
33448


33449

33450
33451

33452

33453
33454
33455
33456
33457
33458
33459
33460
33461
33462
33463
33464
33465
33466
33467
33468
33469
33470
33471

33472
33473
33474
33475
33476
33477
33478
33479
33480
33481
33482
33483
33484
33485
33486
33487
33488
33489
33490
33491
33492
33493
33494
33495
33496
33497
33498
33499
33500
33501
33502
33503
33504
33505
33506
33507
33508
33509
33510
33511
33512
33513
33514
33515
33516
33517
33518
33519
    }
  }else

  if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0)
   || (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
                 || cli_strncmp(azArg[0], "indexes", n)==0) )
  ){

    sqlite3_stmt *pStmt;
    char **azResult;
    int nRow, nAlloc;
    int ii;
    ShellText s;
    initText(&s);
    open_db(p, 0);
    rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
    if( rc ){
      sqlite3_finalize(pStmt);
      return shellDatabaseError(p->db);
    }

    if( nArg>2 && c=='i' ){
      /* It is an historical accident that the .indexes command shows an error
      ** when called with the wrong number of arguments whereas the .tables
      ** command does not. */
      eputz("Usage: .indexes ?LIKE-PATTERN?\n");
      rc = 1;
      sqlite3_finalize(pStmt);
      goto meta_command_exit;
    }

    for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
      const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
      if( zDbName==0 ) continue;

      if( s.zTxt && s.zTxt[0] ) appendText(&s, " UNION ALL ", 0);

      if( sqlite3_stricmp(zDbName, "main")==0 ){
        appendText(&s, "SELECT name FROM ", 0);
      }else{
        appendText(&s, "SELECT ", 0);
        appendText(&s, zDbName, '\'');
        appendText(&s, "||'.'||name FROM ", 0);
      }
      appendText(&s, zDbName, '"');
      appendText(&s, ".sqlite_schema ", 0);
      if( c=='t' ){

        appendText(&s," WHERE type IN ('table','view')"
                      "   AND name NOT LIKE 'sqlite__%' ESCAPE '_'"


                      "   AND name LIKE ?1", 0);

      }else{
        appendText(&s," WHERE type='index'"

                      "   AND tbl_name LIKE ?1", 0);

      }
    }
    rc = sqlite3_finalize(pStmt);
    if( rc==SQLITE_OK ){
      appendText(&s, " ORDER BY 1", 0);
      rc = sqlite3_prepare_v2(p->db, s.zTxt, -1, &pStmt, 0);
    }
    freeText(&s);
    if( rc ) return shellDatabaseError(p->db);

    /* Run the SQL statement prepared by the above block. Store the results
    ** as an array of nul-terminated strings in azResult[].  */
    nRow = nAlloc = 0;
    azResult = 0;
    if( nArg>1 ){
      sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
    }else{
      sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
    }

    while( sqlite3_step(pStmt)==SQLITE_ROW ){
      if( nRow>=nAlloc ){
        char **azNew;
        sqlite3_int64 n2 = 2*(sqlite3_int64)nAlloc + 10;
        azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
        shell_check_oom(azNew);
        nAlloc = (int)n2;
        azResult = azNew;
      }
      azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
      shell_check_oom(azResult[nRow]);
      nRow++;
    }
    if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
      rc = shellDatabaseError(p->db);
    }

    /* Pretty-print the contents of array azResult[] to the output */
    if( rc==0 && nRow>0 ){
      int len, maxlen = 0;
      int i, j;
      int nPrintCol, nPrintRow;
      for(i=0; i<nRow; i++){
        len = strlen30(azResult[i]);
        if( len>maxlen ) maxlen = len;
      }
      nPrintCol = shellScreenWidth()/(maxlen+2);
      if( nPrintCol<1 ) nPrintCol = 1;
      nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
      for(i=0; i<nPrintRow; i++){
        for(j=i; j<nRow; j+=nPrintRow){
          char *zSp = j<nPrintRow ? "" : "  ";
          cli_printf(p->out,
               "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
        }
        cli_puts("\n", p->out);
      }
    }

    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
    sqlite3_free(azResult);
  }else

#ifndef SQLITE_SHELL_FIDDLE
  /* Begin redirecting output to the file "testcase-out.txt" */
  if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
    output_reset(p);
    p->out = output_file_open(p, "testcase-out.txt");







>

|
<
|
|
<
















>



>
|
>

|

<
<
|

<
|

>
|
|
>
>
|
>

|
>
|
>




|
<

<
<

|
<
<
<
<
<
|
<
<
>
|
<
<
|
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







33606
33607
33608
33609
33610
33611
33612
33613
33614
33615

33616
33617

33618
33619
33620
33621
33622
33623
33624
33625
33626
33627
33628
33629
33630
33631
33632
33633
33634
33635
33636
33637
33638
33639
33640
33641
33642
33643


33644
33645

33646
33647
33648
33649
33650
33651
33652
33653
33654
33655
33656
33657
33658
33659
33660
33661
33662
33663
33664

33665


33666
33667





33668


33669
33670


33671







33672


33673


























33674
33675
33676
33677
33678
33679
33680
    }
  }else

  if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0)
   || (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
                 || cli_strncmp(azArg[0], "indexes", n)==0) )
  ){
    int ii;
    sqlite3_stmt *pStmt;
    sqlite3_str *pSql;

    const char *zPattern = nArg>1 ? azArg[1] : 0;


    open_db(p, 0);
    rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
    if( rc ){
      sqlite3_finalize(pStmt);
      return shellDatabaseError(p->db);
    }

    if( nArg>2 && c=='i' ){
      /* It is an historical accident that the .indexes command shows an error
      ** when called with the wrong number of arguments whereas the .tables
      ** command does not. */
      eputz("Usage: .indexes ?LIKE-PATTERN?\n");
      rc = 1;
      sqlite3_finalize(pStmt);
      goto meta_command_exit;
    }
    pSql = sqlite3_str_new(p->db);
    for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
      const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
      if( zDbName==0 ) continue;
      if( sqlite3_str_length(pSql) ){
        sqlite3_str_appendall(pSql, " UNION ALL ");
      }
      if( sqlite3_stricmp(zDbName, "main")==0 ){
        sqlite3_str_appendall(pSql, "SELECT name FROM ");
      }else{


        sqlite3_str_appendf(pSql, "SELECT %Q||'.'||name FROM ", zDbName);
      }

      sqlite3_str_appendf(pSql, "\"%w\".sqlite_schema", zDbName);
      if( c=='t' ){
        sqlite3_str_appendf(pSql,
            " WHERE type IN ('table','view')"
            "   AND name NOT LIKE 'sqlite__%%' ESCAPE '_'"
        );
        if( zPattern ){
          sqlite3_str_appendf(pSql," AND name LIKE %Q", zPattern);
        }
      }else{
        sqlite3_str_appendf(pSql, " WHERE type='index'");
        if( zPattern ){
          sqlite3_str_appendf(pSql," AND tbl_name LIKE %Q", zPattern);
        }
      }
    }
    rc = sqlite3_finalize(pStmt);
    if( rc==SQLITE_OK ){
      sqlite3_str_appendall(pSql, " ORDER BY 1");

    }



    /* Run the SQL statement in "split" mode. */





    modePush(p);


    modeChange(p, MODE_Split);
    shell_exec(p, sqlite3_str_value(pSql), 0);


    sqlite3_str_free(pSql);







    modePop(p);


    if( rc ) return shellDatabaseError(p->db);


























  }else

#ifndef SQLITE_SHELL_FIDDLE
  /* Begin redirecting output to the file "testcase-out.txt" */
  if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
    output_reset(p);
    p->out = output_file_open(p, "testcase-out.txt");
35633
35634
35635
35636
35637
35638
35639










35640
35641
35642
35643
35644
35645
35646
            cli_printf(stderr,
                            "Error: unable to process SQL: %s\n", azCmd[i]);
          }
          sqlite3_free(zErrMsg);
          if( rc==0 ) rc = 1;
          goto shell_main_exit;
        }










      }
    }
  }else{
    /* Run commands received from standard input
    */
    if( stdin_is_interactive ){
      char *zHome;







>
>
>
>
>
>
>
>
>
>







35794
35795
35796
35797
35798
35799
35800
35801
35802
35803
35804
35805
35806
35807
35808
35809
35810
35811
35812
35813
35814
35815
35816
35817
            cli_printf(stderr,
                            "Error: unable to process SQL: %s\n", azCmd[i]);
          }
          sqlite3_free(zErrMsg);
          if( rc==0 ) rc = 1;
          goto shell_main_exit;
        }
        if( data.nPopMode ){
          modePop(&data);
          data.nPopMode = 0;
        }
      }
      if( data.nPopOutput ){
        output_reset(&data);
        data.nPopOutput = 0;
      }else{
        clearTempFile(&data);
      }
    }
  }else{
    /* Run commands received from standard input
    */
    if( stdin_is_interactive ){
      char *zHome;