From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 8EBB16FC8B; Fri, 1 Oct 2021 10:48:20 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 8EBB16FC8B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1633074500; bh=b2v/4Jt0WrMutOHtGlUiycI17qGxenNu5cGwWtvAlP8=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=m2ZPUVjOx9IVBjl0vZGWjz3Kl2d0bL0QSQyHhQS7mT+U+zZiGi6sFEZWc0ANfm/CL FN2knPTs5uBJgYquwDoIGnFlGfG9CkOpBZae4iOA8Q2l8XUSiyq2mgBZoGmLXKm+yz lccNwsREnHGHFQqvsItNHSsijNmo7mOxQe6X0gFU= Received: from smtpng1.i.mail.ru (smtpng1.i.mail.ru [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 1BA3C7414C for ; Fri, 1 Oct 2021 10:43:29 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 1BA3C7414C Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1mWDCa-0005Dz-7b; Fri, 01 Oct 2021 10:43:28 +0300 To: v.shpilevoy@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Fri, 1 Oct 2021 10:43:27 +0300 Message-Id: <0f45e0d6baa3a3ed13cef39d35810ddd7b8b2b4f.1633073760.git.imeevma@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-4EC0790: 10 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD96A58C36AA2E99649DFE41A06634A2C4E52C7A956A585B5AE182A05F53808504012DF20584C5AA950F608ADC19ACAEF8F904923CBE925EC296836764B1D468701 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7956F10FFCC7409BAEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F790063750DEB490C003C9A78638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D856E83ABDB7700DF0682B4A569AEFA7E1117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B66F6A3E018CF4DC80089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CBBB17C150BCA67931F1F3072F68FE4946F06B010598997FE9C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF783E2B6F79C23BED699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D349EC559D073CA5B68B4BF83090707CC99C9B0C75024347B99A0E810695B60FE19600943BB8A4E394B1D7E09C32AA3244CBB784B5D065CDA2A5F484C23CCF08AF05A1673A01BA68E40729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojJNmX3owDPmHap5cB5yASkw== X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5DD5C499EA1BF1BB79F883AFB25483718E83D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v3 15/15] sql: remove field argv from struct sql_context X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mergen Imeev via Tarantool-patches Reply-To: imeevma@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Since the function arguments are always sequential in the array of all VDBE MEMs, we don't need to store the position of each argument. The position of the first MEM and the number of arguments are sufficient to describe all the arguments. Part of #4145 --- src/box/sql/expr.c | 2 +- src/box/sql/func.c | 325 ++++++++++++++++++++++-------------------- src/box/sql/main.c | 5 +- src/box/sql/select.c | 9 +- src/box/sql/sqlInt.h | 7 +- src/box/sql/vdbe.c | 40 ++---- src/box/sql/vdbeInt.h | 1 - 7 files changed, 188 insertions(+), 201 deletions(-) diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index ab7d95f7e..db8355f33 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -4104,7 +4104,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target) } if (func->def->language == FUNC_LANGUAGE_SQL_BUILTIN) { struct sql_context *ctx = - sql_context_new(func, nFarg, coll); + sql_context_new(func, 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 6f6908566..2010b3cf6 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -55,31 +55,31 @@ static struct func_sql_builtin **functions; /** Implementation of the SUM() function. */ static void -step_sum(struct sql_context *ctx, int argc, struct Mem **argv) +step_sum(struct sql_context *ctx, int argc, struct Mem *argv) { assert(argc == 1); (void)argc; assert(mem_is_null(ctx->pOut) || mem_is_num(ctx->pOut)); - if (mem_is_null(argv[0])) + if (mem_is_null(&argv[0])) return; if (mem_is_null(ctx->pOut)) - return mem_copy_as_ephemeral(ctx->pOut, argv[0]); - if (mem_add(ctx->pOut, argv[0], ctx->pOut) != 0) + return mem_copy_as_ephemeral(ctx->pOut, &argv[0]); + if (mem_add(ctx->pOut, &argv[0], ctx->pOut) != 0) ctx->is_aborted = true; } /** Implementation of the TOTAL() function. */ static void -step_total(struct sql_context *ctx, int argc, struct Mem **argv) +step_total(struct sql_context *ctx, int argc, struct Mem *argv) { assert(argc == 1); (void)argc; assert(mem_is_null(ctx->pOut) || mem_is_num(ctx->pOut)); - if (mem_is_null(argv[0])) + if (mem_is_null(&argv[0])) return; if (mem_is_null(ctx->pOut)) mem_set_double(ctx->pOut, 0.0); - if (mem_add(ctx->pOut, argv[0], ctx->pOut) != 0) + if (mem_add(ctx->pOut, &argv[0], ctx->pOut) != 0) ctx->is_aborted = true; } @@ -95,12 +95,12 @@ fin_total(struct Mem *mem) /** Implementation of the AVG() function. */ static void -step_avg(struct sql_context *ctx, int argc, struct Mem **argv) +step_avg(struct sql_context *ctx, int argc, struct Mem *argv) { assert(argc == 1); (void)argc; assert(mem_is_null(ctx->pOut) || mem_is_bin(ctx->pOut)); - if (mem_is_null(argv[0])) + if (mem_is_null(&argv[0])) return; struct Mem *mem; uint32_t *count; @@ -114,14 +114,14 @@ step_avg(struct sql_context *ctx, int argc, struct Mem **argv) count = (uint32_t *)(mem + 1); mem_create(mem); *count = 1; - mem_copy_as_ephemeral(mem, argv[0]); + mem_copy_as_ephemeral(mem, &argv[0]); mem_set_bin_allocated(ctx->pOut, (char *)mem, size); return; } mem = (struct Mem *)ctx->pOut->z; count = (uint32_t *)(mem + 1); ++*count; - if (mem_add(mem, argv[0], mem) != 0) + if (mem_add(mem, &argv[0], mem) != 0) ctx->is_aborted = true; } @@ -148,12 +148,12 @@ fin_avg(struct Mem *mem) /** Implementation of the COUNT() function. */ static void -step_count(struct sql_context *ctx, int argc, struct Mem **argv) +step_count(struct sql_context *ctx, int argc, struct Mem *argv) { assert(argc == 0 || argc == 1); if (mem_is_null(ctx->pOut)) mem_set_uint(ctx->pOut, 0); - if (argc == 1 && mem_is_null(argv[0])) + if (argc == 1 && mem_is_null(&argv[0])) return; assert(mem_is_uint(ctx->pOut)); ++ctx->pOut->u.u; @@ -171,17 +171,17 @@ fin_count(struct Mem *mem) /** Implementation of the MIN() and MAX() functions. */ static void -step_minmax(struct sql_context *ctx, int argc, struct Mem **argv) +step_minmax(struct sql_context *ctx, int argc, struct Mem *argv) { assert(argc == 1); (void)argc; - if (mem_is_null(argv[0])) { + if (mem_is_null(&argv[0])) { if (!mem_is_null(ctx->pOut)) ctx->skipFlag = 1; return; } if (mem_is_null(ctx->pOut)) { - if (mem_copy(ctx->pOut, argv[0]) != 0) + if (mem_copy(ctx->pOut, &argv[0]) != 0) ctx->is_aborted = true; return; } @@ -193,9 +193,9 @@ step_minmax(struct sql_context *ctx, int argc, struct Mem **argv) * the only difference between the two being that the sense of the * comparison is inverted. */ - int cmp = mem_cmp_scalar(ctx->pOut, argv[0], ctx->coll); + int cmp = mem_cmp_scalar(ctx->pOut, &argv[0], ctx->coll); if ((is_max && cmp < 0) || (!is_max && cmp > 0)) { - if (mem_copy(ctx->pOut, argv[0]) != 0) + if (mem_copy(ctx->pOut, &argv[0]) != 0) ctx->is_aborted = true; return; } @@ -204,15 +204,15 @@ step_minmax(struct sql_context *ctx, int argc, struct Mem **argv) /** Implementation of the GROUP_CONCAT() function. */ static void -step_group_concat(struct sql_context *ctx, int argc, struct Mem **argv) +step_group_concat(struct sql_context *ctx, int argc, struct Mem *argv) { assert(argc == 1 || argc == 2); (void)argc; - if (mem_is_null(argv[0])) + if (mem_is_null(&argv[0])) return; - assert(mem_is_str(argv[0]) || mem_is_bin(argv[0])); + assert(mem_is_str(&argv[0]) || mem_is_bin(&argv[0])); if (mem_is_null(ctx->pOut)) { - if (mem_copy(ctx->pOut, argv[0]) != 0) + if (mem_copy(ctx->pOut, &argv[0]) != 0) ctx->is_aborted = true; return; } @@ -222,13 +222,13 @@ step_group_concat(struct sql_context *ctx, int argc, struct Mem **argv) if (argc == 1) { sep = ","; sep_len = 1; - } else if (mem_is_null(argv[1])) { + } else if (mem_is_null(&argv[1])) { sep = ""; sep_len = 0; } else { - assert(mem_is_same_type(argv[0], argv[1])); - sep = argv[1]->z; - sep_len = argv[1]->n; + assert(mem_is_same_type(&argv[0], &argv[1])); + sep = argv[1].z; + sep_len = argv[1].n; } if (mem_append(ctx->pOut, sep, sep_len) != 0) { ctx->is_aborted = true; @@ -236,17 +236,17 @@ step_group_concat(struct sql_context *ctx, int argc, struct Mem **argv) } uint32_t size; char *str; - if (mem_is_zerobin(argv[0])) { - size = argv[0]->u.nZero; + if (mem_is_zerobin(&argv[0])) { + size = argv[0].u.nZero; str = sqlDbMallocRawNN(sql_get(), size); memset(str, 0, size); } else { - size = argv[0]->n; - str = argv[0]->z; + size = argv[0].n; + str = argv[0].z; } if (mem_append(ctx->pOut, str, size) != 0) ctx->is_aborted = true; - if (mem_is_zerobin(argv[0])) + if (mem_is_zerobin(&argv[0])) sqlDbFree(sql_get(), str); } @@ -269,7 +269,7 @@ mem_as_bin(struct Mem *mem) } static void -sql_func_uuid(struct sql_context *ctx, int argc, struct Mem **argv) +sql_func_uuid(struct sql_context *ctx, int argc, struct Mem *argv) { if (argc > 1) { diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, "UUID", @@ -279,9 +279,9 @@ sql_func_uuid(struct sql_context *ctx, int argc, struct Mem **argv) } if (argc == 1) { uint64_t version; - if (mem_get_uint(argv[0], &version) != 0) { + if (mem_get_uint(&argv[0], &version) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - mem_str(argv[0]), "integer"); + mem_str(&argv[0]), "integer"); ctx->is_aborted = true; return; } @@ -301,7 +301,7 @@ sql_func_uuid(struct sql_context *ctx, int argc, struct Mem **argv) * Implementation of the non-aggregate min() and max() functions */ static void -minmaxFunc(sql_context * context, int argc, sql_value ** argv) +minmaxFunc(struct sql_context *context, int argc, struct Mem *argv) { int i; int iBest; @@ -317,30 +317,30 @@ minmaxFunc(sql_context * context, int argc, sql_value ** argv) pColl = context->coll; assert(mask == -1 || mask == 0); iBest = 0; - if (mem_is_null(argv[0])) + if (mem_is_null(&argv[0])) return; for (i = 1; i < argc; i++) { - if (mem_is_null(argv[i])) + if (mem_is_null(&argv[i])) return; - if ((mem_cmp_scalar(argv[iBest], argv[i], pColl) ^ mask) >= 0) + if ((mem_cmp_scalar(&argv[iBest], &argv[i], pColl) ^ mask) >= 0) iBest = i; } - sql_result_value(context, argv[iBest]); + sql_result_value(context, &argv[iBest]); } /* * Return the type of the argument. */ static void -typeofFunc(sql_context * context, int NotUsed, sql_value ** argv) +typeofFunc(struct sql_context *context, int argc, struct Mem *argv) { + (void)argc; const char *z = 0; - UNUSED_PARAMETER(NotUsed); - if ((argv[0]->flags & MEM_Number) != 0) + if ((argv[0].flags & MEM_Number) != 0) return mem_set_str0_static(context->pOut, "number"); - if ((argv[0]->flags & MEM_Scalar) != 0) + if ((argv[0].flags & MEM_Scalar) != 0) return mem_set_str0_static(context->pOut, "scalar"); - switch (argv[0]->type) { + switch (argv[0].type) { case MEM_TYPE_INT: case MEM_TYPE_UINT: z = "integer"; @@ -379,13 +379,13 @@ typeofFunc(sql_context * context, int NotUsed, sql_value ** argv) * Implementation of the length() function */ static void -lengthFunc(sql_context * context, int argc, sql_value ** argv) +lengthFunc(struct sql_context *context, int argc, struct Mem *argv) { int len; assert(argc == 1); UNUSED_PARAMETER(argc); - switch (sql_value_type(argv[0])) { + switch (sql_value_type(&argv[0])) { case MP_BIN: case MP_ARRAY: case MP_MAP: @@ -393,16 +393,16 @@ lengthFunc(sql_context * context, int argc, sql_value ** argv) case MP_UINT: case MP_BOOL: case MP_DOUBLE:{ - mem_as_bin(argv[0]); - sql_result_uint(context, mem_len_unsafe(argv[0])); + mem_as_bin(&argv[0]); + sql_result_uint(context, mem_len_unsafe(&argv[0])); break; } case MP_EXT: case MP_STR:{ - const unsigned char *z = mem_as_ustr(argv[0]); + const unsigned char *z = mem_as_ustr(&argv[0]); if (z == 0) return; - len = sql_utf8_char_count(z, mem_len_unsafe(argv[0])); + len = sql_utf8_char_count(z, mem_len_unsafe(&argv[0])); sql_result_uint(context, len); break; } @@ -420,17 +420,17 @@ lengthFunc(sql_context * context, int argc, sql_value ** argv) * the numeric argument X. */ static void -absFunc(sql_context * context, int argc, sql_value ** argv) +absFunc(struct sql_context *context, int argc, struct Mem *argv) { assert(argc == 1); UNUSED_PARAMETER(argc); - switch (sql_value_type(argv[0])) { + switch (sql_value_type(&argv[0])) { case MP_UINT: { - sql_result_uint(context, mem_get_uint_unsafe(argv[0])); + sql_result_uint(context, mem_get_uint_unsafe(&argv[0])); break; } case MP_INT: { - int64_t value = mem_get_int_unsafe(argv[0]); + int64_t value = mem_get_int_unsafe(&argv[0]); assert(value < 0); sql_result_uint(context, -value); break; @@ -446,7 +446,7 @@ absFunc(sql_context * context, int argc, sql_value ** argv) case MP_ARRAY: case MP_MAP: { diag_set(ClientError, ER_INCONSISTENT_TYPES, "number", - mem_str(argv[0])); + mem_str(&argv[0])); context->is_aborted = true; return; } @@ -455,7 +455,7 @@ absFunc(sql_context * context, int argc, sql_value ** argv) * Abs(X) returns 0.0 if X is a string or blob * that cannot be converted to a numeric value. */ - double rVal = mem_get_double_unsafe(argv[0]); + double rVal = mem_get_double_unsafe(&argv[0]); if (rVal < 0) rVal = -rVal; sql_result_double(context, rVal); @@ -476,11 +476,11 @@ absFunc(sql_context * context, int argc, sql_value ** argv) * occurrence of needle, or 0 if needle never occurs in haystack. */ static void -position_func(struct sql_context *context, int argc, struct Mem **argv) +position_func(struct sql_context *context, int argc, struct Mem *argv) { UNUSED_PARAMETER(argc); - struct Mem *needle = argv[0]; - struct Mem *haystack = argv[1]; + struct Mem *needle = &argv[0]; + struct Mem *haystack = &argv[1]; enum mp_type needle_type = sql_value_type(needle); enum mp_type haystack_type = sql_value_type(haystack); @@ -603,7 +603,7 @@ finish: * Implementation of the printf() function. */ static void -printfFunc(sql_context * context, int argc, sql_value ** argv) +printfFunc(struct sql_context *context, int argc, struct Mem *argv) { PrintfArguments x; StrAccum str; @@ -611,14 +611,22 @@ printfFunc(sql_context * context, int argc, sql_value ** argv) int n; sql *db = sql_context_db_handle(context); - if (argc >= 1 && (zFormat = mem_as_str0(argv[0])) != NULL) { + if (argc >= 1 && (zFormat = mem_as_str0(&argv[0])) != NULL) { x.nArg = argc - 1; x.nUsed = 0; - x.apArg = argv + 1; + x.apArg = sqlDbMallocRawNN(sql_get(), + (argc - 1) * sizeof(*x.apArg)); + if (x.apArg == NULL) { + context->is_aborted = true; + return; + } + for (int i = 1; i < argc; ++i) + x.apArg[i - 1] = &argv[i]; sqlStrAccumInit(&str, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]); str.printfFlags = SQL_PRINTF_SQLFUNC; sqlXPrintf(&str, zFormat, &x); + sqlDbFree(sql_get(), x.apArg); n = str.nChar; sql_result_text(context, sqlStrAccumFinish(&str), n, SQL_DYNAMIC); @@ -638,7 +646,7 @@ printfFunc(sql_context * context, int argc, sql_value ** argv) * If p2 is negative, return the p2 characters preceding p1. */ static void -substrFunc(sql_context * context, int argc, sql_value ** argv) +substrFunc(struct sql_context *context, int argc, struct Mem *argv) { const unsigned char *z; const unsigned char *z2; @@ -653,26 +661,26 @@ substrFunc(sql_context * context, int argc, sql_value ** argv) context->is_aborted = true; return; } - if (mem_is_null(argv[1]) || (argc == 3 && mem_is_null(argv[2]))) + if (mem_is_null(&argv[1]) || (argc == 3 && mem_is_null(&argv[2]))) return; - p0type = sql_value_type(argv[0]); - p1 = mem_get_int_unsafe(argv[1]); + p0type = sql_value_type(&argv[0]); + p1 = mem_get_int_unsafe(&argv[1]); if (p0type == MP_BIN) { - z = mem_as_bin(argv[0]); - len = mem_len_unsafe(argv[0]); + z = mem_as_bin(&argv[0]); + len = mem_len_unsafe(&argv[0]); if (z == 0) return; - assert(len == mem_len_unsafe(argv[0])); + assert(len == mem_len_unsafe(&argv[0])); } else { - z = mem_as_ustr(argv[0]); + z = mem_as_ustr(&argv[0]); if (z == 0) return; len = 0; if (p1 < 0) - len = sql_utf8_char_count(z, mem_len_unsafe(argv[0])); + len = sql_utf8_char_count(z, mem_len_unsafe(&argv[0])); } if (argc == 3) { - p2 = mem_get_int_unsafe(argv[2]); + p2 = mem_get_int_unsafe(&argv[2]); if (p2 < 0) { p2 = -p2; negP2 = 1; @@ -708,7 +716,7 @@ substrFunc(sql_context * context, int argc, sql_value ** argv) * used because '\0' is not supposed to be * end-of-string symbol. */ - int byte_size = mem_len_unsafe(argv[0]); + int byte_size = mem_len_unsafe(&argv[0]); int n_chars = sql_utf8_char_count(z, byte_size); int cnt = 0; int i = 0; @@ -739,7 +747,7 @@ substrFunc(sql_context * context, int argc, sql_value ** argv) * Implementation of the round() function */ static void -roundFunc(sql_context * context, int argc, sql_value ** argv) +roundFunc(struct sql_context *context, int argc, struct Mem *argv) { int64_t n = 0; double r; @@ -750,21 +758,21 @@ roundFunc(sql_context * context, int argc, sql_value ** argv) return; } if (argc == 2) { - if (mem_is_null(argv[1])) + if (mem_is_null(&argv[1])) return; - n = mem_get_int_unsafe(argv[1]); + n = mem_get_int_unsafe(&argv[1]); if (n < 0) n = 0; } - if (mem_is_null(argv[0])) + if (mem_is_null(&argv[0])) return; - if (!mem_is_num(argv[0]) && !mem_is_str(argv[0])) { + if (!mem_is_num(&argv[0]) && !mem_is_str(&argv[0])) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - mem_str(argv[0]), "number"); + mem_str(&argv[0]), "number"); context->is_aborted = true; return; } - r = mem_get_double_unsafe(argv[0]); + r = mem_get_double_unsafe(&argv[0]); /* If Y==0 and X will fit in a 64-bit int, * handle the rounding directly, * otherwise use printf. @@ -787,7 +795,7 @@ roundFunc(sql_context * context, int argc, sql_value ** argv) * NULL. */ static void * -contextMalloc(sql_context * context, i64 nByte) +contextMalloc(struct sql_context *context, i64 nByte) { char *z; sql *db = sql_context_db_handle(context); @@ -812,26 +820,26 @@ contextMalloc(sql_context * context, i64 nByte) #define ICU_CASE_CONVERT(case_type) \ static void \ -case_type##ICUFunc(sql_context *context, int argc, sql_value **argv) \ +case_type##ICUFunc(sql_context *context, int argc, struct Mem *argv) \ { \ char *z1; \ const char *z2; \ int n; \ UNUSED_PARAMETER(argc); \ - if (mem_is_bin(argv[0]) || mem_is_map(argv[0]) || \ - mem_is_array(argv[0])) { \ + if (mem_is_bin(&argv[0]) || mem_is_map(&argv[0]) || \ + mem_is_array(&argv[0])) { \ diag_set(ClientError, ER_INCONSISTENT_TYPES, "string", \ - mem_str(argv[0])); \ + mem_str(&argv[0])); \ context->is_aborted = true; \ return; \ } \ - z2 = mem_as_str0(argv[0]); \ - n = mem_len_unsafe(argv[0]); \ + z2 = mem_as_str0(&argv[0]); \ + n = mem_len_unsafe(&argv[0]); \ /* \ * Verify that the call to _bytes() \ * does not invalidate the _text() pointer. \ */ \ - assert(z2 == mem_as_str0(argv[0])); \ + assert(z2 == mem_as_str0(&argv[0])); \ if (!z2) \ return; \ z1 = contextMalloc(context, ((i64) n) + 1); \ @@ -881,10 +889,11 @@ ICU_CASE_CONVERT(Upper); * Implementation of random(). Return a random integer. */ static void -randomFunc(sql_context * context, int NotUsed, sql_value ** NotUsed2) +randomFunc(struct sql_context *context, int argc, struct Mem *argv) { + (void)argc; + (void)argv; int64_t r; - UNUSED_PARAMETER2(NotUsed, NotUsed2); sql_randomness(sizeof(r), &r); sql_result_int(context, r); } @@ -894,20 +903,20 @@ randomFunc(sql_context * context, int NotUsed, sql_value ** NotUsed2) * that is N bytes long. */ static void -randomBlob(sql_context * context, int argc, sql_value ** argv) +randomBlob(struct sql_context *context, int argc, struct Mem *argv) { int64_t n; unsigned char *p; assert(argc == 1); UNUSED_PARAMETER(argc); - if (mem_is_bin(argv[0]) || mem_is_map(argv[0]) || - mem_is_array(argv[0])) { + if (mem_is_bin(&argv[0]) || mem_is_map(&argv[0]) || + mem_is_array(&argv[0])) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - mem_str(argv[0]), "number"); + mem_str(&argv[0]), "number"); context->is_aborted = true; return; } - n = mem_get_int_unsafe(argv[0]); + n = mem_get_int_unsafe(&argv[0]); if (n < 1) return; p = contextMalloc(context, n); @@ -1137,7 +1146,7 @@ sql_utf8_pattern_compare(const char *pattern, * is NULL then result is NULL as well. */ static void -likeFunc(sql_context *context, int argc, sql_value **argv) +likeFunc(sql_context *context, int argc, struct Mem *argv) { u32 escape = SQL_END_OF_STRING; int nPat; @@ -1148,29 +1157,29 @@ likeFunc(sql_context *context, int argc, sql_value **argv) return; } sql *db = sql_context_db_handle(context); - int rhs_type = sql_value_type(argv[0]); - int lhs_type = sql_value_type(argv[1]); + int rhs_type = sql_value_type(&argv[0]); + int lhs_type = sql_value_type(&argv[1]); if (lhs_type != MP_STR || rhs_type != MP_STR) { if (lhs_type == MP_NIL || rhs_type == MP_NIL) return; const char *str = rhs_type != MP_STR ? - mem_str(argv[0]) : mem_str(argv[1]); + mem_str(&argv[0]) : mem_str(&argv[1]); diag_set(ClientError, ER_INCONSISTENT_TYPES, "string", str); context->is_aborted = true; return; } - const char *zB = mem_as_str0(argv[0]); - const char *zA = mem_as_str0(argv[1]); - const char *zB_end = zB + mem_len_unsafe(argv[0]); - const char *zA_end = zA + mem_len_unsafe(argv[1]); + const char *zB = mem_as_str0(&argv[0]); + const char *zA = mem_as_str0(&argv[1]); + const char *zB_end = zB + mem_len_unsafe(&argv[0]); + const char *zA_end = zA + mem_len_unsafe(&argv[1]); /* * Limit the length of the LIKE pattern to avoid problems * of deep recursion and N*N behavior in * sql_utf8_pattern_compare(). */ - nPat = mem_len_unsafe(argv[0]); + nPat = mem_len_unsafe(&argv[0]); testcase(nPat == db->aLimit[SQL_LIMIT_LIKE_PATTERN_LENGTH]); testcase(nPat == db->aLimit[SQL_LIMIT_LIKE_PATTERN_LENGTH] + 1); if (nPat > db->aLimit[SQL_LIMIT_LIKE_PATTERN_LENGTH]) { @@ -1180,7 +1189,7 @@ likeFunc(sql_context *context, int argc, sql_value **argv) return; } /* Encoding did not change */ - assert(zB == mem_as_str0(argv[0])); + assert(zB == mem_as_str0(&argv[0])); if (argc == 3) { /* @@ -1188,10 +1197,10 @@ likeFunc(sql_context *context, int argc, sql_value **argv) * single UTF-8 character. Otherwise, return an * error. */ - const unsigned char *zEsc = mem_as_ustr(argv[2]); + const unsigned char *zEsc = mem_as_ustr(&argv[2]); if (zEsc == 0) return; - if (sql_utf8_char_count(zEsc, mem_len_unsafe(argv[2])) != 1) { + if (sql_utf8_char_count(zEsc, mem_len_unsafe(&argv[2])) != 1) { diag_set(ClientError, ER_SQL_EXECUTE, "ESCAPE "\ "expression must be a single character"); context->is_aborted = true; @@ -1221,12 +1230,12 @@ likeFunc(sql_context *context, int argc, sql_value **argv) * arguments are equal to each other. */ static void -nullifFunc(sql_context * context, int NotUsed, sql_value ** argv) +nullifFunc(struct sql_context *context, int argc, struct Mem *argv) { + (void)argc; struct coll *pColl = context->coll; - UNUSED_PARAMETER(NotUsed); - if (mem_cmp_scalar(argv[0], argv[1], pColl) != 0) - sql_result_value(context, argv[0]); + if (mem_cmp_scalar(&argv[0], &argv[1], pColl) != 0) + sql_result_value(context, &argv[0]); } /** @@ -1238,10 +1247,10 @@ nullifFunc(sql_context * context, int NotUsed, sql_value ** argv) * @param unused2 Unused. */ static void -sql_func_version(struct sql_context *context, - MAYBE_UNUSED int unused1, - MAYBE_UNUSED sql_value **unused2) +sql_func_version(struct sql_context *context, int argc, struct Mem *argv) { + (void)argc; + (void)argv; sql_result_text(context, tarantool_version(), -1, SQL_STATIC); } @@ -1261,14 +1270,14 @@ static const char hexdigits[] = { * single-quote escapes. */ static void -quoteFunc(sql_context * context, int argc, sql_value ** argv) +quoteFunc(struct sql_context *context, int argc, struct Mem *argv) { assert(argc == 1); UNUSED_PARAMETER(argc); - switch (argv[0]->type) { + switch (argv[0].type) { case MEM_TYPE_UUID: { char buf[UUID_STR_LEN + 1]; - tt_uuid_to_string(&argv[0]->u.uuid, &buf[0]); + tt_uuid_to_string(&argv[0].u.uuid, &buf[0]); sql_result_text(context, buf, UUID_STR_LEN, SQL_TRANSIENT); break; } @@ -1276,16 +1285,16 @@ quoteFunc(sql_context * context, int argc, sql_value ** argv) case MEM_TYPE_DEC: case MEM_TYPE_UINT: case MEM_TYPE_INT: { - sql_result_value(context, argv[0]); + sql_result_value(context, &argv[0]); break; } case MEM_TYPE_BIN: case MEM_TYPE_ARRAY: case MEM_TYPE_MAP: { char *zText = 0; - char const *zBlob = mem_as_bin(argv[0]); - int nBlob = mem_len_unsafe(argv[0]); - assert(zBlob == mem_as_bin(argv[0])); /* No encoding change */ + char const *zBlob = mem_as_bin(&argv[0]); + int nBlob = mem_len_unsafe(&argv[0]); + assert(zBlob == mem_as_bin(&argv[0])); /* No encoding change */ zText = (char *)contextMalloc(context, (2 * (i64) nBlob) + 4); @@ -1310,7 +1319,7 @@ quoteFunc(sql_context * context, int argc, sql_value ** argv) case MEM_TYPE_STR: { int i, j; u64 n; - const unsigned char *zArg = mem_as_ustr(argv[0]); + const unsigned char *zArg = mem_as_ustr(&argv[0]); char *z; if (zArg == 0) @@ -1337,12 +1346,12 @@ quoteFunc(sql_context * context, int argc, sql_value ** argv) } case MEM_TYPE_BOOL: { sql_result_text(context, - SQL_TOKEN_BOOLEAN(mem_get_bool_unsafe(argv[0])), + SQL_TOKEN_BOOLEAN(argv[0].u.b), -1, SQL_TRANSIENT); break; } default:{ - assert(mem_is_null(argv[0])); + assert(mem_is_null(&argv[0])); sql_result_text(context, "NULL", 4, SQL_STATIC); break; } @@ -1354,9 +1363,9 @@ quoteFunc(sql_context * context, int argc, sql_value ** argv) * for the first character of the input string. */ static void -unicodeFunc(sql_context * context, int argc, sql_value ** argv) +unicodeFunc(struct sql_context *context, int argc, struct Mem *argv) { - const unsigned char *z = mem_as_ustr(argv[0]); + const unsigned char *z = mem_as_ustr(&argv[0]); (void)argc; if (z && z[0]) sql_result_uint(context, sqlUtf8Read(&z)); @@ -1368,7 +1377,7 @@ unicodeFunc(sql_context * context, int argc, sql_value ** argv) * is the unicode character for the corresponding integer argument. */ static void -charFunc(sql_context * context, int argc, sql_value ** argv) +charFunc(struct sql_context *context, int argc, struct Mem *argv) { unsigned char *z, *zOut; int i; @@ -1380,10 +1389,10 @@ charFunc(sql_context * context, int argc, sql_value ** argv) for (i = 0; i < argc; i++) { uint64_t x; unsigned c; - if (sql_value_type(argv[i]) == MP_INT) + if (sql_value_type(&argv[i]) == MP_INT) x = 0xfffd; else - x = mem_get_uint_unsafe(argv[i]); + x = mem_get_uint_unsafe(&argv[i]); if (x > 0x10ffff) x = 0xfffd; c = (unsigned)(x & 0x1fffff); @@ -1411,16 +1420,16 @@ charFunc(sql_context * context, int argc, sql_value ** argv) * a hexadecimal rendering as text. */ static void -hexFunc(sql_context * context, int argc, sql_value ** argv) +hexFunc(struct sql_context *context, int argc, struct Mem *argv) { int i, n; const unsigned char *pBlob; char *zHex, *z; assert(argc == 1); UNUSED_PARAMETER(argc); - pBlob = mem_as_bin(argv[0]); - n = mem_len_unsafe(argv[0]); - assert(pBlob == mem_as_bin(argv[0])); /* No encoding change */ + pBlob = mem_as_bin(&argv[0]); + n = mem_len_unsafe(&argv[0]); + assert(pBlob == mem_as_bin(&argv[0])); /* No encoding change */ z = zHex = contextMalloc(context, ((i64) n) * 2 + 1); if (zHex) { for (i = 0; i < n; i++, pBlob++) { @@ -1437,12 +1446,12 @@ hexFunc(sql_context * context, int argc, sql_value ** argv) * The zeroblob(N) function returns a zero-filled blob of size N bytes. */ static void -zeroblobFunc(sql_context * context, int argc, sql_value ** argv) +zeroblobFunc(struct sql_context *context, int argc, struct Mem *argv) { int64_t n; assert(argc == 1); UNUSED_PARAMETER(argc); - n = mem_get_int_unsafe(argv[0]); + n = mem_get_int_unsafe(&argv[0]); if (n < 0) n = 0; if (sql_result_zeroblob64(context, n) != 0) { @@ -1459,7 +1468,7 @@ zeroblobFunc(sql_context * context, int argc, sql_value ** argv) * must be exact. Collating sequences are not used. */ static void -replaceFunc(sql_context * context, int argc, sql_value ** argv) +replaceFunc(struct sql_context *context, int argc, struct Mem *argv) { const unsigned char *zStr; /* The input string A */ const unsigned char *zPattern; /* The pattern string B */ @@ -1474,29 +1483,29 @@ replaceFunc(sql_context * context, int argc, sql_value ** argv) assert(argc == 3); UNUSED_PARAMETER(argc); - zStr = mem_as_ustr(argv[0]); + zStr = mem_as_ustr(&argv[0]); if (zStr == 0) return; - nStr = mem_len_unsafe(argv[0]); - assert(zStr == mem_as_ustr(argv[0])); /* No encoding change */ - zPattern = mem_as_ustr(argv[1]); + nStr = mem_len_unsafe(&argv[0]); + assert(zStr == mem_as_ustr(&argv[0])); /* No encoding change */ + zPattern = mem_as_ustr(&argv[1]); if (zPattern == 0) { - assert(mem_is_null(argv[1]) + assert(mem_is_null(&argv[1]) || sql_context_db_handle(context)->mallocFailed); return; } - nPattern = mem_len_unsafe(argv[1]); + nPattern = mem_len_unsafe(&argv[1]); if (nPattern == 0) { - assert(!mem_is_null(argv[1])); - sql_result_value(context, argv[0]); + assert(!mem_is_null(&argv[1])); + sql_result_value(context, &argv[0]); return; } - assert(zPattern == mem_as_ustr(argv[1])); /* No encoding change */ - zRep = mem_as_ustr(argv[2]); + assert(zPattern == mem_as_ustr(&argv[1])); /* No encoding change */ + zRep = mem_as_ustr(&argv[2]); if (zRep == 0) return; - nRep = mem_len_unsafe(argv[2]); - assert(zRep == mem_as_ustr(argv[2])); + nRep = mem_len_unsafe(&argv[2]); + assert(zRep == mem_as_ustr(&argv[2])); nOut = nStr + 1; assert(nOut < SQL_MAX_LENGTH); zOut = contextMalloc(context, (i64) nOut); @@ -1715,14 +1724,14 @@ trim_func_three_args(struct sql_context *context, sql_value *arg1, * implementation depending on the number of arguments. */ static void -trim_func(struct sql_context *context, int argc, sql_value **argv) +trim_func(struct sql_context *context, int argc, struct Mem *argv) { switch (argc) { case 2: - trim_func_two_args(context, argv[0], argv[1]); + trim_func_two_args(context, &argv[0], &argv[1]); break; case 3: - trim_func_three_args(context, argv[0], argv[1], argv[2]); + trim_func_three_args(context, &argv[0], &argv[1], &argv[2]); break; default: diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, "TRIM", @@ -1738,7 +1747,7 @@ trim_func(struct sql_context *context, int argc, sql_value **argv) * soundex encoding of the string X. */ static void -soundexFunc(sql_context * context, int argc, sql_value ** argv) +soundexFunc(struct sql_context *context, int argc, struct Mem *argv) { (void) argc; char zResult[8]; @@ -1755,14 +1764,14 @@ soundexFunc(sql_context * context, int argc, sql_value ** argv) 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, }; assert(argc == 1); - if (mem_is_bin(argv[0]) || mem_is_map(argv[0]) || - mem_is_array(argv[0])) { + if (mem_is_bin(&argv[0]) || mem_is_map(&argv[0]) || + mem_is_array(&argv[0])) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - mem_str(argv[0]), "string"); + mem_str(&argv[0]), "string"); context->is_aborted = true; return; } - zIn = (u8 *) mem_as_ustr(argv[0]); + zIn = (u8 *) mem_as_ustr(&argv[0]); if (zIn == 0) zIn = (u8 *) ""; for (i = 0; zIn[i] && !sqlIsalpha(zIn[i]); i++) { @@ -1818,7 +1827,7 @@ func_sql_builtin_call_stub(struct func *func, struct port *args, } static void -sql_builtin_stub(sql_context *ctx, int argc, sql_value **argv) +sql_builtin_stub(sql_context *ctx, int argc, struct Mem *argv) { (void) argc; (void) argv; diag_set(ClientError, ER_SQL_EXECUTE, @@ -1922,7 +1931,7 @@ struct sql_func_definition { /** Type of the result of the implementation. */ enum field_type result; /** Call implementation with given arguments. */ - void (*call)(sql_context *ctx, int argc, sql_value **argv); + void (*call)(sql_context *ctx, int argc, struct Mem *argv); /** Call finalization function for this implementation. */ int (*finalize)(struct Mem *mem); }; diff --git a/src/box/sql/main.c b/src/box/sql/main.c index b0d32ae32..a4247c760 100644 --- a/src/box/sql/main.c +++ b/src/box/sql/main.c @@ -221,9 +221,10 @@ setupLookaside(sql * db, void *pBuf, int sz, int cnt) } void -sql_row_count(struct sql_context *context, MAYBE_UNUSED int unused1, - MAYBE_UNUSED sql_value **unused2) +sql_row_count(struct sql_context *context, int argc, struct Mem *argv) { + (void)argc; + (void)argv; sql *db = sql_context_db_handle(context); assert(db->nChange >= 0); sql_result_uint(context, db->nChange); diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 6269c2868..8ca967108 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -5638,7 +5638,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo) regHit = ++pParse->nMem; sqlVdbeAddOp1(v, OP_SkipLoad, regHit); } - struct sql_context *ctx = sql_context_new(pF->func, nArg, coll); + struct sql_context *ctx = sql_context_new(pF->func, coll); if (ctx == NULL) { pParse->is_aborted = true; return; @@ -6750,12 +6750,9 @@ sql_expr_extract_select(struct Parse *parser, struct Select *select) } struct sql_context * -sql_context_new(struct func *func, uint32_t argc, struct coll *coll) +sql_context_new(struct func *func, struct coll *coll) { - uint32_t size = sizeof(struct sql_context); - if (argc > 1) - size += (argc - 1) * sizeof(struct Mem *); - struct sql_context *ctx = sqlDbMallocRawNN(sql_get(), size); + struct sql_context *ctx = sqlDbMallocRawNN(sql_get(), sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->pOut = NULL; diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index 5bce70eaa..7c28c34e1 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -481,8 +481,7 @@ sql_randomness(int N, void *P); * Return the number of affected rows in the last SQL statement. */ void -sql_row_count(struct sql_context *context, MAYBE_UNUSED int unused1, - MAYBE_UNUSED sql_value **unused2); +sql_row_count(struct sql_context *context, int argc, struct Mem *argv); int sql_column_count(sql_stmt * pStmt); @@ -4130,7 +4129,7 @@ void sqlStrAccumReset(StrAccum *); void sqlSelectDestInit(SelectDest *, int, int, int); struct sql_context * -sql_context_new(struct func *func, uint32_t argc, struct coll *coll); +sql_context_new(struct func *func, struct coll *coll); void sql_context_delete(struct sql_context *ctx); @@ -4369,7 +4368,7 @@ struct func_sql_builtin { * Access checks are redundant, because all SQL built-ins * are predefined and are executed on SQL privilege level. */ - void (*call)(sql_context *ctx, int argc, sql_value **argv); + void (*call)(struct sql_context *ctx, int argc, struct Mem *argv); /** * A VDBE-memory-compatible finalize method * (is valid only for aggregate function). diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 5dd68912c..43ce4fdfc 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1183,35 +1183,26 @@ case OP_SkipLoad: { * See also: AggStep, AggFinal */ case OP_BuiltinFunction: { - int i; int argc = pOp->p1; sql_context *pCtx; assert(pOp->p4type==P4_FUNCCTX); pCtx = pOp->p4.pCtx; - /* 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 - * checks to see if the register array has changed, and if so it - * reinitializes the relavant parts of the sql_context object - */ pOut = vdbe_prepare_null_out(p, pOp->p3); - if (pCtx->pOut != pOut) { + if (pCtx->pOut != pOut) pCtx->pOut = pOut; - for(i = 0; i < argc; ++i) - pCtx->argv[i] = &aMem[pOp->p2 + i]; - } #ifdef SQL_DEBUG - for(i = 0; i < argc; i++) { - assert(memIsValid(pCtx->argv[i])); - REGISTER_TRACE(p, pOp->p2+i, pCtx->argv[i]); + for(int i = 0; i < argc; i++) { + assert(memIsValid(&aMem[pOp->p2 + i])); + REGISTER_TRACE(p, pOp->p2 + i, &aMem[pOp->p2 + i]); } #endif pCtx->is_aborted = false; assert(pCtx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN); struct func_sql_builtin *func = (struct func_sql_builtin *)pCtx->func; - func->call(pCtx, argc, pCtx->argv); + func->call(pCtx, argc, &aMem[pOp->p2]); /* If the function returned an error, throw an exception */ if (pCtx->is_aborted) @@ -4141,7 +4132,6 @@ case OP_DecrJumpZero: { /* jump, in1 */ * successors. */ case OP_AggStep: { - int i; int argc = pOp->p1; sql_context *pCtx; Mem *pMem; @@ -4150,33 +4140,25 @@ case OP_AggStep: { pCtx = pOp->p4.pCtx; pMem = &aMem[pOp->p3]; - /* 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 - * checks to see if the register array has changed, and if so it - * reinitializes the relavant parts of the sql_context object - */ - if (pCtx->pOut != pMem) { + if (pCtx->pOut != pMem) pCtx->pOut = pMem; - for(i = 0; i < argc; ++i) - pCtx->argv[i] = &aMem[pOp->p2 + i]; - } #ifdef SQL_DEBUG - for(i = 0; i < argc; i++) { - assert(memIsValid(pCtx->argv[i])); - REGISTER_TRACE(p, pOp->p2+i, pCtx->argv[i]); + for(int i = 0; i < argc; i++) { + assert(memIsValid(&aMem[pOp->p2 + i])); + REGISTER_TRACE(p, pOp->p2 + i, &aMem[pOp->p2 + i]); } #endif pCtx->skipFlag = 0; assert(pCtx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN); struct func_sql_builtin *func = (struct func_sql_builtin *)pCtx->func; - func->call(pCtx, argc, pCtx->argv); + func->call(pCtx, argc, &aMem[pOp->p2]); if (pCtx->is_aborted) goto abort_due_to_error; if (pCtx->skipFlag) { assert(pOp[-1].opcode == OP_SkipLoad); - i = pOp[-1].p1; + int i = pOp[-1].p1; if (i) mem_set_bool(&aMem[i], true); } break; diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index 5e2692d06..8dbba4908 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -179,7 +179,6 @@ struct sql_context { */ bool is_aborted; u8 skipFlag; /* Skip accumulator loading if true */ - sql_value *argv[1]; /* Argument set */ }; /* A bitfield type for use inside of structures. Always follow with :N where -- 2.25.1