@ -51,7 +51,6 @@
typedef struct
typedef struct
{
{
int location;
int location;
int leaderlen;
} sql_error_callback_arg;
} sql_error_callback_arg;
#define parser_errposition(pos) plpgsql_scanner_errposition(pos)
#define parser_errposition(pos) plpgsql_scanner_errposition(pos)
@ -67,7 +66,7 @@ static PLpgSQL_expr *read_sql_construct(int until,
int until2,
int until2,
int until3,
int until3,
const char *expected,
const char *expected,
const char *sqlstart ,
RawParseMode parsemode ,
bool isexpression,
bool isexpression,
bool valid_sql,
bool valid_sql,
bool trim,
bool trim,
@ -78,7 +77,7 @@ static PLpgSQL_expr *read_sql_expression(int until,
static PLpgSQL_expr *read_sql_expression2(int until, int until2,
static PLpgSQL_expr *read_sql_expression2(int until, int until2,
const char *expected,
const char *expected,
int *endtoken);
int *endtoken);
static PLpgSQL_expr *read_sql_stmt(const char *sqlstart );
static PLpgSQL_expr *read_sql_stmt(void );
static PLpgSQL_type *read_datatype(int tok);
static PLpgSQL_type *read_datatype(int tok);
static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location);
static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location);
static PLpgSQL_stmt_fetch *read_fetch_direction(void);
static PLpgSQL_stmt_fetch *read_fetch_direction(void);
@ -99,8 +98,8 @@ static PLpgSQL_row *read_into_scalar_list(char *initial_name,
static PLpgSQL_row *make_scalar_list1(char *initial_name,
static PLpgSQL_row *make_scalar_list1(char *initial_name,
PLpgSQL_datum *initial_datum,
PLpgSQL_datum *initial_datum,
int lineno, int location);
int lineno, int location);
static void check_sql_expr(const char *stmt, int location,
static void check_sql_expr(const char *stmt,
int leaderle n);
RawParseMode parseMode, int locatio n);
static void plpgsql_sql_error_callback(void *arg);
static void plpgsql_sql_error_callback(void *arg);
static PLpgSQL_type *parse_datatype(const char *string, int location);
static PLpgSQL_type *parse_datatype(const char *string, int location);
static void check_labels(const char *start_label,
static void check_labels(const char *start_label,
@ -540,7 +539,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
{
{
PLpgSQL_var *new;
PLpgSQL_var *new;
PLpgSQL_expr *curname_def;
PLpgSQL_expr *curname_def;
char buf[102 4];
char buf[NAMEDATALEN * 2 + 6 4];
char *cp1;
char *cp1;
char *cp2;
char *cp2;
@ -557,9 +556,9 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
curname_def = palloc0(sizeof(PLpgSQL_expr));
curname_def = palloc0(sizeof(PLpgSQL_expr));
strcpy(buf, "SELECT ");
/* Note: refname has been truncated to NAMEDATALEN */
cp1 = new->refname;
cp1 = new->refname;
cp2 = buf + strlen(buf) ;
cp2 = buf;
/*
/*
* Don't trust standard_conforming_strings here;
* Don't trust standard_conforming_strings here;
* it might change before we use the string.
* it might change before we use the string.
@ -575,6 +574,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
}
}
strcpy(cp2, "'::pg_catalog.refcursor");
strcpy(cp2, "'::pg_catalog.refcursor");
curname_def->query = pstrdup(buf);
curname_def->query = pstrdup(buf);
curname_def->parseMode = RAW_PARSE_PLPGSQL_EXPR;
new->default_val = curname_def;
new->default_val = curname_def;
new->cursor_explicit_expr = $7;
new->cursor_explicit_expr = $7;
@ -602,7 +602,7 @@ opt_scrollable :
decl_cursor_query :
decl_cursor_query :
{
{
$$ = read_sql_stmt("" );
$$ = read_sql_stmt();
}
}
;
;
@ -904,15 +904,37 @@ proc_stmt : pl_block ';'
{ $$ = $1; }
{ $$ = $1; }
;
;
stmt_perform : K_PERFORM expr_until_semi
stmt_perform : K_PERFORM
{
{
PLpgSQL_stmt_perform *new;
PLpgSQL_stmt_perform *new;
int startloc;
new = palloc0(sizeof(PLpgSQL_stmt_perform));
new = palloc0(sizeof(PLpgSQL_stmt_perform));
new->cmd_type = PLPGSQL_STMT_PERFORM;
new->cmd_type = PLPGSQL_STMT_PERFORM;
new->lineno = plpgsql_location_to_lineno(@1);
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->expr = $2;
plpgsql_push_back_token(K_PERFORM);
/*
* Since PERFORM isn't legal SQL, we have to cheat to
* the extent of substituting "SELECT" for "PERFORM"
* in the parsed text. It does not seem worth
* inventing a separate parse mode for this one case.
* We can't do syntax-checking until after we make the
* substitution.
*/
new->expr = read_sql_construct(';', 0, 0, ";",
RAW_PARSE_DEFAULT,
false, false, true,
&startloc, NULL);
/* overwrite "perform" ... */
memcpy(new->expr->query, " SELECT", 7);
/* left-justify to get rid of the leading space */
memmove(new->expr->query, new->expr->query + 1,
strlen(new->expr->query));
/* offset syntax error position to account for that */
check_sql_expr(new->expr->query, new->expr->parseMode,
startloc + 1);
$$ = (PLpgSQL_stmt *)new;
$$ = (PLpgSQL_stmt *)new;
}
}
@ -926,7 +948,8 @@ stmt_call : K_CALL
new->cmd_type = PLPGSQL_STMT_CALL;
new->cmd_type = PLPGSQL_STMT_CALL;
new->lineno = plpgsql_location_to_lineno(@1);
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->expr = read_sql_stmt("CALL ");
plpgsql_push_back_token(K_CALL);
new->expr = read_sql_stmt();
new->is_call = true;
new->is_call = true;
$$ = (PLpgSQL_stmt *)new;
$$ = (PLpgSQL_stmt *)new;
@ -941,7 +964,8 @@ stmt_call : K_CALL
new->cmd_type = PLPGSQL_STMT_CALL;
new->cmd_type = PLPGSQL_STMT_CALL;
new->lineno = plpgsql_location_to_lineno(@1);
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->expr = read_sql_stmt("DO ");
plpgsql_push_back_token(K_DO);
new->expr = read_sql_stmt();
new->is_call = false;
new->is_call = false;
$$ = (PLpgSQL_stmt *)new;
$$ = (PLpgSQL_stmt *)new;
@ -949,16 +973,40 @@ stmt_call : K_CALL
}
}
;
;
stmt_assign : assign_var assign_operator expr_until_semi
stmt_assign : T_DATUM
{
{
PLpgSQL_stmt_assign *new;
PLpgSQL_stmt_assign *new;
RawParseMode pmode;
/* see how many names identify the datum */
switch ($1.ident ? 1 : list_length($1.idents))
{
case 1:
pmode = RAW_PARSE_PLPGSQL_ASSIGN1;
break;
case 2:
pmode = RAW_PARSE_PLPGSQL_ASSIGN2;
break;
case 3:
pmode = RAW_PARSE_PLPGSQL_ASSIGN3;
break;
default:
elog(ERROR, "unexpected number of names");
pmode = 0; /* keep compiler quiet */
}
check_assignable($1.datum, @1);
new = palloc0(sizeof(PLpgSQL_stmt_assign));
new = palloc0(sizeof(PLpgSQL_stmt_assign));
new->cmd_type = PLPGSQL_STMT_ASSIGN;
new->cmd_type = PLPGSQL_STMT_ASSIGN;
new->lineno = plpgsql_location_to_lineno(@1);
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->varno = $1->dno;
new->varno = $1.datum->dno;
new->expr = $3;
/* Push back the head name to include it in the stmt */
plpgsql_push_back_token(T_DATUM);
new->expr = read_sql_construct(';', 0, 0, ";",
pmode,
false, true, true,
NULL, NULL);
$$ = (PLpgSQL_stmt *)new;
$$ = (PLpgSQL_stmt *)new;
}
}
@ -1452,16 +1500,16 @@ for_control : for_variable K_IN
/*
/*
* Read tokens until we see either a ".."
* Read tokens until we see either a ".."
* or a LOOP. The text we read may not
* or a LOOP. The text we read may be either
* necessarily be a well-formed SQL
* an expression or a whole SQL statement, so
* statement, so we need to invoke
* we need to invoke read_sql_construct directly,
* read_sql_construct directly .
* and tell it not to check syntax yet .
*/
*/
expr1 = read_sql_construct(DOT_DOT,
expr1 = read_sql_construct(DOT_DOT,
K_LOOP,
K_LOOP,
0,
0,
"LOOP",
"LOOP",
"SELECT " ,
RAW_PARSE_DEFAULT ,
true,
true,
false,
false,
true,
true,
@ -1476,8 +1524,13 @@ for_control : for_variable K_IN
PLpgSQL_var *fvar;
PLpgSQL_var *fvar;
PLpgSQL_stmt_fori *new;
PLpgSQL_stmt_fori *new;
/* Check first expression is well-formed */
/*
check_sql_expr(expr1->query, expr1loc, 7);
* Relabel first expression as an expression;
* then we can check its syntax.
*/
expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR;
check_sql_expr(expr1->query, expr1->parseMode,
expr1loc);
/* Read and check the second one */
/* Read and check the second one */
expr2 = read_sql_expression2(K_LOOP, K_BY,
expr2 = read_sql_expression2(K_LOOP, K_BY,
@ -1522,12 +1575,8 @@ for_control : for_variable K_IN
else
else
{
{
/*
/*
* No "..", so it must be a query loop. We've
* No "..", so it must be a query loop.
* prefixed an extra SELECT to the query text,
* so we need to remove that before performing
* syntax checking.
*/
*/
char *tmp_query;
PLpgSQL_stmt_fors *new;
PLpgSQL_stmt_fors *new;
if (reverse)
if (reverse)
@ -1536,12 +1585,9 @@ for_control : for_variable K_IN
errmsg("cannot specify REVERSE in query FOR loop"),
errmsg("cannot specify REVERSE in query FOR loop"),
parser_errposition(tokloc)));
parser_errposition(tokloc)));
Assert(strncmp(expr1->query, "SELECT ", 7) == 0);
/* Check syntax as a regular query */
tmp_query = pstrdup(expr1->query + 7);
check_sql_expr(expr1->query, expr1->parseMode,
pfree(expr1->query);
expr1loc);
expr1->query = tmp_query;
check_sql_expr(expr1->query, expr1loc, 0);
new = palloc0(sizeof(PLpgSQL_stmt_fors));
new = palloc0(sizeof(PLpgSQL_stmt_fors));
new->cmd_type = PLPGSQL_STMT_FORS;
new->cmd_type = PLPGSQL_STMT_FORS;
@ -1870,7 +1916,7 @@ stmt_raise : K_RAISE
expr = read_sql_construct(',', ';', K_USING,
expr = read_sql_construct(',', ';', K_USING,
", or ; or USING",
", or ; or USING",
"SELECT " ,
RAW_PARSE_PLPGSQL_EXPR ,
true, true, true,
true, true, true,
NULL, &tok);
NULL, &tok);
new->params = lappend(new->params, expr);
new->params = lappend(new->params, expr);
@ -1958,7 +2004,7 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
* variable. (The composite case is probably a syntax error, but we'll let
* variable. (The composite case is probably a syntax error, but we'll let
* the core parser decide that.) Normally, we should assume that such a
* the core parser decide that.) Normally, we should assume that such a
* word is a SQL statement keyword that isn't also a plpgsql keyword.
* word is a SQL statement keyword that isn't also a plpgsql keyword.
* However, if the next token is assignment or '[', it can't be a valid
* However, if the next token is assignment or '[' or '.' , it can't be a valid
* SQL statement, and what we're probably looking at is an intended variable
* SQL statement, and what we're probably looking at is an intended variable
* assignment. Give an appropriate complaint for that, instead of letting
* assignment. Give an appropriate complaint for that, instead of letting
* the core parser throw an unhelpful "syntax error".
* the core parser throw an unhelpful "syntax error".
@ -1977,7 +2023,8 @@ stmt_execsql : K_IMPORT
tok = yylex();
tok = yylex();
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
if (tok == '=' || tok == COLON_EQUALS || tok == '[')
if (tok == '=' || tok == COLON_EQUALS ||
tok == '[' || tok == '.')
word_is_not_variable(&($1), @1);
word_is_not_variable(&($1), @1);
$$ = make_execsql_stmt(T_WORD, @1);
$$ = make_execsql_stmt(T_WORD, @1);
}
}
@ -1987,7 +2034,8 @@ stmt_execsql : K_IMPORT
tok = yylex();
tok = yylex();
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
if (tok == '=' || tok == COLON_EQUALS || tok == '[')
if (tok == '=' || tok == COLON_EQUALS ||
tok == '[' || tok == '.')
cword_is_not_variable(&($1), @1);
cword_is_not_variable(&($1), @1);
$$ = make_execsql_stmt(T_CWORD, @1);
$$ = make_execsql_stmt(T_CWORD, @1);
}
}
@ -2001,7 +2049,7 @@ stmt_dynexecute : K_EXECUTE
expr = read_sql_construct(K_INTO, K_USING, ';',
expr = read_sql_construct(K_INTO, K_USING, ';',
"INTO or USING or ;",
"INTO or USING or ;",
"SELECT " ,
RAW_PARSE_PLPGSQL_EXPR ,
true, true, true,
true, true, true,
NULL, &endtoken);
NULL, &endtoken);
@ -2040,7 +2088,7 @@ stmt_dynexecute : K_EXECUTE
{
{
expr = read_sql_construct(',', ';', K_INTO,
expr = read_sql_construct(',', ';', K_INTO,
", or ; or INTO",
", or ; or INTO",
"SELECT " ,
RAW_PARSE_PLPGSQL_EXPR ,
true, true, true,
true, true, true,
NULL, &endtoken);
NULL, &endtoken);
new->params = lappend(new->params, expr);
new->params = lappend(new->params, expr);
@ -2122,7 +2170,7 @@ stmt_open : K_OPEN cursor_variable
else
else
{
{
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
new->query = read_sql_stmt("" );
new->query = read_sql_stmt();
}
}
}
}
else
else
@ -2246,8 +2294,8 @@ stmt_set : K_SET
new->cmd_type = PLPGSQL_STMT_SET;
new->cmd_type = PLPGSQL_STMT_SET;
new->lineno = plpgsql_location_to_lineno(@1);
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->stmtid = ++plpgsql_curr_compile->nstatements;
plpgsql_push_back_token(K_SET);
new->expr = read_sql_stmt("SET " );
new->expr = read_sql_stmt();
$$ = (PLpgSQL_stmt *)new;
$$ = (PLpgSQL_stmt *)new;
}
}
@ -2259,7 +2307,8 @@ stmt_set : K_SET
new->cmd_type = PLPGSQL_STMT_SET;
new->cmd_type = PLPGSQL_STMT_SET;
new->lineno = plpgsql_location_to_lineno(@1);
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->expr = read_sql_stmt("RESET ");
plpgsql_push_back_token(K_RESET);
new->expr = read_sql_stmt();
$$ = (PLpgSQL_stmt *)new;
$$ = (PLpgSQL_stmt *)new;
}
}
@ -2656,7 +2705,8 @@ static PLpgSQL_expr *
read_sql_expression(int until, const char *expected)
read_sql_expression(int until, const char *expected)
{
{
return read_sql_construct(until, 0, 0, expected,
return read_sql_construct(until, 0, 0, expected,
"SELECT ", true, true, true, NULL, NULL);
RAW_PARSE_PLPGSQL_EXPR,
true, true, true, NULL, NULL);
}
}
/* Convenience routine to read an expression with two possible terminators */
/* Convenience routine to read an expression with two possible terminators */
@ -2665,15 +2715,17 @@ read_sql_expression2(int until, int until2, const char *expected,
int *endtoken)
int *endtoken)
{
{
return read_sql_construct(until, until2, 0, expected,
return read_sql_construct(until, until2, 0, expected,
"SELECT ", true, true, true, NULL, endtoken);
RAW_PARSE_PLPGSQL_EXPR,
true, true, true, NULL, endtoken);
}
}
/* Convenience routine to read a SQL statement that must end with ';' */
/* Convenience routine to read a SQL statement that must end with ';' */
static PLpgSQL_expr *
static PLpgSQL_expr *
read_sql_stmt(const char *sqlstart )
read_sql_stmt(void )
{
{
return read_sql_construct(';', 0, 0, ";",
return read_sql_construct(';', 0, 0, ";",
sqlstart, false, true, true, NULL, NULL);
RAW_PARSE_DEFAULT,
false, true, true, NULL, NULL);
}
}
/*
/*
@ -2683,9 +2735,9 @@ read_sql_stmt(const char *sqlstart)
* until2: token code for alternate terminator (pass 0 if none)
* until2: token code for alternate terminator (pass 0 if none)
* until3: token code for another alternate terminator (pass 0 if none)
* until3: token code for another alternate terminator (pass 0 if none)
* expected: text to use in complaining that terminator was not found
* expected: text to use in complaining that terminator was not found
* sqlstart: text to prefix to the accumulated SQL text
* parsemode: raw_parser() mode to use
* isexpression: whether to say we're reading an "expression" or a "statement"
* isexpression: whether to say we're reading an "expression" or a "statement"
* valid_sql: whether to check the syntax of the expr (prefixed with sqlstart)
* valid_sql: whether to check the syntax of the expr
* trim: trim trailing whitespace
* trim: trim trailing whitespace
* startloc: if not NULL, location of first token is stored at *startloc
* startloc: if not NULL, location of first token is stored at *startloc
* endtoken: if not NULL, ending token is stored at *endtoken
* endtoken: if not NULL, ending token is stored at *endtoken
@ -2696,7 +2748,7 @@ read_sql_construct(int until,
int until2,
int until2,
int until3,
int until3,
const char *expected,
const char *expected,
const char *sqlstart ,
RawParseMode parsemode ,
bool isexpression,
bool isexpression,
bool valid_sql,
bool valid_sql,
bool trim,
bool trim,
@ -2711,7 +2763,6 @@ read_sql_construct(int until,
PLpgSQL_expr *expr;
PLpgSQL_expr *expr;
initStringInfo(&ds);
initStringInfo(&ds);
appendStringInfoString(&ds, sqlstart);
/* special lookup mode for identifiers within the SQL text */
/* special lookup mode for identifiers within the SQL text */
save_IdentifierLookup = plpgsql_IdentifierLookup;
save_IdentifierLookup = plpgsql_IdentifierLookup;
@ -2787,6 +2838,7 @@ read_sql_construct(int until,
expr = palloc0(sizeof(PLpgSQL_expr));
expr = palloc0(sizeof(PLpgSQL_expr));
expr->query = pstrdup(ds.data);
expr->query = pstrdup(ds.data);
expr->parseMode = parsemode;
expr->plan = NULL;
expr->plan = NULL;
expr->paramnos = NULL;
expr->paramnos = NULL;
expr->rwparam = -1;
expr->rwparam = -1;
@ -2794,7 +2846,7 @@ read_sql_construct(int until,
pfree(ds.data);
pfree(ds.data);
if (valid_sql)
if (valid_sql)
check_sql_expr(expr->query, startlocation, strlen(sqlstart) );
check_sql_expr(expr->query, expr->parseMode, startlocation);
return expr;
return expr;
}
}
@ -3033,13 +3085,14 @@ make_execsql_stmt(int firsttoken, int location)
expr = palloc0(sizeof(PLpgSQL_expr));
expr = palloc0(sizeof(PLpgSQL_expr));
expr->query = pstrdup(ds.data);
expr->query = pstrdup(ds.data);
expr->parseMode = RAW_PARSE_DEFAULT;
expr->plan = NULL;
expr->plan = NULL;
expr->paramnos = NULL;
expr->paramnos = NULL;
expr->rwparam = -1;
expr->rwparam = -1;
expr->ns = plpgsql_ns_top();
expr->ns = plpgsql_ns_top();
pfree(ds.data);
pfree(ds.data);
check_sql_expr(expr->query, location, 0 );
check_sql_expr(expr->query, expr->parseMode, location);
execsql = palloc(sizeof(PLpgSQL_stmt_execsql));
execsql = palloc(sizeof(PLpgSQL_stmt_execsql));
execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
@ -3382,7 +3435,7 @@ make_return_query_stmt(int location)
{
{
/* ordinary static query */
/* ordinary static query */
plpgsql_push_back_token(tok);
plpgsql_push_back_token(tok);
new->query = read_sql_stmt("" );
new->query = read_sql_stmt();
}
}
else
else
{
{
@ -3637,13 +3690,12 @@ make_scalar_list1(char *initial_name,
* borders. So it is best to bail out as early as we can.
* borders. So it is best to bail out as early as we can.
*
*
* It is assumed that "stmt" represents a copy of the function source text
* It is assumed that "stmt" represents a copy of the function source text
* beginning at offset "location", with leader text of length "leaderlen"
* beginning at offset "location". We use this assumption to transpose
* (typically "SELECT ") prefixed to the source text. We use this assumption
* any error cursor position back to the function source text.
* to transpose any error cursor position back to the function source text.
* If no error cursor is provided, we'll just point at "location".
* If no error cursor is provided, we'll just point at "location".
*/
*/
static void
static void
check_sql_expr(const char *stmt, int location, int leaderle n)
check_sql_expr(const char *stmt, RawParseMode parseMode, int location)
{
{
sql_error_callback_arg cbarg;
sql_error_callback_arg cbarg;
ErrorContextCallback syntax_errcontext;
ErrorContextCallback syntax_errcontext;
@ -3653,7 +3705,6 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
return;
return;
cbarg.location = location;
cbarg.location = location;
cbarg.leaderlen = leaderlen;
syntax_errcontext.callback = plpgsql_sql_error_callback;
syntax_errcontext.callback = plpgsql_sql_error_callback;
syntax_errcontext.arg = &cbarg;
syntax_errcontext.arg = &cbarg;
@ -3661,7 +3712,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
error_context_stack = &syntax_errcontext;
error_context_stack = &syntax_errcontext;
oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
(void) raw_parser(stmt, RAW_PARSE_DEFAULT );
(void) raw_parser(stmt, parseMode );
MemoryContextSwitchTo(oldCxt);
MemoryContextSwitchTo(oldCxt);
/* Restore former ereport callback */
/* Restore former ereport callback */
@ -3686,12 +3737,12 @@ plpgsql_sql_error_callback(void *arg)
* Note we are dealing with 1-based character numbers at this point.
* Note we are dealing with 1-based character numbers at this point.
*/
*/
errpos = geterrposition();
errpos = geterrposition();
if (errpos > cbarg->leaderlen )
if (errpos > 0 )
{
{
int myerrpos = getinternalerrposition();
int myerrpos = getinternalerrposition();
if (myerrpos > 0) /* safety check */
if (myerrpos > 0) /* safety check */
internalerrposition(myerrpos + errpos - cbarg->leaderlen - 1);
internalerrposition(myerrpos + errpos - 1);
}
}
/* In any case, flush errposition --- we want internalerrposition only */
/* In any case, flush errposition --- we want internalerrposition only */
@ -3717,7 +3768,6 @@ parse_datatype(const char *string, int location)
ErrorContextCallback syntax_errcontext;
ErrorContextCallback syntax_errcontext;
cbarg.location = location;
cbarg.location = location;
cbarg.leaderlen = 0;
syntax_errcontext.callback = plpgsql_sql_error_callback;
syntax_errcontext.callback = plpgsql_sql_error_callback;
syntax_errcontext.arg = &cbarg;
syntax_errcontext.arg = &cbarg;
@ -3780,7 +3830,6 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
int argc;
int argc;
char **argv;
char **argv;
StringInfoData ds;
StringInfoData ds;
char *sqlstart = "SELECT ";
bool any_named = false;
bool any_named = false;
tok = yylex();
tok = yylex();
@ -3881,12 +3930,12 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
*/
*/
item = read_sql_construct(',', ')', 0,
item = read_sql_construct(',', ')', 0,
",\" or \")",
",\" or \")",
sqlstart ,
RAW_PARSE_PLPGSQL_EXPR ,
true, true,
true, true,
false, /* do not trim */
false, /* do not trim */
NULL, &endtoken);
NULL, &endtoken);
argv[argpos] = item->query + strlen(sqlstart) ;
argv[argpos] = item->query;
if (endtoken == ')' && !(argc == row->nfields - 1))
if (endtoken == ')' && !(argc == row->nfields - 1))
ereport(ERROR,
ereport(ERROR,
@ -3905,7 +3954,6 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
/* Make positional argument list */
/* Make positional argument list */
initStringInfo(&ds);
initStringInfo(&ds);
appendStringInfoString(&ds, sqlstart);
for (argc = 0; argc < row->nfields; argc++)
for (argc = 0; argc < row->nfields; argc++)
{
{
Assert(argv[argc] != NULL);
Assert(argv[argc] != NULL);
@ -3921,10 +3969,10 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
if (argc < row->nfields - 1)
if (argc < row->nfields - 1)
appendStringInfoString(&ds, ", ");
appendStringInfoString(&ds, ", ");
}
}
appendStringInfoChar(&ds, ';');
expr = palloc0(sizeof(PLpgSQL_expr));
expr = palloc0(sizeof(PLpgSQL_expr));
expr->query = pstrdup(ds.data);
expr->query = pstrdup(ds.data);
expr->parseMode = RAW_PARSE_PLPGSQL_EXPR;
expr->plan = NULL;
expr->plan = NULL;
expr->paramnos = NULL;
expr->paramnos = NULL;
expr->rwparam = -1;
expr->rwparam = -1;
@ -4097,14 +4145,14 @@ make_case(int location, PLpgSQL_expr *t_expr,
PLpgSQL_expr *expr = cwt->expr;
PLpgSQL_expr *expr = cwt->expr;
StringInfoData ds;
StringInfoData ds;
/* copy expression query without SELECT keyword (expr->query + 7) */
/* We expect to have expressions not statements */
Assert(strncmp(expr->query, "SELECT ", 7) == 0 );
Assert(expr->parseMode == RAW_PARSE_PLPGSQL_EXPR );
/* And d o the string hacking */
/* D o the string hacking */
initStringInfo(&ds);
initStringInfo(&ds);
appendStringInfo(&ds, "SELECT \"%s\" IN (%s)",
appendStringInfo(&ds, "\"%s\" IN (%s)",
varname, expr->query + 7 );
varname, expr->query);
pfree(expr->query);
pfree(expr->query);
expr->query = pstrdup(ds.data);
expr->query = pstrdup(ds.data);