From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: imeevma@tarantool.org Cc: tarantool-patches@dev.tarantool.org Subject: Re: [Tarantool-patches] [PATCH v1 2/2] sql: introduce mem_snprintf() Date: Thu, 18 Nov 2021 00:03:18 +0100 [thread overview] Message-ID: <8e6f11df-1fae-8b02-b7d6-34165e35e707@tarantool.org> (raw) In-Reply-To: <c3335c0f66ad4ec5a20898ed3857f1a692437ace.1636992280.git.imeevma@gmail.com> Hi! Thanks for the patch! See 5 comments below. > diff --git a/src/box/sql/func.c b/src/box/sql/func.c > index 5abaf490d..0f8f0b5cc 100644 > --- a/src/box/sql/func.c > +++ b/src/box/sql/func.c > @@ -869,9 +869,14 @@ func_printf(struct sql_context *ctx, int argc, const struct Mem *argv) > if (argc < 1 || mem_is_null(&argv[0])) > return; > if (argc == 1 || !mem_is_str(&argv[0])) { > - struct Mem *mem = ctx->pOut; > - if (mem_copy(mem, &argv[0]) != 0 || mem_to_str(mem) != 0) > + uint32_t size = mem_snprintf(NULL, 0, &argv[0]); 1. You are not checking for an error here. mem_snprintf() returns int, not uint. I am fine with making it never failing, but then we need to at least add some assertions inside of mem_snprintf() that its internal snprintf() calls never fail. We can keep returning 'int' though because it makes the function compatible with SNPRINT macro. > + char *str = sqlDbMallocRawNN(sql_get(), size + 1); > + if (str == NULL) { > ctx->is_aborted = true; > + return; > + } > + mem_snprintf(str, size + 1, &argv[0]); > + mem_set_str_allocated(ctx->pOut, str, size); > return; > } > diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c > index 9ddeea5bb..6e1729f32 100644 > --- a/src/box/sql/mem.c > +++ b/src/box/sql/mem.c > @@ -116,30 +116,51 @@ mem_is_field_compatible(const struct Mem *mem, enum field_type type) > return field_mp_plain_type_is_compatible(type, mp_type, true); > } > > -const char * > -mem_str(const struct Mem *mem) > +int > +mem_snprintf(char *buf, uint32_t size, const struct Mem *mem) > { > - char buf[STR_VALUE_MAX_LEN]; > - const char *type = mem_type_to_str(mem); > switch (mem->type) { > case MEM_TYPE_NULL: > - return "NULL"; > + return snprintf(buf, size, "NULL"); > case MEM_TYPE_STR: > + case MEM_TYPE_BIN: > + return snprintf(buf, size, "%.*s", mem->n, mem->z); 2. Why is bin displayed as hex in mem_str() but as a plain string here? > + case MEM_TYPE_INT: > + return snprintf(buf, size, "%lld", mem->u.i); > + case MEM_TYPE_UINT: > + return snprintf(buf, size, "%llu", > + (unsigned long long)mem->u.u); > + case MEM_TYPE_DOUBLE: { > + char str[BUF_SIZE]; > + sql_snprintf(BUF_SIZE, str, "%!.15g", mem->u.r); > + return snprintf(buf, size, "%s", str); > + } > + case MEM_TYPE_DEC: > + return snprintf(buf, size, "%s", decimal_str(&mem->u.d)); > + case MEM_TYPE_MAP: > + case MEM_TYPE_ARRAY: > + return mp_snprint(buf, size, mem->z); > + case MEM_TYPE_UUID: > + return snprintf(buf, size, "%s", tt_uuid_str(&mem->u.uuid)); > + case MEM_TYPE_BOOL: > + return snprintf(buf, size, "%s", mem->u.b ? "TRUE" : "FALSE"); 3. You can drop '%s' here: return snprintf(buf, size, mem->u.b ? "TRUE" : "FALSE"); > + default: > + return snprintf(buf, size, "unknown"); 4. Maybe add an assertion that it is not possible? We don't have non-typed mems AFAIK. > + } > +} > diff --git a/src/box/sql/printf.c b/src/box/sql/printf.c > index 8da7c9878..08e18c15d 100644 > --- a/src/box/sql/printf.c > +++ b/src/box/sql/printf.c > @@ -160,19 +160,12 @@ getTextArg(PrintfArguments * p) > { > if (p->nArg <= p->nUsed) > return 0; > - struct Mem mem; > - mem_create(&mem); > - mem_copy_as_ephemeral(&mem, &p->apArg[p->nUsed++]); > - if (mem_to_str(&mem) != 0) { > - mem_destroy(&mem); > - return NULL; > - } > - char *str = sqlDbMallocRawNN(sql_get(), mem.n + 1); > + const struct Mem *mem = &p->apArg[p->nUsed++]; > + uint32_t size = mem_snprintf(NULL, 0, mem); > + char *str = sqlDbMallocRawNN(sql_get(), size + 1); > if (str == NULL) > return NULL; > - memcpy(str, mem.z, mem.n); > - str[mem.n] = '\0'; > - mem_destroy(&mem); > + mem_snprintf(str, size + 1, mem); 5. Hm. I suspect this pattern of snprintf + malloc + snprintf is going to be frequent. Maybe wrap it into a function like mem_strdup()? It would do these 3 actions inside. WDYT?
next prev parent reply other threads:[~2021-11-17 23:03 UTC|newest] Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-11-15 16:06 [Tarantool-patches] [PATCH v1 0/2] Introduce mem_snprintf() Mergen Imeev via Tarantool-patches 2021-11-15 16:06 ` [Tarantool-patches] [PATCH v1 1/2] sql: omit quotes for UUID values in errors Mergen Imeev via Tarantool-patches 2021-11-15 16:06 ` [Tarantool-patches] [PATCH v1 2/2] sql: introduce mem_snprintf() Mergen Imeev via Tarantool-patches 2021-11-17 23:03 ` Vladislav Shpilevoy via Tarantool-patches [this message] 2021-11-19 12:02 ` Mergen Imeev via Tarantool-patches 2021-11-21 15:27 ` [Tarantool-patches] [PATCH v1 0/2] Introduce mem_snprintf() Vladislav Shpilevoy via Tarantool-patches 2021-11-22 8:22 Mergen Imeev via Tarantool-patches 2021-11-22 8:22 ` [Tarantool-patches] [PATCH v1 2/2] sql: introduce mem_snprintf() Mergen Imeev via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=8e6f11df-1fae-8b02-b7d6-34165e35e707@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=imeevma@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH v1 2/2] sql: introduce mem_snprintf()' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox