/ Changes On Branch stat4-function
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Changes In Branch stat4-function Excluding Merge-Ins

This is equivalent to a diff from a2715b04 to a991bb1a

2015-03-12
21:22
When STAT4 is enabled, allow probes of the STAT4 table using the value of constant functions computed at compile-time. check-in: 0f250957 user: drh tags: trunk
21:02
Always disallow functions as the DEFAULT of a column. Add assert()s and Closed-Leaf check-in: a991bb1a user: drh tags: stat4-function
18:38
If an error occurs in the compile-time evaluation of an application-defined function, then propagate back out the exact error code, not just the generic SQLITE_ERROR. check-in: 93f42586 user: drh tags: stat4-function
05:08
Improve the text on one of the opcode documentation comments in vdbe.c. check-in: 08958f57 user: drh tags: trunk
2015-03-11
20:06
Allow the query planner to evaluate deterministic scalar SQL functions used in WHERE constraints if all arguments are SQL literals in order to compare the results with sqlite_stat4 sample data. check-in: b7f1fc26 user: dan tags: stat4-function
14:34
Expand the multi-process test cases to repeat each case 20 times and to repeat tests using different journal modes. check-in: a2715b04 user: drh tags: trunk
2015-03-10
15:34
Fix an incrblob2 test case so that it works on 32-bit systems. check-in: 8d0b11c9 user: drh tags: trunk

Changes to src/alter.c.

686
687
688
689
690
691
692

693


694
695
696
697
698
699
700
  }

  /* Ensure the default expression is something that sqlite3ValueFromExpr()
  ** can handle (i.e. not CURRENT_TIME etc.)
  */
  if( pDflt ){
    sqlite3_value *pVal = 0;

    if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){


      db->mallocFailed = 1;
      return;
    }
    if( !pVal ){
      sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
      return;
    }







>
|
>
>







686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  }

  /* Ensure the default expression is something that sqlite3ValueFromExpr()
  ** can handle (i.e. not CURRENT_TIME etc.)
  */
  if( pDflt ){
    sqlite3_value *pVal = 0;
    int rc;
    rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal);
    assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
    if( rc!=SQLITE_OK ){
      db->mallocFailed = 1;
      return;
    }
    if( !pVal ){
      sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
      return;
    }

Changes to src/func.c.

18
19
20
21
22
23
24


25
26
27
28
29
30
31
32
#include <assert.h>
#include "vdbeInt.h"

/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){


  VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1];
  assert( pOp->opcode==OP_CollSeq );
  assert( pOp->p4type==P4_COLLSEQ );
  return pOp->p4.pColl;
}

/*
** Indicate that the accumulator load should be skipped on this







>
>
|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <assert.h>
#include "vdbeInt.h"

/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
  VdbeOp *pOp;
  assert( context->pVdbe!=0 );
  pOp = &context->pVdbe->aOp[context->iOp-1];
  assert( pOp->opcode==OP_CollSeq );
  assert( pOp->p4type==P4_COLLSEQ );
  return pOp->p4.pColl;
}

/*
** Indicate that the accumulator load should be skipped on this

Changes to src/vdbeapi.c.

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
...
629
630
631
632
633
634
635
636




637
638
639
640






641


642
643

644
645
646
647
648
649
650
651
652
...
708
709
710
711
712
713
714





715
716
717
718
719
720
721
...
731
732
733
734
735
736
737





738
739
740
741
742
743
744
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
}
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
  pCtx->isError = errCode;
  pCtx->fErrorOrAux = 1;
#ifdef SQLITE_DEBUG
  pCtx->pVdbe->rcApp = errCode;
#endif
  if( pCtx->pOut->flags & MEM_Null ){
    sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, 
                         SQLITE_UTF8, SQLITE_STATIC);
  }
}

................................................................................
*/
sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
  assert( p && p->pFunc );
  return p->pOut->db;
}

