Обсуждение: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed

Поиск
Список
Период
Сортировка

quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed

От
Chao Li
Дата:
Hi Hackers,

== Background ==

While reviewing a patch, I noticed that quoteOneName() duplicates the logic of quote_identifier() for adding double quotes to identifiers.  The main difference is that quoteOneName() does *not* honor the GUC `quote_all_identifiers`.

The typical usage pattern of quoteOneName() looks like this:

```
    // Define a local buffer with size MAX_QUOTED_NAME_LEN
    // MAX_QUOTED_NAME_LEN = MAX_NAMELEN * 2 + 3 to ensure no overflow
    char attname[MAX_QUOTED_NAME_LEN];

    // Add quotes and copy into the stack buffer
    quoteOneName(attname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));

    // Copy the quoted identifier into a StringInfo
    appendStringInfoString(&querybuf, attname);
```

This pattern is expensive because:

* it allocates a larger-than-necessary buffer on the stack
* it incurs two pallocs and two data copies

Looking further, the common pattern around quote_identifier() is similar:

```
    appendStringInfoString(&relations, quote_identifier(relname));
```

This also incurs two pallocs and two copies: quote_identifier() allocates a temporary buffer and copies the quoted identifier into it, and then appendStringInfoString() may allocate and copy again.

== Idea ==

I'd like to propose introducing `appendStringInfoIdentifier()`, which adds the quoting logic directly to StringInfo.  The goals are:

* eventually deprecate quoteOneName() — I'm not aware of a reason why it should ignore the GUC `quote_all_identifiers`
* simplify the usage patterns for quoting identifiers
* avoid unnecessary intermediate buffers, pallocs, and data copies

== About the attached patch ==

Attached v1 is not intended to be the final version — it is mainly to demonstrate the idea and get feedback on the design direction.

* 0001 implements `appendStringInfoIdentifier()` and uses it in a few places
* 0002 switches ri_triggers.c to use it, resolving a complicated usage pattern and showing a path toward removing quoteOneName()

Comments and suggestions on the overall direction would be very welcome.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/




Вложения

Re: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed

От
Chao Li
Дата:

On Mon, Nov 17, 2025 at 5:48 PM Chao Li <li.evan.chao@gmail.com> wrote:
Hi Hackers,

== Background ==

While reviewing a patch, I noticed that quoteOneName() duplicates the logic of quote_identifier() for adding double quotes to identifiers.  The main difference is that quoteOneName() does *not* honor the GUC `quote_all_identifiers`.

The typical usage pattern of quoteOneName() looks like this:

```
    // Define a local buffer with size MAX_QUOTED_NAME_LEN
    // MAX_QUOTED_NAME_LEN = MAX_NAMELEN * 2 + 3 to ensure no overflow
    char attname[MAX_QUOTED_NAME_LEN];

    // Add quotes and copy into the stack buffer
    quoteOneName(attname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));

    // Copy the quoted identifier into a StringInfo
    appendStringInfoString(&querybuf, attname);
```

This pattern is expensive because:

* it allocates a larger-than-necessary buffer on the stack
* it incurs two pallocs and two data copies

Looking further, the common pattern around quote_identifier() is similar:

```
    appendStringInfoString(&relations, quote_identifier(relname));
```

This also incurs two pallocs and two copies: quote_identifier() allocates a temporary buffer and copies the quoted identifier into it, and then appendStringInfoString() may allocate and copy again.

== Idea ==

I'd like to propose introducing `appendStringInfoIdentifier()`, which adds the quoting logic directly to StringInfo.  The goals are:

* eventually deprecate quoteOneName() — I'm not aware of a reason why it should ignore the GUC `quote_all_identifiers`
* simplify the usage patterns for quoting identifiers
* avoid unnecessary intermediate buffers, pallocs, and data copies

== About the attached patch ==

Attached v1 is not intended to be the final version — it is mainly to demonstrate the idea and get feedback on the design direction.

* 0001 implements `appendStringInfoIdentifier()` and uses it in a few places
* 0002 switches ri_triggers.c to use it, resolving a complicated usage pattern and showing a path toward removing quoteOneName()

Comments and suggestions on the overall direction would be very welcome.


