3333 * Portions Copyright (c) 1994, Regents of the University of California
3434 *
3535 * 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 $
3737 *
3838 *-------------------------------------------------------------------------
3939 */
@@ -59,6 +59,7 @@ typedef struct StackElem
5959 YY_BUFFER_STATE buf; /* flex input control structure */
6060 char *bufstring; /* data actually being scanned by flex */
6161 char *origstring; /* copy of original data, if needed */
62+ char *varname; /* name of variable providing data, or NULL */
6263 struct StackElem *next;
6364} StackElem;
6465
@@ -113,7 +114,9 @@ static char *option_quote;
113114
114115int yylex (void );
115116
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);
117120static YY_BUFFER_STATE prepare_buffer (const char *txt, int len,
118121 char **txtcopy);
119122static void emit (const char *txt, int len);
@@ -688,15 +691,28 @@ other .
688691
689692:[A-Za-z0-9_]+ {
690693 /* Possible psql variable substitution */
694+ const char *varname = yytext + 1 ;
691695 const char *value;
692696
693- value = GetVariable (pset.vars , yytext + 1 );
697+ value = GetVariable (pset.vars , varname );
694698
695699 if (value)
696700 {
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+ }
700716 }
701717 else
702718 {
@@ -836,12 +852,7 @@ other .
836852 * We were expanding a variable, so pop the inclusion
837853 * stack and keep lexing
838854 */
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);
845856
846857 stackelem = cur_state->buffer_stack ;
847858 if (stackelem != NULL )
@@ -926,6 +937,7 @@ other .
926937 * further examination. This is consistent with the
927938 * pre-8.0 code behavior, if not with the way that
928939 * variables are handled outside backslash commands.
940+ * Note that we needn't guard against recursion here.
929941 */
930942 if (value)
931943 appendPQExpBufferStr (output_buf, value);
@@ -1315,16 +1327,7 @@ psql_scan_finish(PsqlScanState state)
13151327{
13161328 /* Drop any incomplete variable expansions. */
13171329 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);
13281331
13291332 /* Done with the outer scan buffer, too */
13301333 if (state->scanbufhandle )
@@ -1670,11 +1673,19 @@ psql_scan_slash_command_end(PsqlScanState state)
16701673 * NOTE SIDE EFFECT: the new buffer is made the active flex input buffer.
16711674 */
16721675static void
1673- push_new_buffer (const char *newstr)
1676+ push_new_buffer (const char *newstr, const char *varname )
16741677{
16751678 StackElem *stackelem;
16761679
16771680 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+
16781689 stackelem->buf = prepare_buffer (newstr, strlen (newstr),
16791690 &stackelem->bufstring );
16801691 cur_state->curline = stackelem->bufstring ;
@@ -1692,6 +1703,46 @@ push_new_buffer(const char *newstr)
16921703 cur_state->buffer_stack = stackelem;
16931704}
16941705
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+
16951746/*
16961747 * Set up a flex input buffer to scan the given data. We always make a
16971748 * copy of the data. If working in an unsafe encoding, the copy has
0 commit comments