SQLite4
Check-in [8ac71062f5]
Not logged in

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

Overview
Comment:Add the "CREATE INDEX idx ON tbl USING nm(...)" syntax.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8ac71062f53c96ddbf9b513da5799b9f5f688cad
User & Date: dan 2012-12-19 20:01:06
Context
2012-12-20
18:41
Add "tokenizer=xxx" syntax to fts5. check-in: e0748900db user: dan tags: trunk
2012-12-19
20:01
Add the "CREATE INDEX idx ON tbl USING nm(...)" syntax. check-in: 8ac71062f5 user: dan tags: trunk
2012-12-18
15:47
Add support for NEAR to the fts expression parser. check-in: b1a2a17679 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

  2303   2303     sqlite4VdbeAddOp2(v, OP_Next, iTab, addr1+1);
  2304   2304     sqlite4VdbeJumpHere(v, addr1);
  2305   2305     sqlite4ReleaseTempReg(pParse, regKey);
  2306   2306   
  2307   2307     sqlite4VdbeAddOp1(v, OP_Close, iTab);
  2308   2308     sqlite4VdbeAddOp1(v, OP_Close, iIdx);
  2309   2309   }
         2310  +
         2311  +/*
         2312  +** The CreateIndex structure indicated by the first argument contains the
         2313  +** results of parsing the first part of a CREATE INDEX statement. 
         2314  +** Specifically, everything up to and including the "ON tblname" clause.
         2315  +** The index may be an ordinary index, or it may be a "USING fts5" index.
         2316  +** This function performs processing common to both.
         2317  +*/
         2318  +static Table *createIndexFindTable(
         2319  +  Parse *pParse,                  /* Parsing context */
         2320  +  CreateIndex *p,                 /* First part of CREATE INDEX statement */
         2321  +  Token **ppIdxName,              /* OUT: Pointer to index name token */
         2322  +  char **pzIdxName,               /* OUT: DbMalloc'd copy of index name */
         2323  +  int *piDb                       /* OUT: Database to create index in */
         2324  +){
         2325  +  DbFixer sFix;                   /* For assigning database names to pTblName */
         2326  +  sqlite4 *db = pParse->db;       /* Database handle */
         2327  +  Token *pName = 0;               /* Token containing unqualified index name */
         2328  +  char *zName;                    /* Name of index being created */
         2329  +  int iDb;                        /* Index of database in db->aDb[] */
         2330  +  Table *pTab;                    /* Table object to return */
         2331  +
         2332  +  /* Use the two-part index name to determine the database 
         2333  +  ** to search for the table. 'Fix' the table name to this db
         2334  +  ** before looking up the table.  */
         2335  +  iDb = sqlite4TwoPartName(pParse, &p->tName1, &p->tName2, &pName);
         2336  +  if( iDb<0 ) return 0;
         2337  +  assert( pName && pName->z );
         2338  +
         2339  +#ifndef SQLITE4_OMIT_TEMPDB
         2340  +  /* If the index name was unqualified, check if the the table
         2341  +  ** is a temp table. If so, set the database to 1. Do not do this
         2342  +  ** if initialising a database schema.  */
         2343  +  if( !db->init.busy ){
         2344  +    pTab = sqlite4SrcListLookup(pParse, p->pTblName);
         2345  +    if( p->tName2.n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
         2346  +      iDb = 1;
         2347  +    }
         2348  +  }
         2349  +#endif
         2350  +
         2351  +  if( sqlite4FixInit(&sFix, pParse, iDb, "index", pName) &&
         2352  +      sqlite4FixSrcList(&sFix, p->pTblName)
         2353  +  ){
         2354  +    /* Because the parser constructs pTblName from a single identifier,
         2355  +    ** sqlite4FixSrcList can never fail. */
         2356  +    assert(0);
         2357  +  }
         2358  +
         2359  +  pTab = sqlite4SrcListLookup(pParse, p->pTblName);
         2360  +  if( !pTab || db->mallocFailed ) return 0;
         2361  +  assert( db->aDb[iDb].pSchema==pTab->pSchema );
         2362  +  assert( pParse->nErr==0 );
         2363  +
         2364  +  /* TODO: We will need to reinstate this block when sqlite_master is 
         2365  +  ** modified to use an implicit primary key.  */
         2366  +#if 0
         2367  +  if( sqlite4StrNICmp(pTab->zName, "sqlite_", 7)==0 
         2368  +       && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){
         2369  +    sqlite4ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
         2370  +    goto exit_create_index;
         2371  +  }
         2372  +#endif
         2373  +
         2374  +  /* Verify that this is not an attempt to create an index on a view or
         2375  +  ** virtual table. */
         2376  +  if( IsView(pTab) ){
         2377  +    sqlite4ErrorMsg(pParse, "views may not be indexed");
         2378  +    return 0;
         2379  +  }
         2380  +  if( IsVirtual(pTab) ){
         2381  +    sqlite4ErrorMsg(pParse, "virtual tables may not be indexed");
         2382  +    return 0;
         2383  +  }
         2384  +
         2385  +  /* Ensure that the proposed index name is not reserved. */
         2386  +  assert( pName->z!=0 );
         2387  +  zName = sqlite4NameFromToken(db, pName);
         2388  +  if( zName==0 || sqlite4CheckObjectName(pParse, zName) ) return 0;
         2389  +
         2390  +  /* Unless SQLite is currently parsing an existing database schema, check
         2391  +  ** that there is not already an index or table using the proposed name.  */
         2392  +  if( !db->init.busy ){
         2393  +    char *zDb = db->aDb[iDb].zName;
         2394  +    if( sqlite4FindTable(db, zName, zDb)!=0 ){
         2395  +      sqlite4ErrorMsg(pParse, "there is already a table named %s", zName);
         2396  +    }
         2397  +    else if( sqlite4FindIndex(db, zName, zDb)!=0 ){
         2398  +      if( p->bIfnotexist ){
         2399  +        assert( !db->init.busy );
         2400  +        sqlite4CodeVerifySchema(pParse, iDb);
         2401  +        pTab = 0;
         2402  +      }else{
         2403  +        sqlite4ErrorMsg(pParse, "index %s already exists", zName);
         2404  +      }
         2405  +    }
         2406  +  }
         2407  +
         2408  +  if( pParse->nErr || pTab==0 ){
         2409  +    sqlite4DbFree(db, zName);
         2410  +    pTab = 0;
         2411  +    zName = 0;
         2412  +  }
         2413  +  *ppIdxName = pName;
         2414  +  *pzIdxName = zName;
         2415  +  *piDb = iDb;
         2416  +  return pTab;
         2417  +}
         2418  +
         2419  +#ifndef SQLITE4_OMIT_AUTHORIZATION
         2420  +static int createIndexAuth(
         2421  +  Parse *pParse,                  /* Parser context */
         2422  +  Table *pTab,                    /* Table index is being created on */
         2423  +  const char *zIdx                /* Name of index being created */
         2424  +){
         2425  +  sqlite4 *db;
         2426  +  int iDb;
         2427  +  int iOp;
         2428  +  const char *zDb;
         2429  +
         2430  +  db = pParse->db;
         2431  +  iDb = sqlite4SchemaToIndex(db, pTab->pSchema);
         2432  +  zDb = db->aDb[iDb].zName;
         2433  +
         2434  +  if( sqlite4AuthCheck(pParse, SQLITE4_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
         2435  +    return 1;
         2436  +  }
         2437  +
         2438  +  iOp = (!OMIT_TEMPDB && iDb==1)?SQLITE4_CREATE_TEMP_INDEX:SQLITE4_CREATE_INDEX;
         2439  +  if( sqlite4AuthCheck(pParse, iOp, zIdx, pTab->zName, zDb) ){
         2440  +    return 1;
         2441  +  }
         2442  +
         2443  +  return 0;
         2444  +}
         2445  +#else
         2446  +# define createIndexAuth(a, b, c) 0
         2447  +#endif // SQLITE4_OMIT_AUTHORIZATION
         2448  +
         2449  +static void createIndexWriteSchema(
         2450  +  Parse *pParse,
         2451  +  Index *pIdx,
         2452  +  Token *pName,
         2453  +  Token *pEnd
         2454  +){
         2455  +  sqlite4 *db = pParse->db;
         2456  +  int iDb;
         2457  +
         2458  +  assert( db->init.busy==0 );
         2459  +  iDb = sqlite4SchemaToIndex(db, pIdx->pSchema);
         2460  +  pIdx->tnum = ++pParse->nMem;
         2461  +  allocateTableNumber(pParse, iDb, pIdx->tnum);
         2462  +
         2463  +  if( pIdx->eIndexType!=SQLITE4_INDEX_PRIMARYKEY ){
         2464  +    Vdbe *v;
         2465  +    char *zStmt;
         2466  +
         2467  +    v = sqlite4GetVdbe(pParse);
         2468  +    if( v==0 ) return;
         2469  +
         2470  +    sqlite4BeginWriteOperation(pParse, 1, iDb);
         2471  +
         2472  +    /* Unless this index is an automatic index created by a UNIQUE 
         2473  +    ** constraint, assemble a CREATE INDEX statement to write into the 
         2474  +    ** sqlite_master table.  */
         2475  +    if( pIdx->eIndexType!=SQLITE4_INDEX_UNIQUE ){
         2476  +      int n = (int)(pEnd->z - pName->z) + pEnd->n;
         2477  +      const char *zUnique = (pIdx->onError==OE_None ? "" : " UNIQUE");
         2478  +      zStmt = sqlite4MPrintf(db, "CREATE%s INDEX %.*s", zUnique, n, pName->z);
         2479  +    }else{
         2480  +      /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
         2481  +      zStmt = 0;
         2482  +    }
         2483  +
         2484  +    /* Add an entry in sqlite_master for this index */
         2485  +    sqlite4NestedParse(pParse, 
         2486  +        "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
         2487  +        db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
         2488  +        pIdx->zName,
         2489  +        pIdx->pTable->zName,
         2490  +        pIdx->tnum,
         2491  +        zStmt
         2492  +    );
         2493  +    sqlite4DbFree(db, zStmt);
         2494  +
         2495  +    /* Fill the index with data and reparse the schema. Code an OP_Expire
         2496  +    ** to invalidate all pre-compiled statements.
         2497  +    */
         2498  +    if( pIdx->eIndexType!=SQLITE4_INDEX_UNIQUE ){
         2499  +      sqlite4RefillIndex(pParse, pIdx, 1);
         2500  +      sqlite4ChangeCookie(pParse, iDb);
         2501  +      sqlite4VdbeAddParseSchemaOp(v, iDb,
         2502  +          sqlite4MPrintf(db, "name='%q' AND type='index'", pIdx->zName));
         2503  +      sqlite4VdbeAddOp1(v, OP_Expire, 0);
         2504  +    }
         2505  +  }
         2506  +}
         2507  +
         2508  +void sqlite4CreateUsingIndex(
         2509  +  Parse *pParse,                  /* Parsing context */
         2510  +  CreateIndex *p,                 /* First part of CREATE INDEX statement */
         2511  +  Token *pUsing,                  /* Token following USING keyword */
         2512  +  Token *pEnd                     /* Final '(' in CREATE INDEX */
         2513  +){
         2514  +  sqlite4 *db = pParse->db;
         2515  +  if( p->bUnique ){
         2516  +    sqlite4ErrorMsg(pParse, "USING %.*s index may not be UNIQUE", 
         2517  +        pUsing->n, pUsing->z
         2518  +    );
         2519  +  }else{
         2520  +    Index *pIdx = 0;              /* New index object */
         2521  +    Table *pTab;
         2522  +    Token *pIdxName = 0;
         2523  +    char *zIdx = 0;
         2524  +    int iDb = 0;
         2525  +
         2526  +    pTab = createIndexFindTable(pParse, p, &pIdxName, &zIdx, &iDb);
         2527  +    if( pTab && 0==createIndexAuth(pParse, pTab, zIdx) ){
         2528  +      char *zExtra = 0;
         2529  +      pIdx = newIndex(pParse, pTab, zIdx, 0, 0, 0, &zExtra);
         2530  +    }
         2531  +    if( pIdx ){
         2532  +      pIdx->eIndexType = SQLITE4_INDEX_FTS5;
         2533  +      if( db->init.busy ){
         2534  +        db->flags |= SQLITE4_InternChanges;
         2535  +        pIdx->tnum = db->init.newTnum;
         2536  +      }else{
         2537  +        createIndexWriteSchema(pParse, pIdx, pIdxName, pEnd);
         2538  +      }
         2539  +
         2540  +      addIndexToHash(db, pIdx);
         2541  +
         2542  +      if( pParse->nErr==0 ){
         2543  +        pIdx->pNext = pTab->pIndex;
         2544  +        pTab->pIndex = pIdx;
         2545  +      }else{
         2546  +        sqlite4DbFree(db, pIdx);
         2547  +      }
         2548  +    }
         2549  +
         2550  +    sqlite4DbFree(db, zIdx);
         2551  +  }
         2552  +
         2553  +  sqlite4SrcListDelete(db, p->pTblName);
         2554  +}
  2310   2555   
  2311   2556   /*
  2312   2557   ** Create a new index for an SQL table.  pName1.pName2 is the name of the index 
  2313   2558   ** and pTblList is the name of the table that is to be indexed.  Both will 
  2314   2559   ** be NULL for a primary key or an index that is created to satisfy a
  2315   2560   ** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable
  2316   2561   ** as the table to be indexed.  pParse->pNewTable is a table that is
................................................................................
  2361   2606       goto exit_create_index;
  2362   2607     }
  2363   2608   
  2364   2609     /*
  2365   2610     ** Find the table that is to be indexed.  Return early if not found.
  2366   2611     */
  2367   2612     if( pTblName!=0 ){
         2613  +    CreateIndex sCreate;
         2614  +    sCreate.bUnique = onError;
         2615  +    sCreate.bIfnotexist = ifNotExist;
         2616  +    sCreate.tCreate = *pStart;
         2617  +    sCreate.tName1 = *pName1;
         2618  +    sCreate.tName2 = *pName2;
         2619  +    sCreate.pTblName = pTblName;
  2368   2620   
  2369         -    /* Use the two-part index name to determine the database 
  2370         -    ** to search for the table. 'Fix' the table name to this db
  2371         -    ** before looking up the table.
  2372         -    */
  2373         -    assert( !bPrimaryKey );
  2374         -    assert( pName1 && pName2 );
  2375         -    iDb = sqlite4TwoPartName(pParse, pName1, pName2, &pName);
  2376         -    if( iDb<0 ) goto exit_create_index;
  2377         -    assert( pName && pName->z );
         2621  +    pTab = createIndexFindTable(pParse, &sCreate, &pName, &zName, &iDb);
         2622  +    if( !pTab ) goto exit_create_index;
  2378   2623   
  2379         -#ifndef SQLITE4_OMIT_TEMPDB
  2380         -    /* If the index name was unqualified, check if the the table
  2381         -    ** is a temp table. If so, set the database to 1. Do not do this
  2382         -    ** if initialising a database schema.
  2383         -    */
  2384         -    if( !db->init.busy ){
  2385         -      pTab = sqlite4SrcListLookup(pParse, pTblName);
  2386         -      if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
  2387         -        iDb = 1;
  2388         -      }
  2389         -    }
  2390         -#endif
  2391         -
  2392         -    if( sqlite4FixInit(&sFix, pParse, iDb, "index", pName) &&
  2393         -        sqlite4FixSrcList(&sFix, pTblName)
  2394         -    ){
  2395         -      /* Because the parser constructs pTblName from a single identifier,
  2396         -      ** sqlite4FixSrcList can never fail. */
  2397         -      assert(0);
  2398         -    }
  2399         -    pTab = sqlite4LocateTable(pParse, 0, pTblName->a[0].zName, 
  2400         -        pTblName->a[0].zDatabase);
  2401         -    if( !pTab || db->mallocFailed ) goto exit_create_index;
  2402         -    assert( db->aDb[iDb].pSchema==pTab->pSchema );
  2403   2624     }else{
         2625  +
  2404   2626       assert( pName==0 );
  2405   2627       assert( pStart==0 );
  2406   2628       pTab = pParse->pNewTable;
  2407   2629       if( !pTab ) goto exit_create_index;
  2408   2630       iDb = sqlite4SchemaToIndex(db, pTab->pSchema);
  2409   2631     }
  2410   2632     pDb = &db->aDb[iDb];
  2411   2633   
  2412   2634     assert( pTab!=0 );
  2413   2635     assert( pParse->nErr==0 );
  2414         -
  2415         -  /* TODO: We will need to reinstate this block when sqlite_master is 
  2416         -  ** modified to use an implicit primary key.  */
  2417         -#if 0
  2418         -  if( sqlite4StrNICmp(pTab->zName, "sqlite_", 7)==0 
  2419         -       && memcmp(&pTab->zName[7],"altertab_",9)!=0 ){
  2420         -    sqlite4ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
  2421         -    goto exit_create_index;
  2422         -  }
  2423         -#endif
  2424         -
  2425         -#ifndef SQLITE4_OMIT_VIEW
  2426         -  if( pTab->pSelect ){
  2427         -    assert( !bPrimaryKey );
  2428         -    sqlite4ErrorMsg(pParse, "views may not be indexed");
  2429         -    goto exit_create_index;
  2430         -  }
  2431         -#endif
  2432         -#ifndef SQLITE4_OMIT_VIRTUALTABLE
  2433         -  if( IsVirtual(pTab) ){
  2434         -    assert( !bPrimaryKey );
  2435         -    sqlite4ErrorMsg(pParse, "virtual tables may not be indexed");
  2436         -    goto exit_create_index;
  2437         -  }
  2438         -#endif
  2439         -
  2440         -  /*
  2441         -  ** Find the name of the index.  Make sure there is not already another
  2442         -  ** index or table with the same name.  
  2443         -  **
  2444         -  ** Exception:  If we are reading the names of permanent indices from the
  2445         -  ** sqlite_master table (because some other process changed the schema) and
  2446         -  ** one of the index names collides with the name of a temporary table or
  2447         -  ** index, then we will continue to process this index.
  2448         -  **
  2449         -  ** If pName==0 it means that we are
  2450         -  ** dealing with a primary key or UNIQUE constraint.  We have to invent our
  2451         -  ** own name.
  2452         -  */
  2453         -  if( pName ){
  2454         -    assert( !bPrimaryKey );
  2455         -    zName = sqlite4NameFromToken(db, pName);
  2456         -    if( zName==0 ) goto exit_create_index;
  2457         -    assert( pName->z!=0 );
  2458         -    if( SQLITE4_OK!=sqlite4CheckObjectName(pParse, zName) ){
  2459         -      goto exit_create_index;
  2460         -    }
  2461         -    if( !db->init.busy ){
  2462         -      if( sqlite4FindTable(db, zName, 0)!=0 ){
  2463         -        sqlite4ErrorMsg(pParse, "there is already a table named %s", zName);
  2464         -        goto exit_create_index;
  2465         -      }
  2466         -    }
  2467         -    if( sqlite4FindIndex(db, zName, pDb->zName)!=0 ){
  2468         -      if( !ifNotExist ){
  2469         -        sqlite4ErrorMsg(pParse, "index %s already exists", zName);
  2470         -      }else{
  2471         -        assert( !db->init.busy );
  2472         -        sqlite4CodeVerifySchema(pParse, iDb);
  2473         -      }
  2474         -      goto exit_create_index;
  2475         -    }
  2476         -  }else if( !bPrimaryKey ){
  2477         -    int n;
  2478         -    Index *pLoop;
  2479         -    for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
  2480         -    zName = sqlite4MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n);
  2481         -  }else{
  2482         -    zName = sqlite4MPrintf(db, "%s", pTab->zName);
  2483         -  }
  2484         -  if( zName==0 ){
  2485         -    goto exit_create_index;
  2486         -  }
  2487         -
  2488         -  /* Check for authorization to create an index.
  2489         -  */
  2490         -#ifndef SQLITE4_OMIT_AUTHORIZATION
  2491         -  if( bPrimaryKey==0 ){
  2492         -    const char *zDb = pDb->zName;
  2493         -    if( sqlite4AuthCheck(pParse, SQLITE4_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
  2494         -      goto exit_create_index;
  2495         -    }
  2496         -    i = SQLITE4_CREATE_INDEX;
  2497         -    if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE4_CREATE_TEMP_INDEX;
  2498         -    if( sqlite4AuthCheck(pParse, i, zName, pTab->zName, zDb) ){
         2636  +  assert( IsVirtual(pTab)==0 && IsView(pTab)==0 );
         2637  +
         2638  +  /* If pName==0 it means that we are dealing with a primary key or 
         2639  +  ** UNIQUE constraint.  We have to invent our own name.  */
         2640  +  if( pName==0 ){
         2641  +    if( !bPrimaryKey ){
         2642  +      int n;
         2643  +      Index *pLoop;
         2644  +      for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
         2645  +      zName = sqlite4MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n);
         2646  +    }else{
         2647  +      zName = sqlite4MPrintf(db, "%s", pTab->zName);
         2648  +    }
         2649  +    if( zName==0 ){
  2499   2650         goto exit_create_index;
  2500   2651       }
  2501   2652     }
  2502         -#endif
         2653  +
         2654  +  /* Check for authorization to create the index.  */
         2655  +  if( bPrimaryKey==0 && createIndexAuth(pParse, pTab, zName) ){
         2656  +    goto exit_create_index;
         2657  +  }
  2503   2658   
  2504   2659     /* If pList==0, it means this routine was called as a result of a PRIMARY
  2505   2660     ** KEY or UNIQUE constraint attached to the last column added to the table 
  2506   2661     ** under construction. So create a fake list to simulate this.
  2507   2662     **
  2508   2663     ** TODO: This 'fake list' could be created by the caller to reduce the
  2509   2664     ** number of parameters passed to this function.
................................................................................
  2688   2843     **
  2689   2844     ** If pTblName==0 it means this index is generated as a primary key
  2690   2845     ** or UNIQUE constraint of a CREATE TABLE statement.  Since the table
  2691   2846     ** has just been created, it contains no data and the index initialization
  2692   2847     ** step can be skipped.
  2693   2848     */
  2694   2849     else{
  2695         -    pIndex->tnum = ++pParse->nMem;
  2696         -    allocateTableNumber(pParse, iDb, pIndex->tnum);
  2697         -    if( bPrimaryKey==0 ){
  2698         -      Vdbe *v;
  2699         -      char *zStmt;
  2700         -
  2701         -      v = sqlite4GetVdbe(pParse);
  2702         -      if( v==0 ) goto exit_create_index;
  2703         -
  2704         -      /* Create the rootpage for the index
  2705         -      */
  2706         -      sqlite4BeginWriteOperation(pParse, 1, iDb);
  2707         -
  2708         -      /* Gather the complete text of the CREATE INDEX statement into
  2709         -       ** the zStmt variable
  2710         -       */
  2711         -      if( pStart ){
  2712         -        assert( pEnd!=0 );
  2713         -        /* A named index with an explicit CREATE INDEX statement */
  2714         -        zStmt = sqlite4MPrintf(db, "CREATE%s INDEX %.*s",
  2715         -            onError==OE_None ? "" : " UNIQUE",
  2716         -            (int)(pEnd->z - pName->z) + 1,
  2717         -            pName->z);
  2718         -      }else{
  2719         -        /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
  2720         -        /* zStmt = sqlite4MPrintf(""); */
  2721         -        zStmt = 0;
  2722         -      }
  2723         -
  2724         -      /* Add an entry in sqlite_master for this index
  2725         -      */
  2726         -      sqlite4NestedParse(pParse, 
  2727         -          "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
  2728         -          db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
  2729         -          pIndex->zName,
  2730         -          pTab->zName,
  2731         -          pIndex->tnum,
  2732         -          zStmt
  2733         -          );
  2734         -      sqlite4DbFree(db, zStmt);
  2735         -
  2736         -      /* Fill the index with data and reparse the schema. Code an OP_Expire
  2737         -       ** to invalidate all pre-compiled statements.
  2738         -       */
  2739         -      if( pTblName ){
  2740         -        sqlite4RefillIndex(pParse, pIndex, 1);
  2741         -        sqlite4ChangeCookie(pParse, iDb);
  2742         -        sqlite4VdbeAddParseSchemaOp(v, iDb,
  2743         -            sqlite4MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
  2744         -        sqlite4VdbeAddOp1(v, OP_Expire, 0);
  2745         -      }
  2746         -    }
         2850  +    createIndexWriteSchema(pParse, pIndex, pName, pEnd);
  2747   2851     }
  2748   2852   
  2749   2853     /* When adding an index to the list of indices for a table, make
  2750   2854     ** sure all indices labeled OE_Replace come after all those labeled
  2751   2855     ** OE_Ignore.  This is necessary for the correct constraint check
  2752   2856     ** processing (in sqlite4GenerateConstraintChecks()) as part of
  2753   2857     ** UPDATE and INSERT statements.  
................................................................................
  2840   2944         sqlite4ErrorMsg(pParse, "no such index: %S", pName, 0);
  2841   2945       }else{
  2842   2946         sqlite4CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
  2843   2947       }
  2844   2948       pParse->checkSchema = 1;
  2845   2949       goto exit_drop_index;
  2846   2950     }
  2847         -  if( pIndex->eIndexType!=SQLITE4_INDEX_USER ){
         2951  +  if( pIndex->eIndexType!=SQLITE4_INDEX_USER 
         2952  +   && pIndex->eIndexType!=SQLITE4_INDEX_FTS5 
         2953  +  ){
  2848   2954       sqlite4ErrorMsg(pParse, "index associated with UNIQUE "
  2849   2955         "or PRIMARY KEY constraint cannot be dropped", 0);
  2850   2956       goto exit_drop_index;
  2851   2957     }
  2852   2958     iDb = sqlite4SchemaToIndex(db, pIndex->pSchema);
  2853   2959   #ifndef SQLITE4_OMIT_AUTHORIZATION
  2854   2960     {

Changes to src/fts5.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   */
    13     13   
    14     14   #include "sqliteInt.h"
    15     15   
           16  +/*
           17  +** Default distance value for NEAR operators.
           18  +*/
    16     19   #define FTS5_DEFAULT_NEAR 10
    17     20   
    18     21   /*
    19     22   ** Token types used by expression parser.
    20     23   */
    21     24   #define TOKEN_EOF       0         /* end of expression - no more tokens */
    22     25   #define TOKEN_PRIMITIVE 1         /* quoted string or non-keyword */
................................................................................
    39     42   struct Fts5Tokenizer {
    40     43     char *zName;                   /* Name of tokenizer (nul-terminated) */
    41     44     void *pCtx;
    42     45     int (*xCreate)(void*, const char**, int, sqlite4_tokenizer**);
    43     46     int (*xTokenize)(void*, sqlite4_tokenizer*,
    44     47         const char*, int, int(*x)(void*, int, const char*, int)
    45     48     );
    46         -  int (*xDestroy)(void*, sqlite4_tokenizer *);
           49  +  int (*xDestroy)(sqlite4_tokenizer *);
    47     50     Fts5Tokenizer *pNext;
    48     51   };
    49     52   
    50     53   /*
    51     54   ** Expression grammar:
    52     55   **
    53     56   **   phrase := PRIMITIVE
................................................................................
   727    730     sqlite4 *db,
   728    731     const char *zName,
   729    732     void *pCtx,
   730    733     int (*xCreate)(void*, const char**, int, sqlite4_tokenizer**),
   731    734     int (*xTokenize)(void*, sqlite4_tokenizer*,
   732    735         const char*, int, int(*x)(void*, int, const char*, int)
   733    736     ),
   734         -  int (*xDestroy)(void*, sqlite4_tokenizer *)
          737  +  int (*xDestroy)(sqlite4_tokenizer *)
   735    738   ){
   736    739     int rc = SQLITE4_OK;
   737    740     sqlite4_mutex_enter(db->mutex);
   738    741   
   739    742     /* It is not possible to override an existing tokenizer */
   740    743     if( fts5FindTokenizer(db, zName) ){
   741    744       rc = SQLITE4_ERROR;
................................................................................
   872    875     sqlite4_context *pCtx, 
   873    876     int nVal, 
   874    877     sqlite4_value **aVal
   875    878   ){
   876    879     int rc;
   877    880     Fts5Expr *pExpr = 0;
   878    881     Fts5Tokenizer *pTok;
   879         -  sqlite4_tokenizer *p;
          882  +  sqlite4_tokenizer *p = 0;
   880    883     sqlite4 *db;
   881    884   
   882    885     const char *zTokenizer;
   883    886     const char *zExpr;
   884    887     const char *zTbl;
   885    888     char *zErr = 0;
   886    889     char *zRet = 0;
................................................................................
   933    936   
   934    937     fts5PrintExpr(db, azCol, pExpr, &zRet);
   935    938     sqlite4_result_text(pCtx, zRet, -1, SQLITE4_TRANSIENT);
   936    939     fts5ExpressionFree(db, pExpr);
   937    940     sqlite4_free(sqlite4_db_env(db), zRet);
   938    941   
   939    942    fts5_parse_expr_out:
          943  +  if( p ) pTok->xDestroy(p);
   940    944     sqlite4DbFree(db, azCol);
   941    945     sqlite4_finalize(pStmt);
   942    946     if( zErr ){
   943    947       sqlite4_result_error(pCtx, zErr, -1);
   944    948       sqlite4DbFree(db, zErr);
   945    949     }
   946    950   }

Changes to src/fts5func.c.

    19     19     int nArg, 
    20     20     sqlite4_tokenizer **pp
    21     21   ){
    22     22     *pp = (sqlite4_tokenizer *)pCtx;
    23     23     return SQLITE4_OK;
    24     24   }
    25     25   
    26         -static int fts5SimpleDestroy(void *pCtx, sqlite4_tokenizer *p){
           26  +static int fts5SimpleDestroy(sqlite4_tokenizer *p){
    27     27     return SQLITE4_OK;
    28     28   }
    29     29   
    30     30   static char fts5Tolower(char c){
    31     31     if( c>='A' && c<='Z' ) c = c + ('a' - 'A');
    32     32     return c;
    33     33   }

Changes to src/parse.y.

  1083   1083       {A = sqlite4ExprListAppend(pParse,X,Y.pExpr);}
  1084   1084   nexprlist(A) ::= expr(Y).
  1085   1085       {A = sqlite4ExprListAppend(pParse,0,Y.pExpr);}
  1086   1086   
  1087   1087   
  1088   1088   ///////////////////////////// The CREATE INDEX command ///////////////////////
  1089   1089   //
  1090         -cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
  1091         -        ON nm(Y) LP idxlist(Z) RP(E). {
  1092         -  sqlite4CreateIndex(pParse, &X, &D, 
  1093         -                     sqlite4SrcListAppend(pParse->db,0,&Y,0), Z, U,
  1094         -                      &S, &E, SQLITE4_SO_ASC, NE, 0);
         1090  +%type createindex {CreateIndex}
         1091  +%destructor createindex {sqlite4SrcListDelete(pParse->db, $$.pTblName);}
         1092  +
         1093  +createindex(C) ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) 
         1094  +        nm(X) dbnm(D) ON nm(Y). {
         1095  +  C.bUnique = U;
         1096  +  C.bIfnotexist = NE;
         1097  +  C.tCreate = S;
         1098  +  C.tName1 = X;
         1099  +  C.tName2 = D;
         1100  +  C.pTblName = sqlite4SrcListAppend(pParse->db, 0, &Y, 0);
         1101  +}
         1102  +
         1103  +cmd ::= createindex(C) LP idxlist(Z) RP(E). {
         1104  +  sqlite4CreateIndex(pParse, &C.tName1, &C.tName2, C.pTblName, Z, 
         1105  +                C.bUnique, &C.tCreate, &E, SQLITE4_SO_ASC, C.bIfnotexist, 0);
  1095   1106   }
  1096   1107   
  1097   1108   %type uniqueflag {int}
  1098   1109   uniqueflag(A) ::= UNIQUE.  {A = OE_Abort;}
  1099   1110   uniqueflag(A) ::= .        {A = OE_None;}
  1100   1111   
  1101   1112   %type idxlist {ExprList*}
................................................................................
  1127   1138     sqlite4ExprListCheckLength(pParse, A, "index");
  1128   1139     if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z;
  1129   1140   }
  1130   1141   
  1131   1142   %type collate {Token}
  1132   1143   collate(C) ::= .                 {C.z = 0; C.n = 0;}
  1133   1144   collate(C) ::= COLLATE ids(X).   {C = X;}
         1145  +
         1146  +cmd ::= createindex(C) USING nm(F) LP RP(E). {
         1147  +  sqlite4CreateUsingIndex(pParse, &C, &F, &E);
         1148  +}
  1134   1149   
  1135   1150   
  1136   1151   ///////////////////////////// The DROP INDEX command /////////////////////////
  1137   1152   //
  1138   1153   cmd ::= DROP INDEX ifexists(E) fullname(X).   {sqlite4DropIndex(pParse, X, E);}
  1139   1154   
  1140   1155   ///////////////////////////// The PRAGMA command /////////////////////////////
................................................................................
  1357   1372   vtabargtoken ::= ANY(X).            {sqlite4VtabArgExtend(pParse,&X);}
  1358   1373   vtabargtoken ::= lp anylist RP(X).  {sqlite4VtabArgExtend(pParse,&X);}
  1359   1374   lp ::= LP(X).                       {sqlite4VtabArgExtend(pParse,&X);}
  1360   1375   anylist ::= .
  1361   1376   anylist ::= anylist LP anylist RP.
  1362   1377   anylist ::= anylist ANY.
  1363   1378   %endif  SQLITE4_OMIT_VIRTUALTABLE
         1379  +

Changes to src/sqlite.h.in.

  4384   4384     const char *zName,
  4385   4385     void *pCtx,
  4386   4386     int (*xCreate)(void*, const char**, int, sqlite4_tokenizer**),
  4387   4387     int (*xTokenize)(void*, sqlite4_tokenizer*,
  4388   4388         const char*, int, 
  4389   4389         int(*x)(void *ctx, int iWeight, const char *zToken, int nToken)
  4390   4390     ),
  4391         -  int (*xDestroy)(void*, sqlite4_tokenizer *)
         4391  +  int (*xDestroy)(sqlite4_tokenizer *)
  4392   4392   );
  4393   4393   
  4394   4394   /*
  4395   4395   ** Undo the hack that converts floating point types to integer for
  4396   4396   ** builds on processors without floating point support.
  4397   4397   */
  4398   4398   #ifdef SQLITE4_OMIT_FLOATING_POINT

Changes to src/sqliteInt.h.

   547    547   typedef struct AggInfo AggInfo;
   548    548   typedef struct AggInfoCol AggInfoCol;
   549    549   typedef struct AggInfoFunc AggInfoFunc;
   550    550   typedef struct AuthContext AuthContext;
   551    551   typedef struct AutoincInfo AutoincInfo;
   552    552   typedef struct CollSeq CollSeq;
   553    553   typedef struct Column Column;
          554  +typedef struct CreateIndex CreateIndex;
   554    555   typedef struct Db Db;
   555    556   typedef struct Schema Schema;
   556    557   typedef struct Expr Expr;
   557    558   typedef struct ExprList ExprList;
   558    559   typedef struct ExprListItem ExprListItem;
   559    560   typedef struct ExprSpan ExprSpan;
   560    561   typedef struct FKey FKey;
................................................................................
  1433   1434   #endif
  1434   1435   };
  1435   1436   
  1436   1437   /* Index.eIndexType must be set to one of the following. */
  1437   1438   #define SQLITE4_INDEX_USER       0 /* Index created by CREATE INDEX statement */
  1438   1439   #define SQLITE4_INDEX_UNIQUE     1 /* Index created by UNIQUE constraint */
  1439   1440   #define SQLITE4_INDEX_PRIMARYKEY 2 /* Index is the tables PRIMARY KEY */
  1440         -#define SQLITE4_INDEX_TEMP       3 /* Index is an automatic index */
         1441  +#define SQLITE4_INDEX_FTS5       3 /* Index is an FTS5 index */
         1442  +#define SQLITE4_INDEX_TEMP       4 /* Index is an automatic index */
  1441   1443   
  1442   1444   /*
  1443   1445   ** Each sample stored in the sqlite_stat3 table is represented in memory 
  1444   1446   ** using a structure of this type.  See documentation at the top of the
  1445   1447   ** analyze.c source file for additional information.
  1446   1448   */
  1447   1449   struct IndexSample {
................................................................................
  1465   1467   ** may contain random values.  Do not make any assumptions about Token.dyn
  1466   1468   ** and Token.n when Token.z==0.
  1467   1469   */
  1468   1470   struct Token {
  1469   1471     const char *z;     /* Text of the token.  Not NULL-terminated! */
  1470   1472     unsigned int n;    /* Number of characters in this token */
  1471   1473   };
         1474  +
         1475  +/*
         1476  +** An instance of this structure holds the results of parsing the first
         1477  +** part of a CREATE INDEX statement. Instances exist only transiently 
         1478  +** during parsing.
         1479  +*/
         1480  +struct CreateIndex {
         1481  +  int bUnique;                    /* True if the UNIQUE keyword was present */
         1482  +  int bIfnotexist;                /* True if IF NOT EXISTS was present */
         1483  +  Token tCreate;                  /* CREATE token */
         1484  +  Token tName1;                   /* First part of two part name */
         1485  +  Token tName2;                   /* Second part of two part name */
         1486  +  SrcList *pTblName;              /* Table index is created on */ 
         1487  +};
  1472   1488   
  1473   1489   /*
  1474   1490   ** One for each column used in source tables.
  1475   1491   */
  1476   1492   struct AggInfoCol {
  1477   1493     Table *pTab;             /* Source table */
  1478   1494     int iTable;              /* Cursor number of the source table */

Changes to src/vdbecodec.c.

   331    331     int nAlloc;    /* Slots of aOut[] allocated */
   332    332   };
   333    333   
   334    334   /*
   335    335   ** Enlarge a memory allocation, if necessary
   336    336   */
   337    337   static int enlargeEncoderAllocation(KeyEncoder *p, int needed){
          338  +  assert( p->nOut<=p->nAlloc );
   338    339     if( p->nOut+needed>p->nAlloc ){
   339    340       u8 *aNew;
   340    341       p->nAlloc = p->nAlloc + needed + 10;
   341    342       aNew = sqlite4DbRealloc(p->db, p->aOut, p->nAlloc);
   342    343       if( aNew==0 ){
   343    344         sqlite4DbFree(p->db, p->aOut);
   344    345         memset(p, 0, sizeof(*p));
................................................................................
   592    593       p->aOut[p->nOut++] = 0x24;   /* Text */
   593    594       if( pColl==0 || pColl->xMkKey==0 ){
   594    595         memcpy(p->aOut+p->nOut, pEnc->z, pEnc->n);
   595    596         p->nOut += pEnc->n;
   596    597       }else{
   597    598         int nSpc = p->nAlloc-p->nOut;
   598    599         n = pColl->xMkKey(pColl->pUser, pEnc->n, pEnc->z, nSpc, p->aOut+p->nOut);
   599         -      if( n>nSpc ){
   600         -        if( enlargeEncoderAllocation(p, n) ) return SQLITE4_NOMEM;
          600  +      if( n+1>nSpc ){
          601  +        if( enlargeEncoderAllocation(p, n+1) ) return SQLITE4_NOMEM;
   601    602           n = pColl->xMkKey(pColl->pUser, pEnc->n, pEnc->z, n, p->aOut+p->nOut);
   602    603         }
   603    604         p->nOut += n;
   604    605       }
   605    606       p->aOut[p->nOut++] = 0x00;
   606    607   
   607    608       /* Release any memory allocated to hold the translated text */
................................................................................
   632    633       }
   633    634       if( s>1 ) p->aOut[p->nOut++] = 0x80 | t;
   634    635       p->aOut[p->nOut++] = 0x00;
   635    636     }
   636    637     if( sortOrder==SQLITE4_SO_DESC ){
   637    638       for(i=iStart; i<p->nOut; i++) p->aOut[i] ^= 0xff;
   638    639     }
          640  +  assert( p->nOut<=p->nAlloc );
   639    641     return SQLITE4_OK;
   640    642   }
   641    643   
   642    644   /*
   643    645   ** Variables aKey/nKey contain an encoded index key. This function returns
   644    646   ** the length (in bytes) of the key with all but the first nField fields
   645    647   ** removed.

Added test/fts5create.test.

            1  +# 2012 December 18
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#*************************************************************************
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +set testprefix fts5create
           16  +
           17  +do_execsql_test 1.1 { 
           18  +  CREATE TABLE t1(a, b, c);
           19  +}
           20  +
           21  +do_execsql_test 1.2 { 
           22  +  CREATE INDEX ft1 ON t1 USING fts5();
           23  +  SELECT * FROM sqlite_master;
           24  +} {
           25  +  table t1 t1  2 "CREATE TABLE t1(a, b, c)"
           26  +  index ft1 t1 3 "CREATE INDEX ft1 ON t1 USING fts5()"
           27  +}
           28  +
           29  +do_execsql_test 1.3 { 
           30  +  DROP INDEX ft1;
           31  +  SELECT * FROM sqlite_master;
           32  +} {
           33  +  table t1 t1  2 "CREATE TABLE t1(a, b, c)"
           34  +}
           35  +
           36  +
           37  +finish_test

Changes to test/simple.test.

    96     96   #
    97     97   do_execsql_test 3.3 { INSERT INTO t1 VALUES('one', '111') } {}
    98     98   
    99     99   
   100    100   #-------------------------------------------------------------------------
   101    101   reset_db
   102    102   
          103  +breakpoint
   103    104   do_execsql_test 4.1 { CREATE TABLE t1(k PRIMARY KEY, v) }
   104    105   do_execsql_test 4.2 { CREATE INDEX i1 ON t1(v) }
   105    106   
   106    107   do_execsql_test 4.3 { 
   107    108     SELECT * FROM sqlite_master
   108    109   } {
   109    110     table t1 t1 2 {CREATE TABLE t1(k PRIMARY KEY, v)}