/ Check-in [4a51cf28]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Modify the vdbe code generated by ANALYZE to use fewer memory cells and cursor slots.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sqlite_stat4
Files: files | file ages | folders
SHA1:4a51cf289fad8aebc637b5f96488de18e861195d
User & Date: dan 2013-08-05 19:04:07
Context
2013-08-06
20:01
When possible, use the multi-column samples in sqlite_stat4 to estimate the number of index rows scanned by a query plan. check-in: 2973f5ca user: dan tags: sqlite_stat4
2013-08-05
19:04
Modify the vdbe code generated by ANALYZE to use fewer memory cells and cursor slots. check-in: 4a51cf28 user: dan tags: sqlite_stat4
18:00
Use N separate cursors when scanning an index with N columns to collect sqlite_stat4 data. This fixes a problem with collecting incorrect nEq values from multi-column indexes. check-in: 3a71afe6 user: dan tags: sqlite_stat4
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/analyze.c.

501
502
503
504
505
506
507
508

509
510
511
512

513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541


542
543

544

545
546
547
548
549
550
551
...
564
565
566
567
568
569
570
571

572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
...
699
700
701
702
703
704
705
706
707
708


709
710
711
712
713
714
715
...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
...
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
...
908
909
910
911
912
913
914

915
916
917
918
919
920

921
922
923
924
925
926
927
928
929
930
931
...
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
** a single table.
*/
static void analyzeOneTable(
  Parse *pParse,   /* Parser context */
  Table *pTab,     /* Table whose indices are to be analyzed */
  Index *pOnlyIdx, /* If not NULL, only analyze this one index */
  int iStatCur,    /* Index of VdbeCursor that writes the sqlite_stat1 table */
  int iMem         /* Available memory locations begin here */

){
  sqlite3 *db = pParse->db;    /* Database handle */
  Index *pIdx;                 /* An index to being analyzed */
  int iIdxCur;                 /* Cursor open on index being analyzed */

  Vdbe *v;                     /* The virtual machine being built up */
  int i;                       /* Loop counter */
  int topOfLoop;               /* The top of the loop */
  int endOfLoop;               /* The end of the loop */
  int jZeroRows = -1;          /* Jump from here if number of rows is zero */
  int iDb;                     /* Index of database containing pTab */
  u8 needTableCnt = 1;         /* True to count the table */
  int regTabname = iMem++;     /* Register containing table name */
  int regIdxname = iMem++;     /* Register containing index name */
  int regStat1 = iMem++;       /* The stat column of sqlite_stat1 */
#ifdef SQLITE_ENABLE_STAT4
  int regNumEq = regStat1;     /* Number of instances.  Same as regStat1 */
  int regNumLt = iMem++;       /* Number of keys less than regSample */
  int regNumDLt = iMem++;      /* Number of distinct keys less than regSample */
  int regSample = iMem++;      /* The next sample value */
  int regRowid = regSample;    /* Rowid of a sample */
  int regAccum = iMem++;       /* Register to hold Stat4Accum object */
  int regLoop = iMem++;        /* Loop counter */
  int regCount = iMem++;       /* Number of rows in the table or index */
  int regTemp1 = iMem++;       /* Intermediate register */
  int regTemp2 = iMem++;       /* Intermediate register */
  int once = 1;                /* One-time initialization */
  int shortJump = 0;           /* Instruction address */
  int iTabCur = pParse->nTab++; /* Table cursor */
#endif
  int regCol = iMem++;         /* Content of a column in analyzed table */
  int regRec = iMem++;         /* Register holding completed record */
  int regTemp = iMem++;        /* Temporary use register */
  int regNewRowid = iMem++;    /* Rowid for the inserted record */



  int regStat4 = iMem++;       /* Register to hold Stat4Accum object */



  v = sqlite3GetVdbe(pParse);
  if( v==0 || NEVER(pTab==0) ){
    return;
  }
  if( pTab->tnum==0 ){
    /* Do not gather statistics on views or virtual tables */
    return;
................................................................................
    return;
  }
#endif

  /* Establish a read-lock on the table at the shared-cache level. 
  ** Also open a read-only cursor on the table.  */
  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
  iTabCur = pParse->nTab++;

  sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
  sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);

  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    int nCol;                     /* Number of columns indexed by pIdx */
    KeyInfo *pKey;                /* KeyInfo structure for pIdx */
    int addrIfNot = 0;            /* address of OP_IfNot */
    int *aChngAddr;               /* Array of jump instruction addresses */

    int regRowid;                 /* Register for rowid of current row */
    int regPrev;                  /* First in array of previous values */
    int regDLte;                  /* First in array of nDlt registers */
    int regLt;                    /* First in array of nLt registers */
    int regEq;                    /* First in array of nEq registers */
    int regCnt;                   /* Number of index entries */
    int regEof;                   /* True once cursors are all at EOF */
    int endOfScan;                /* Label to jump to once scan is finished */

    if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
    if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
    VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName));
    nCol = pIdx->nColumn;
    aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol);
................................................................................
    ** of the corresponding length. As required to calculate the contents
    ** of the sqlite_stat1 entry.
    **
    ** Currently, the last memory cell allocated (that with the largest 
    ** integer identifier) is regStat4. Immediately following regStat4
    ** we allocate the following:
    **
    **     regRowid -    1 register
    **     regEq -    nCol registers
    **     regLt -    nCol registers
    **     regDLte -  nCol registers
    **     regCnt -      1 register
    **     regPrev -  nCol registers
    **     regEof -      1 register
    **
    ** The regRowid, regEq, regLt and regDLte registers must be positioned in 
    ** that order immediately following regStat4 so that they can be passed
    ** to the stat4_push() function.
    **
    ** All of the above are initialized to contain integer value 0.
    */
    regRowid = regStat4+1;        /* Rowid argument */
    regEq = regRowid+1;           /* First in array of nEq value registers */
    regLt = regEq+nCol;           /* First in array of nLt value registers */
    regDLte = regLt+nCol;         /* First in array of nDLt value registers */
    regCnt = regDLte+nCol;        /* Row counter */
    regPrev = regCnt+1;           /* First in array of prev. value registers */
    regEof = regPrev+nCol;        /* True once last row read from index */
    if( regEof+1>pParse->nMem ){
      pParse->nMem = regPrev+nCol;
    }

    /* Open a read-only cursor for each column of the index. */
    assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
    iIdxCur = pParse->nTab++;
    pParse->nTab += (nCol-1);
    for(i=0; i<nCol; i++){
      int iMode = (i==0 ? P4_KEYINFO_HANDOFF : P4_KEYINFO);
      sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur+i, pIdx->tnum, iDb);
      sqlite3VdbeChangeP4(v, -1, (char*)pKey, iMode); 
      VdbeComment((v, "%s", pIdx->zName));
    }

................................................................................
    sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_STAT4_SAMPLES, regStat4+3);
    sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4);
    sqlite3VdbeChangeP4(v, -1, (char*)&stat4InitFuncdef, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, 3);
#endif /* SQLITE_ENABLE_STAT4 */

    /* Initialize all the memory registers allocated above to 0. */
    for(i=regRowid; i<=regEof; i++){
      sqlite3VdbeAddOp2(v, OP_Integer, 0, i);
    }



    /* Rewind all cursors open on the index. If the table is entry, this
    ** will cause control to jump to address endOfScan immediately.  */
    endOfScan = sqlite3VdbeMakeLabel(v);
    for(i=0; i<nCol; i++){
      sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur+i, endOfScan);
    }
................................................................................
        VdbeComment((v, "if( regPrev(%d) != csr(%d)(%d) )", j, i, j));
      }
      sqlite3VdbeAddOp2(v, OP_Goto, 0, iDo);
      sqlite3VdbeResolveLabel(v, iNe);
    }

    /* Invoke stat4_push() */
    sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp2);
    sqlite3VdbeChangeP4(v, -1, (char*)&stat4PushFuncdef, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, 2 + 3*nCol);

    sqlite3VdbeAddOp2(v, OP_If, regEof, endOfScan);
    for(i=0; i<nCol-1; i++){
      char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
      sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+nCol-1, i, regCol);
................................................................................
      sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
    }
    sqlite3VdbeAddOp2(v, OP_Goto, 0, aChngAddr[nCol-1]);
    sqlite3DbFree(db, aChngAddr);

    sqlite3VdbeResolveLabel(v, endOfScan);

    /* Close all the cursors */
    for(i=0; i<nCol; i++){
      sqlite3VdbeAddOp1(v, OP_Close, iIdxCur+i);
      VdbeComment((v, "close index cursor %d", i));
    }

#ifdef SQLITE_ENABLE_STAT4
    /* Add rows to the sqlite_stat4 table */
    regLoop = regStat4+1;
    sqlite3VdbeAddOp2(v, OP_Integer, -1, regLoop);
    shortJump = sqlite3VdbeAddOp2(v, OP_AddImm, regLoop, 1);
    sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regTemp1);
    sqlite3VdbeChangeP4(v, -1, (char*)&stat4GetFuncdef, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, 2);
    sqlite3VdbeAddOp1(v, OP_IsNull, regTemp1);

    sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, shortJump, regTemp1);
    for(i=0; i<nCol; i++){
      int iCol = pIdx->aiColumn[i];
      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regPrev+i);
    }
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regPrev, nCol, regSample);
    sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);

................................................................................
    sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid);
    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    sqlite3VdbeJumpHere(v, jZeroRows);
  }

  sqlite3VdbeAddOp1(v, OP_Close, iTabCur);

  /* TODO: Not sure about this... */
  if( pParse->nMem<regRec ) pParse->nMem = regRec;
}


/*
** Generate code that will cause the most recent index analysis to
** be loaded into internal hash tables where is can be used.
*/
................................................................................
*/
static void analyzeDatabase(Parse *pParse, int iDb){
  sqlite3 *db = pParse->db;
  Schema *pSchema = db->aDb[iDb].pSchema;    /* Schema of database iDb */
  HashElem *k;
  int iStatCur;
  int iMem;


  sqlite3BeginWriteOperation(pParse, 0, iDb);
  iStatCur = pParse->nTab;
  pParse->nTab += 3;
  openStatTable(pParse, iDb, iStatCur, 0, 0);
  iMem = pParse->nMem+1;

  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
  for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
    Table *pTab = (Table*)sqliteHashData(k);
    analyzeOneTable(pParse, pTab, 0, iStatCur, iMem);
  }
  loadAnalysis(pParse, iDb);
}

/*
** Generate code that will do an analysis of a single table in
** a database.  If pOnlyIdx is not NULL then it is a single index
................................................................................
  iStatCur = pParse->nTab;
  pParse->nTab += 3;
  if( pOnlyIdx ){
    openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx");
  }else{
    openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
  }
  analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem+1);
  loadAnalysis(pParse, iDb);
}

/*
** Generate code for the ANALYZE command.  The parser calls this routine
** when it recognizes an ANALYZE command.
**







|
>




>


<
<











<
<

<
<
<
<

<





>
>


>

>







 







|
>






<


<




<
<







 







<



<

<







<



<
|
<
<
|
<



|
|







 







|


>
>







 







|







 







<
<
<
<
<
<





|


|

|







 







<
<
<
<
<







 







>






>



|







 







|







501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516


517
518
519
520
521
522
523
524
525
526
527


528




529

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

576
577

578
579
580
581


582
583
584
585
586
587
588
...
641
642
643
644
645
646
647

648
649
650

651

652
653
654
655
656
657
658

659
660
661

662


663

664
665
666
667
668
669
670
671
672
673
674
675
...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
...
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
...
774
775
776
777
778
779
780






781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
...
862
863
864
865
866
867
868





869
870
871
872
873
874
875
...
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
...
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
** a single table.
*/
static void analyzeOneTable(
  Parse *pParse,   /* Parser context */
  Table *pTab,     /* Table whose indices are to be analyzed */
  Index *pOnlyIdx, /* If not NULL, only analyze this one index */
  int iStatCur,    /* Index of VdbeCursor that writes the sqlite_stat1 table */
  int iMem,        /* Available memory locations begin here */
  int iTab         /* Next available cursor */
){
  sqlite3 *db = pParse->db;    /* Database handle */
  Index *pIdx;                 /* An index to being analyzed */
  int iIdxCur;                 /* Cursor open on index being analyzed */
  int iTabCur;                 /* Table cursor */
  Vdbe *v;                     /* The virtual machine being built up */
  int i;                       /* Loop counter */


  int jZeroRows = -1;          /* Jump from here if number of rows is zero */
  int iDb;                     /* Index of database containing pTab */
  u8 needTableCnt = 1;         /* True to count the table */
  int regTabname = iMem++;     /* Register containing table name */
  int regIdxname = iMem++;     /* Register containing index name */
  int regStat1 = iMem++;       /* The stat column of sqlite_stat1 */
#ifdef SQLITE_ENABLE_STAT4
  int regNumEq = regStat1;     /* Number of instances.  Same as regStat1 */
  int regNumLt = iMem++;       /* Number of keys less than regSample */
  int regNumDLt = iMem++;      /* Number of distinct keys less than regSample */
  int regSample = iMem++;      /* The next sample value */


  int regLoop = iMem++;        /* Loop counter */




  int shortJump = 0;           /* Instruction address */

#endif
  int regCol = iMem++;         /* Content of a column in analyzed table */
  int regRec = iMem++;         /* Register holding completed record */
  int regTemp = iMem++;        /* Temporary use register */
  int regNewRowid = iMem++;    /* Rowid for the inserted record */
  int regEof = iMem++;         /* True once cursors are all at EOF */
  int regCnt = iMem++;         /* Row counter */

  int regStat4 = iMem++;       /* Register to hold Stat4Accum object */
  int regRowid = iMem++;       /* Rowid argument passed to stat4_push() */

  pParse->nMem = MAX(pParse->nMem, regRowid);
  v = sqlite3GetVdbe(pParse);
  if( v==0 || NEVER(pTab==0) ){
    return;
  }
  if( pTab->tnum==0 ){
    /* Do not gather statistics on views or virtual tables */
    return;
................................................................................
    return;
  }
#endif

  /* Establish a read-lock on the table at the shared-cache level. 
  ** Also open a read-only cursor on the table.  */
  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
  iTabCur = iTab++;
  pParse->nTab = MAX(pParse->nTab, iTab);
  sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
  sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);

  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    int nCol;                     /* Number of columns indexed by pIdx */
    KeyInfo *pKey;                /* KeyInfo structure for pIdx */

    int *aChngAddr;               /* Array of jump instruction addresses */


    int regPrev;                  /* First in array of previous values */
    int regDLte;                  /* First in array of nDlt registers */
    int regLt;                    /* First in array of nLt registers */
    int regEq;                    /* First in array of nEq registers */


    int endOfScan;                /* Label to jump to once scan is finished */

    if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
    if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
    VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName));
    nCol = pIdx->nColumn;
    aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol);
................................................................................
    ** of the corresponding length. As required to calculate the contents
    ** of the sqlite_stat1 entry.
    **
    ** Currently, the last memory cell allocated (that with the largest 
    ** integer identifier) is regStat4. Immediately following regStat4
    ** we allocate the following:
    **

    **     regEq -    nCol registers
    **     regLt -    nCol registers
    **     regDLte -  nCol registers

    **     regPrev -  nCol registers

    **
    ** The regRowid, regEq, regLt and regDLte registers must be positioned in 
    ** that order immediately following regStat4 so that they can be passed
    ** to the stat4_push() function.
    **
    ** All of the above are initialized to contain integer value 0.
    */

    regEq = regRowid+1;           /* First in array of nEq value registers */
    regLt = regEq+nCol;           /* First in array of nLt value registers */
    regDLte = regLt+nCol;         /* First in array of nDLt value registers */

    regPrev = regDLte+nCol;       /* First in array of prev. value registers */


    pParse->nMem = MAX(pParse->nMem, regPrev+nCol);


    /* Open a read-only cursor for each column of the index. */
    assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
    iIdxCur = iTab;
    pParse->nTab = MAX(pParse->nTab, iTab+nCol);
    for(i=0; i<nCol; i++){
      int iMode = (i==0 ? P4_KEYINFO_HANDOFF : P4_KEYINFO);
      sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur+i, pIdx->tnum, iDb);
      sqlite3VdbeChangeP4(v, -1, (char*)pKey, iMode); 
      VdbeComment((v, "%s", pIdx->zName));
    }

