diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index bd81726647..c2a9fd465e 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -37,7 +37,7 @@ Parser::Parser(MemoryPool& pool, USHORT aClientDialect, USHORT aDbDialect, USHOR db_dialect(aDbDialect), parser_version(aParserVersion), transformedString(pool), - introducerMarks(pool), + strMarks(pool), stmt_ambiguous(false) { yyps = 0; @@ -112,15 +112,22 @@ void Parser::transformString(const char* start, unsigned length, string& dest) HalfStaticArray buffer; const char* pos = start; - for (size_t i = 0; i < introducerMarks.getCount(); ++i) + // We need only the "introduced" strings, in the bounds of "start" and "length" and in "pos" + // order. Let collect them. + + SortedArray introducedMarks; + + GenericMap >::ConstAccessor accessor(&strMarks); + for (bool found = accessor.getFirst(); found; found = accessor.getNext()) { - const IntroducerMark& mark = introducerMarks[i]; + const StrMark& mark = accessor.current()->second; + if (mark.introduced && mark.pos >= fromBegin && mark.pos < fromBegin + length) + introducedMarks.add(mark); + } - if (mark.pos < fromBegin) - continue; - - if (mark.pos >= fromBegin + length) - break; + for (size_t i = 0; i < introducedMarks.getCount(); ++i) + { + const StrMark& mark = introducedMarks[i]; const char* s = lex.start + mark.pos; buffer.add(pos, s - pos); diff --git a/src/dsql/Parser.h b/src/dsql/Parser.h index 22afde6c75..f9602d88d3 100644 --- a/src/dsql/Parser.h +++ b/src/dsql/Parser.h @@ -91,8 +91,22 @@ private: USHORT param_number; }; - struct IntroducerMark + struct StrMark { + StrMark() + : introduced(false), + pos(0), + length(0), + str(NULL) + { + } + + bool operator >(const StrMark& o) const + { + return pos > o.pos; + } + + bool introduced; unsigned pos; unsigned length; dsql_str* str; @@ -156,7 +170,7 @@ private: USHORT parser_version; Firebird::string transformedString; - Firebird::Array introducerMarks; + Firebird::GenericMap > strMarks; bool stmt_ambiguous; dsql_nod* DSQL_parse; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 580c7ab20c..fe81f799f8 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -5131,12 +5131,10 @@ sql_string str->str_charset = $1; if (str->type == dsql_str::TYPE_SIMPLE || str->type == dsql_str::TYPE_ALTERNATE) { - IntroducerMark mark; - mark.pos = lex.last_token - lex.start; - mark.length = lex.ptr - lex.last_token; - mark.str = str; - - introducerMarks.push(mark); + StrMark* mark = strMarks.get(str); + fb_assert(mark); + if (mark) + mark->introduced = true; } $$ = str; } @@ -6432,6 +6430,9 @@ int Parser::yylexAux() if (tok_class & CHR_QUOTE) { + StrMark mark; + mark.pos = lex.last_token - lex.start; + char* buffer = string; size_t buffer_len = sizeof (string); const char* buffer_end = buffer + buffer_len - 1; @@ -6519,6 +6520,11 @@ int Parser::yylexAux() yylval.legacyStr = MAKE_string(buffer, p - buffer); if (buffer != string) gds__free (buffer); + + mark.length = lex.ptr - lex.last_token; + mark.str = yylval.legacyStr; + strMarks.put(mark.str, mark); + return STRING; } @@ -6655,6 +6661,9 @@ int Parser::yylexAux() if ((c == 'q' || c == 'Q') && lex.ptr + 3 < lex.end && *lex.ptr == '\'') { + StrMark mark; + mark.pos = lex.last_token - lex.start; + char endChar = *++lex.ptr; switch (endChar) { @@ -6679,6 +6688,11 @@ int Parser::yylexAux() yylval.legacyStr = MAKE_string(lex.last_token + 3, lex.ptr - lex.last_token - 4); yylval.legacyStr->type = dsql_str::TYPE_ALTERNATE; lex.ptr++; + + mark.length = lex.ptr - lex.last_token; + mark.str = yylval.legacyStr; + strMarks.put(mark.str, mark); + return STRING; } }