33
33
* Portions Copyright (c) 1994, Regents of the University of California
34
34
*
35
35
* IDENTIFICATION
36
- * $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.32 2010/01/29 17:44:12 rhaas Exp $
36
+ * $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.33 2010/05/05 22:18:56 tgl Exp $
37
37
*
38
38
*-------------------------------------------------------------------------
39
39
*/
@@ -59,6 +59,7 @@ typedef struct StackElem
59
59
YY_BUFFER_STATE buf; /* flex input control structure */
60
60
char *bufstring; /* data actually being scanned by flex */
61
61
char *origstring; /* copy of original data, if needed */
62
+ char *varname; /* name of variable providing data, or NULL */
62
63
struct StackElem *next;
63
64
} StackElem;
64
65
@@ -113,7 +114,9 @@ static char *option_quote;
113
114
114
115
int yylex (void );
115
116
116
- static void push_new_buffer (const char *newstr);
117
+ static void push_new_buffer (const char *newstr, const char *varname);
118
+ static void pop_buffer_stack (PsqlScanState state);
119
+ static bool var_is_current_source (PsqlScanState state, const char *varname);
117
120
static YY_BUFFER_STATE prepare_buffer (const char *txt, int len,
118
121
char **txtcopy);
119
122
static void emit (const char *txt, int len);
@@ -688,15 +691,28 @@ other .
688
691
689
692
:[A-Za-z0-9_]+ {
690
693
/* Possible psql variable substitution */
694
+ const char *varname = yytext + 1 ;
691
695
const char *value;
692
696
693
- value = GetVariable (pset.vars , yytext + 1 );
697
+ value = GetVariable (pset.vars , varname );
694
698
695
699
if (value)
696
700
{
697
- /* It is a variable, perform substitution */
698
- push_new_buffer (value);
699
- /* yy_scan_string already made buffer active */
701
+ /* It is a variable, check for recursion */
702
+ if (var_is_current_source (cur_state, varname))
703
+ {
704
+ /* Recursive expansion --- don't go there */
705
+ psql_error (" skipping recursive expansion of variable \" %s\"\n " ,
706
+ varname);
707
+ /* Instead copy the string as is */
708
+ ECHO;
709
+ }
710
+ else
711
+ {
712
+ /* OK, perform substitution */
713
+ push_new_buffer (value, varname);
714
+ /* yy_scan_string already made buffer active */
715
+ }
700
716
}
701
717
else
702
718
{
@@ -836,12 +852,7 @@ other .
836
852
* We were expanding a variable, so pop the inclusion
837
853
* stack and keep lexing
838
854
*/
839
- cur_state->buffer_stack = stackelem->next ;
840
- yy_delete_buffer (stackelem->buf );
841
- free (stackelem->bufstring );
842
- if (stackelem->origstring )
843
- free (stackelem->origstring );
844
- free (stackelem);
855
+ pop_buffer_stack (cur_state);
845
856
846
857
stackelem = cur_state->buffer_stack ;
847
858
if (stackelem != NULL )
@@ -926,6 +937,7 @@ other .
926
937
* further examination. This is consistent with the
927
938
* pre-8.0 code behavior, if not with the way that
928
939
* variables are handled outside backslash commands.
940
+ * Note that we needn't guard against recursion here.
929
941
*/
930
942
if (value)
931
943
appendPQExpBufferStr (output_buf, value);
@@ -1315,16 +1327,7 @@ psql_scan_finish(PsqlScanState state)
1315
1327
{
1316
1328
/* Drop any incomplete variable expansions. */
1317
1329
while (state->buffer_stack != NULL )
1318
- {
1319
- StackElem *stackelem = state->buffer_stack ;
1320
-
1321
- state->buffer_stack = stackelem->next ;
1322
- yy_delete_buffer (stackelem->buf );
1323
- free (stackelem->bufstring );
1324
- if (stackelem->origstring )
1325
- free (stackelem->origstring );
1326
- free (stackelem);
1327
- }
1330
+ pop_buffer_stack (state);
1328
1331
1329
1332
/* Done with the outer scan buffer, too */
1330
1333
if (state->scanbufhandle )
@@ -1670,11 +1673,19 @@ psql_scan_slash_command_end(PsqlScanState state)
1670
1673
* NOTE SIDE EFFECT: the new buffer is made the active flex input buffer.
1671
1674
*/
1672
1675
static void
1673
- push_new_buffer (const char *newstr)
1676
+ push_new_buffer (const char *newstr, const char *varname )
1674
1677
{
1675
1678
StackElem *stackelem;
1676
1679
1677
1680
stackelem = (StackElem *) pg_malloc (sizeof (StackElem));
1681
+
1682
+ /*
1683
+ * In current usage, the passed varname points at the current flex
1684
+ * input buffer; we must copy it before calling prepare_buffer()
1685
+ * because that will change the buffer state.
1686
+ */
1687
+ stackelem->varname = varname ? pg_strdup (varname) : NULL ;
1688
+
1678
1689
stackelem->buf = prepare_buffer (newstr, strlen (newstr),
1679
1690
&stackelem->bufstring );
1680
1691
cur_state->curline = stackelem->bufstring ;
@@ -1692,6 +1703,46 @@ push_new_buffer(const char *newstr)
1692
1703
cur_state->buffer_stack = stackelem;
1693
1704
}
1694
1705
1706
+ /*
1707
+ * Pop the topmost buffer stack item (there must be one!)
1708
+ *
1709
+ * NB: after this, the flex input state is unspecified; caller must
1710
+ * switch to an appropriate buffer to continue lexing.
1711
+ */
1712
+ static void
1713
+ pop_buffer_stack (PsqlScanState state)
1714
+ {
1715
+ StackElem *stackelem = state->buffer_stack ;
1716
+
1717
+ state->buffer_stack = stackelem->next ;
1718
+ yy_delete_buffer (stackelem->buf );
1719
+ free (stackelem->bufstring );
1720
+ if (stackelem->origstring )
1721
+ free (stackelem->origstring );
1722
+ if (stackelem->varname )
1723
+ free (stackelem->varname );
1724
+ free (stackelem);
1725
+ }
1726
+
1727
+ /*
1728
+ * Check if specified variable name is the source for any string
1729
+ * currently being scanned
1730
+ */
1731
+ static bool
1732
+ var_is_current_source (PsqlScanState state, const char *varname)
1733
+ {
1734
+ StackElem *stackelem;
1735
+
1736
+ for (stackelem = state->buffer_stack ;
1737
+ stackelem != NULL ;
1738
+ stackelem = stackelem->next )
1739
+ {
1740
+ if (stackelem->varname && strcmp (stackelem->varname , varname) == 0 )
1741
+ return true ;
1742
+ }
1743
+ return false ;
1744
+ }
1745
+
1695
1746
/*
1696
1747
* Set up a flex input buffer to scan the given data. We always make a
1697
1748
* copy of the data. If working in an unsafe encoding, the copy has
0 commit comments