/ Check-in [777189ce]
Login

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

Overview
Comment:Store application-defined function names as lower-case to avoid the need for case conversions before calling xFindFunction on virtual tables. Avoid using lookaside to store the destructors for application defined functions, as lookaside should be reserved for transient allocations.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 777189ce88799f93f393fd14fd716111c85bcdcb23690fd561f78ea2bd2ce5da
User & Date: drh 2018-05-26 16:00:26
Context
2018-05-28
18:25
When compiling with SQLITE_DEBUG, add run-time checks to ensure that no statement aborts unless either there have been no writes or else there is a statement journal. check-in: ce99c772 user: drh tags: trunk
17:31
When compiling with SQLITE_DEBUG, add run-time checks to ensure that no statement aborts unless either there have been no writes or else there is a statement journal. check-in: 5a4542db user: drh tags: stmt-journal-testing
2018-05-26
18:03
Experimental change that allows overloaded functions to be analyzed by the xBestIndex method and used by the xFilter method of a virtual table. Leaf check-in: a353b1d7 user: drh tags: vtab-func-constraint
16:00
Store application-defined function names as lower-case to avoid the need for case conversions before calling xFindFunction on virtual tables. Avoid using lookaside to store the destructors for application defined functions, as lookaside should be reserved for transient allocations. check-in: 777189ce user: drh tags: trunk
13:55
Add a single sentence of documentation about the virtual table scan flags. No changes to code. check-in: 27b4fa5d user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/callback.c.

   402    402     /* If the createFlag parameter is true and the search did not reveal an
   403    403     ** exact match for the name, number of arguments and encoding, then add a
   404    404     ** new entry to the hash table and return it.
   405    405     */
   406    406     if( createFlag && bestScore<FUNC_PERFECT_MATCH && 
   407    407         (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
   408    408       FuncDef *pOther;
          409  +    u8 *z;
   409    410       pBest->zName = (const char*)&pBest[1];
   410    411       pBest->nArg = (u16)nArg;
   411    412       pBest->funcFlags = enc;
   412    413       memcpy((char*)&pBest[1], zName, nName+1);
          414  +    for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z];
   413    415       pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
   414    416       if( pOther==pBest ){
   415    417         sqlite3DbFree(db, pBest);
   416    418         sqlite3OomFault(db);
   417    419         return 0;
   418    420       }else{
   419    421         pBest->pNext = pOther;

Changes to src/main.c.

  1804   1804   #ifdef SQLITE_ENABLE_API_ARMOR
  1805   1805     if( !sqlite3SafetyCheckOk(db) ){
  1806   1806       return SQLITE_MISUSE_BKPT;
  1807   1807     }
  1808   1808   #endif
  1809   1809     sqlite3_mutex_enter(db->mutex);
  1810   1810     if( xDestroy ){
  1811         -    pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
         1811  +    pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor));
  1812   1812       if( !pArg ){
         1813  +      sqlite3OomFault(db);
  1813   1814         xDestroy(p);
  1814   1815         goto out;
  1815   1816       }
         1817  +    pArg->nRef = 0;
  1816   1818       pArg->xDestroy = xDestroy;
  1817   1819       pArg->pUserData = p;
  1818   1820     }
  1819   1821     rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
  1820   1822     if( pArg && pArg->nRef==0 ){
  1821   1823       assert( rc!=SQLITE_OK );
  1822   1824       xDestroy(p);
  1823         -    sqlite3DbFree(db, pArg);
         1825  +    sqlite3_free(pArg);
  1824   1826     }
  1825   1827   
  1826   1828    out:
  1827   1829     rc = sqlite3ApiExit(db, rc);
  1828   1830     sqlite3_mutex_leave(db->mutex);
  1829   1831     return rc;
  1830   1832   }
