@@ -120,6 +120,7 @@ static bool var_is_current_source(PsqlScanState state, const char *varname);
120
120
static YY_BUFFER_STATE prepare_buffer (const char *txt, int len,
121
121
char **txtcopy);
122
122
static void emit (const char *txt, int len);
123
+ static char *extract_substring (const char *txt, int len);
123
124
static void escape_variable (bool as_ident);
124
125
125
126
#define ECHO emit (yytext, yyleng)
@@ -384,6 +385,9 @@ realfail2 ({integer}|{decimal})[Ee][-+]
384
385
385
386
param \${integer}
386
387
388
+ /* psql-specific: characters allowed in variable names */
389
+ variable_char [A-Za-z\200 -\377_0-9 ]
390
+
387
391
other .
388
392
389
393
/*
@@ -680,11 +684,12 @@ other .
680
684
return LEXRES_BACKSLASH;
681
685
}
682
686
683
- :[A-Za-z0-9_] + {
687
+ :{variable_char} + {
684
688
/* Possible psql variable substitution */
685
- const char *varname = yytext + 1 ;
689
+ char *varname ;
686
690
const char *value;
687
691
692
+ varname = extract_substring (yytext + 1 , yyleng - 1 );
688
693
value = GetVariable (pset.vars , varname);
689
694
690
695
if (value)
@@ -713,13 +718,15 @@ other .
713
718
*/
714
719
ECHO;
715
720
}
721
+
722
+ free (varname);
716
723
}
717
724
718
- :' [A-Za-z0-9_] +' {
725
+ :' {variable_char} +' {
719
726
escape_variable (false );
720
727
}
721
728
722
- :\" [A-Za-z0-9_] +\" {
729
+ :\" {variable_char} +\" {
723
730
escape_variable(true);
724
731
}
725
732
@@ -728,13 +735,13 @@ other .
728
735
* two rules above fails to match completely.
729
736
*/
730
737
731
- :'[A-Za-z0-9_] * {
738
+ :'{variable_char} * {
732
739
/* Throw back everything but the colon */
733
740
yyless(1);
734
741
ECHO;
735
742
}
736
743
737
- :\" [A-Za-z0-9_] * {
744
+ :\" {variable_char} * {
738
745
/* Throw back everything but the colon */
739
746
yyless(1);
740
747
ECHO;
@@ -930,15 +937,18 @@ other .
930
937
}
931
938
}
932
939
933
- :[A-Za-z0-9_] + {
940
+ :{variable_char} + {
934
941
/* Possible psql variable substitution */
935
942
if (option_type == OT_VERBATIM)
936
943
ECHO;
937
944
else
938
945
{
946
+ char *varname;
939
947
const char *value;
940
948
941
- value = GetVariable (pset.vars , yytext + 1 );
949
+ varname = extract_substring (yytext + 1 , yyleng - 1 );
950
+ value = GetVariable (pset.vars , varname);
951
+ free (varname);
942
952
943
953
/*
944
954
* The variable value is just emitted without any
@@ -956,7 +966,7 @@ other .
956
966
return LEXRES_OK;
957
967
}
958
968
959
- :' [A-Za-z0-9_] +' {
969
+ :' {variable_char} +' {
960
970
if (option_type == OT_VERBATIM)
961
971
ECHO;
962
972
else
@@ -967,7 +977,7 @@ other .
967
977
}
968
978
969
979
970
- :\" [A-Za-z0-9_] +\" {
980
+ :\" {variable_char} +\" {
971
981
if (option_type == OT_VERBATIM)
972
982
ECHO;
973
983
else
@@ -977,14 +987,14 @@ other .
977
987
}
978
988
}
979
989
980
- :'[A-Za-z0-9_] * {
990
+ :'{variable_char} * {
981
991
/* Throw back everything but the colon */
982
992
yyless(1);
983
993
ECHO;
984
994
BEGIN(xslashdefaultarg);
985
995
}
986
996
987
- :\" [A-Za-z0-9_] * {
997
+ :\" {variable_char} * {
988
998
/* Throw back everything but the colon */
989
999
yyless(1);
990
1000
ECHO;
@@ -1844,16 +1854,58 @@ emit(const char *txt, int len)
1844
1854
}
1845
1855
}
1846
1856
1857
+ /*
1858
+ * extract_substring --- fetch the true value of (part of) the current token
1859
+ *
1860
+ * This is like emit(), except that the data is returned as a malloc'd string
1861
+ * rather than being pushed directly to output_buf.
1862
+ */
1863
+ static char *
1864
+ extract_substring (const char *txt, int len)
1865
+ {
1866
+ char *result = (char *) pg_malloc (len + 1 );
1867
+
1868
+ if (cur_state->safe_encoding )
1869
+ memcpy (result, txt, len);
1870
+ else
1871
+ {
1872
+ /* Gotta do it the hard way */
1873
+ const char *reference = cur_state->refline ;
1874
+ int i;
1875
+
1876
+ reference += (txt - cur_state->curline );
1877
+
1878
+ for (i = 0 ; i < len; i++)
1879
+ {
1880
+ char ch = txt[i];
1881
+
1882
+ if (ch == (char ) 0xFF )
1883
+ ch = reference[i];
1884
+ result[i] = ch;
1885
+ }
1886
+ }
1887
+ result[len] = ' \0 ' ;
1888
+ return result;
1889
+ }
1890
+
1891
+ /*
1892
+ * escape_variable --- process :'VARIABLE' or :"VARIABLE"
1893
+ *
1894
+ * If the variable name is found, escape its value using the appropriate
1895
+ * quoting method and emit the value to output_buf. (Since the result is
1896
+ * surely quoted, there is never any reason to rescan it.) If we don't
1897
+ * find the variable or the escaping function fails, emit the token as-is.
1898
+ */
1847
1899
static void
1848
1900
escape_variable (bool as_ident)
1849
1901
{
1850
- char saved_char ;
1902
+ char *varname ;
1851
1903
const char *value;
1852
1904
1853
1905
/* Variable lookup. */
1854
- saved_char = yytext[ yyleng - 1 ] ;
1855
- yytext[yyleng - 1 ] = ' \0 ' ;
1856
- value = GetVariable (pset. vars , yytext + 2 );
1906
+ varname = extract_substring ( yytext + 2 , yyleng - 3 ) ;
1907
+ value = GetVariable (pset. vars , varname) ;
1908
+ free (varname );
1857
1909
1858
1910
/* Escaping. */
1859
1911
if (value)
@@ -1870,9 +1922,11 @@ escape_variable(bool as_ident)
1870
1922
else
1871
1923
escaped_value =
1872
1924
PQescapeLiteral (pset.db , value, strlen (value));
1925
+
1873
1926
if (escaped_value == NULL )
1874
1927
{
1875
1928
const char *error = PQerrorMessage (pset.db );
1929
+
1876
1930
psql_error (" %s" , error);
1877
1931
}
1878
1932
else
@@ -1888,6 +1942,5 @@ escape_variable(bool as_ident)
1888
1942
* If we reach this point, some kind of error has occurred. Emit the
1889
1943
* original text into the output buffer.
1890
1944
*/
1891
- yytext[yyleng - 1 ] = saved_char;
1892
1945
emit (yytext, yyleng);
1893
1946
}
0 commit comments