Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd0cfc01

Browse files
committed
Allow psql variables to be interpolated with literal or identifier escaping.
Loosely based on a patch by Pavel Stehule.
1 parent76be0c8 commitd0cfc01

File tree

2 files changed

+123
-37
lines changed

2 files changed

+123
-37
lines changed

‎doc/src/sgml/ref/psql-ref.sgml

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.236 2009/12/24 23:36:39 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.237 2010/01/29 17:44:12 rhaas Exp $
33
PostgreSQL documentation
44
-->
55

@@ -658,7 +658,12 @@ testdb=&gt;
658658
<para>
659659
If an unquoted argument begins with a colon (<literal>:</literal>),
660660
it is taken as a <application>psql</> variable and the value of the
661-
variable is used as the argument instead.
661+
variable is used as the argument instead. If the variable name is
662+
surrounded by single quotes (e.g. <literal>:'var'</literal>), it
663+
will be escaped as an SQL literal and the result will be used as
664+
the argument. If the variable name is surrounded by double quotes,
665+
it will be escaped as an SQL identifier and the result will be used
666+
as the argument.
662667
</para>
663668

664669
<para>
@@ -2711,59 +2716,62 @@ bar
27112716
<para>
27122717
An additional useful feature of <application>psql</application>
27132718
variables is that you can substitute (<quote>interpolate</quote>)
2714-
them into regular <acronym>SQL</acronym> statements. The syntax for
2715-
this is again to prepend the variable name with a colon
2719+
them into regular <acronym>SQL</acronym> statements.
2720+
<application>psql</application> provides special facilities for
2721+
ensuring that values used as SQL literals and identifiers are
2722+
properly escaped. The syntax for interpolating a value without
2723+
any special escaping is again to prepend the variable name with a colon
27162724
(<literal>:</literal>):
27172725
<programlisting>
27182726
testdb=&gt; <userinput>\set foo 'my_table'</userinput>
27192727
testdb=&gt; <userinput>SELECT * FROM :foo;</userinput>
27202728
</programlisting>
2721-
would then query the table <literal>my_table</literal>. The value of
2722-
the variable is copied literally, so it can even contain unbalanced
2723-
quotes or backslash commands. You must make sure that it makes sense
2724-
where you put it. Variable interpolation will not be performed into
2725-
quoted <acronym>SQL</acronym> entities.
2729+
would then query the table <literal>my_table</literal>. Note that this
2730+
may be unsafe: the value of the variable is copied literally, so it can
2731+
even contain unbalanced quotes or backslash commands. You must make sure
2732+
that it makes sense where you put it.
2733+
</para>
2734+
2735+
<para>
2736+
When a value is to be used as an SQL literal or identifier, it is
2737+
safest to arrange for it to be escaped. To escape the value of
2738+
a variable as an SQL literal, write a colon followed by the variable
2739+
name in single quotes. To escape the value an SQL identifier, write
2740+
a colon followed by the variable name in double quotes. The previous
2741+
example would be more safely written this way:
2742+
<programlisting>
2743+
testdb=&gt; <userinput>\set foo 'my_table'</userinput>
2744+
testdb=&gt; <userinput>SELECT * FROM :"foo";</userinput>
2745+
</programlisting>
2746+
Variable interpolation will not be performed into quoted
2747+
<acronym>SQL</acronym> entities.
27262748
</para>
27272749

27282750
<para>
27292751
One possible use of this mechanism is to
27302752
copy the contents of a file into a table column. First load the file into a
27312753
variable and then proceed as above:
27322754
<programlisting>
2733-
testdb=&gt; <userinput>\set content '''' `cat my_file.txt` ''''</userinput>
2734-
testdb=&gt; <userinput>INSERT INTO my_table VALUES (:content);</userinput>
2735-
</programlisting>
2736-
One problem with this approach is that <filename>my_file.txt</filename>
2737-
might contain single quotes. These need to be escaped so that
2738-
they don't cause a syntax error when the second line is processed. This
2739-
could be done with the program <command>sed</command>:
2740-
<programlisting>
2741-
testdb=&gt; <userinput>\set content '''' `sed -e "s/'/''/g" &lt; my_file.txt` ''''</userinput>
2742-
</programlisting>
2743-
If you are using non-standard-conforming strings then you'll also need
2744-
to double backslashes. This is a bit tricky:
2745-
<programlisting>
2746-
testdb=&gt; <userinput>\set content '''' `sed -e "s/'/''/g" -e 's/\\/\\\\/g' &lt; my_file.txt` ''''</userinput>
2755+
testdb=&gt; <userinput>\set content `cat my_file.txt`</userinput>
2756+
testdb=&gt; <userinput>INSERT INTO my_table VALUES (:'content');</userinput>
27472757
</programlisting>
2748-
Note the use of different shell quoting conventions so that neither
2749-
the single quote marks nor the backslashes are special to the shell.
2750-
Backslashes are still special to <command>sed</command>, however, so
2751-
we need to double them. (Perhaps
2752-
at one point you thought it was great that all Unix commands use the
2753-
same escape character.)
2758+
(Note that this still won't work if my_file.txt contains NUL bytes.
2759+
psql does not support embedded NUL bytes in variable values.)
27542760
</para>
27552761