CF entry added: https://commitfest.postgresql.org/patch/6240/. And here comes the v2 patch set.
 
Best regards,
Chao Li (Evan)
---------------------
HighGo Software Co., Ltd.
Вложения

Re: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed

От
Álvaro Herrera
Дата:
Hi,

> -                appendStringInfo(&buffer, _("text search configuration %s"),
> -                                 quote_qualified_identifier(nspname,
> -                                                            NameStr(cfgForm->cfgname)));
> +                appendStringInfoQualifiedIdentifier(&buffer,
> +                                                    _("text search configuration "),
> +                                                    nspname, NameStr(cfgForm->cfgname), NULL);
>                  ReleaseSysCache(tup);
>                  break;
>              }

This doesn't work from a i18n point of view.  In the original
formulation, the translator is free to place the %s wherever it suits
the language.  In the new one there's no such freedom: the name will be
appended at the end.  Some existing translations:

ko.po:msgid "text search configuration %s"
ko.po-msgstr "%s 전문 검색 구성"

tr.po:msgid "text search configuration %s"
tr.po-msgstr "%s metin arama yapılandırması"

-- 
Álvaro Herrera               48°01'N 7°57'E  —  https://www.EnterpriseDB.com/
"I must say, I am absolutely impressed with what pgsql's implementation of
VALUES allows me to do. It's kind of ridiculous how much "work" goes away in
my code.  Too bad I can't do this at work (Oracle 8/9)."       (Tom Allison)
           http://archives.postgresql.org/pgsql-general/2007-06/msg00016.php



Re: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed

От
Chao Li
Дата:

On Thu, Nov 20, 2025 at 8:28 PM Álvaro Herrera <alvherre@kurilemu.de> wrote:
Hi,

> -                appendStringInfo(&buffer, _("text search configuration %s"),
> -                                 quote_qualified_identifier(nspname,
> -                                                            NameStr(cfgForm->cfgname)));
> +                appendStringInfoQualifiedIdentifier(&buffer,
> +                                                    _("text search configuration "),
> +                                                    nspname, NameStr(cfgForm->cfgname), NULL);
>                  ReleaseSysCache(tup);
>                  break;
>              }

This doesn't work from a i18n point of view.  In the original
formulation, the translator is free to place the %s wherever it suits
the language.  In the new one there's no such freedom: the name will be
appended at the end.  Some existing translations:

ko.po:msgid "text search configuration %s"
ko.po-msgstr "%s 전문 검색 구성"

tr.po:msgid "text search configuration %s"
tr.po-msgstr "%s metin arama yapılandırması"

Thanks for the feedback. I reverted that piece of change in v3.

Best regards,
Chao Li (Evan)
---------------------
HighGo Software Co., Ltd.
Вложения

Re: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed

От
Chao Li
Дата:
Fixed a compile warning in v4.

Best regards,
Chao Li (Evan)
---------------------
HighGo Software Co., Ltd.
https://www.highgo.com/


On Fri, Nov 21, 2025 at 1:52 PM Chao Li <li.evan.chao@gmail.com> wrote:

On Thu, Nov 20, 2025 at 8:28 PM Álvaro Herrera <alvherre@kurilemu.de> wrote:
Hi,

> -                appendStringInfo(&buffer, _("text search configuration %s"),
> -                                 quote_qualified_identifier(nspname,
> -                                                            NameStr(cfgForm->cfgname)));
> +                appendStringInfoQualifiedIdentifier(&buffer,
> +                                                    _("text search configuration "),
> +                                                    nspname, NameStr(cfgForm->cfgname), NULL);
>                  ReleaseSysCache(tup);
>                  break;
>              }

This doesn't work from a i18n point of view.  In the original
formulation, the translator is free to place the %s wherever it suits
the language.  In the new one there's no such freedom: the name will be
appended at the end.  Some existing translations:

ko.po:msgid "text search configuration %s"
ko.po-msgstr "%s 전문 검색 구성"

tr.po:msgid "text search configuration %s"
tr.po-msgstr "%s metin arama yapılandırması"

Thanks for the feedback. I reverted that piece of change in v3.

Best regards,
Chao Li (Evan)
---------------------
HighGo Software Co., Ltd.
Вложения