Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4854ead

Browse files
committed
Reduce an unnecessary O(N^3) loop in lexer.
The lexer's handling of operators contained an O(N^3) hazard when dealing with long strings of + or - characters; it seems hard to prevent this case from being O(N^2), but the additional N multiplier was not needed. Backpatch all the way since this has been there since 7.x, and it presents at least a mild hazard in that trying to do Bind, PREPARE or EXPLAIN on a hostile query could take excessive time (without honouring cancels or timeouts) even if the query was never executed.
1 parent 90b0f30 commit 4854ead

File tree

3 files changed

+61
-22
lines changed

3 files changed

+61
-22
lines changed

src/backend/parser/scan.l

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -881,20 +881,33 @@ other .
881881
* to forbid operator names like '?-' that could not be
882882
* sequences of SQL operators.
883883
*/
884-
while (nchars > 1 &&
885-
(yytext[nchars - 1] == '+' ||
886-
yytext[nchars - 1] == '-'))
884+
if (nchars > 1 &&
885+
(yytext[nchars - 1] == '+' ||
886+
yytext[nchars - 1] == '-'))
887887
{
888888
int ic;
889889

890890
for (ic = nchars - 2; ic >= 0; ic--)
891891
{
892-
if (strchr("~!@#^&|`?%", yytext[ic]))
892+
char c = yytext[ic];
893+
if (c == '~' || c == '!' || c == '@' ||
894+
c == '#' || c == '^' || c == '&' ||
895+
c == '|' || c == '`' || c == '?' ||
896+
c == '%')
893897
break;
894898
}
895-
if (ic >= 0)
896-
break; /* found a char that makes it OK */
897-
nchars--; /* else remove the +/-, and check again */
899+
if (ic < 0)
900+
{
901+
/*
902+
* didn't find a qualifying character, so remove
903+
* all trailing [+-]
904+
*/
905+
do {
906+
nchars--;
907+
} while (nchars > 1 &&
908+
(yytext[nchars - 1] == '+' ||
909+
yytext[nchars - 1] == '-'));
910+
}
898911
}
899912

900913
SET_YYLLOC();

src/fe_utils/psqlscan.l

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -798,20 +798,33 @@ other .
798798
* to forbid operator names like '?-' that could not be
799799
* sequences of SQL operators.
800800
*/
801-
while (nchars > 1 &&
802-
(yytext[nchars - 1] == '+' ||
803-
yytext[nchars - 1] == '-'))
801+
if (nchars > 1 &&
802+
(yytext[nchars - 1] == '+' ||
803+
yytext[nchars - 1] == '-'))
804804
{
805805
int ic;
806806

807807
for (ic = nchars - 2; ic >= 0; ic--)
808808
{
809-
if (strchr("~!@#^&|`?%", yytext[ic]))
809+
char c = yytext[ic];
810+
if (c == '~' || c == '!' || c == '@' ||
811+
c == '#' || c == '^' || c == '&' ||
812+
c == '|' || c == '`' || c == '?' ||
813+
c == '%')
810814
break;
811815
}
812-
if (ic >= 0)
813-
break; /* found a char that makes it OK */
814-
nchars--; /* else remove the +/-, and check again */
816+
if (ic < 0)
817+
{
818+
/*
819+
* didn't find a qualifying character, so remove
820+
* all trailing [+-]
821+
*/
822+
do {
823+
nchars--;
824+
} while (nchars > 1 &&
825+
(yytext[nchars - 1] == '+' ||
826+
yytext[nchars - 1] == '-'));
827+
}
815828
}
816829

817830
if (nchars < yyleng)

src/interfaces/ecpg/preproc/pgc.l

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -687,20 +687,33 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
687687
* to forbid operator names like '?-' that could not be
688688
* sequences of SQL operators.
689689
*/
690-
while (nchars > 1 &&
691-
(yytext[nchars-1] == '+' ||
692-
yytext[nchars-1] == '-'))
690+
if (nchars > 1 &&
691+
(yytext[nchars - 1] == '+' ||
692+
yytext[nchars - 1] == '-'))
693693
{
694694
int ic;
695695

696-
for (ic = nchars-2; ic >= 0; ic--)
696+
for (ic = nchars - 2; ic >= 0; ic--)
697697
{
698-
if (strchr("~!@#^&|`?%", yytext[ic]))
698+
char c = yytext[ic];
699+
if (c == '~' || c == '!' || c == '@' ||
700+
c == '#' || c == '^' || c == '&' ||
701+
c == '|' || c == '`' || c == '?' ||
702+
c == '%')
699703
break;
700704
}
701-
if (ic >= 0)
702-
break; /* found a char that makes it OK */
703-
nchars--; /* else remove the +/-, and check again */
705+
if (ic < 0)
706+
{
707+
/*
708+
* didn't find a qualifying character, so remove
709+
* all trailing [+-]
710+
*/
711+
do {
712+
nchars--;
713+
} while (nchars > 1 &&
714+
(yytext[nchars - 1] == '+' ||
715+
yytext[nchars - 1] == '-'));
716+
}
704717
}
705718

706719
if (nchars < yyleng)

0 commit comments

Comments
 (0)