/*
** Return the current time for a statement




*/
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
  Vdbe *v = p->pVdbe;
  int rc;






  if( v->iCurrentTime==0 ){


    rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime);
    if( rc ) v->iCurrentTime = 0;

  }
  return v->iCurrentTime;
}

/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context.  The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
................................................................................
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
*/
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
  AuxData *pAuxData;

  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );





  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
  }

  return (pAuxData ? pAuxData->pAux : 0);
}

................................................................................
  void (*xDelete)(void*)
){
  AuxData *pAuxData;
  Vdbe *pVdbe = pCtx->pVdbe;

  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  if( iArg<0 ) goto failed;






  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
  }
  if( pAuxData==0 ){
    pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
    if( !pAuxData ) goto failed;







|







 







|
>
>
>
>


<

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

|







 







>
>
>
>
>







 







>
>
>
>
>







366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
...
629
630
631
632
633
634
635
636
637
638
639
640
641
642

643
644
645
646
647
648
649
650
651
652
653

654
655
656
657
658
659
660
661
662
663
...
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
}
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
  pCtx->isError = errCode;
  pCtx->fErrorOrAux = 1;
#ifdef SQLITE_DEBUG
  if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif
  if( pCtx->pOut->flags & MEM_Null ){
    sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, 
                         SQLITE_UTF8, SQLITE_STATIC);
  }
}

................................................................................
*/
sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
  assert( p && p->pFunc );
  return p->pOut->db;
}

/*
** Return the current time for a statement.  If the current time
** is requested more than once within the same run of a single prepared
** statement, the exact same time is returned for each invocation regardless
** of the amount of time that elapses between invocations.  In other words,
** the time returned is always the time of the first call.
*/
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){

  int rc;
  sqlite3_int64 iTime = 0;
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
  sqlite3_int64 *piTime = &iTime;
  assert( p->pVdbe!=0 );
#else
  sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime;
  if( *piTime==0 )
#endif
  {
    rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime);

    if( rc ) *piTime = 0;
  }
  return *piTime;
}

/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context.  The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
................................................................................
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
*/
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
  AuxData *pAuxData;

  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#if SQLITE_ENABLE_STAT3_OR_STAT4
  if( pCtx->pVdbe==0 ) return 0;
#else
  assert( pCtx->pVdbe!=0 );
#endif
  for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
  }

  return (pAuxData ? pAuxData->pAux : 0);
}

................................................................................
  void (*xDelete)(void*)
){
  AuxData *pAuxData;
  Vdbe *pVdbe = pCtx->pVdbe;

  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  if( iArg<0 ) goto failed;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( pVdbe==0 ) goto failed;
#else
  assert( pVdbe!=0 );
#endif

  for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
    if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
  }
  if( pAuxData==0 ){
    pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
    if( !pAuxData ) goto failed;

Changes to src/vdbemem.c.

1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
....
1130
1131
1132
1133
1134
1135
1136









































































































1137
1138
1139
1140
1141
1142
1143
....
1161
1162
1163
1164
1165
1166
1167






1168
1169
1170
1171
1172
1173
1174
....
1237
1238
1239
1240
1241
1242
1243




1244
1245
1246
1247
1248
1249
1250
** Allocate and return a pointer to a new sqlite3_value object. If
** the second argument to this function is NULL, the object is allocated
** by calling sqlite3ValueNew().
**
** Otherwise, if the second argument is non-zero, then this function is 
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that 
** that function will return to its caller here. Then return a pointer 
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( p ){
    UnpackedRecord *pRec = p->ppRec[0];

................................................................................
  }
#else
  UNUSED_PARAMETER(p);
#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
  return sqlite3ValueNew(db);
}










































































































