aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sqlite.h.in42
-rw-r--r--src/test_window.c84
2 files changed, 111 insertions, 15 deletions
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 9df546a26..b98960a01 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -4621,11 +4621,13 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
**
** ^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
-** these 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.
+** 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
@@ -4671,7 +4673,8 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
** ^(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, xFunc, xStep and xFinal, are
+** ^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
@@ -4680,15 +4683,24 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
** SQL function or aggregate, pass NULL pointers for all three function
** callbacks.
**
-** ^(If the ninth parameter to sqlite3_create_function_v2() 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 of the tenth parameter 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().
+** ^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
diff --git a/src/test_window.c b/src/test_window.c
index 31dcb8e1e..576c58f6c 100644
--- a/src/test_window.c
+++ b/src/test_window.c
@@ -219,6 +219,89 @@ static int SQLITE_TCLAPI test_create_window_misuse(
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;
@@ -227,6 +310,7 @@ int Sqlitetest_window_Init(Tcl_Interp *interp){
} 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++){