31
31
* Portions Copyright (c) 1994, Regents of the University of California
32
32
*
33
33
* IDENTIFICATION
34
- * $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.9 2004/12/31 22:03:15 pgsql Exp $
34
+ * $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.9.4.1 2010/05/05 22:19:31 tgl Exp $
35
35
*
36
36
*-------------------------------------------------------------------------
37
37
*/
@@ -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);
@@ -541,15 +544,28 @@ other .
541
544
542
545
:[A-Za-z0-9_]+ {
543
546
/* Possible psql variable substitution */
547
+ const char *varname = yytext + 1 ;
544
548
const char *value;
545
549
546
- value = GetVariable (pset.vars , yytext + 1 );
550
+ value = GetVariable (pset.vars , varname );
547
551
548
552
if (value)
549
553
{
550
- /* It is a variable, perform substitution */
551
- push_new_buffer (value);
552
- /* yy_scan_string already made buffer active */
554
+ /* It is a variable, check for recursion */
555
+ if (var_is_current_source (cur_state, varname))
556
+ {
557
+ /* Recursive expansion --- don't go there */
558
+ psql_error (" skipping recursive expansion of variable \" %s\"\n " ,
559
+ varname);
560
+ /* Instead copy the string as is */
561
+ ECHO;
562
+ }
563
+ else
564
+ {
565
+ /* OK, perform substitution */
566
+ push_new_buffer (value, varname);
567
+ /* yy_scan_string already made buffer active */
568
+ }
553
569
}
554
570
else
555
571
{
@@ -661,12 +677,7 @@ other .
661
677
* We were expanding a variable, so pop the inclusion
662
678
* stack and keep lexing
663
679
*/
664
- cur_state->buffer_stack = stackelem->next ;
665
- yy_delete_buffer (stackelem->buf );
666
- free (stackelem->bufstring );
667
- if (stackelem->origstring )
668
- free (stackelem->origstring );
669
- free (stackelem);
680
+ pop_buffer_stack (cur_state);
670
681
671
682
stackelem = cur_state->buffer_stack ;
672
683
if (stackelem != NULL )
@@ -751,6 +762,7 @@ other .
751
762
* further examination. This is consistent with the
752
763
* pre-8.0 code behavior, if not with the way that
753
764
* variables are handled outside backslash commands.
765
+ * Note that we needn't guard against recursion here.
754
766
*/
755
767
if (value)
756
768
appendPQExpBufferStr (output_buf, value);
@@ -1116,16 +1128,7 @@ psql_scan_finish(PsqlScanState state)
1116
1128
{
1117
1129
/* Drop any incomplete variable expansions. */
1118
1130
while (state->buffer_stack != NULL )
1119
- {
1120
- StackElem *stackelem = state->buffer_stack ;
1121
-
1122
- state->buffer_stack = stackelem->next ;
1123
- yy_delete_buffer (stackelem->buf );
1124
- free (stackelem->bufstring );
1125
- if (stackelem->origstring )
1126
- free (stackelem->origstring );
1127
- free (stackelem);
1128
- }
1131
+ pop_buffer_stack (state);
1129
1132
1130
1133
/* Done with the outer scan buffer, too */
1131
1134
if (state->scanbufhandle )
@@ -1469,7 +1472,7 @@ psql_scan_slash_pushback(PsqlScanState state, const char *str)
1469
1472
/* needed for push_new_buffer */
1470
1473
cur_state = state;
1471
1474
1472
- push_new_buffer (str);
1475
+ push_new_buffer (str, NULL );
1473
1476
}
1474
1477
1475
1478
@@ -1481,11 +1484,19 @@ psql_scan_slash_pushback(PsqlScanState state, const char *str)
1481
1484
* NOTE SIDE EFFECT: the new buffer is made the active flex input buffer.
1482
1485
*/
1483
1486
static void
1484
- push_new_buffer (const char *newstr)
1487
+ push_new_buffer (const char *newstr, const char *varname )
1485
1488
{
1486
1489
StackElem *stackelem;
1487
1490
1488
1491
stackelem = (StackElem *) pg_malloc (sizeof (StackElem));
1492
+
1493
+ /*
1494
+ * In current usage, the passed varname points at the current flex
1495
+ * input buffer; we must copy it before calling prepare_buffer()
1496
+ * because that will change the buffer state.
1497
+ */
1498
+ stackelem->varname = varname ? pg_strdup (varname) : NULL ;
1499
+
1489
1500
stackelem->buf = prepare_buffer (newstr, strlen (newstr),
1490
1501
&stackelem->bufstring );
1491
1502
cur_state->curline = stackelem->bufstring ;
@@ -1503,6 +1514,46 @@ push_new_buffer(const char *newstr)
1503
1514
cur_state->buffer_stack = stackelem;
1504
1515
}
1505
1516
1517
+ /*
1518
+ * Pop the topmost buffer stack item (there must be one!)
1519
+ *
1520
+ * NB: after this, the flex input state is unspecified; caller must
1521
+ * switch to an appropriate buffer to continue lexing.
1522
+ */
1523
+ static void
1524
+ pop_buffer_stack (PsqlScanState state)
1525
+ {
1526
+ StackElem *stackelem = state->buffer_stack ;
1527
+
1528
+ state->buffer_stack = stackelem->next ;
1529
+ yy_delete_buffer (stackelem->buf );
1530
+ free (stackelem->bufstring );
1531
+ if (stackelem->origstring )
1532
+ free (stackelem->origstring );
1533
+ if (stackelem->varname )
1534
+ free (stackelem->varname );
1535
+ free (stackelem);
1536
+ }
1537
+
1538
+ /*
1539
+ * Check if specified variable name is the source for any string
1540
+ * currently being scanned
1541
+ */
1542
+ static bool
1543
+ var_is_current_source (PsqlScanState state, const char *varname)
1544
+ {
1545
+ StackElem *stackelem;
1546
+
1547
+ for (stackelem = state->buffer_stack ;
1548
+ stackelem != NULL ;
1549
+ stackelem = stackelem->next )
1550
+ {
1551
+ if (stackelem->varname && strcmp (stackelem->varname , varname) == 0 )
1552
+ return true ;
1553
+ }
1554
+ return false ;
1555
+ }
1556
+
1506
1557
/*
1507
1558
* Set up a flex input buffer to scan the given data. We always make a
1508
1559
* copy of the data. If working in an unsafe encoding, the copy has
0 commit comments