/ Check-in [f0fd2163]
Login

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

Overview
Comment:Add the "prefixes" table-valued function in the ext/misc folder.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f0fd2163fc23a555ef03af43294a14fcabae6921f52e64c979286c745b4f6218
User & Date: drh 2019-01-14 16:16:30
Context
2019-01-14
19:13
Fix a problem causing some Tcl test cases to fail with errors like "expected: [<multiline-whitespace>], got: []". check-in: 11b8a4cb user: dan tags: trunk
16:16
Add the "prefixes" table-valued function in the ext/misc folder. check-in: f0fd2163 user: drh tags: trunk
15:35
Fix a problem causing a crash if an fts5vocab table was created to query an fts3/4 FTS index. check-in: 9cd64ce4 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Added ext/misc/prefixes.c.

            1  +/*
            2  +** 2018-04-19
            3  +**
            4  +** The author disclaims copyright to this source code.  In place of
            5  +** a legal notice, here is a blessing:
            6  +**
            7  +**    May you do good and not evil.
            8  +**    May you find forgiveness for yourself and forgive others.
            9  +**    May you share freely, never taking more than you give.
           10  +**
           11  +*************************************************************************
           12  +**
           13  +** This file implements a table-valued function:
           14  +**
           15  +**      prefixes('abcdefg')
           16  +**
           17  +** The function has a single (non-HIDDEN) column named prefix that takes
           18  +** on all prefixes of the string in its argument, including an empty string
           19  +** and the input string itself.  The order of prefixes is from longest
           20  +** to shortest.
           21  +*/
           22  +#if !defined(SQLITEINT_H)
           23  +#include "sqlite3ext.h"
           24  +#endif
           25  +SQLITE_EXTENSION_INIT1
           26  +#include <string.h>
           27  +#include <assert.h>
           28  +
           29  +/* prefixes_vtab is a subclass of sqlite3_vtab which is
           30  +** underlying representation of the virtual table
           31  +*/
           32  +typedef struct prefixes_vtab prefixes_vtab;
           33  +struct prefixes_vtab {
           34  +  sqlite3_vtab base;  /* Base class - must be first */
           35  +  /* No additional fields are necessary */
           36  +};
           37  +
           38  +/* prefixes_cursor is a subclass of sqlite3_vtab_cursor which will
           39  +** serve as the underlying representation of a cursor that scans
           40  +** over rows of the result
           41  +*/
           42  +typedef struct prefixes_cursor prefixes_cursor;
           43  +struct prefixes_cursor {
           44  +  sqlite3_vtab_cursor base;  /* Base class - must be first */
           45  +  sqlite3_int64 iRowid;      /* The rowid */
           46  +  char *zStr;                /* Original string to be prefixed */
           47  +  int nStr;                  /* Length of the string in bytes */
           48  +};
           49  +
           50  +/*
           51  +** The prefixesConnect() method is invoked to create a new
           52  +** template virtual table.
           53  +**
           54  +** Think of this routine as the constructor for prefixes_vtab objects.
           55  +**
           56  +** All this routine needs to do is:
           57  +**
           58  +**    (1) Allocate the prefixes_vtab object and initialize all fields.
           59  +**
           60  +**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
           61  +**        result set of queries against the virtual table will look like.
           62  +*/
           63  +static int prefixesConnect(
           64  +  sqlite3 *db,
           65  +  void *pAux,
           66  +  int argc, const char *const*argv,
           67  +  sqlite3_vtab **ppVtab,
           68  +  char **pzErr
           69  +){
           70  +  prefixes_vtab *pNew;
           71  +  int rc;
           72  +
           73  +  rc = sqlite3_declare_vtab(db,
           74  +           "CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)"
           75  +       );
           76  +  if( rc==SQLITE_OK ){
           77  +    pNew = sqlite3_malloc( sizeof(*pNew) );
           78  +    *ppVtab = (sqlite3_vtab*)pNew;
           79  +    if( pNew==0 ) return SQLITE_NOMEM;
           80  +    memset(pNew, 0, sizeof(*pNew));
           81  +  }
           82  +  return rc;
           83  +}
           84  +
           85  +/*
           86  +** This method is the destructor for prefixes_vtab objects.
           87  +*/
           88  +static int prefixesDisconnect(sqlite3_vtab *pVtab){
           89  +  prefixes_vtab *p = (prefixes_vtab*)pVtab;
           90  +  sqlite3_free(p);
           91  +  return SQLITE_OK;
           92  +}
           93  +
           94  +/*
           95  +** Constructor for a new prefixes_cursor object.
           96  +*/
           97  +static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
           98  +  prefixes_cursor *pCur;
           99  +  pCur = sqlite3_malloc( sizeof(*pCur) );
          100  +  if( pCur==0 ) return SQLITE_NOMEM;
          101  +  memset(pCur, 0, sizeof(*pCur));
          102  +  *ppCursor = &pCur->base;
          103  +  return SQLITE_OK;
          104  +}
          105  +
          106  +/*
          107  +** Destructor for a prefixes_cursor.
          108  +*/
          109  +static int prefixesClose(sqlite3_vtab_cursor *cur){
          110  +  prefixes_cursor *pCur = (prefixes_cursor*)cur;
          111  +  sqlite3_free(pCur->zStr);
          112  +  sqlite3_free(pCur);
          113  +  return SQLITE_OK;
          114  +}
          115  +
          116  +
          117  +/*
          118  +** Advance a prefixes_cursor to its next row of output.
          119  +*/
          120  +static int prefixesNext(sqlite3_vtab_cursor *cur){
          121  +  prefixes_cursor *pCur = (prefixes_cursor*)cur;
          122  +  pCur->iRowid++;
          123  +  return SQLITE_OK;
          124  +}
          125  +
          126  +/*
          127  +** Return values of columns for the row at which the prefixes_cursor
          128  +** is currently pointing.
          129  +*/
          130  +static int prefixesColumn(
          131  +  sqlite3_vtab_cursor *cur,   /* The cursor */
          132  +  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
          133  +  int i                       /* Which column to return */
          134  +){
          135  +  prefixes_cursor *pCur = (prefixes_cursor*)cur;
          136  +  switch( i ){
          137  +    case 0:
          138  +      sqlite3_result_text(ctx, pCur->zStr, pCur->nStr - (int)pCur->iRowid,
          139  +                          0); 
          140  +      break;
          141  +    default:
          142  +      sqlite3_result_text(ctx, pCur->zStr, pCur->nStr, 0);
          143  +      break;
          144  +  }
          145  +  return SQLITE_OK;
          146  +}
          147  +
          148  +/*
          149  +** Return the rowid for the current row.  In this implementation, the
          150  +** rowid is the same as the output value.
          151  +*/
          152  +static int prefixesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
          153  +  prefixes_cursor *pCur = (prefixes_cursor*)cur;
          154  +  *pRowid = pCur->iRowid;
          155  +  return SQLITE_OK;
          156  +}
          157  +
          158  +/*
          159  +** Return TRUE if the cursor has been moved off of the last
          160  +** row of output.
          161  +*/
          162  +static int prefixesEof(sqlite3_vtab_cursor *cur){
          163  +  prefixes_cursor *pCur = (prefixes_cursor*)cur;
          164  +  return pCur->iRowid>pCur->nStr;
          165  +}
          166  +
          167  +/*
          168  +** This method is called to "rewind" the prefixes_cursor object back
          169  +** to the first row of output.  This method is always called at least
          170  +** once prior to any call to prefixesColumn() or prefixesRowid() or 
          171  +** prefixesEof().
          172  +*/
          173  +static int prefixesFilter(
          174  +  sqlite3_vtab_cursor *pVtabCursor, 
          175  +  int idxNum, const char *idxStr,
          176  +  int argc, sqlite3_value **argv
          177  +){
          178  +  prefixes_cursor *pCur = (prefixes_cursor *)pVtabCursor;
          179  +  sqlite3_free(pCur->zStr);
          180  +  if( argc>0 ){
          181  +    pCur->zStr = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
          182  +    pCur->nStr = pCur->zStr ? (int)strlen(pCur->zStr) : 0;
          183  +  }else{
          184  +    pCur->zStr = 0;
          185  +    pCur->nStr = 0;
          186  +  }
          187  +  pCur->iRowid = 0;
          188  +  return SQLITE_OK;
          189  +}
          190  +
          191  +/*
          192  +** SQLite will invoke this method one or more times while planning a query
          193  +** that uses the virtual table.  This routine needs to create
          194  +** a query plan for each invocation and compute an estimated cost for that
          195  +** plan.
          196  +*/
          197  +static int prefixesBestIndex(
          198  +  sqlite3_vtab *tab,
          199  +  sqlite3_index_info *pIdxInfo
          200  +){
          201  +  /* Search for a usable equality constraint against column 1 
          202  +  ** (original_string) and use it if at all possible */
          203  +  int i;
          204  +  const struct sqlite3_index_constraint *p;
          205  +
          206  +  for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
          207  +    if( p->iColumn!=1 ) continue;
          208  +    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
          209  +    if( !p->usable ) continue;
          210  +    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
          211  +    pIdxInfo->aConstraintUsage[i].omit = 1;
          212  +    pIdxInfo->estimatedCost = (double)10;
          213  +    pIdxInfo->estimatedRows = 10;
          214  +    return SQLITE_OK;
          215  +  }
          216  +  pIdxInfo->estimatedCost = (double)1000000000;
          217  +  pIdxInfo->estimatedRows = 1000000000;
          218  +  return SQLITE_OK;
          219  +}
          220  +
          221  +/*
          222  +** This following structure defines all the methods for the 
          223  +** virtual table.
          224  +*/
          225  +static sqlite3_module prefixesModule = {
          226  +  /* iVersion    */ 0,
          227  +  /* xCreate     */ 0,
          228  +  /* xConnect    */ prefixesConnect,
          229  +  /* xBestIndex  */ prefixesBestIndex,
          230  +  /* xDisconnect */ prefixesDisconnect,
          231  +  /* xDestroy    */ 0,
          232  +  /* xOpen       */ prefixesOpen,
          233  +  /* xClose      */ prefixesClose,
          234  +  /* xFilter     */ prefixesFilter,
          235  +  /* xNext       */ prefixesNext,
          236  +  /* xEof        */ prefixesEof,
          237  +  /* xColumn     */ prefixesColumn,
          238  +  /* xRowid      */ prefixesRowid,
          239  +  /* xUpdate     */ 0,
          240  +  /* xBegin      */ 0,
          241  +  /* xSync       */ 0,
          242  +  /* xCommit     */ 0,
          243  +  /* xRollback   */ 0,
          244  +  /* xFindMethod */ 0,
          245  +  /* xRename     */ 0,
          246  +  /* xSavepoint  */ 0,
          247  +  /* xRelease    */ 0,
          248  +  /* xRollbackTo */ 0,
          249  +  /* xShadowName */ 0
          250  +};
          251  +
          252  +
          253  +#ifdef _WIN32
          254  +__declspec(dllexport)
          255  +#endif
          256  +int sqlite3_prefixes_init(
          257  +  sqlite3 *db, 
          258  +  char **pzErrMsg, 
          259  +  const sqlite3_api_routines *pApi
          260  +){
          261  +  int rc = SQLITE_OK;
          262  +  SQLITE_EXTENSION_INIT2(pApi);
          263  +  rc = sqlite3_create_module(db, "prefixes", &prefixesModule, 0);
          264  +  return rc;
          265  +}