Hi, The other infrastructure patch that has been mark ready for commit then commented further upon by Tom is $subject, even if the function provided as been renamed to pg_execute_sql_file().
Please find attached the newer version that fixes Tom concerns, removing the VARIADIC forms of the functions (those placeholders idea). The git tree already contains a fixed extension code, but the next patch for that one will have to wait some more (psql refactoring). Regards, -- Dimitri Fontaine http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support
*** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** *** 14449,14466 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); </row> <row> <entry> ! <literal><function>pg_read_file(<parameter>filename</> <type>text</>, <parameter>offset</> <type>bigint</>, <parameter>length</> <type>bigint</>)</function></literal> </entry> <entry><type>text</type></entry> <entry>Return the contents of a text file</entry> </row> <row> <entry> <literal><function>pg_stat_file(<parameter>filename</> <type>text</>)</function></literal> </entry> <entry><type>record</type></entry> <entry>Return information about a file</entry> </row> </tbody> </tgroup> </table> --- 14449,14488 ---- </row> <row> <entry> ! <literal><function>pg_read_file(<parameter>filename</> <type>text</>, <parameter>offset</> <type>bigint</> [, <parameter>length</> <type>bigint</>])</function></literal> </entry> <entry><type>text</type></entry> <entry>Return the contents of a text file</entry> </row> <row> <entry> + <literal><function>pg_read_binary_file(<parameter>filename</> <type>text</>, <parameter>offset</> <type>bigint</> [, <parameter>length</> <type>bigint</>])</function></literal> + </entry> + <entry><type>bytea</type></entry> + <entry>Return the contents of a file</entry> + </row> + <row> + <entry> <literal><function>pg_stat_file(<parameter>filename</> <type>text</>)</function></literal> </entry> <entry><type>record</type></entry> <entry>Return information about a file</entry> </row> + <row> + <entry> + <literal><function>pg_execute_sql_string(<parameter>sql</> <type>text</>) )</function></literal> + </entry> + <entry><type>void</type></entry> + <entry>Execute the given string as <acronym>SQL</> commands.</entry> + </row> + <row> + <entry> + <literal><function>pg_execute_sql_file(<parameter>filename</> <type>text</> [, <parameter>encoding</parameter> <type>name</type>]) )</function></literal> + </entry> + <entry><type>void</type></entry> + <entry>Execute contents of the given file as <acronym>SQL</> commands, + expected in either database encoding or given encoding.</entry> + </row> </tbody> </tgroup> </table> *************** *** 14482,14487 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); --- 14504,14533 ---- at the given <parameter>offset</>, returning at most <parameter>length</> bytes (less if the end of file is reached first). If <parameter>offset</> is negative, it is relative to the end of the file. + When the parameter <parameter>length</> is omitted, + <function>pg_read_file</> reads until the end of the file. + The part of a file must be a valid text in the server encoding. + </para> + + <indexterm> + <primary>pg_read_binary_file</primary> + </indexterm> + <para> + <function>pg_read_binary_file</> returns part of a file as like as + <function>pg_read_file</>, but the result is a bytea value. + <programlisting> + SELECT convert_from(pg_read_binary_file('postgresql.conf', -69), 'utf8'); + convert_from + ------------------------------------------------------------------------------- + #custom_variable_classes = '' # list of custom variable class names+ + + (1 row) + </programlisting> + </para> + <para> + When the parameter <parameter>length</> is + omited, <function>pg_read_binary_file</> reads until the end of the + file. </para> <indexterm> *************** *** 14499,14504 **** SELECT (pg_stat_file('filename')).modification; --- 14545,14582 ---- </programlisting> </para> + <indexterm> + <primary>pg_execute_sql_string</primary> + </indexterm> + <para> + <function>pg_execute_sql_string</> makes the server execute the given string + as <acronym>SQL</> commands. + The script may contain placeholders that will be replaced by the optional + parameters, that are pairs of variable names and values. Here's an example: + <programlisting> + SELECT pg_execute_sql_string('CREATE SCHEMA utils'); + pg_execute_sql_string + ----------------------- + + (1 row) + + SELECT oid, * from pg_namespace where nspname = 'utils'; + oid | nspname | nspowner | nspacl + -------+---------+----------+-------- + 16387 | utils | 10 | + (2 rows) + </programlisting> + </para> + + <indexterm> + <primary>pg_execute_sql_file</primary> + </indexterm> + <para> + <function>pg_execute_sql_file</> makes the server execute contents in a file + as <acronym>SQL</> commands. You can give an encoding name of the file to the + function. If omitted, the server encoding is used. + </para> + <para> The functions shown in <xref linkend="functions-advisory-locks"> manage advisory locks. For details about proper use of these functions, see *** a/src/backend/utils/adt/genfile.c --- b/src/backend/utils/adt/genfile.c *************** *** 21,31 **** --- 21,33 ---- #include <dirent.h> #include "catalog/pg_type.h" + #include "executor/spi.h" #include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "postmaster/syslogger.h" #include "storage/fd.h" + #include "utils/array.h" #include "utils/builtins.h" #include "utils/memutils.h" #include "utils/timestamp.h" *************** *** 80,104 **** convert_and_check_filename(text *arg) /* ! * Read a section of a file, returning it as text */ ! Datum ! pg_read_file(PG_FUNCTION_ARGS) { ! text *filename_t = PG_GETARG_TEXT_P(0); ! int64 seek_offset = PG_GETARG_INT64(1); ! int64 bytes_to_read = PG_GETARG_INT64(2); ! char *buf; ! size_t nbytes; ! FILE *file; ! char *filename; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to read files")))); ! filename = convert_and_check_filename(filename_t); if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) ereport(ERROR, --- 82,126 ---- /* ! * Read a section of a file, returning it as bytea ! * ! * Will read all the file if given a nagative bytes_to_read, and a negative ! * offset is applied from the end of the file (SEEK_END) */ ! static bytea * ! read_binary_file(const char *filename, int64 offset, int64 bytes_to_read) { ! FILE *file; ! bytea *buf; ! int64 nbytes; + /* Only superuser can read files. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to read files")))); ! if (bytes_to_read >= 0) ! nbytes = bytes_to_read; ! else if (offset < 0) ! nbytes = -offset; ! else ! { ! struct stat fst; ! ! if (stat(filename, &fst) < 0) ! ereport(ERROR, ! (errcode_for_file_access(), ! errmsg("could not stat file \"%s\": %m", filename))); ! ! nbytes = fst.st_size; ! } ! ! /* not sure why anyone thought that int64 length was a good idea */ ! if (nbytes > (MaxAllocSize - VARHDRSZ)) ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("requested length too large"))); if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) ereport(ERROR, *************** *** 106,146 **** pg_read_file(PG_FUNCTION_ARGS) errmsg("could not open file \"%s\" for reading: %m", filename))); ! if (fseeko(file, (off_t) seek_offset, ! (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not seek in file \"%s\": %m", filename))); ! if (bytes_to_read < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("requested length cannot be negative"))); ! /* not sure why anyone thought that int64 length was a good idea */ ! if (bytes_to_read > (MaxAllocSize - VARHDRSZ)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("requested length too large"))); ! buf = palloc((Size) bytes_to_read + VARHDRSZ); ! nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file); ! if (ferror(file)) ereport(ERROR, ! (errcode_for_file_access(), ! errmsg("could not read file \"%s\": %m", filename))); ! ! /* Make sure the input is valid */ ! pg_verifymbstr(VARDATA(buf), nbytes, false); ! SET_VARSIZE(buf, nbytes + VARHDRSZ); ! FreeFile(file); ! pfree(filename); ! PG_RETURN_TEXT_P(buf); } /* --- 128,270 ---- errmsg("could not open file \"%s\" for reading: %m", filename))); ! if (fseeko(file, (off_t) offset, ! (offset >= 0) ? SEEK_SET : SEEK_END) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not seek in file \"%s\": %m", filename))); ! buf = (bytea *) palloc((Size) nbytes + VARHDRSZ); ! nbytes = fread(VARDATA(buf), 1, (size_t) nbytes, file); ! ! if (ferror(file)) ! ereport(ERROR, ! (errcode_for_file_access(), ! errmsg("could not read file \"%s\": %m", filename))); ! ! FreeFile(file); ! ! SET_VARSIZE(buf, nbytes + VARHDRSZ); ! ! return buf; ! } ! ! /* ! * In addition to read_binary_file, verify the contents are encoded in the ! * database encoding. ! */ ! static text * ! read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read) ! { ! bytea *content = read_binary_file(filename, seek_offset, bytes_to_read); ! ! /* Make sure the input is valid */ ! pg_verifymbstr(VARDATA(content), VARSIZE(content) - VARHDRSZ, false); ! ! /* Abuse knowledge that we're bytea and text are both varlena */ ! return (text *) content; ! } ! ! /* ! * read given file and return the content converted to given encoding ! */ ! char * ! read_text_file_with_endoding(const char *filename, const char *encoding_name) ! { ! int src_encoding; ! int dest_encoding = GetDatabaseEncoding(); ! bytea *content; ! const char *src_str; ! char *dest_str; ! int len; ! ! /* use database encoding if not given */ ! if (encoding_name == NULL) ! src_encoding = dest_encoding; ! else ! src_encoding = pg_char_to_encoding(encoding_name); ! ! if (src_encoding < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("invalid source encoding name \"%s\"", ! encoding_name))); ! ! /* superuser checks will be done in reading files */ ! content = read_binary_file(filename, 0, -1); ! ! /* make sure that source string is valid */ ! len = VARSIZE_ANY_EXHDR(content); ! src_str = VARDATA_ANY(content); ! pg_verify_mbstr_len(src_encoding, src_str, len, false); ! ! /* convert the encoding to the database encoding */ ! dest_str = (char *) pg_do_encoding_conversion( ! (unsigned char *) src_str, len, src_encoding, dest_encoding); ! if (dest_str != src_str) ! return dest_str; ! else ! return text_to_cstring((text *)content); ! } ! /* ! * Read a section of a file, returning its content as text ! */ ! Datum ! pg_read_file(PG_FUNCTION_ARGS) ! { ! char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0)); ! int64 seek_offset = PG_GETARG_INT64(1); ! int64 bytes_to_read = PG_GETARG_INT64(2); ! ! if (bytes_to_read < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("requested length cannot be negative"))); ! ! PG_RETURN_TEXT_P(read_text_file(filename, seek_offset, bytes_to_read)); ! } ! ! /* ! * Read till the end of a file, returning its content as text ! */ ! Datum ! pg_read_whole_file(PG_FUNCTION_ARGS) ! { ! char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0)); ! int64 seek_offset = PG_GETARG_INT64(1); ! PG_RETURN_TEXT_P(read_text_file(filename, seek_offset, -1)); ! } ! /* ! * Read a section of a file, returning its content as bytea ! */ ! Datum ! pg_read_binary_file(PG_FUNCTION_ARGS) ! { ! char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0)); ! int64 seek_offset = PG_GETARG_INT64(1); ! int64 bytes_to_read = PG_GETARG_INT64(2); ! if (bytes_to_read < 0) ereport(ERROR, ! (errcode(ERRCODE_INVALID_PARAMETER_VALUE), ! errmsg("requested length cannot be negative"))); ! PG_RETURN_BYTEA_P(read_binary_file(filename, seek_offset, bytes_to_read)); ! } ! /* ! * Read till the end of a file, returning its content as bytea ! */ ! Datum ! pg_read_whole_binary_file(PG_FUNCTION_ARGS) ! { ! char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0)); ! int64 seek_offset = PG_GETARG_INT64(1); ! PG_RETURN_BYTEA_P(read_binary_file(filename, seek_offset, -1)); } /* *************** *** 149,155 **** pg_read_file(PG_FUNCTION_ARGS) Datum pg_stat_file(PG_FUNCTION_ARGS) { ! text *filename_t = PG_GETARG_TEXT_P(0); char *filename; struct stat fst; Datum values[6]; --- 273,279 ---- Datum pg_stat_file(PG_FUNCTION_ARGS) { ! text *filename_t = PG_GETARG_TEXT_PP(0); char *filename; struct stat fst; Datum values[6]; *************** *** 234,240 **** pg_ls_dir(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); fctx = palloc(sizeof(directory_fctx)); ! fctx->location = convert_and_check_filename(PG_GETARG_TEXT_P(0)); fctx->dirdesc = AllocateDir(fctx->location); --- 358,364 ---- oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); fctx = palloc(sizeof(directory_fctx)); ! fctx->location = convert_and_check_filename(PG_GETARG_TEXT_PP(0)); fctx->dirdesc = AllocateDir(fctx->location); *************** *** 264,266 **** pg_ls_dir(PG_FUNCTION_ARGS) --- 388,466 ---- SRF_RETURN_DONE(funcctx); } + + /* + * Execute given SQL string. + */ + void + execute_sql_string(const char *filename, const char *sql) + { + /* + * We abuse some internal knowledge from spi.h here. As we don't know + * which queries are going to get executed, we don't know what to expect + * as an OK return code from SPI_execute(). We assume that + * SPI_OK_CONNECT, SPI_OK_FINISH and SPI_OK_FETCH are quite improbable, + * though, and the errors are negatives. So a valid return code is + * considered to be SPI_OK_UTILITY or anything from there. + */ + if (SPI_connect() != SPI_OK_CONNECT) + elog(ERROR, "SPI_connect failed"); + + if (SPI_execute(sql, false, 0) < SPI_OK_UTILITY) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + (filename != NULL + ? errmsg("could not execute sql file: '%s'", filename) + : errmsg("could not execute sql string")))); + + if (SPI_finish() != SPI_OK_FINISH) + elog(ERROR, "SPI_finish failed"); + } + + /* + * Execute given SQL file's content in given encoding + */ + void + execute_sql_file(const char *filename, const char *encoding_name) + { + execute_sql_string(filename, + read_text_file_with_endoding(filename, encoding_name)); + } + + /* + * Execute SQL string. + */ + Datum + pg_execute_sql_string(PG_FUNCTION_ARGS) + { + text *sql = PG_GETARG_TEXT_PP(0); + + execute_sql_string(NULL, text_to_cstring(sql)); + PG_RETURN_VOID(); + } + + /* + * Read a file, and execute the contents as SQL commands. + */ + Datum + pg_execute_sql_file(PG_FUNCTION_ARGS) + { + char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + execute_sql_file(filename, NULL); + PG_RETURN_VOID(); + } + + /* + * In addition to pg_execute_sql_file, convert the encoding of the contents + * to the database encoding. + */ + Datum + pg_convert_and_execute_sql_file(PG_FUNCTION_ARGS) + { + char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *encoding_name = NameStr(*PG_GETARG_NAME(1)); + + execute_sql_file(filename, encoding_name); + PG_RETURN_VOID(); + } *** a/src/backend/utils/adt/varlena.c --- b/src/backend/utils/adt/varlena.c *************** *** 24,29 **** --- 24,30 ---- #include "miscadmin.h" #include "parser/scansup.h" #include "regex/regex.h" + #include "utils/array.h" #include "utils/builtins.h" #include "utils/bytea.h" #include "utils/lsyscache.h" *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 3399,3412 **** DESCR("reload configuration files"); DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ )); DESCR("rotate log file"); ! DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ pg_stat_file _null_ _null_ _null_ )); DESCR("return file information"); ! DATA(insert OID = 2624 ( pg_read_file PGNSP PGUID 12 1 0 0 f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ )); DESCR("read text from a file"); ! DATA(insert OID = 2625 ( pg_ls_dir PGNSP PGUID 12 1 1000 0 f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ )); DESCR("list all files in a directory"); ! DATA(insert OID = 2626 ( pg_sleep PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ )); DESCR("sleep for the specified time in seconds"); DATA(insert OID = 2971 ( text PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "16" _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ )); DESCR("convert boolean to text"); --- 3399,3424 ---- DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ )); DESCR("rotate log file"); ! DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ pg_stat_file _null_ _null_ _null_ )); DESCR("return file information"); ! DATA(insert OID = 2624 ( pg_read_file PGNSP PGUID 12 1 0 0 f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ )); DESCR("read text from a file"); ! DATA(insert OID = 3935 ( pg_read_file PGNSP PGUID 12 1 0 0 f f f t f v 2 0 25 "25 20" _null_ _null_ _null_ _null_ pg_read_whole_file _null_ _null_ _null_ )); ! DESCR("read text from a file"); ! DATA(insert OID = 2625 ( pg_ls_dir PGNSP PGUID 12 1 1000 0 f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ )); DESCR("list all files in a directory"); ! DATA(insert OID = 2626 ( pg_sleep PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ )); DESCR("sleep for the specified time in seconds"); + DATA(insert OID = 3930 ( pg_read_binary_file PGNSP PGUID 12 1 0 0 f f f t f v 3 0 17 "25 20 20" _null_ _null_ _null_ _null_ pg_read_binary_file _null_ _null_ _null_ )); + DESCR("read bytea from a file"); + DATA(insert OID = 3936 ( pg_read_binary_file PGNSP PGUID 12 1 0 0 f f f t f v 2 0 17 "25 20" _null_ _null_ _null_ _null_ pg_read_whole_binary_file _null_ _null_ _null_ )); + DESCR("read bytea from a file"); + DATA(insert OID = 3932 ( pg_execute_sql_string PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "25" _null_ _null_ _null_ _null_ pg_execute_sql_string _null_ _null_ _null_ )); + DESCR("execute queries read from a string"); + DATA(insert OID = 3927 ( pg_execute_sql_file PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "25" _null_ _null_ _null_ _null_ pg_execute_sql_file _null_ _null_ _null_ )); + DESCR("execute queries read from a file"); + DATA(insert OID = 3934 ( pg_execute_sql_file PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "25 19" _null_ _null_ _null_ _null_ pg_convert_and_execute_sql_file _null_ _null_ _null_ )); + DESCR("execute queries read from a file"); DATA(insert OID = 2971 ( text PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "16" _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ )); DESCR("convert boolean to text"); *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** *** 442,448 **** extern Datum pg_relation_filepath(PG_FUNCTION_ARGS); --- 442,455 ---- /* genfile.c */ extern Datum pg_stat_file(PG_FUNCTION_ARGS); extern Datum pg_read_file(PG_FUNCTION_ARGS); + extern Datum pg_read_whole_file(PG_FUNCTION_ARGS); + extern Datum pg_read_binary_file(PG_FUNCTION_ARGS); + extern Datum pg_read_whole_binary_file(PG_FUNCTION_ARGS); extern Datum pg_ls_dir(PG_FUNCTION_ARGS); + extern Datum replace_placeholders(PG_FUNCTION_ARGS); + extern Datum pg_execute_sql_string(PG_FUNCTION_ARGS); + extern Datum pg_execute_sql_file(PG_FUNCTION_ARGS); + extern Datum pg_convert_and_execute_sql_file(PG_FUNCTION_ARGS); /* misc.c */ extern Datum current_database(PG_FUNCTION_ARGS); *** /dev/null --- b/src/include/utils/genfile.h *************** *** 0 **** --- 1,28 ---- + /*-------------------------------------------------------------------- + * genfile.h + * + * External declarations pertaining to backend/utils/misc/genfile.c + * + * Copyright (c) 2000-2010, PostgreSQL Global Development Group + * + * src/include/utils/genfile.h + *-------------------------------------------------------------------- + */ + #ifndef GENFILE_H + #define GENFILE_H + + #include <dirent.h> + #include "utils/array.h" + + typedef struct + { + char *location; + DIR *dirdesc; + } directory_fctx; + + char *read_text_file_with_endoding(const char *filename, + const char *encoding_name); + void execute_sql_string(const char *filename, const char *sql); + void execute_sql_file(const char *filename, const char *encoding_name); + + #endif /* GENFILE_H */ *** a/src/test/regress/expected/strings.out --- b/src/test/regress/expected/strings.out *************** *** 1603,1605 **** SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 --- 1603,1616 ---- Th\000o\x02\x03 (1 row) + -- + -- test execute + -- + SELECT pg_execute_sql_string($do$ DO $$BEGIN RAISE INFO 'foo'; END;$$ $do$); + INFO: foo + CONTEXT: SQL statement " DO $$BEGIN RAISE INFO 'foo'; END;$$ " + pg_execute_sql_string + ----------------------- + + (1 row) + *** a/src/test/regress/sql/strings.sql --- b/src/test/regress/sql/strings.sql *************** *** 552,554 **** SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea); --- 552,559 ---- SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape'); SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape'); SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape'); + + -- + -- test execute + -- + SELECT pg_execute_sql_string($do$ DO $$BEGIN RAISE INFO 'foo'; END;$$ $do$);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers