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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers