Best Practices

Halo Database Implements MySQL String and Identifier Quoting

D
DBA Team
October 25, 2023

1. In the Halo database

Strings: Quoted with single quotes ('')

sql
select 'halo';

Identifiers: Can be referenced directly or quoted with double quotes ("")

sql
select id from test;

select "id" from "test";

Among these, identifiers quoted with double quotes can contain special characters, can be keywords, and are case-sensitive.

2. In the MySQL database

Strings: Quoted with single quotes ('') or double quotes (""). Both functions are the same.

sql
select 'halo';

or select "halo";

Among these, identifiers quoted with backticks (`) can contain special characters and can be keywords. By default, they are case-insensitive.

3. Specific Implementation

In the Halo database's syntax file, the tokens for strings and identifiers are Sconst and Ident respectively. In the lexical file, the specific modifications are as follows:

Step 1: Add backtick identifier recognition rules as follows:

c
{xbtstart}      {
                  SET_YYLLOC();
                  BEGIN(xbt);
                  startlit();
              }
<xbt>{xbtstop}  {
                  char       *ident;
                  BEGIN(INITIAL);
                  if (yyextra->literallen == 0)
                      yyerror("zero-length delimited identifier");
                  // ident = litbufdup(yyscanner);
                  // if (yyextra->literallen >= NAMEDATALEN)
                  //  truncate_identifier(ident, yyextra->literallen, true);
                  ident = downcase_truncate_identifier(yyextra->literalbuf, yyextra->literallen, true);
                  yylval->str = ident;
                  return IDENT;
              }
<xbt>{xbtdouble}    {
                  addlitchar('`', yyscanner);
              }
<xbt>{xbtinside}    {
                  addlit(yytext, yyleng, yyscanner);
              }
<xbt><<EOF>>    { yyerror("unterminated backtick identifier"); }

Step 2: Remove parts of the single quote string rules (such as escaping octal and hexadecimal in strings) as follows:

c
<xe>{xeoctesc}  {
                  unsigned char c = strtoul(yytext + 1, NULL, 8);
                  check_escape_warning(yyscanner);
                  addlitchar(c, yyscanner);
                  if (c == '\0' || IS_HIGHBIT_SET(c))
                      yyextra->saw_non_ascii = true;
              }
<xe>{xehexesc}  {
                  unsigned char c = strtoul(yytext + 2, NULL, 16);
                  check_escape_warning(yyscanner);
                  addlitchar(c, yyscanner);
                  if (c == '\0' || IS_HIGHBIT_SET(c))
                      yyextra->saw_non_ascii = true;
              }

Step 3: Remove the identifier recognition rules related to double quotes and add double quote string recognition rules. The result is as follows:

c
{xdqstart}      {
                  yyextra->warn_on_first_escape = false;
                  yyextra->saw_non_ascii = false;
                  SET_YYLLOC();
                  // if (yyextra->standard_conforming_strings)
                  //  BEGIN(xdq);
                  // else
                  //  BEGIN(xde);
                  BEGIN(xde);
                  startlit();
              }
<xdq,xde>{dquote} {
                  /*
                   * When we are scanning a quoted string and see an end
                   * quote, we must look ahead for a possible continuation.
                   * If we don't see one, we know the end quote was in fact
                   * the end of the string.  To reduce the lexer table size,
                   * we use a single "xqs" state to do the lookahead for all
                   * types of strings.
                   */
                  yyextra->state_before_str_stop = YYSTATE;
                  BEGIN(xdqs);
              }
<xdqs>{dquotecontinue} {
                  /*
                   * Found a quote continuation, so return to the in-quote
                   * state and continue scanning the literal.  Nothing is
                   * added to the literal's contents.
                   */
                  BEGIN(yyextra->state_before_str_stop);
              }
<xdqs>{dquotecontinuefail} |
<xdqs>{other} |
<xdqs><<EOF>>   {
                  /*
                   * Failed to see a quote continuation.  Throw back
                   * everything after the end quote, and handle the string
                   * according to the state we were in previously.
                   */
                  yyless(0);
                  BEGIN(INITIAL);
                  switch (yyextra->state_before_str_stop)
                  {
                      case xdq:
                      case xde:
                          /*
                           * Check that the data remains valid, if it might
                           * have been made invalid by unescaping any chars.
                           */
                          if (yyextra->saw_non_ascii)
                              pg_verifymbstr(yyextra->literalbuf,
                                             yyextra->literallen,
                                             false);
                          yylval->str = litbufdup(yyscanner);
                          return SCONST;
                      default:
                          yyerror("unhandled previous state in xdqs");
                  }
              }
<xdq,xde>{xdqdouble} {
                  addlitchar('"', yyscanner);
              }
<xdq>{xdqinside}  {
                  addlit(yytext, yyleng, yyscanner);
              }
<xde>{xdeinside}  {
                  addlit(yytext, yyleng, yyscanner);
              }
<xde>{xdeescape}  {
                  if (yytext[1] == '"')
                  {
                      if (yyextra->backslash_quote == BACKSLASH_QUOTE_OFF ||
                          (yyextra->backslash_quote == BACKSLASH_QUOTE_SAFE_ENCODING &&
                           PG_ENCODING_IS_CLIENT_ONLY(pg_get_client_encoding())))
                          ereport(ERROR,
                                  (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                   errmsg("unsafe use of \\\" in a string literal"),
                                   errhint("Use \"\" to write double quotes in strings. \\\" is insecure in client-only encodings."),
                                   lexer_errposition()));
                  }
                  if(yytext[1] == '0')
                      yytext[1] = '\0';
                  check_string_escape_warning(yytext[1], yyscanner);
                  addlitchar(unescape_single_char(yytext[1], yyscanner),
                             yyscanner);
              }
<xde>.          {
                  /* This is only needed for \\ just before EOF */
                  addlitchar(yytext[0], yyscanner);
              }
<xdq,xde><<EOF>>        { yyerror("unterminated double quoted string"); }

4. Result Display

String:

Identifier:


Latest Articles

Security Announcement
April 11, 2025

Xihe (Halo) Database Critical Patch Update Announcement - April 2025

Security Announcement
June 20, 2024

Xihe (Halo) Database Critical Patch Update Announcement - June 2024

Security Announcement
December 18, 2023

Xihe (Halo) Database Critical Patch Update Announcement - December 2023