@ -2723,10 +2723,11 @@ read_sql_construct(int until,
if (parenlevel < 0)
if (parenlevel < 0)
yyerror("mismatched parentheses");
yyerror("mismatched parentheses");
}
}
/*
/*
* End of function definition is an error, and we don't expect to
* End of function definition is an error, and we don't expect to hit
* hit a semicolon either (unless it's the until symbol, in which
* a semicolon either (unless it's the until symbol, in which case we
* case we should have fallen out above).
* should have fallen out above).
*/
*/
if (tok == 0 || tok == ';')
if (tok == 0 || tok == ';')
{
{
@ -2983,8 +2984,8 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
/*
/*
* Scan to the end of the SQL command. Identify any INTO-variables
* Scan to the end of the SQL command. Identify any INTO-variables clause
* clause lurking within it, and parse that via read_into_target().
* lurking within it, and parse that via read_into_target().
*
*
* The end of the statement is defined by a semicolon ... except that
* The end of the statement is defined by a semicolon ... except that
* semicolons within parentheses or BEGIN/END blocks don't terminate a
* semicolons within parentheses or BEGIN/END blocks don't terminate a
@ -3006,12 +3007,12 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
* but it's not very likely.
* but it's not very likely.
*
*
* 3. IMPORT FOREIGN SCHEMA ... INTO. This is not allowed in CREATE RULE
* 3. IMPORT FOREIGN SCHEMA ... INTO. This is not allowed in CREATE RULE
* or WITH, so we just check for IMPORT as the command's first token.
* or WITH, so we just check for IMPORT as the command's first token. (If
* (If IMPORT FOREIGN SCHEMA returned data someone might wish to capture
* IMPORT FOREIGN SCHEMA returned data someone might wish to capture with
* with an INTO-variables clause, we'd have to work much harder here.)
* an INTO-variables clause, we'd have to work much harder here.)
*
*
* Fortunately, INTO is a fully reserved word in the main grammar, so
* Fortunately, INTO is a fully reserved word in the main grammar, so at
* at least we need not worry about it appearing as an identifier.
* least we need not worry about it appearing as an identifier.
*
*
* Any future additional uses of INTO in the main grammar will doubtless
* Any future additional uses of INTO in the main grammar will doubtless
* break this logic again ... beware!
* break this logic again ... beware!
@ -3087,9 +3088,9 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
if (have_into)
if (have_into)
{
{
/*
/*
* Insert an appropriate number of spaces corresponding to the
* Insert an appropriate number of spaces corresponding to the INTO
* INTO text, so that locations within the redacted SQL statement
* text, so that locations within the redacted SQL statement still
* still line up with those in the original source text.
* line up with those in the original source text.
*/
*/
plpgsql_append_source_text(&ds, location, into_start_loc);
plpgsql_append_source_text(&ds, location, into_start_loc);
appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
@ -3137,8 +3138,8 @@ read_fetch_direction(void)
bool check_FROM = true;
bool check_FROM = true;
/*
/*
* We create the PLpgSQL_stmt_fetch struct here, but only fill in
* We create the PLpgSQL_stmt_fetch struct here, but only fill in the
* the fields arising from the optional direction clause
* fields arising from the optional direction clause
*/
*/
fetch = (PLpgSQL_stmt_fetch *) palloc0(sizeof(PLpgSQL_stmt_fetch));
fetch = (PLpgSQL_stmt_fetch *) palloc0(sizeof(PLpgSQL_stmt_fetch));
fetch->cmd_type = PLPGSQL_STMT_FETCH;
fetch->cmd_type = PLPGSQL_STMT_FETCH;
@ -3223,12 +3224,12 @@ read_fetch_direction(void)
else
else
{
{
/*
/*
* Assume it's a count expression with no preceding keyword.
* Assume it's a count expression with no preceding keyword. Note: we
* Note: we allow this syntax because core SQL does, but it's
* allow this syntax because core SQL does, but it's ambiguous with
* ambiguous with the case of an omitted direction clause; for
* the case of an omitted direction clause; for instance, "MOVE n IN
* instance, "MOVE n IN c" will fail if n is a variable, because the
* c" will fail if n is a variable, because the preceding else-arm
* preceding else-arm will trigger. Perhaps this can be improved
* will trigger. Perhaps this can be improved someday, but it hardly
* someday, but it hardly s eems worth a lot of work.
* seems worth a lot of work.
*/
*/
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
fetch->expr = read_sql_expression2(K_FROM, K_IN,
fetch->expr = read_sql_expression2(K_FROM, K_IN,
@ -3357,8 +3358,8 @@ make_return_stmt(int location)
/*
/*
* Not (just) a variable name, so treat as expression.
* Not (just) a variable name, so treat as expression.
*
*
* Note that a well-formed expression is _required_ here;
* Note that a well-formed expression is _required_ here; anything
* anything else is a compile-time error.
* else is a compile-time error.
*/
*/
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
new->expr = read_sql_expression(';', ";");
new->expr = read_sql_expression(';', ";");
@ -3420,8 +3421,8 @@ make_return_next_stmt(int location)
/*
/*
* Not (just) a variable name, so treat as expression.
* Not (just) a variable name, so treat as expression.
*
*
* Note that a well-formed expression is _required_ here;
* Note that a well-formed expression is _required_ here; anything
* anything else is a compile-time error.
* else is a compile-time error.
*/
*/
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
new->expr = read_sql_expression(';', ";");
new->expr = read_sql_expression(';', ";");
@ -3540,11 +3541,11 @@ read_into_target(PLpgSQL_variable **target, bool *strict)
}
}
/*
/*
* Currently, a row or record variable can be the single INTO target,
* Currently, a row or record variable can be the single INTO target, but
* but not a member of a multi-target list. So we throw error if there
* not a member of a multi-target list. So we throw error if there is a
* is a comma after it, because that probably means the user tried to
* comma after it, because that probably means the user tried to write a
* write a multi-target list. If this ever gets generalized, we should
* multi-target list. If this ever gets generalized, we should probably
* probably refactor read_into_scalar_list so it handles all cases.
* refactor read_into_scalar_list so it handles all cases.
*/
*/
switch (tok)
switch (tok)
{
{
@ -3630,8 +3631,8 @@ read_into_scalar_list(char *initial_name,
}
}
/*
/*
* We read an extra, non-comma token from yylex(), so push it
* We read an extra, non-comma token from yylex(), so push it back onto
* back onto the input stream
* the input stream
*/
*/
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
@ -3741,14 +3742,14 @@ plpgsql_sql_error_callback(void *arg)
/*
/*
* First, set up internalerrposition to point to the start of the
* First, set up internalerrposition to point to the start of the
* statement text within the function text. Note this converts
* statement text within the function text. Note this converts location
* location (a byte offset) to a character number.
* (a byte offset) to a character number.
*/
*/
parser_errposition(cbarg->location);
parser_errposition(cbarg->location);
/*
/*
* If the core parser provided an error position, transpose it.
* If the core parser provided an error position, transpose it. Note we
* Note we are dealing with 1-based character numbers at this point.
* are dealing with 1-based character numbers at this point.
*/
*/
errpos = geterrposition();
errpos = geterrposition();
if (errpos > 0)
if (errpos > 0)
@ -4121,9 +4122,9 @@ make_case(int location, PLpgSQL_expr *t_expr,
/*
/*
* When test expression is present, we create a var for it and then
* When test expression is present, we create a var for it and then
* convert all the WHEN expressions to "VAR IN (original_expression)".
* convert all the WHEN expressions to "VAR IN (original_expression)".
* This is a bit klugy, but okay since we haven't yet done more than
* This is a bit klugy, but okay since we haven't yet done more than read
* read the expressions as text. (Note that previous parsing won't
* the expressions as text. (Note that previous parsing won't have
* have complained if the WHEN ... THEN expression contained multiple
* complained if the WHEN ... THEN expression contained multiple
* comma-separated values.)
* comma-separated values.)
*/
*/
if (t_expr)
if (t_expr)