aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btree.c2
-rw-r--r--src/ctime.c3
-rw-r--r--src/func.c8
-rw-r--r--src/main.c3
-rw-r--r--src/parse.y72
-rw-r--r--src/sqlite.h.in10
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/test_config.c16
-rw-r--r--src/vdbeblob.c5
9 files changed, 116 insertions, 5 deletions
diff --git a/src/btree.c b/src/btree.c
index c752b0771..f985ce340 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -5989,7 +5989,7 @@ int sqlite3BtreeIndexMoveto(
&& indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
&& pIdxKey->errCode==SQLITE_OK
){
- pCur->curFlags &= ~BTCF_ValidOvfl;
+ pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast);
if( !pCur->pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
diff --git a/src/ctime.c b/src/ctime.c
index 0ffe2a5bd..fe7849fec 100644
--- a/src/ctime.c
+++ b/src/ctime.c
@@ -295,6 +295,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
"ENABLE_OFFSET_SQL_FUNC",
#endif
+#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+ "ENABLE_ORDERED_SET_AGGREGATES",
+#endif
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK",
#endif
diff --git a/src/func.c b/src/func.c
index 8fcda11dc..a634a7fbe 100644
--- a/src/func.c
+++ b/src/func.c
@@ -2049,7 +2049,11 @@ static void minMaxFinalize(sqlite3_context *context){
** group_concat(EXPR, ?SEPARATOR?)
** string_agg(EXPR, SEPARATOR)
**
-** The SEPARATOR goes before the EXPR string. This is tragic. The
+** Content is accumulated in GroupConcatCtx.str with the SEPARATOR
+** coming before the EXPR value, except for the first entry which
+** omits the SEPARATOR.
+**
+** It is tragic that the SEPARATOR goes before the EXPR string. The
** groupConcatInverse() implementation would have been easier if the
** SEPARATOR were appended after EXPR. And the order is undocumented,
** so we could change it, in theory. But the old behavior has been
@@ -2153,7 +2157,7 @@ static void groupConcatInverse(
/* pGCC is always non-NULL since groupConcatStep() will have always
** run first to initialize it */
if( ALWAYS(pGCC) ){
- int nVS;
+ int nVS; /* Number of characters to remove */
/* Must call sqlite3_value_text() to convert the argument into text prior
** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
(void)sqlite3_value_text(argv[0]);
diff --git a/src/main.c b/src/main.c
index 5d6212208..ac08eea04 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1926,7 +1926,8 @@ int sqlite3CreateFunc(
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
- SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE);
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS|
+ SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
diff --git a/src/parse.y b/src/parse.y
index 926dd6e7d..a6a5e046d 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -264,6 +264,9 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
CURRENT FOLLOWING PARTITION PRECEDING RANGE UNBOUNDED
EXCLUDE GROUPS OTHERS TIES
%endif SQLITE_OMIT_WINDOWFUNC
+%ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+ WITHIN
+%endif SQLITE_ENABLE_ORDERED_SET_AGGREGATES
%ifndef SQLITE_OMIT_GENERATED_COLUMNS
GENERATED ALWAYS
%endif
@@ -1179,6 +1182,65 @@ expr(A) ::= idj(X) LP STAR RP. {
A = sqlite3ExprFunction(pParse, 0, &X, 0);
}
+%ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+%include {
+ /* Generate an expression node that represents an ordered-set aggregate function.
+ **
+ ** SQLite does not do anything special to evaluate ordered-set aggregates. The
+ ** aggregate function itself is expected to do any required ordering on its own.
+ ** This is just syntactic sugar.
+ **
+ ** This syntax: percentile(f) WITHIN GROUP ( ORDER BY y )
+ **
+ ** Is equivalent to: percentile(y,f)
+ **
+ ** The purpose of this function is to generate an Expr node from the first syntax
+ ** into a TK_FUNCTION node that looks like it came from the second syntax.
+ **
+ ** Only functions that have the SQLITE_SELFORDER1 perperty are allowed to do this
+ ** transformation. Because DISTINCT is not allowed in the ordered-set aggregate
+ ** syntax, an error is raised if DISTINCT is used.
+ */
+ static Expr *sqlite3ExprAddOrderedsetFunction(
+ Parse *pParse, /* Parsing context */
+ Token *pFuncname, /* Name of the function */
+ int isDistinct, /* DISTINCT or ALL qualifier */
+ ExprList *pOrig, /* Arguments to the function */
+ Expr *pOrderby /* Expression in the ORDER BY clause */
+ ){
+ ExprList *p; /* Modified argument list */
+ Expr *pExpr; /* Final result */
+ p = sqlite3ExprListAppend(pParse, 0, pOrderby);
+ if( pOrig ){
+ int i;
+ for(i=0; i<pOrig->nExpr; i++){
+ p = sqlite3ExprListAppend(pParse, p, pOrig->a[i].pExpr);
+ pOrig->a[i].pExpr = 0;
+ }
+ sqlite3ExprListDelete(pParse->db, pOrig);
+ }
+ pExpr = sqlite3ExprFunction(pParse, p, pFuncname, 0);
+ if( pParse->nErr==0 ){
+ FuncDef *pDef;
+ u8 enc = ENC(pParse->db);
+ assert( pExpr!=0 ); /* Because otherwise pParse->nErr would not be zero */
+ assert( p!=0 ); /* Because otherwise pParse->nErr would not be zero */
+ pDef = sqlite3FindFunction(pParse->db, pExpr->u.zToken, -2, enc, 0);
+ if( pDef==0 || (pDef->funcFlags & SQLITE_SELFORDER1)==0 ){
+ sqlite3ErrorMsg(pParse, "%#T() is not an ordered-set aggregate", pExpr);
+ }else if( isDistinct==SF_Distinct ){
+ sqlite3ErrorMsg(pParse, "DISTINCT not allowed on ordered-set aggregate %T()",
+ pFuncname);
+ }
+ }
+ return pExpr;
+ }
+}
+expr(A) ::= idj(X) LP distinct(D) exprlist(Y) RP WITHIN GROUP LP ORDER BY expr(E) RP. {
+ A = sqlite3ExprAddOrderedsetFunction(pParse, &X, D, Y, E);
+}
+%endif SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+
%ifndef SQLITE_OMIT_WINDOWFUNC
expr(A) ::= idj(X) LP distinct(D) exprlist(Y) RP filter_over(Z). {
A = sqlite3ExprFunction(pParse, Y, &X, D);
@@ -1193,7 +1255,15 @@ expr(A) ::= idj(X) LP STAR RP filter_over(Z). {
A = sqlite3ExprFunction(pParse, 0, &X, 0);
sqlite3WindowAttach(pParse, A, Z);
}
-%endif
+%ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+expr(A) ::= idj(X) LP distinct(D) exprlist(Y) RP WITHIN GROUP LP ORDER BY expr(E) RP
+ filter_over(Z). {
+ A = sqlite3ExprAddOrderedsetFunction(pParse, &X, D, Y, E);
+ sqlite3WindowAttach(pParse, A, Z);
+}
+%endif SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+
+%endif SQLITE_OMIT_WINDOWFUNC
term(A) ::= CTIME_KW(OP). {
A = sqlite3ExprFunction(pParse, 0, &OP, 0);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 810ccecc9..5546793c9 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -5615,6 +5615,15 @@ int sqlite3_create_window_function(
** [sqlite3_result_subtype()] should avoid setting this property, as the
** purpose of this property is to disable certain optimizations that are
** incompatible with subtypes.
+**
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
+** that internally orders the values provided to the first argument. The
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
+** used to invoke this function. If the ordered-set aggregate notation is
+** used on a function that lacks this flag, then an error is raised. Note
+** that the ordered-set aggregate syntax is only available if SQLite is
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd>
** </dl>
*/
@@ -5623,6 +5632,7 @@ int sqlite3_create_window_function(
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
#define SQLITE_RESULT_SUBTYPE 0x001000000
+#define SQLITE_SELFORDER1 0x002000000
/*
** CAPI3REF: Deprecated Functions
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index d1ffce6d8..0dab59f7a 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -658,6 +658,8 @@
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
# define float sqlite_int64
+# define fabs(X) ((X)<0?-(X):(X))
+# define sqlite3IsOverflow(X) 0
# define LONGDOUBLE_TYPE sqlite_int64
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
diff --git a/src/test_config.c b/src/test_config.c
index 58de5a462..49527861a 100644
--- a/src/test_config.c
+++ b/src/test_config.c
@@ -189,6 +189,14 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","0",TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+ Tcl_SetVar2(interp, "sqlite_options",
+ "ordered_set_aggregates","1",TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options",
+ "ordered_set_aggregates","0",TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "1", TCL_GLOBAL_ONLY);
#else
@@ -341,6 +349,14 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "columnmetadata", "0", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_ORDEREDSETFUNC
+ Tcl_SetVar2(interp, "sqlite_options", "ordered_set_funcs", "1",
+ TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "ordered_set_funcs", "0",
+ TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
Tcl_SetVar2(interp, "sqlite_options", "oversize_cell_check", "1",
TCL_GLOBAL_ONLY);
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 522447dbc..6cb36da37 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -167,6 +167,11 @@ int sqlite3_blob_open(
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
+ if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){
+ pTab = 0;
+ sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s",
+ zTable);
+ }
#ifndef SQLITE_OMIT_VIEW
if( pTab && IsView(pTab) ){
pTab = 0;