................................................................................
  1853   1855     sqlite3DbFree(db, zFunc8);
  1854   1856     rc = sqlite3ApiExit(db, rc);
  1855   1857     sqlite3_mutex_leave(db->mutex);
  1856   1858     return rc;
  1857   1859   }
  1858   1860   #endif
  1859   1861   
         1862  +
         1863  +/*
         1864  +** The following is the implementation of an SQL function that always
         1865  +** fails with an error message stating that the function is used in the
         1866  +** wrong context.  The sqlite3_overload_function() API might construct
         1867  +** SQL function that use this routine so that the functions will exist
         1868  +** for name resolution but are actually overloaded by the xFindFunction
         1869  +** method of virtual tables.
         1870  +*/
         1871  +static void sqlite3InvalidFunction(
         1872  +  sqlite3_context *context,  /* The function calling context */
         1873  +  int NotUsed,               /* Number of arguments to the function */
         1874  +  sqlite3_value **NotUsed2   /* Value of each argument */
         1875  +){
         1876  +  const char *zName = (const char*)sqlite3_user_data(context);
         1877  +  char *zErr;
         1878  +  UNUSED_PARAMETER2(NotUsed, NotUsed2);
         1879  +  zErr = sqlite3_mprintf(
         1880  +      "unable to use function %s in the requested context", zName);
         1881  +  sqlite3_result_error(context, zErr, -1);
         1882  +  sqlite3_free(zErr);
         1883  +}
  1860   1884   
  1861   1885   /*
  1862   1886   ** Declare that a function has been overloaded by a virtual table.
  1863   1887   **
  1864   1888   ** If the function already exists as a regular global function, then
  1865   1889   ** this routine is a no-op.  If the function does not exist, then create
  1866   1890   ** a new one that always throws a run-time error.  
................................................................................
  1871   1895   ** properly.
  1872   1896   */
  1873   1897   int sqlite3_overload_function(
  1874   1898     sqlite3 *db,
  1875   1899     const char *zName,
  1876   1900     int nArg
  1877   1901   ){
  1878         -  int rc = SQLITE_OK;
         1902  +  int rc;
         1903  +  char *zCopy;
  1879   1904   
  1880   1905   #ifdef SQLITE_ENABLE_API_ARMOR
  1881   1906     if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
  1882   1907       return SQLITE_MISUSE_BKPT;
  1883   1908     }
  1884   1909   #endif
  1885   1910     sqlite3_mutex_enter(db->mutex);
  1886         -  if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
  1887         -    rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
  1888         -                           0, sqlite3InvalidFunction, 0, 0, 0);
  1889         -  }
  1890         -  rc = sqlite3ApiExit(db, rc);
         1911  +  rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
  1891   1912     sqlite3_mutex_leave(db->mutex);
  1892         -  return rc;
         1913  +  if( rc ) return SQLITE_OK;
         1914  +  zCopy = sqlite3_mprintf(zName);
         1915  +  if( zCopy==0 ) return SQLITE_NOMEM;
         1916  +  return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
         1917  +                           zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
  1893   1918   }
  1894   1919   
  1895   1920   #ifndef SQLITE_OMIT_TRACE
  1896   1921   /*
  1897   1922   ** Register a trace function.  The pArg from the previously registered trace
  1898   1923   ** is returned.  
  1899   1924   **

Changes to src/sqliteInt.h.

  4162   4162   int sqlite3KeyInfoIsWriteable(KeyInfo*);
  4163   4163   #endif
  4164   4164   int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
  4165   4165     void (*)(sqlite3_context*,int,sqlite3_value **),
  4166   4166     void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
  4167   4167     FuncDestructor *pDestructor
  4168   4168   );
         4169  +void sqlite3NoopDestructor(void*);
  4169   4170   void sqlite3OomFault(sqlite3*);
  4170   4171   void sqlite3OomClear(sqlite3*);
  4171   4172   int sqlite3ApiExit(sqlite3 *db, int);
  4172   4173   int sqlite3OpenTempDatabase(Parse *);
  4173   4174   
  4174   4175   void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
  4175   4176   char *sqlite3StrAccumFinish(StrAccum*);
................................................................................
  4264   4265   void sqlite3VtabArgInit(Parse*);
  4265   4266   void sqlite3VtabArgExtend(Parse*, Token*);
  4266   4267   int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
  4267   4268   int sqlite3VtabCallConnect(Parse*, Table*);
  4268   4269   int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
  4269   4270   int sqlite3VtabBegin(sqlite3 *, VTable *);
  4270   4271   FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
  4271         -void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
  4272   4272   sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
  4273   4273   int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
  4274   4274   int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
  4275   4275   void sqlite3ParserReset(Parse*);
  4276   4276   int sqlite3Reprepare(Vdbe*);
  4277   4277   void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
  4278   4278   CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);

Changes to src/vdbeapi.c.

   783    783     if( *piTime==0 ){
   784    784       rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime);
   785    785       if( rc ) *piTime = 0;
   786    786     }
   787    787     return *piTime;
   788    788   }
   789    789   
   790         -/*
   791         -** The following is the implementation of an SQL function that always
   792         -** fails with an error message stating that the function is used in the
   793         -** wrong context.  The sqlite3_overload_function() API might construct
   794         -** SQL function that use this routine so that the functions will exist
   795         -** for name resolution but are actually overloaded by the xFindFunction
   796         -** method of virtual tables.
   797         -*/
   798         -void sqlite3InvalidFunction(
   799         -  sqlite3_context *context,  /* The function calling context */
   800         -  int NotUsed,               /* Number of arguments to the function */
   801         -  sqlite3_value **NotUsed2   /* Value of each argument */
   802         -){
   803         -  const char *zName = context->pFunc->zName;
   804         -  char *zErr;
   805         -  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   806         -  zErr = sqlite3_mprintf(
   807         -      "unable to use function %s in the requested context", zName);
   808         -  sqlite3_result_error(context, zErr, -1);
   809         -  sqlite3_free(zErr);
   810         -}
   811         -
   812    790   /*
   813    791   ** Create a new aggregate context for p and return a pointer to
   814    792   ** its pMem->z element.
   815    793   */
   816    794   static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
   817    795     Mem *pMem = p->pMem;
   818    796     assert( (pMem->flags & MEM_Agg)==0 );