27562762
<para>
2757-
Since colons can legally appear in SQL commands,the following rule
2758-
applies: the character sequence
2759-
<quote>:name</quote> is not changed unless <quote>name</> isthe name
2760-
of a variable thatis currently set. In any case you can escape
2761-
a colon with a backslash to protect it from substitution. (The
2762-
colon syntax for variables is standard <acronym>SQL</acronym> for
2763+
Since colons can legally appear in SQL commands,an apparent attempt
2764+
at interpolation (such as <literal>:name</literal>,
2765+
<literal>:'name'</literal>, or <literal>:"name"</literal>) isnot
2766+
changed unless the named variableis currently set. In any case you
2767+
can escapea colon with a backslash to protect it from substitution.
2768+
(Thecolon syntax for variables is standard <acronym>SQL</acronym> for
27632769
embedded query languages, such as <application>ECPG</application>.
27642770
The colon syntax for array slices and type casts are
27652771
<productname>PostgreSQL</productname> extensions, hence the
2766-
conflict.)
2772+
conflict. The colon syntax for escaping a variable's value as an
2773+
SQL literal or identifier is a <application>psql</application>
2774+
extension.)
27672775
</para>
27682776

27692777
</refsect3>

‎src/bin/psql/psqlscan.l

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Portions Copyright (c) 1994, Regents of the University of California
3434
*
3535
* IDENTIFICATION
36-
* $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.31 2010/01/02 16:57:59 momjian Exp $
36+
* $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.32 2010/01/29 17:44:12 rhaas Exp $
3737
*
3838
*-------------------------------------------------------------------------
3939
*/
@@ -118,6 +118,7 @@ static YY_BUFFER_STATE prepare_buffer(const char *txt, int len,
118118
char **txtcopy);
119119
staticvoidemit(constchar *txt,int len);
120120
staticboolis_utf16_surrogate_first(uint32 c);
121+
staticvoidescape_variable(bool as_ident);
121122

122123
#defineECHOemit(yytext, yyleng)
123124

@@ -707,6 +708,14 @@ other.
707708
}
708709
}
709710

711+
:'[A-Za-z0-9_]+'{
712+
escape_variable(false);
713+
}
714+
715+
:\"[A-Za-z0-9_]+\"{
716+
escape_variable(true);
717+
}
718+
710719
/*
711720
* Back to backend-compatible rules.
712721
*/
@@ -927,6 +936,27 @@ other.
927936
return LEXRES_OK;
928937
}
929938

939+
:'[A-Za-z0-9_]+'{
940+
if (option_type == OT_VERBATIM)
941+
ECHO;
942+
else
943+
{
944+
escape_variable(false);
945+
return LEXRES_OK;
946+
}
947+
}
948+
949+
950+
:\"[A-Za-z0-9_]+\"{
951+
if (option_type == OT_VERBATIM)
952+
ECHO;
953+
else
954+
{
955+
escape_variable(true);
956+
return LEXRES_OK;
957+
}
958+
}
959+
930960
"|"{
931961
ECHO;
932962
if (option_type == OT_FILEPIPE)
@@ -1740,3 +1770,51 @@ is_utf16_surrogate_first(uint32 c)
17401770
{
17411771
return (c >=0xD800 && c <=0xDBFF);
17421772
}
1773+
1774+
staticvoid
1775+
escape_variable(bool as_ident)
1776+
{
1777+
charsaved_char;
1778+
constchar *value;
1779+
1780+
/* Variable lookup. */
1781+
saved_char = yytext[yyleng -1];
1782+
yytext[yyleng -1] ='\0';
1783+
value =GetVariable(pset.vars, yytext +2);
1784+
1785+
/* Escaping. */
1786+
if (value)
1787+
{
1788+
if (!pset.db)
1789+
psql_error("can't escape without active connection\n");
1790+
else
1791+
{
1792+
char *escaped_value;
1793+
1794+
if (as_ident)
1795+
escaped_value =
1796+
PQescapeIdentifier(pset.db, value,strlen(value));
1797+
else
1798+
escaped_value =
1799+
PQescapeLiteral(pset.db, value,strlen(value));
1800+
if (escaped_value ==NULL)
1801+
{
1802+
constchar *error =PQerrorMessage(pset.db);
1803+
psql_error("%s", error);
1804+
}
1805+
else
1806+
{
1807+
appendPQExpBufferStr(output_buf, escaped_value);
1808+
PQfreemem(escaped_value);
1809+
return;
1810+
}
1811+
}
1812+
}
1813+
1814+
/*
1815+
* If we reach this point, some kind of error has occurred. Emit the
1816+
* original text into the output buffer.
1817+
*/
1818+
yytext[yyleng -1] = saved_char;
1819+
emit(yytext, yyleng);
1820+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp