Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add documentation comment for sqlite3_create_window_function(). And further tests. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | exp-window-functions |
Files: | files | file ages | folders |
SHA3-256: |
3f2705b93368f7b0dfd2e03387c3d0b5 |
User & Date: | dan 2018-06-25 20:34:28.258 |
Context
2018-06-26
| ||
20:19 | Merge latest trunk changes. (check-in: d9f814b443 user: dan tags: exp-window-functions) | |
2018-06-25
| ||
20:34 | Add documentation comment for sqlite3_create_window_function(). And further tests. (check-in: 3f2705b933 user: dan tags: exp-window-functions) | |
11:42 | Fix another problem that could cause a crash when a window function was used in a view. (check-in: e954145a3a user: dan tags: exp-window-functions) | |
Changes
Changes to src/sqlite.h.in.
︙ | ︙ | |||
4617 4618 4619 4620 4621 4622 4623 | ** KEYWORDS: {function creation routines} ** KEYWORDS: {application-defined SQL function} ** KEYWORDS: {application-defined SQL functions} ** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior | | | | | | > > | 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 | ** KEYWORDS: {function creation routines} ** KEYWORDS: {application-defined SQL function} ** KEYWORDS: {application-defined SQL functions} ** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior ** of existing SQL functions or aggregates. The only differences between ** the three "sqlite3_create_function*" routines are the text encoding ** expected for the second parameter (the name of the function being ** created) and the presence or absence of a destructor callback for ** the application data pointer. Function sqlite3_create_window_function() ** is similar, but allows the user to supply the extra callback functions ** needed by [aggregate window functions]. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database ** connection then application-defined SQL functions must be added ** to each database connection separately. ** ** ^The second parameter is the name of the SQL function to be created or |
︙ | ︙ | |||
4667 4668 4669 4670 4671 4672 4673 | ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** | | > > > > > > > > > > > | | | | | | < | | | 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 | ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters passed to the three ** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue ** and xInverse) passed to sqlite3_create_window_function are pointers to ** C-lanugage callbacks that implement the new function. xStep and xFinal ** must both be non-NULL. xValue and xInverse may either both be NULL, in ** which case a regular aggregate function is created, or must both be ** non-NULL, in which case the new function may be used as either an aggregate ** or aggregate window function. More details regarding the implementation ** of aggregate window functions are ** [user-defined window functions|available here]. ** ** ^(If the final parameter to sqlite3_create_function_v2() or ** sqlite3_create_window_function() is not NULL, then it is destructor for ** the application data pointer. The destructor is invoked when the function ** is deleted, either by being overloaded or when the database connection ** closes.)^ ^The destructor is also invoked if the call to ** sqlite3_create_function_v2() fails. ^When the destructor callback is ** invoked, it is passed a single argument which is a copy of the application ** data pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of ** arguments or differing preferred text encodings. ^SQLite will use ** the implementation that most closely matches the way in which the ** SQL function is used. ^A function implementation with a non-negative ** nArg parameter is a better match than a function implementation with |
︙ | ︙ |
Changes to src/test_window.c.
︙ | ︙ | |||
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | 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; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | return TCL_OK; error: Tcl_SetObjResult(interp, Tcl_NewStringObj("misuse test error", -1)); return TCL_ERROR; } /* ** xStep for sumint(). */ static void sumintStep( sqlite3_context *ctx, int nArg, sqlite3_value *apArg[] ){ sqlite3_int64 *pInt; assert( nArg==1 ); if( sqlite3_value_type(apArg[0])!=SQLITE_INTEGER ){ sqlite3_result_error(ctx, "invalid argument", -1); return; } pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64)); if( pInt ){ *pInt += sqlite3_value_int64(apArg[0]); } } /* ** xInverse for sumint(). */ static void sumintInverse( sqlite3_context *ctx, int nArg, sqlite3_value *apArg[] ){ sqlite3_int64 *pInt; pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64)); *pInt -= sqlite3_value_int64(apArg[0]); } /* ** xFinal for sumint(). */ static void sumintFinal(sqlite3_context *ctx){ sqlite3_int64 res = 0; sqlite3_int64 *pInt; pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0); if( pInt ) res = *pInt; sqlite3_result_int64(ctx, res); } /* ** xValue for sumint(). */ static void sumintValue(sqlite3_context *ctx){ sqlite3_int64 res = 0; sqlite3_int64 *pInt; pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0); if( pInt ) res = *pInt; sqlite3_result_int64(ctx, res); } static int SQLITE_TCLAPI test_create_sumint( 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, "sumint", 1, SQLITE_UTF8, 0, sumintStep, sumintFinal, sumintValue, sumintInverse, 0 ); 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 }, { "test_create_window_function_misuse", test_create_window_misuse, 0 }, { "test_create_sumint", test_create_sumint, 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.
︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 | INSERT INTO t1 VALUES(2, 'e'); INSERT INTO t1 VALUES(3, 'f'); } do_execsql_test 1.1 { SELECT win(a) OVER (ORDER BY b), median(a) OVER (ORDER BY b) FROM t1; } {4 4 {4 6} 5 {1 4 6} 4 {1 4 5 6} 4.5 {1 2 4 5 6} 4 {1 2 3 4 5 6} 3.5} finish_test | > > > > > > > > > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | INSERT INTO t1 VALUES(2, 'e'); INSERT INTO t1 VALUES(3, 'f'); } do_execsql_test 1.1 { SELECT win(a) OVER (ORDER BY b), median(a) OVER (ORDER BY b) FROM t1; } {4 4 {4 6} 5 {1 4 6} 4 {1 4 5 6} 4.5 {1 2 4 5 6} 4 {1 2 3 4 5 6} 3.5} test_create_sumint db do_execsql_test 2.0 { SELECT sumint(a) OVER (ORDER BY rowid) FROM t1 ORDER BY rowid; } {4 10 11 16 18 21} do_execsql_test 2.1 { SELECT sumint(a) OVER (ORDER BY rowid ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t1 ORDER BY rowid; } {10 11 12 8 10 5} finish_test |