Changes to src/vdbemem.c.

   796    796     }else{
   797    797       pMem->u.i = val;
   798    798       pMem->flags = MEM_Int;
   799    799     }
   800    800   }
   801    801   
   802    802   /* A no-op destructor */
   803         -static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
          803  +void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
   804    804   
   805    805   /*
   806    806   ** Set the value stored in *pMem should already be a NULL.
   807    807   ** Also store a pointer to go with it.
   808    808   */
   809    809   void sqlite3VdbeMemSetPointer(
   810    810     Mem *pMem,

Changes to src/vtab.c.

  1045   1045     Table *pTab;
  1046   1046     sqlite3_vtab *pVtab;
  1047   1047     sqlite3_module *pMod;
  1048   1048     void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
  1049   1049     void *pArg = 0;
  1050   1050     FuncDef *pNew;
  1051   1051     int rc = 0;
  1052         -  char *zLowerName;
  1053         -  unsigned char *z;
  1054         -
  1055   1052   
  1056   1053     /* Check to see the left operand is a column in a virtual table */
  1057   1054     if( NEVER(pExpr==0) ) return pDef;
  1058   1055     if( pExpr->op!=TK_COLUMN ) return pDef;
  1059   1056     pTab = pExpr->pTab;
  1060   1057     if( pTab==0 ) return pDef;
  1061   1058     if( !IsVirtual(pTab) ) return pDef;
................................................................................
  1062   1059     pVtab = sqlite3GetVTable(db, pTab)->pVtab;
  1063   1060     assert( pVtab!=0 );
  1064   1061     assert( pVtab->pModule!=0 );
  1065   1062     pMod = (sqlite3_module *)pVtab->pModule;
  1066   1063     if( pMod->xFindFunction==0 ) return pDef;
  1067   1064    
  1068   1065     /* Call the xFindFunction method on the virtual table implementation
  1069         -  ** to see if the implementation wants to overload this function 
         1066  +  ** to see if the implementation wants to overload this function.
         1067  +  **
         1068  +  ** Though undocumented, we have historically always invoked xFindFunction
         1069  +  ** with an all lower-case function name.  Continue in this tradition to
         1070  +  ** avoid any chance of an incompatibility.
  1070   1071     */
  1071         -  zLowerName = sqlite3DbStrDup(db, pDef->zName);
  1072         -  if( zLowerName ){
  1073         -    for(z=(unsigned char*)zLowerName; *z; z++){
  1074         -      *z = sqlite3UpperToLower[*z];
         1072  +#ifdef SQLITE_DEBUG
         1073  +  {
         1074  +    int i;
         1075  +    for(i=0; pDef->zName[i]; i++){
         1076  +      unsigned char x = (unsigned char)pDef->zName[i];
         1077  +      assert( x==sqlite3UpperToLower[x] );
  1075   1078       }
  1076         -    rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
  1077         -    sqlite3DbFree(db, zLowerName);
  1078   1079     }
         1080  +#endif
         1081  +  rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg);
  1079   1082     if( rc==0 ){
  1080   1083       return pDef;
  1081   1084     }
  1082   1085   
  1083   1086     /* Create a new ephemeral function definition for the overloaded
  1084   1087     ** function */
  1085   1088     pNew = sqlite3DbMallocZero(db, sizeof(*pNew)