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 6BBFC6EC5F; Thu, 15 Apr 2021 01:42:08 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 6BBFC6EC5F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1618440128; bh=3T4DCaN52jWlihsU/wP47PAqXKjKsxyMMVMkoLWzhfY=; h=Date:To:Cc:References:In-Reply-To:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=E386SQDtOAS+sMKdbtC603VpVKKgxGXzbJqkJUCIS9Vjt2VHFC4XDrJ8rDv6FPQaG fRYfgsYwme0sKBfebo+RdQ7ff+lWG7qRJHz5oqBZ7ug9G5wxcVyt0tn4h1Qg59Q/3y kR3ng2pY8xO14LberaCBZegRC+dkfRhUVooU7o4I= Received: from smtp3.mail.ru (smtp3.mail.ru [94.100.179.58]) (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 E379C6EC5F for ; Thu, 15 Apr 2021 01:42:06 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org E379C6EC5F Received: by smtp3.mail.ru with esmtpa (envelope-from ) id 1lWoD0-0007uE-5h; Thu, 15 Apr 2021 01:42:06 +0300 Date: Thu, 15 Apr 2021 01:42:04 +0300 To: Vladislav Shpilevoy Cc: tarantool-patches@dev.tarantool.org Message-ID: <20210414224204.GB303346@tarantool.org> References: <2ce8b15b5c1869dec995b4a9f348fe7649f6af47.1617984948.git.imeevma@gmail.com> <6128a7ea-7fb9-8fd6-dc99-0feeb4759e6c@tarantool.org> <20210413123601.GA108689@tarantool.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92FFCB8E6708E7480BE79914FF86F9151AC38CC435EA4A654182A05F53808504098276696D2E65E92B547D3D48E84737032BB224C944B11C5960B86CF0DF508AC X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7BF6CFCE92D77DF21EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006379A70878BADDF00B98638F802B75D45FF914D58D5BE9E6BC1A93B80C6DEB9DEE97C6FB206A91F05B2110AB17E5DEBB09E8750BA14FA3AD63E89428004B1FE94FDD2E47CDBA5A96583C09775C1D3CA48CFCA5A41EBD8A3A0199FA2833FD35BB23D2EF20D2F80756B5F868A13BD56FB6657A471835C12D1D977725E5C173C3A84C3CA5A41EBD8A3A0199FA2833FD35BB23DF004C90652538430302FCEF25BFAB3454AD6D5ED66289B5278DA827A17800CE723492FEEC4BE097BD32BA5DBAC0009BE395957E7521B51C20BC6067A898B09E4090A508E0FED6299176DF2183F8FC7C056235C9C6E49608FCD04E86FAF290E2D7E9C4E3C761E06A71DD303D21008E298D5E8D9A59859A8B6B372FE9A2E580EFC725E5C173C3A84C3E0287E8A3902ECA435872C767BF85DA2F004C90652538430E4A6367B16DE6309 X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A2368A440D3B0F6089093C9A16E5BC824A2A04A2ABAA09D25379311020FFC8D4AD48C8163CD7E2ABE70F918237F7B1FE32 X-C1DE0DAB: 0D63561A33F958A5F87FA8449B895244B432C7013DF5C7F3ABC8E322720045EED59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA7502E6951B79FF9A3F410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34F38194B2C99DC128C75D185E9462E4E3488D19BC6B62E038CD531A5564C09A1CEA6B51471A23A4751D7E09C32AA3244C8FE6EE7D1457804ED817E458FF886B8FC86C126E7119A0FE729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojrcJA+pXcDulCZ8hGR9El6A== X-Mailru-Sender: 5C3750E245F362008BC1685FEC6306EDC07E2E53729F4E94B547D3D48E84737014D23FB96A9F340B5105BD0848736F9966FEC6BF5C9C28D97E07721503EA2E00ED97202A5A4E92BF7402F9BA4338D657ED14614B50AE0675 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v5 09/52] sql: introduce mem_str() 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: Mergen Imeev Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Thank you for the review and diff! My answer below. Also, I forgot to mention in the last letter that I pushed rebased and fixed patches onto old branch, imeevma/gh-5818-encapsulate-mem-type-checking-and-changing New patch below. On Thu, Apr 15, 2021 at 12:23:36AM +0200, Vladislav Shpilevoy wrote: > Good job on the fixes! > > > diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c > > index 79c3d60e0..907c9f5c6 100644 > > --- a/src/box/sql/vdbeaux.c > > +++ b/src/box/sql/vdbeaux.c > > @@ -1108,21 +1108,10 @@ displayP4(Op * pOp, char *zTemp, int nTemp) > > break; > > } > > case P4_MEM:{ > > - Mem *pMem = pOp->p4.pMem; > > - if (pMem->flags & MEM_Str) { > > - zP4 = pMem->z; > > - } else if (pMem->flags & MEM_Int) { > > - sqlXPrintf(&x, "%lld", pMem->u.i); > > - } else if (pMem->flags & MEM_UInt) { > > - sqlXPrintf(&x, "%llu", pMem->u.u); > > - } else if (pMem->flags & MEM_Real) { > > - sqlXPrintf(&x, "%.16g", pMem->u.r); > > - } else if (pMem->flags & MEM_Null) { > > - zP4 = "NULL"; > > - } else { > > - assert(pMem->flags & MEM_Blob); > > - zP4 = "(binary string)"; > > - } > > + const char *value = mem_str(pOp->p4.pMem); > > + int len = strlen(value); > > + uint32_t size = MIN(len, nTemp - 1); > > Why do you need that limit? The accum is created as > sqlStrAccumInit(&x, 0, zTemp, nTemp, 0). The last argument 0 means > it won't realloc anything, so it is safe to append. The same in the > next diff hunk. > > Consider this diff: > > ==================== > diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c > index a2a0fc33e..95a035fd4 100644 > --- a/src/box/sql/mem.c > +++ b/src/box/sql/mem.c > @@ -52,7 +52,9 @@ mem_str(const struct Mem *mem) > case MEM_Null: > return "NULL"; > case MEM_Str: > - return tt_sprintf("%.*s", mem->n, mem->z); > + if ((mem->flags & MEM_Term) != 0) > + return mem->z; > + return tt_cstr(mem->z, mem->n); > case MEM_Int: > return tt_sprintf("%lld", mem->u.i); > case MEM_UInt: > @@ -68,9 +70,8 @@ mem_str(const struct Mem *mem) > case MEM_Bool: > return mem->u.b ? "TRUE" : "FALSE"; > default: > - break; > + return "unknown"; > } > - return "unknown"; > } > > static inline bool > diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c > index 907c9f5c6..9ef0445bd 100644 > --- a/src/box/sql/vdbeaux.c > +++ b/src/box/sql/vdbeaux.c > @@ -1109,9 +1109,7 @@ displayP4(Op * pOp, char *zTemp, int nTemp) > } > case P4_MEM:{ > const char *value = mem_str(pOp->p4.pMem); > - int len = strlen(value); > - uint32_t size = MIN(len, nTemp - 1); > - sqlStrAccumAppend(&x, value, size); > + sqlStrAccumAppend(&x, value, strlen(value)); > break; > } > case P4_INTARRAY:{ > diff --git a/src/box/sql/vdbetrace.c b/src/box/sql/vdbetrace.c > index 677de65e2..a26880041 100644 > --- a/src/box/sql/vdbetrace.c > +++ b/src/box/sql/vdbetrace.c > @@ -146,9 +146,7 @@ sqlVdbeExpandSql(Vdbe * p, /* The prepared statement being evaluated */ > nextIndex = idx + 1; > assert(idx > 0 && idx <= p->nVar); > const char *value = mem_str(&p->aVar[idx - 1]); > - uint32_t len = strlen(value); > - uint32_t size = MIN(len, sizeof(zBase) - 1); > - sqlStrAccumAppend(&out, value, size); > + sqlStrAccumAppend(&out, value, strlen(value)); > } > } > if (out.accError) Thank you again! I applied this patch and checked that tests are fine. New patch: commit cd39e0296477effaa054a139604ee52a382dd7be Author: Mergen Imeev Date: Tue Mar 2 13:52:11 2021 +0300 sql: introduce mem_str() This patch introduces mem_str() which allows to receive value of MEM as a string. Due to the limitations of static_alloc(), this function cannot be used to safely retrieve a value of MEM converted to string. This function is suitable for debugging, displaying the value in an error message, etc. Part of #5818 diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 46814f341..99ce938d5 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -543,7 +543,7 @@ roundFunc(sql_context * context, int argc, sql_value ** argv) enum mp_type mp_type = sql_value_type(argv[0]); if (mp_type_is_bloblike(mp_type)) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(argv[0]), "numeric"); + mem_str(argv[0]), "numeric"); context->is_aborted = true; return; } @@ -685,7 +685,7 @@ randomBlob(sql_context * context, int argc, sql_value ** argv) UNUSED_PARAMETER(argc); if (mp_type_is_bloblike(sql_value_type(argv[0]))) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(argv[0]), "numeric"); + mem_str(argv[0]), "numeric"); context->is_aborted = true; return; } @@ -1577,7 +1577,7 @@ soundexFunc(sql_context * context, int argc, sql_value ** argv) enum mp_type mp_type = sql_value_type(argv[0]); if (mp_type_is_bloblike(mp_type)) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(argv[0]), "text"); + mem_str(argv[0]), "text"); context->is_aborted = true; return; } @@ -1650,7 +1650,7 @@ sum_step(struct sql_context *context, int argc, sql_value **argv) if (type != MP_DOUBLE && type != MP_INT && type != MP_UINT) { if (mem_apply_numeric_type(argv[0]) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(argv[0]), "number"); + mem_str(argv[0]), "number"); context->is_aborted = true; return; } diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index 25f5f2f2d..95a035fd4 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -40,6 +40,40 @@ #include "lua/utils.h" #include "lua/msgpack.h" +enum { + BUF_SIZE = 32, +}; + +const char * +mem_str(const struct Mem *mem) +{ + char buf[BUF_SIZE]; + switch (mem->flags & MEM_PURE_TYPE_MASK) { + case MEM_Null: + return "NULL"; + case MEM_Str: + if ((mem->flags & MEM_Term) != 0) + return mem->z; + return tt_cstr(mem->z, mem->n); + case MEM_Int: + return tt_sprintf("%lld", mem->u.i); + case MEM_UInt: + return tt_sprintf("%llu", mem->u.u); + case MEM_Real: + sql_snprintf(BUF_SIZE, &buf[0], "%!.15g", mem->u.r); + return tt_sprintf("%s", buf); + case MEM_Blob: + if ((mem->flags & MEM_Subtype) == 0) + return "varbinary"; + assert(mem->subtype == SQL_SUBTYPE_MSGPACK); + return mp_str(mem->z); + case MEM_Bool: + return mem->u.b ? "TRUE" : "FALSE"; + default: + return "unknown"; + } +} + static inline bool mem_has_msgpack_subtype(struct Mem *mem) { @@ -1592,18 +1626,6 @@ sqlValueText(sql_value * pVal) return valueToText(pVal); } -const char * -sql_value_to_diag_str(sql_value *value) -{ - enum mp_type mp_type = sql_value_type(value); - if (mp_type_is_bloblike(mp_type)) { - if (mem_has_msgpack_subtype(value)) - return sqlValueText(value); - return "varbinary"; - } - return sqlValueText(value); -} - enum sql_subtype sql_value_subtype(sql_value * pVal) { diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h index acc8ce054..7b9456426 100644 --- a/src/box/sql/mem.h +++ b/src/box/sql/mem.h @@ -87,6 +87,13 @@ struct Mem { */ #define MEMCELLSIZE offsetof(Mem,zMalloc) +/** + * Return a string that represent content of MEM. String is either allocated + * using static_alloc() of just a static variable. + */ +const char * +mem_str(const struct Mem *mem); + /* One or more of the following flags are set to indicate the validOK * representations of the value stored in the Mem struct. * @@ -358,15 +365,6 @@ sql_value_text(struct Mem *); const void *sqlValueText(struct Mem *); -/** - * Return pointer to a string with the data type in the case of - * binary data stored in @a value. Otherwise, return the result - * of sql_value_text(). It is used due to the fact that not all - * binary strings can be displayed correctly (e.g. contain - * unprintable symbols). - */ -const char * -sql_value_to_diag_str(struct Mem *value); #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) enum sql_subtype diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index d03725106..cfd694c2a 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1265,12 +1265,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } else { if (sqlVdbeRealValue(pIn1, &rA) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "numeric"); + mem_str(pIn1), "numeric"); goto abort_due_to_error; } if (sqlVdbeRealValue(pIn2, &rB) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn2), "numeric"); + mem_str(pIn2), "numeric"); goto abort_due_to_error; } assert(((type1 | type2) & MEM_Real) != 0); @@ -1546,12 +1546,12 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ bool unused; if (sqlVdbeIntValue(pIn2, (int64_t *) &iA, &unused) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn2), "integer"); + mem_str(pIn2), "integer"); goto abort_due_to_error; } if (sqlVdbeIntValue(pIn1, (int64_t *) &iB, &unused) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "integer"); + mem_str(pIn1), "integer"); goto abort_due_to_error; } op = pOp->opcode; @@ -1616,7 +1616,7 @@ case OP_MustBeInt: { /* jump, in1 */ if ((pIn1->flags & (MEM_Int | MEM_UInt)) == 0) { if (pOp->p2==0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "integer"); + mem_str(pIn1), "integer"); goto abort_due_to_error; } else { goto jump_to_p2; @@ -1673,7 +1673,7 @@ case OP_Cast: { /* in1 */ UPDATE_MAX_BLOBSIZE(pIn1); if (rc == 0) break; - diag_set(ClientError, ER_SQL_TYPE_MISMATCH, sql_value_to_diag_str(pIn1), + diag_set(ClientError, ER_SQL_TYPE_MISMATCH, mem_str(pIn1), field_type_strs[pOp->p2]); goto abort_due_to_error; } @@ -1846,7 +1846,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ if (mem_apply_numeric_type(pIn3) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn3), + mem_str(pIn3), "numeric"); goto abort_due_to_error; } @@ -2112,7 +2112,7 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ v1 = pIn1->u.b; } else { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "boolean"); + mem_str(pIn1), "boolean"); goto abort_due_to_error; } pIn2 = &aMem[pOp->p2]; @@ -2122,7 +2122,7 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ v2 = pIn2->u.b; } else { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn2), "boolean"); + mem_str(pIn2), "boolean"); goto abort_due_to_error; } if (pOp->opcode==OP_And) { @@ -2152,7 +2152,7 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ if ((pIn1->flags & MEM_Null)==0) { if ((pIn1->flags & MEM_Bool) == 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "boolean"); + mem_str(pIn1), "boolean"); goto abort_due_to_error; } mem_set_bool(pOut, ! pIn1->u.b); @@ -2177,7 +2177,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ bool is_neg; if (sqlVdbeIntValue(pIn1, &i, &is_neg) != 0) { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "integer"); + mem_str(pIn1), "integer"); goto abort_due_to_error; } mem_set_i64(pOut, ~i); @@ -2223,7 +2223,7 @@ case OP_IfNot: { /* jump, in1 */ c = pOp->opcode == OP_IfNot ? ! pIn1->u.b : pIn1->u.b; } else { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), "boolean"); + mem_str(pIn1), "boolean"); goto abort_due_to_error; } VdbeBranchTaken(c!=0, 2); @@ -2403,7 +2403,7 @@ case OP_ApplyType: { continue; type_mismatch: diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn1), field_type_strs[type]); + mem_str(pIn1), field_type_strs[type]); goto abort_due_to_error; } break; @@ -3032,7 +3032,7 @@ case OP_SeekGT: { /* jump, in3 */ is_neg = i < 0; } else { diag_set(ClientError, ER_SQL_TYPE_MISMATCH, - sql_value_to_diag_str(pIn3), "integer"); + mem_str(pIn3), "integer"); goto abort_due_to_error; } iKey = i; diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 79c3d60e0..9ef0445bd 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -1108,21 +1108,8 @@ displayP4(Op * pOp, char *zTemp, int nTemp) break; } case P4_MEM:{ - Mem *pMem = pOp->p4.pMem; - if (pMem->flags & MEM_Str) { - zP4 = pMem->z; - } else if (pMem->flags & MEM_Int) { - sqlXPrintf(&x, "%lld", pMem->u.i); - } else if (pMem->flags & MEM_UInt) { - sqlXPrintf(&x, "%llu", pMem->u.u); - } else if (pMem->flags & MEM_Real) { - sqlXPrintf(&x, "%.16g", pMem->u.r); - } else if (pMem->flags & MEM_Null) { - zP4 = "NULL"; - } else { - assert(pMem->flags & MEM_Blob); - zP4 = "(binary string)"; - } + const char *value = mem_str(pOp->p4.pMem); + sqlStrAccumAppend(&x, value, strlen(value)); break; } case P4_INTARRAY:{ diff --git a/src/box/sql/vdbetrace.c b/src/box/sql/vdbetrace.c index e84bb3192..a26880041 100644 --- a/src/box/sql/vdbetrace.c +++ b/src/box/sql/vdbetrace.c @@ -97,8 +97,6 @@ sqlVdbeExpandSql(Vdbe * p, /* The prepared statement being evaluated */ int nextIndex = 1; /* Index of next ? host parameter */ int n; /* Length of a token prefix */ int nToken; /* Length of the parameter token */ - int i; /* Loop counter */ - Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ char zBase[100]; /* Initial working space */ @@ -147,33 +145,8 @@ sqlVdbeExpandSql(Vdbe * p, /* The prepared statement being evaluated */ zRawSql += nToken; nextIndex = idx + 1; assert(idx > 0 && idx <= p->nVar); - pVar = &p->aVar[idx - 1]; - if (pVar->flags & MEM_Null) { - sqlStrAccumAppend(&out, "NULL", 4); - } else if (pVar->flags & MEM_Int) { - sqlXPrintf(&out, "%lld", pVar->u.i); - } else if (pVar->flags & MEM_UInt) { - sqlXPrintf(&out, "%llu", pVar->u.u); - } else if (pVar->flags & MEM_Real) { - sqlXPrintf(&out, "%!.15g", pVar->u.r); - } else if (pVar->flags & MEM_Str) { - int nOut; /* Number of bytes of the string text to include in output */ - nOut = pVar->n; - sqlXPrintf(&out, "'%.*q'", nOut, pVar->z); - } else if (pVar->flags & MEM_Zero) { - sqlXPrintf(&out, "zeroblob(%d)", - pVar->u.nZero); - } else { - int nOut; /* Number of bytes of the blob to include in output */ - assert(pVar->flags & MEM_Blob); - sqlStrAccumAppend(&out, "x'", 2); - nOut = pVar->n; - for (i = 0; i < nOut; i++) { - sqlXPrintf(&out, "%02x", - pVar->z[i] & 0xff); - } - sqlStrAccumAppend(&out, "'", 1); - } + const char *value = mem_str(&p->aVar[idx - 1]); + sqlStrAccumAppend(&out, value, strlen(value)); } } if (out.accError)