................................................................................
    sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_STAT4_SAMPLES, regStat4+3);
    sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4);
    sqlite3VdbeChangeP4(v, -1, (char*)&stat4InitFuncdef, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, 3);
#endif /* SQLITE_ENABLE_STAT4 */

    /* Initialize all the memory registers allocated above to 0. */
    for(i=regEq; i<regDLte+nCol; i++){
      sqlite3VdbeAddOp2(v, OP_Integer, 0, i);
    }
    sqlite3VdbeAddOp2(v, OP_Integer, 0, regCnt);
    sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof);

    /* Rewind all cursors open on the index. If the table is entry, this
    ** will cause control to jump to address endOfScan immediately.  */
    endOfScan = sqlite3VdbeMakeLabel(v);
    for(i=0; i<nCol; i++){
      sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur+i, endOfScan);
    }
................................................................................
        VdbeComment((v, "if( regPrev(%d) != csr(%d)(%d) )", j, i, j));
      }
      sqlite3VdbeAddOp2(v, OP_Goto, 0, iDo);
      sqlite3VdbeResolveLabel(v, iNe);
    }

    /* Invoke stat4_push() */
    sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp);
    sqlite3VdbeChangeP4(v, -1, (char*)&stat4PushFuncdef, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, 2 + 3*nCol);

    sqlite3VdbeAddOp2(v, OP_If, regEof, endOfScan);
    for(i=0; i<nCol-1; i++){
      char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
      sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+nCol-1, i, regCol);
................................................................................
      sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
    }
    sqlite3VdbeAddOp2(v, OP_Goto, 0, aChngAddr[nCol-1]);
    sqlite3DbFree(db, aChngAddr);

    sqlite3VdbeResolveLabel(v, endOfScan);







#ifdef SQLITE_ENABLE_STAT4
    /* Add rows to the sqlite_stat4 table */
    regLoop = regStat4+1;
    sqlite3VdbeAddOp2(v, OP_Integer, -1, regLoop);
    shortJump = sqlite3VdbeAddOp2(v, OP_AddImm, regLoop, 1);
    sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regTemp);
    sqlite3VdbeChangeP4(v, -1, (char*)&stat4GetFuncdef, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, 2);
    sqlite3VdbeAddOp1(v, OP_IsNull, regTemp);

    sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, shortJump, regTemp);
    for(i=0; i<nCol; i++){
      int iCol = pIdx->aiColumn[i];
      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regPrev+i);
    }
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regPrev, nCol, regSample);
    sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);

................................................................................
    sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
    sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid);
    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
    sqlite3VdbeJumpHere(v, jZeroRows);
  }





}


/*
** Generate code that will cause the most recent index analysis to
** be loaded into internal hash tables where is can be used.
*/
................................................................................
*/
static void analyzeDatabase(Parse *pParse, int iDb){
  sqlite3 *db = pParse->db;
  Schema *pSchema = db->aDb[iDb].pSchema;    /* Schema of database iDb */
  HashElem *k;
  int iStatCur;
  int iMem;
  int iTab;

  sqlite3BeginWriteOperation(pParse, 0, iDb);
  iStatCur = pParse->nTab;
  pParse->nTab += 3;
  openStatTable(pParse, iDb, iStatCur, 0, 0);
  iMem = pParse->nMem+1;
  iTab = pParse->nTab;
  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
  for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
    Table *pTab = (Table*)sqliteHashData(k);
    analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
  }
  loadAnalysis(pParse, iDb);
}

/*
** Generate code that will do an analysis of a single table in
** a database.  If pOnlyIdx is not NULL then it is a single index
................................................................................
  iStatCur = pParse->nTab;
  pParse->nTab += 3;
  if( pOnlyIdx ){
    openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx");
  }else{
    openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
  }
  analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab);
  loadAnalysis(pParse, iDb);
}

/*
** Generate code for the ANALYZE command.  The parser calls this routine
** when it recognizes an ANALYZE command.
**