SQLite

Check-in [5b08f29f45]
Login

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

Overview
Comment:Use a hash table to improve the preformance of column name uniqueness checking.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5b08f29f458c600401860c7d70d8174cf61e69f8
User & Date: drh 2015-11-14 20:52:43.849
Context
2015-11-14
22:04
Code simplification in sqlite3ColumnsFromExprList(). Update the %z format code so that it works with buffers obtained from sqlite3DbMalloc(). Add a testcase for the slow column name uniquifier. (check-in: 9272426057 user: drh tags: trunk)
20:52
Use a hash table to improve the preformance of column name uniqueness checking. (check-in: 5b08f29f45 user: drh tags: trunk)
16:47
Use randomness to prevent slowness in the generated-column-name uniqueness checking. (check-in: 6266712968 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/select.c.
1598
1599
1600
1601
1602
1603
1604

1605

1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
  int i, j;                   /* Loop counters */
  u32 cnt;                    /* Index added to make the name unique */
  Column *aCol, *pCol;        /* For looping over result columns */
  int nCol;                   /* Number of columns in the result set */
  Expr *p;                    /* Expression for a single result column */
  char *zName;                /* Column name */
  int nName;                  /* Size of name in zName[] */



  if( pEList ){
    nCol = pEList->nExpr;
    aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
    testcase( aCol==0 );
  }else{
    nCol = 0;
    aCol = 0;
  }
  *pnCol = nCol;
  *paCol = aCol;

  for(i=0, pCol=aCol; i<nCol; i++, pCol++){
    /* Get an appropriate name for the column
    */
    p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
    if( (zName = pEList->a[i].zName)!=0 ){
      /* If the column contains an "AS <name>" phrase, use <name> as the name */
      zName = sqlite3DbStrDup(db, zName);
    }else{







>

>











|







1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
  int i, j;                   /* Loop counters */
  u32 cnt;                    /* Index added to make the name unique */
  Column *aCol, *pCol;        /* For looping over result columns */
  int nCol;                   /* Number of columns in the result set */
  Expr *p;                    /* Expression for a single result column */
  char *zName;                /* Column name */
  int nName;                  /* Size of name in zName[] */
  Hash ht;                    /* Hash table of column names */

  sqlite3HashInit(&ht);
  if( pEList ){
    nCol = pEList->nExpr;
    aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
    testcase( aCol==0 );
  }else{
    nCol = 0;
    aCol = 0;
  }
  *pnCol = nCol;
  *paCol = aCol;

  for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
    /* Get an appropriate name for the column
    */
    p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
    if( (zName = pEList->a[i].zName)!=0 ){
      /* If the column contains an "AS <name>" phrase, use <name> as the name */
      zName = sqlite3DbStrDup(db, zName);
    }else{
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658

1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670


1671


1672
1673
1674
1675
1676
1677
1678
        assert( !ExprHasProperty(pColExpr, EP_IntValue) );
        zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
      }else{
        /* Use the original text of the column expression as its name */
        zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
      }
    }
    if( db->mallocFailed ){
      sqlite3DbFree(db, zName);
      break;
    }

    /* Make sure the column name is unique.  If the name is not unique,
    ** append an integer to the name so that it becomes unique.
    */
    nName = sqlite3Strlen30(zName);
    for(j=cnt=0; j<i; j++){
      if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
        char *zNewName;
        int k;

        for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
        if( k>=0 && zName[k]==':' ) nName = k;
        zName[nName] = 0;
        zNewName = sqlite3MPrintf(db, "%s:%u", zName, ++cnt);
        sqlite3DbFree(db, zName);
        zName = zNewName;
        j = -1;
        if( zName==0 ) break;
        if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
      }
    }
    pCol->zName = zName;


  }


  if( db->mallocFailed ){
    for(j=0; j<i; j++){
      sqlite3DbFree(db, aCol[j].zName);
    }
    sqlite3DbFree(db, aCol);
    *paCol = 0;
    *pnCol = 0;







<
<
<
<




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

>
>
|
>
>







1641
1642
1643
1644
1645
1646
1647




1648
1649
1650
1651

1652
1653
1654

1655
1656
1657
1658
1659
1660
1661


1662
1663

1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
        assert( !ExprHasProperty(pColExpr, EP_IntValue) );
        zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
      }else{
        /* Use the original text of the column expression as its name */
        zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
      }
    }





    /* Make sure the column name is unique.  If the name is not unique,
    ** append an integer to the name so that it becomes unique.
    */

    cnt = 0;
    while( zName && sqlite3HashFind(&ht, zName)!=0 ){
      char *zNewName;

      nName = sqlite3Strlen30(zName);
      for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
      if( zName[j]==':' ) nName = j;
      zName[nName] = 0;
      zNewName = sqlite3MPrintf(db, "%s:%u", zName, ++cnt);
      sqlite3DbFree(db, zName);
      zName = zNewName;


      if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
    }

    pCol->zName = zName;
    if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
      db->mallocFailed = 1;
    }
  }
  sqlite3HashClear(&ht);
  if( db->mallocFailed ){
    for(j=0; j<i; j++){
      sqlite3DbFree(db, aCol[j].zName);
    }
    sqlite3DbFree(db, aCol);
    *paCol = 0;
    *pnCol = 0;