[Tarantool-patches] [PATCH v2 04/15] sql: move collation to struct sql_context
imeevma at tarantool.org
imeevma at tarantool.org
Tue Sep 21 13:59:08 MSK 2021
This patch makes it easier to get a collation by a function.
Needed for #4145
---
src/box/sql/date.c | 43 -------------------------------------------
src/box/sql/expr.c | 6 +-----
src/box/sql/func.c | 26 ++++++--------------------
src/box/sql/select.c | 12 +++++-------
src/box/sql/sqlInt.h | 3 +--
src/box/sql/vdbe.c | 18 +++---------------
src/box/sql/vdbeInt.h | 4 +---
src/box/sql/vdbeapi.c | 27 ---------------------------
8 files changed, 17 insertions(+), 122 deletions(-)
diff --git a/src/box/sql/date.c b/src/box/sql/date.c
index dbf460498..914a00dd2 100644
--- a/src/box/sql/date.c
+++ b/src/box/sql/date.c
@@ -1247,46 +1247,3 @@ ctimestampFunc(sql_context * context,
datetimeFunc(context, 0, 0);
}
#endif /* !defined(SQL_OMIT_DATETIME_FUNCS) */
-
-#ifdef SQL_OMIT_DATETIME_FUNCS
-/*
- * If the library is compiled to omit the full-scale date and time
- * handling (to get a smaller binary), the following minimal version
- * of the functions current_time(), current_date() and current_timestamp()
- * are included instead. This is to support column declarations that
- * include "DEFAULT CURRENT_TIME" etc.
- *
- * This function uses the C-library functions time(), gmtime()
- * and strftime(). The format string to pass to strftime() is supplied
- * as the user-data for the function.
- */
-static void
-currentTimeFunc(sql_context * context, int argc, sql_value ** argv)
-{
- time_t t;
- char *zFormat = (char *)sql_user_data(context);
- sql_int64 iT;
- struct tm *pTm;
- struct tm sNow;
- char zBuf[20];
-
- UNUSED_PARAMETER(argc);
- UNUSED_PARAMETER(argv);
-
- iT = sqlStmtCurrentTime(context);
- if (iT <= 0)
- return;
- t = iT / 1000 - 10000 * (sql_int64) 21086676;
-#if HAVE_GMTIME_R
- pTm = gmtime_r(&t, &sNow);
-#else
- pTm = gmtime(&t);
- if (pTm)
- memcpy(&sNow, pTm, sizeof(sNow));
-#endif
- if (pTm) {
- strftime(zBuf, 20, zFormat, &sNow);
- sql_result_text(context, zBuf, -1, SQL_TRANSIENT);
- }
-}
-#endif
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 6446ef091..ab7d95f7e 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -4102,13 +4102,9 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
pParse->is_aborted = true;
return 0;
}
- if (sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL)) {
- sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
- (char *)coll, P4_COLLSEQ);
- }
if (func->def->language == FUNC_LANGUAGE_SQL_BUILTIN) {
struct sql_context *ctx =
- sql_context_new(v, func, nFarg);
+ sql_context_new(func, nFarg, coll);
if (ctx == NULL) {
pParse->is_aborted = true;
return -1;
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 9009f9e4f..b4461c6ee 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -100,20 +100,6 @@ sql_func_uuid(struct sql_context *ctx, int argc, struct Mem **argv)
mem_set_uuid(ctx->pOut, &uuid);
}
-/*
- * Return the collating function associated with a function.
- */
-static struct coll *
-sqlGetFuncCollSeq(sql_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 || pOp->p4.pColl == NULL);
- return pOp->p4.pColl;
-}
-
/*
* Indicate that the accumulator load should be skipped on this
* iteration of the aggregate loop.
@@ -141,7 +127,7 @@ minmaxFunc(sql_context * context, int argc, sql_value ** argv)
context->is_aborted = true;
return;
}
- pColl = sqlGetFuncCollSeq(context);
+ pColl = context->coll;
assert(mask == -1 || mask == 0);
iBest = 0;
if (mem_is_null(argv[0]))
@@ -402,7 +388,7 @@ position_func(struct sql_context *context, int argc, struct Mem **argv)
n_haystack_bytes);
}
int beg_offset = 0;
- struct coll *coll = sqlGetFuncCollSeq(context);
+ struct coll *coll = context->coll;
int c;
for (c = 0; c + n_needle_chars <= n_haystack_chars; c++) {
if (coll->cmp((const char *) haystack_str + beg_offset,
@@ -667,7 +653,7 @@ case_type##ICUFunc(sql_context *context, int argc, sql_value **argv) \
return; \
} \
UErrorCode status = U_ZERO_ERROR; \
- struct coll *coll = sqlGetFuncCollSeq(context); \
+ struct coll *coll = context->coll; \
const char *locale = NULL; \
if (coll != NULL && coll->type == COLL_TYPE_ICU) { \
locale = ucol_getLocaleByType(coll->collator, \
@@ -1029,7 +1015,7 @@ likeFunc(sql_context *context, int argc, sql_value **argv)
if (!zA || !zB)
return;
int res;
- struct coll *coll = sqlGetFuncCollSeq(context);
+ struct coll *coll = context->coll;
assert(coll != NULL);
res = sql_utf8_pattern_compare(zB, zA, zB_end, zA_end, coll, escape);
@@ -1050,7 +1036,7 @@ likeFunc(sql_context *context, int argc, sql_value **argv)
static void
nullifFunc(sql_context * context, int NotUsed, sql_value ** argv)
{
- struct coll *pColl = sqlGetFuncCollSeq(context);
+ struct coll *pColl = context->coll;
UNUSED_PARAMETER(NotUsed);
if (mem_cmp_scalar(argv[0], argv[1], pColl) != 0)
sql_result_value(context, argv[0]);
@@ -1761,7 +1747,7 @@ minmaxStep(sql_context * context, int NotUsed, sql_value ** argv)
if (!mem_is_null(pBest))
sqlSkipAccumulatorLoad(context);
} else if (!mem_is_null(pBest)) {
- struct coll *pColl = sqlGetFuncCollSeq(context);
+ struct coll *pColl = context->coll;
/*
* This step function is used for both the min()
* and max() aggregates, the only difference
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 459325a88..2880f8ea0 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -5621,8 +5621,8 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
pParse->is_aborted = true;
return;
}
+ struct coll *coll = NULL;
if (sql_func_flag_is_set(pF->func, SQL_FUNC_NEEDCOLL)) {
- struct coll *coll = NULL;
struct ExprList_item *pItem;
int j;
assert(pList != 0); /* pList!=0 if pF->pFunc has NEEDCOLL */
@@ -5636,10 +5636,9 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
}
if (regHit == 0 && pAggInfo->nAccumulator)
regHit = ++pParse->nMem;
- sqlVdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
- (char *)coll, P4_COLLSEQ);
+ sqlVdbeAddOp1(v, OP_SkipLoad, regHit);
}
- struct sql_context *ctx = sql_context_new(v, pF->func, nArg);
+ struct sql_context *ctx = sql_context_new(pF->func, nArg, coll);
if (ctx == NULL) {
pParse->is_aborted = true;
return;
@@ -6751,7 +6750,7 @@ sql_expr_extract_select(struct Parse *parser, struct Select *select)
}
struct sql_context *
-sql_context_new(struct Vdbe *vdbe, struct func *func, uint32_t argc)
+sql_context_new(struct func *func, uint32_t argc, struct coll *coll)
{
uint32_t size = sizeof(struct sql_context);
if (argc > 1)
@@ -6763,7 +6762,6 @@ sql_context_new(struct Vdbe *vdbe, struct func *func, uint32_t argc)
ctx->func = func;
ctx->is_aborted = false;
ctx->skipFlag = 0;
- ctx->pVdbe = vdbe;
- ctx->iOp = 0;
+ ctx->coll = coll;
return ctx;
}
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index c2701dbde..710bd86cf 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4142,7 +4142,7 @@ void sqlStrAccumReset(StrAccum *);
void sqlSelectDestInit(SelectDest *, int, int, int);
struct sql_context *
-sql_context_new(struct Vdbe *vdbe, struct func *func, uint32_t argc);
+sql_context_new(struct func *func, uint32_t argc, struct coll *coll);
/*
* Create an expression to load @a column from datasource
@@ -4204,7 +4204,6 @@ void sqlParser(void *, int, Token, Parse *);
int sqlParserStackPeak(void *);
#endif
-sql_int64 sqlStmtCurrentTime(sql_context *);
int sqlVdbeParameterIndex(Vdbe *, const char *, int);
int sqlTransferBindings(sql_stmt *, sql_stmt *);
int sqlReprepare(Vdbe *);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 2ff7ce8f4..12dc9126b 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1159,23 +1159,13 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
break;
}
-/* Opcode: CollSeq P1 * * P4
- *
- * P4 is a pointer to a CollSeq struct. If the next call to a user function
- * or aggregate calls sqlGetFuncCollSeq(), this collation sequence will
- * be returned. This is used by the built-in min(), max() and nullif()
- * functions.
+/* Opcode: SkipLoad P1 * * * *
*
* If P1 is not zero, then it is a register that a subsequent min() or
* max() aggregate will set to true if the current row is not the minimum or
* maximum. The P1 register is initialized to false by this instruction.
- *
- * The interface used by the implementation of the aforementioned functions
- * to retrieve the collation sequence set by this opcode is not available
- * publicly. Only built-in functions have access to this feature.
*/
-case OP_CollSeq: {
- assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl == NULL);
+case OP_SkipLoad: {
if (pOp->p1) {
mem_set_bool(&aMem[pOp->p1], false);
}
@@ -1199,7 +1189,6 @@ case OP_BuiltinFunction: {
assert(pOp->p4type==P4_FUNCCTX);
pCtx = pOp->p4.pCtx;
- pCtx->iOp = (int)(pOp - aOp);
/* If this function is inside of a trigger, the register array in aMem[]
* might change from one evaluation to the next. The next block of code
@@ -4160,7 +4149,6 @@ case OP_AggStep: {
assert(pOp->p4type==P4_FUNCCTX);
pCtx = pOp->p4.pCtx;
- pCtx->iOp = (int)(pOp - aOp);
pMem = &aMem[pOp->p3];
/* If this function is inside of a trigger, the register array in aMem[]
@@ -4195,7 +4183,7 @@ case OP_AggStep: {
}
assert(mem_is_null(&t));
if (pCtx->skipFlag) {
- assert(pOp[-1].opcode==OP_CollSeq);
+ assert(pOp[-1].opcode == OP_SkipLoad);
i = pOp[-1].p1;
if (i) mem_set_bool(&aMem[i], true);
}
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 575ab3f3d..b9a18f1a1 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -173,9 +173,7 @@ struct sql_context {
/* A pointer to function implementation. */
struct func *func;
Mem *pMem; /* Memory cell used to store aggregate context */
- Vdbe *pVdbe; /* The VM that owns this context */
- /** Instruction number of OP_BuiltinFunction0. */
- int iOp;
+ struct coll *coll;
/*
* True, if an error occurred during the execution of the
* function.
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 115940227..6e598513c 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -349,33 +349,6 @@ sql_context_db_handle(sql_context * p)
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.
- */
-sql_int64
-sqlStmtCurrentTime(sql_context * p)
-{
- int rc;
-#ifndef SQL_ENABLE_OR_STAT4
- sql_int64 *piTime = &p->pVdbe->iCurrentTime;
- assert(p->pVdbe != 0);
-#else
- sql_int64 iTime = 0;
- sql_int64 *piTime =
- p->pVdbe != 0 ? &p->pVdbe->iCurrentTime : &iTime;
-#endif
- if (*piTime == 0) {
- rc = sqlOsCurrentTimeInt64(p->pOut->db->pVfs, piTime);
- if (rc)
- *piTime = 0;
- }
- return *piTime;
-}
-
/*
* Allocate or return the aggregate context for a user function. A new
* context is allocated on the first call. Subsequent calls return the
--
2.25.1
More information about the Tarantool-patches
mailing list