/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
** using valueNew().
**
** If pCtx is NULL and an error occurs after the sqlite3_value object
** has been allocated, it is freed before returning. Or, if pCtx is not
................................................................................

  if( !pExpr ){
    *ppVal = 0;
    return SQLITE_OK;
  }
  while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
  if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;







  if( op==TK_CAST ){
    u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
    rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
    testcase( rc!=SQLITE_OK );
    if( *ppVal ){
      sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8);
................................................................................
    zVal = &pExpr->u.zToken[2];
    nVal = sqlite3Strlen30(zVal)-1;
    assert( zVal[nVal]=='\'' );
    sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
                         0, SQLITE_DYNAMIC);
  }
#endif





  *ppVal = pVal;
  return rc;

no_mem:
  db->mallocFailed = 1;
  sqlite3DbFree(db, zVal);







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
....
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
....
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
....
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
** Allocate and return a pointer to a new sqlite3_value object. If
** the second argument to this function is NULL, the object is allocated
** by calling sqlite3ValueNew().
**
** Otherwise, if the second argument is non-zero, then this function is 
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that 
** that function will return to its caller here. Then return a pointer to
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( p ){
    UnpackedRecord *pRec = p->ppRec[0];

................................................................................
  }
#else
  UNUSED_PARAMETER(p);
#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
  return sqlite3ValueNew(db);
}

/*
** The expression object indicated by the second argument is guaranteed
** to be a scalar SQL function. If
**
**   * all function arguments are SQL literals,
**   * the SQLITE_FUNC_CONSTANT function flag is set, and
**   * the SQLITE_FUNC_NEEDCOLL function flag is not set,
**
** then this routine attempts to invoke the SQL function. Assuming no
** error occurs, output parameter (*ppVal) is set to point to a value 
** object containing the result before returning SQLITE_OK.
**
** Affinity aff is applied to the result of the function before returning.
** If the result is a text value, the sqlite3_value object uses encoding 
** enc.
**
** If the conditions above are not met, this function returns SQLITE_OK
** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
** NULL and an SQLite error code returned.
*/
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
static int valueFromFunction(
  sqlite3 *db,                    /* The database connection */
  Expr *p,                        /* The expression to evaluate */
  u8 enc,                         /* Encoding to use */
  u8 aff,                         /* Affinity to use */
  sqlite3_value **ppVal,          /* Write the new value here */
  struct ValueNewStat4Ctx *pCtx   /* Second argument for valueNew() */
){
  sqlite3_context ctx;            /* Context object for function invocation */
  sqlite3_value **apVal = 0;      /* Function arguments */
  int nVal = 0;                   /* Size of apVal[] array */
  FuncDef *pFunc = 0;             /* Function definition */
  sqlite3_value *pVal = 0;        /* New value */
  int rc = SQLITE_OK;             /* Return code */
  int nName;                      /* Size of function name in bytes */
  ExprList *pList = 0;            /* Function arguments */
  int i;                          /* Iterator variable */

  assert( pCtx!=0 );
  assert( (p->flags & EP_TokenOnly)==0 );
  pList = p->x.pList;
  if( pList ) nVal = pList->nExpr;
  nName = sqlite3Strlen30(p->u.zToken);
  pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
  assert( pFunc );
  if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0 
   || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
  ){
    return SQLITE_OK;
  }

  if( pList ){
    apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
    if( apVal==0 ){
      rc = SQLITE_NOMEM;
      goto value_from_function_out;
    }
    for(i=0; i<nVal; i++){
      rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
      if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
    }
  }

  pVal = valueNew(db, pCtx);
  if( pVal==0 ){
    rc = SQLITE_NOMEM;
    goto value_from_function_out;
  }

  memset(&ctx, 0, sizeof(ctx));
  ctx.pOut = pVal;
  ctx.pFunc = pFunc;
  pFunc->xFunc(&ctx, nVal, apVal);
  if( ctx.isError ){
    rc = ctx.isError;
    sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
    pCtx->pParse->rc = rc;
  }else{
    sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
    assert( rc==SQLITE_OK );
    rc = sqlite3VdbeChangeEncoding(pVal, enc);
    if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
      rc = SQLITE_TOOBIG;
    }
  }

 value_from_function_out:
  if( rc!=SQLITE_OK ){
    pVal = 0;
  }
  if( apVal ){
    for(i=0; i<nVal; i++){
      sqlite3ValueFree(apVal[i]);
    }
    sqlite3DbFree(db, apVal);
  }

  *ppVal = pVal;
  return rc;
}
#else
# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */

