SQLite

Check-in [5720dcd8b1]
Login

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

Overview
Comment:Ensure that all four callbacks are provided when registering a window function (otherwise SQLITE_MISUSE is returned).
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | exp-window-functions
Files: files | file ages | folders
SHA3-256: 5720dcd8b111b1f8712c8fb4b441ccb129e838db8c26a6e9e0f095dc6a851f6b
User & Date: dan 2018-06-18 17:36:41.529
Context
2018-06-18
20:34
Fix problems with using window functions in CREATE VIEW statements. (check-in: 943bccd2a6 user: dan tags: exp-window-functions)
17:36
Ensure that all four callbacks are provided when registering a window function (otherwise SQLITE_MISUSE is returned). (check-in: 5720dcd8b1 user: dan tags: exp-window-functions)
16:55
Add new API function sqlite3_create_window_function(), for creating new aggregate window functions. (check-in: da03fb4318 user: dan tags: exp-window-functions)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
1692
1693
1694
1695
1696
1697
1698

1699
1700
1701
1702
1703
1704
1705
  int extraFlags;

  assert( sqlite3_mutex_held(db->mutex) );
  if( zFunctionName==0 ||
      (xSFunc && (xFinal || xStep)) || 
      (!xSFunc && (xFinal && !xStep)) ||
      (!xSFunc && (!xFinal && xStep)) ||

      (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
      (255<(nName = sqlite3Strlen30( zFunctionName))) ){
    return SQLITE_MISUSE_BKPT;
  }

  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
  extraFlags = enc &  SQLITE_DETERMINISTIC;







>







1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
  int extraFlags;

  assert( sqlite3_mutex_held(db->mutex) );
  if( zFunctionName==0 ||
      (xSFunc && (xFinal || xStep)) || 
      (!xSFunc && (xFinal && !xStep)) ||
      (!xSFunc && (!xFinal && xStep)) ||
      ((xValue || xInverse) && (!xStep || !xFinal || !xValue || !xInverse)) ||
      (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
      (255<(nName = sqlite3Strlen30( zFunctionName))) ){
    return SQLITE_MISUSE_BKPT;
  }

  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
  extraFlags = enc &  SQLITE_DETERMINISTIC;
Changes to src/test_window.c.
171
172
173
174
175
176
177











































178
179
180
181
182
183
184
185

186
187
188
189
190
191
192
  if( rc!=SQLITE_OK ){
    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
    return TCL_ERROR;
  }

  return TCL_OK;
}












































int Sqlitetest_window_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     int clientData;
  } aObjCmd[] = {
     { "sqlite3_create_window_function", test_create_window, 0 },

  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
  }
  return TCL_OK;







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








>







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  if( rc!=SQLITE_OK ){
    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
    return TCL_ERROR;
  }

  return TCL_OK;
}

static int SQLITE_TCLAPI test_create_window_misuse(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3 *db;
  int rc;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
      0, testWindowFinal, testWindowValue, testWindowInverse,
      0
  );
  if( rc!=SQLITE_MISUSE ) goto error;
  rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
      testWindowStep, 0, testWindowValue, testWindowInverse,
      0
  );
  if( rc!=SQLITE_MISUSE ) goto error;
  rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
      testWindowStep, testWindowFinal, 0, testWindowInverse,
      0
  );
  if( rc!=SQLITE_MISUSE ) goto error;
  rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
      testWindowStep, testWindowFinal, testWindowValue, 0,
      0
  );
  if( rc!=SQLITE_MISUSE ) goto error;

  return TCL_OK;

 error:
  Tcl_SetObjResult(interp, Tcl_NewStringObj("misuse test error", -1));
  return TCL_ERROR;
}

int Sqlitetest_window_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     int clientData;
  } aObjCmd[] = {
     { "sqlite3_create_window_function", test_create_window, 0 },
     { "test_create_window_function_misuse", test_create_window_misuse, 0 },
  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
  }
  return TCL_OK;
Changes to test/window5.test.
45
46
47
48
49
50
51




52
53
54
55
56
57
58
}
proc w_value {ctx} {
  lsort $ctx
}

sqlite3_create_window_function db median m_step m_value m_value m_inverse
sqlite3_create_window_function db win m_step w_value w_value m_inverse





do_execsql_test 1.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(4, 'a');
  INSERT INTO t1 VALUES(6, 'b');
  INSERT INTO t1 VALUES(1, 'c');
  INSERT INTO t1 VALUES(5, 'd');







>
>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
}
proc w_value {ctx} {
  lsort $ctx
}

sqlite3_create_window_function db median m_step m_value m_value m_inverse
sqlite3_create_window_function db win m_step w_value w_value m_inverse

do_test 0.0 {
  test_create_window_function_misuse db
} {}

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(4, 'a');
  INSERT INTO t1 VALUES(6, 'b');
  INSERT INTO t1 VALUES(1, 'c');
  INSERT INTO t1 VALUES(5, 'd');