variables-escape.diff
application/octet-stream
Filename: variables-escape.diff
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| ./command.c | 54 | 29 |
| ./mainloop.c | 16 | 3 |
| ./psqlscan.h | 2 | 0 |
| ./psqlscan.l | 188 | 0 |
*** ./command.c.orig 2010-01-02 17:57:59.000000000 +0100
--- ./command.c 2010-01-22 13:14:28.325976489 +0100
***************
*** 938,944 ****
{
char *opt0 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
!
if (!opt0)
{
/* list all variables */
--- 938,944 ----
{
char *opt0 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
!
if (!opt0)
{
/* list all variables */
***************
*** 947,984 ****
}
else
{
! /*
! * Set variable to the concatenation of the arguments.
! */
! char *newval;
! char *opt;
!
! opt = psql_scan_slash_option(scan_state,
! OT_NORMAL, NULL, false);
! newval = pg_strdup(opt ? opt : "");
! free(opt);
!
! while ((opt = psql_scan_slash_option(scan_state,
! OT_NORMAL, NULL, false)))
{
! newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
! if (!newval)
{
! psql_error("out of memory\n");
! exit(EXIT_FAILURE);
}
- strcat(newval, opt);
- free(opt);
}
!
! if (!SetVariable(pset.vars, opt0, newval))
! {
! psql_error("\\%s: error\n", cmd);
success = false;
! }
! free(newval);
}
- free(opt0);
}
/* \t -- turn off headers and row count */
--- 947,1009 ----
}
else
{
! if (psql_scan_is_valid(scan_state))
{
! /*
! * Set variable to the concatenation of the arguments. Don't allow add variable,
! * when scanning isn't valid - these check are more strict, we protect content of
! * variables against to invalid value.
! */
! char *newval;
! char *opt;
!
! opt = psql_scan_slash_option(scan_state,
! OT_NORMAL, NULL, false);
!
! if (psql_scan_is_valid(scan_state))
! {
! newval = pg_strdup(opt ? opt : "");
! free(opt);
!
! while ((opt = psql_scan_slash_option(scan_state,
! OT_NORMAL, NULL, false)))
! {
! if (psql_scan_is_valid(scan_state))
! {
! newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
! if (!newval)
! {
! psql_error("out of memory\n");
! exit(EXIT_FAILURE);
! }
! strcat(newval, opt);
! free(opt);
! }
! else
! {
! success = false;
! free(opt);
! break;
! }
! }
!
! if (success && !SetVariable(pset.vars, opt0, newval))
! {
! psql_error("\\%s: error\n", cmd);
! success = false;
! }
! free(newval);
! }
! else
{
! success = false;
! free(opt);
}
}
! else
success = false;
! free(opt0);
}
}
/* \t -- turn off headers and row count */
***************
*** 1163,1171 ****
else
status = PSQL_CMD_UNKNOWN;
! if (!success)
status = PSQL_CMD_ERROR;
!
return status;
}
--- 1188,1196 ----
else
status = PSQL_CMD_UNKNOWN;
! if (!success || !psql_scan_is_valid(scan_state))
status = PSQL_CMD_ERROR;
!
return status;
}
*** ./mainloop.c.orig 2010-01-02 17:57:59.000000000 +0100
--- ./mainloop.c 2010-01-22 12:02:49.273610342 +0100
***************
*** 253,260 ****
line_saved_in_history = true;
}
! /* execute query */
! success = SendQuery(query_buf->data);
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
/* transfer query to previous_buf by pointer-swapping */
--- 253,270 ----
line_saved_in_history = true;
}
! /*
! * execute query
! *
! * When scanning isn't valid from out of memory
! * or broken chars reason do nothing. Error message
! * was displayed. So only don't send invalid commands
! */
! if (psql_scan_is_valid(scan_state))
! success = SendQuery(query_buf->data);
! else
! success = false;
!
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
/* transfer query to previous_buf by pointer-swapping */
***************
*** 267,273 ****
resetPQExpBuffer(query_buf);
added_nl_pos = -1;
! /* we need not do psql_scan_reset() here */
}
else if (scan_result == PSCAN_BACKSLASH)
{
--- 277,283 ----
resetPQExpBuffer(query_buf);
added_nl_pos = -1;
! psql_scan_reset(scan_state);
}
else if (scan_result == PSCAN_BACKSLASH)
{
***************
*** 342,347 ****
--- 352,360 ----
}
else if (slashCmdStatus == PSQL_CMD_TERMINATE)
break;
+ else if (slashCmdStatus != PSQL_CMD_UNKNOWN)
+ /* reset parsing state - reset flag valid */
+ psql_scan_reset(scan_state);
}
/* fall out of loop if lexer reached EOL */
*** ./psqlscan.h.orig 2010-01-02 17:57:59.000000000 +0100
--- ./psqlscan.h 2010-01-22 11:30:35.236914189 +0100
***************
*** 61,64 ****
--- 61,66 ----
extern void psql_scan_slash_command_end(PsqlScanState state);
+ extern bool psql_scan_is_valid(PsqlScanState state);
+
#endif /* PSQLSCAN_H */
*** ./psqlscan.l.orig 2010-01-02 17:57:59.000000000 +0100
--- ./psqlscan.l 2010-01-22 12:03:31.210739617 +0100
***************
*** 93,98 ****
--- 93,99 ----
int paren_depth; /* depth of nesting in parentheses */
int xcdepth; /* depth of nesting in slash-star comments */
char *dolqstart; /* current $foo$ quote start string */
+ bool valid; /* current scan is valid */
} PsqlScanStateData;
static PsqlScanState cur_state; /* current state while active */
***************
*** 119,124 ****
--- 120,128 ----
static void emit(const char *txt, int len);
static bool is_utf16_surrogate_first(uint32 c);
+ static void appendLiteral(PGconn *conn, PQExpBuffer buf, const char *str);
+ static void appendIdentifier(PGconn *conn, PQExpBuffer buf, const char *str);
+
#define ECHO emit(yytext, yyleng)
%}
***************
*** 706,711 ****
--- 710,778 ----
ECHO;
}
}
+
+ :'[A-Za-z0-9_]+' {
+ /*
+ * Possible psql variable substitution with
+ * literal escaping.
+ */
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ if (value)
+ {
+ /* It is a variable, perform substitution */
+ PQExpBufferData buf;
+
+ initPQExpBuffer(&buf);
+ appendLiteral(pset.db, &buf, value);
+ push_new_buffer(buf.data);
+ termPQExpBuffer(&buf);
+
+ /* yy_scan_string already made buffer active */
+ }
+ else
+ {
+ /*
+ * if the variable doesn't exist we'll copy the
+ * string as is
+ */
+ ECHO;
+ }
+ }
+
+ :\"[A-Za-z0-9_]+\" {
+ /*
+ * Possible psql variable substitution with
+ * identifier escaping.
+ */
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ if (value)
+ {
+ /* It is a variable, perform substitution */
+ PQExpBufferData buf;
+
+ initPQExpBuffer(&buf);
+ appendIdentifier(pset.db, &buf, value);
+ push_new_buffer(buf.data);
+ termPQExpBuffer(&buf);
+ /* yy_scan_string already made buffer active */
+ }
+ else
+ {
+ /*
+ * if the variable doesn't exist we'll copy the
+ * string as is
+ */
+ ECHO;
+ }
+ }
/*
* Back to backend-compatible rules.
***************
*** 927,932 ****
--- 994,1053 ----
return LEXRES_OK;
}
+
+ :'[A-Za-z0-9_]+' {
+ /* Possible psql variable substitution with literal escaping */
+ if (option_type == OT_VERBATIM)
+ ECHO;
+ else
+ {
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ /*
+ * The variable value is just emitted without any
+ * further examination. This is consistent with the
+ * pre-8.0 code behavior, if not with the way that
+ * variables are handled outside backslash commands.
+ */
+ if (value)
+ appendLiteral(pset.db, output_buf, value);
+ }
+
+ *option_quote = ':';
+
+ return LEXRES_OK;
+ }
+
+ :\"[A-Za-z0-9_]+\" {
+ /* Possible psql variable substitution with identifier escaping */
+ if (option_type == OT_VERBATIM)
+ ECHO;
+ else
+ {
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ /*
+ * The variable value is just emitted without any
+ * further examination. This is consistent with the
+ * pre-8.0 code behavior, if not with the way that
+ * variables are handled outside backslash commands.
+ */
+ if (value)
+ appendIdentifier(pset.db, output_buf, value);
+ }
+
+ *option_quote = ':';
+
+ return LEXRES_OK;
+ }
+
+
"|" {
ECHO;
if (option_type == OT_FILEPIPE)
***************
*** 1325,1330 ****
--- 1446,1452 ----
if (state->dolqstart)
free(state->dolqstart);
state->dolqstart = NULL;
+ state->valid = true;
}
/*
***************
*** 1341,1346 ****
--- 1463,1478 ----
}
/*
+ * Return true if lexer doesn't detect "out of memory" or
+ * bad multibyte characters problem.
+ */
+ bool
+ psql_scan_is_valid(PsqlScanState state)
+ {
+ return state->valid;
+ }
+
+ /*
* Scan the command name of a psql backslash command. This should be called
* after psql_scan() returns PSCAN_BACKSLASH. It is assumed that the input
* has been consumed through the leading backslash.
***************
*** 1740,1742 ****
--- 1872,1930 ----
{
return (c >= 0xD800 && c <= 0xDBFF);
}
+
+ /*
+ * Convert a string value to an SQL Literal and append it to
+ * the given buffer.
+ */
+ static void
+ appendLiteral(PGconn *conn, PQExpBuffer buf, const char *str)
+ {
+ char *escaped_str;
+ size_t len;
+
+ len = strlen(str);
+ escaped_str = PQescapeLiteral(conn, str, len);
+
+ if (escaped_str == NULL)
+ {
+ const char *error_message = PQerrorMessage(pset.db);
+
+ if (strlen(error_message))
+ psql_error("%s", error_message);
+ }
+ else
+ {
+ /* only valid value is appended */
+ appendPQExpBufferStr(buf, escaped_str);
+ free(escaped_str);
+ }
+ }
+
+ /*
+ * Convert a string value to an SQL identifier and append it to
+ * the given buffer.
+ */
+ static void
+ appendIdentifier(PGconn *conn, PQExpBuffer buf, const char *str)
+ {
+ char *escaped_str;
+ size_t len;
+
+ len = strlen(str);
+ escaped_str = PQescapeIdentifier(conn, str, len);
+
+ if (escaped_str == NULL)
+ {
+ const char *error_message = PQerrorMessage(pset.db);
+
+ if (strlen(error_message))
+ psql_error("%s", error_message);
+ }
+ else
+ {
+ /* only valid value is appended */
+ appendPQExpBufferStr(buf, escaped_str);
+ free(escaped_str);
+ }
+ }