/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
** using valueNew().
**
** If pCtx is NULL and an error occurs after the sqlite3_value object
** has been allocated, it is freed before returning. Or, if pCtx is not
................................................................................

  if( !pExpr ){
    *ppVal = 0;
    return SQLITE_OK;
  }
  while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
  if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;

  /* Compressed expressions only appear when parsing the DEFAULT clause
  ** on a table column definition, and hence only when pCtx==0.  This
  ** check ensures that an EP_TokenOnly expression is never passed down
  ** into valueFromFunction(). */
  assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 );

  if( op==TK_CAST ){
    u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
    rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
    testcase( rc!=SQLITE_OK );
    if( *ppVal ){
      sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8);
................................................................................
    zVal = &pExpr->u.zToken[2];
    nVal = sqlite3Strlen30(zVal)-1;
    assert( zVal[nVal]=='\'' );
    sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
                         0, SQLITE_DYNAMIC);
  }
#endif

  else if( op==TK_FUNCTION && pCtx!=0 ){
    rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
  }

  *ppVal = pVal;
  return rc;

no_mem:
  db->mallocFailed = 1;
  sqlite3DbFree(db, zVal);

Added test/analyzeF.test.





























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# 2015-03-12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# Test that deterministic scalar functions passed constant arguments
# are used with stat4 data.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix analyzeF

ifcapable {!stat4} {
  finish_test
  return
}

proc isqrt {i} { expr { int(sqrt($i)) } }
db func isqrt isqrt

do_execsql_test 1.0 {
  CREATE TABLE t1(x INTEGER, y INTEGER);
  WITH data(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM data
  )
  INSERT INTO t1 SELECT isqrt(i), isqrt(i) FROM data LIMIT 400;
  CREATE INDEX t1x ON t1(x);
  CREATE INDEX t1y ON t1(y);
  ANALYZE;
}

proc str {a} { return $a }
db func str str

# Note: tests 7 to 12 might be unstable - as they assume SQLite will
# prefer the expression to the right of the AND clause. Which of
# course could change.
#
# Note 2: tests 9 and 10 depend on the tcl interface creating functions
# without the SQLITE_DETERMINISTIC flag set.
#
foreach {tn where idx} {
  1 "x = 4 AND y = 19"     {t1x (x=?)}
  2 "x = 19 AND y = 4"     {t1y (y=?)}
  3 "x = '4' AND y = '19'" {t1x (x=?)}
  4 "x = '19' AND y = '4'" {t1y (y=?)}
  5 "x = substr('5195', 2, 2) AND y = substr('145', 2, 1)" {t1y (y=?)}
  6 "x = substr('145', 2, 1) AND y = substr('5195', 2, 2)" {t1x (x=?)}

  7  "x = substr('5195', 2, 2+0) AND y = substr('145', 2, 1+0)" {t1y (y=?)}
  8  "x = substr('145', 2, 1+0) AND y = substr('5195', 2, 2+0)" {t1y (y=?)}

  9  "x = str('19') AND y = str('4')" {t1y (y=?)}
  10 "x = str('4') AND y = str('19')" {t1y (y=?)}

  11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)}
  12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)}
} {
  set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}"
  do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res
}

do_catchsql_test 2.1 {
  SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
} {1 {no such function: func}}
do_catchsql_test 2.2 {
  UPDATE t1 SET y=y+1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
} {1 {no such function: func}}


finish_test