summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc-xc/src/sgml/lobj.sgmlin10
-rw-r--r--doc-xc/src/sgml/ref/#create_user_mapping.sgmlin#132
-rw-r--r--doc-xc/src/sgml/ref/alter_large_object.sgmlin12
-rw-r--r--doc-xc/src/sgml/ref/create_user_mapping.sgmlin2
-rw-r--r--src/backend/libpq/be-fsstubs.c105
-rw-r--r--src/test/regress/output/largeobject_3.source264
6 files changed, 516 insertions, 9 deletions
diff --git a/doc-xc/src/sgml/lobj.sgmlin b/doc-xc/src/sgml/lobj.sgmlin
index b22d9ef2c0..bef3495c09 100644
--- a/doc-xc/src/sgml/lobj.sgmlin
+++ b/doc-xc/src/sgml/lobj.sgmlin
@@ -12,13 +12,9 @@
-->
&xconly;
<para>
- Current implementation of large object is based
- upon <literal>OID</>. Because <productname>Postgres-XC</>
- (<productname>XC</> in short) inherits all this background and OID
- is kept consisitent only locally in each datanode and
- coordinators, <productname>XC</> does not provide consisitent
- means to handle the large object. This may be improved in the
- future releases.
+ Large objects are not supported by <productname>Postgres-XC</>.
+ <productname>Postgres-XC</> does not provide consistent means
+ to handle the large object as OID is inconsistent among cluster nodes.
</para>
<!## end>
diff --git a/doc-xc/src/sgml/ref/#create_user_mapping.sgmlin# b/doc-xc/src/sgml/ref/#create_user_mapping.sgmlin#
new file mode 100644
index 0000000000..9b9d9a983a
--- /dev/null
+++ b/doc-xc/src/sgml/ref/#create_user_mapping.sgmlin#
@@ -0,0 +1,132 @@
+<!--
+doc/src/sgml/ref/create_user_mapping.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-CREATEUSERMAPPING">
+ <refmeta>
+ <refentrytitle>CREATE USER MAPPING</refentrytitle>
+ <manvolnum>7</manvolnum>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>CREATE USER MAPPING</refname>
+ <refpurpose>define a new mapping of a user to a foreign server</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-createusermapping">
+ <primary>CREATE USER MAPPING</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+CREATE USER MAPPING FOR { <replaceable class="parameter">user_name</replaceable> | USER | CURRENT_USER | PUBLIC }
+ SERVER <replaceable class="parameter">server_name</replaceable>
+ [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [ , ... ] ) ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+<!## XC>
+&xconly;
+ <para>
+ <command>USER MAPPING</> has not been supported
+ by <productname>Postgres-XC</> yet. This command may be supported
+ in the future releases.
+ </para>
+<!## end>
+<!## PG>
+&pgonly;
+
+ <para>
+ <command>CREATE USER MAPPING</command> defines a mapping of a user
+ to a foreign server. A user mapping typically encapsulates
+ connection information that a foreign-data wrapper uses together
+ with the information encapsulated be a foreign server to access an
+ external data resource.
+ </para>
+
+ <para>
+ The owner of a foreign server can create user mappings for that
+ server for any user. Also, a user can create a user mapping for
+ his own user name if <literal>USAGE</> privilege on the server has
+ been granted to the user.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">user_name</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing user that is mapped to foreign server.
+ <literal>CURRENT_USER</> and <literal>USER</> match the name of
+ the current user. When <literal>PUBLIC</> is specified, a
+ so-called public mapping is created that is used when no
+ user-specific mapping is applicable.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">server_name</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing server for which the user mapping is
+ to be created.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ This clause specifies the options of the user mapping. The
+ options typically define the actual user name and password of
+ the mapping. Option names must be unique. The allowed option
+ names and values are specific to the server's foreign-data wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Create a user mapping for user <literal>bob</>, server <literal>foo</>:
+<programlisting>
+CREATE USER MAPPING FOR bob SERVER foo OPTIONS (user 'bob', password 'secret');
+</programlisting>
+ </para>
+
+<!## end>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>CREATE USER MAPPING</command> conforms to ISO/IEC 9075-9 (SQL/MED).
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-alterusermapping"></member>
+ <member><xref linkend="sql-dropusermapping"></member>
+ <member><xref linkend="sql-createforeigndatawrapper"></member>
+ <member><xref linkend="sql-createserver"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
diff --git a/doc-xc/src/sgml/ref/alter_large_object.sgmlin b/doc-xc/src/sgml/ref/alter_large_object.sgmlin
index c5ad69d347..fce746b6d4 100644
--- a/doc-xc/src/sgml/ref/alter_large_object.sgmlin
+++ b/doc-xc/src/sgml/ref/alter_large_object.sgmlin
@@ -27,7 +27,15 @@ ALTER LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable>
<refsect1>
<title>Description</title>
-
+<!## XC>
+&xconly;
+ <para>
+ <command>LARGE OBJECT</> has not been supported
+ by <productname>Postgres-XC</> yet. This command may be supported
+ in the future releases.
+ </para>
+<!## end>
+<!## PG>
&pgnotice;
<para>
@@ -60,6 +68,8 @@ ALTER LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable>
</listitem>
</varlistentry>
</variablelist>
+
+<!## end>
</refsect1>
<refsect1>
diff --git a/doc-xc/src/sgml/ref/create_user_mapping.sgmlin b/doc-xc/src/sgml/ref/create_user_mapping.sgmlin
index 1f804e3578..9b9d9a983a 100644
--- a/doc-xc/src/sgml/ref/create_user_mapping.sgmlin
+++ b/doc-xc/src/sgml/ref/create_user_mapping.sgmlin
@@ -37,7 +37,7 @@ CREATE USER MAPPING FOR { <replaceable class="parameter">user_name</replaceable>
in the future releases.
</para>
<!## end>
-<!## XC>
+<!## PG>
&pgonly;
<para>
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index 155385f0b9..070e1451e8 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -101,6 +101,13 @@ lo_open(PG_FUNCTION_ARGS)
LargeObjectDesc *lobjDesc;
int fd;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
#if FSDB
elog(DEBUG4, "lo_open(%u,%d)", lobjId, mode);
#endif
@@ -127,6 +134,13 @@ lo_close(PG_FUNCTION_ARGS)
{
int32 fd = PG_GETARG_INT32(0);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -157,6 +171,13 @@ lo_read(int fd, char *buf, int len)
{
int status;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -183,6 +204,13 @@ lo_write(int fd, const char *buf, int len)
{
int status;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -219,6 +247,13 @@ lo_lseek(PG_FUNCTION_ARGS)
int32 whence = PG_GETARG_INT32(2);
int status;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -234,6 +269,13 @@ lo_creat(PG_FUNCTION_ARGS)
{
Oid lobjId;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
/*
* We don't actually need to store into fscxt, but create it anyway to
* ensure that AtEOXact_LargeObject knows there is state to clean up
@@ -250,6 +292,13 @@ lo_create(PG_FUNCTION_ARGS)
{
Oid lobjId = PG_GETARG_OID(0);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
/*
* We don't actually need to store into fscxt, but create it anyway to
* ensure that AtEOXact_LargeObject knows there is state to clean up
@@ -266,6 +315,13 @@ lo_tell(PG_FUNCTION_ARGS)
{
int32 fd = PG_GETARG_INT32(0);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -279,6 +335,13 @@ lo_unlink(PG_FUNCTION_ARGS)
{
Oid lobjId = PG_GETARG_OID(0);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
/* Must be owner of the largeobject */
if (!lo_compat_privileges &&
!pg_largeobject_ownercheck(lobjId, GetUserId()))
@@ -322,6 +385,13 @@ loread(PG_FUNCTION_ARGS)
bytea *retval;
int totalread;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (len < 0)
len = 0;
@@ -340,6 +410,13 @@ lowrite(PG_FUNCTION_ARGS)
int bytestowrite;
int totalwritten;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
bytestowrite = VARSIZE(wbuf) - VARHDRSZ;
totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
PG_RETURN_INT32(totalwritten);
@@ -358,6 +435,13 @@ lo_import(PG_FUNCTION_ARGS)
{
text *filename = PG_GETARG_TEXT_PP(0);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
PG_RETURN_OID(lo_import_internal(filename, InvalidOid));
}
@@ -371,6 +455,13 @@ lo_import_with_oid(PG_FUNCTION_ARGS)
text *filename = PG_GETARG_TEXT_PP(0);
Oid oid = PG_GETARG_OID(1);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
PG_RETURN_OID(lo_import_internal(filename, oid));
}
@@ -451,6 +542,13 @@ lo_export(PG_FUNCTION_ARGS)
LargeObjectDesc *lobj;
mode_t oumask;
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
#ifndef ALLOW_DANGEROUS_LO_FUNCTIONS
if (!superuser())
ereport(ERROR,
@@ -513,6 +611,13 @@ lo_truncate(PG_FUNCTION_ARGS)
int32 fd = PG_GETARG_INT32(0);
int32 len = PG_GETARG_INT32(1);
+#ifdef PGXC
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support large object yet"),
+ errdetail("The feature is not currently supported")));
+#endif
+
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/test/regress/output/largeobject_3.source b/src/test/regress/output/largeobject_3.source
new file mode 100644
index 0000000000..5c350f37a4
--- /dev/null
+++ b/src/test/regress/output/largeobject_3.source
@@ -0,0 +1,264 @@
+--
+-- Test large object support
+--
+-- ensure consistent test output regardless of the default bytea format
+SET bytea_output TO escape;
+-- Load a file
+CREATE TABLE lotest_stash_values (loid oid, junk integer, fd integer);
+-- lo_creat(mode integer) returns oid
+-- The mode arg to lo_creat is unused, some vestigal holdover from ancient times
+-- returns the large object id
+INSERT INTO lotest_stash_values (loid) VALUES( lo_creat(42) );
+ERROR: Postgres-XC does not support large object yet
+DETAIL: The feature is not currently supported
+-- NOTE: large objects require transactions
+BEGIN;
+-- lo_open(lobjId oid, mode integer) returns integer
+-- The mode parameter to lo_open uses two constants:
+-- INV_READ = 0x20000
+-- INV_WRITE = 0x40000
+-- The return value is a file descriptor-like value which remains valid for the
+-- transaction.
+UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer));
+-- loread/lowrite names are wonky, different from other functions which are lo_*
+-- lowrite(fd integer, data bytea) returns integer
+-- the integer is the number of bytes written
+SELECT lowrite(fd, '
+Whose woods these are I think I know,
+His house is in the village though.
+He will not see me stopping here,
+To watch his woods fill up with snow.
+
+My little horse must think it queer,
+To stop without a farmhouse near,
+Between the woods and frozen lake,
+The darkest evening of the year.
+
+He gives his harness bells a shake,
+To ask if there is some mistake.
+The only other sound''s the sweep,
+Of easy wind and downy flake.
+
+The woods are lovely, dark and deep,
+But I have promises to keep,
+And miles to go before I sleep,
+And miles to go before I sleep.
+
+ -- Robert Frost
+') FROM lotest_stash_values;
+ lowrite
+---------
+(0 rows)
+
+-- lo_close(fd integer) returns integer
+-- return value is 0 for success, or <0 for error (actually only -1, but...)
+SELECT lo_close(fd) FROM lotest_stash_values;
+ lo_close
+----------
+(0 rows)
+
+END;
+-- Read out a portion
+BEGIN;
+UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
+-- lo_lseek(fd integer, offset integer, whence integer) returns integer
+-- offset is in bytes, whence is one of three values:
+-- SEEK_SET (= 0) meaning relative to beginning
+-- SEEK_CUR (= 1) meaning relative to current position
+-- SEEK_END (= 2) meaning relative to end (offset better be negative)
+-- returns current position in file
+SELECT lo_lseek(fd, 422, 0) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+-- loread/lowrite names are wonky, different from other functions which are lo_*
+-- loread(fd integer, len integer) returns bytea
+SELECT loread(fd, 35) FROM lotest_stash_values;
+ loread
+--------
+(0 rows)
+
+SELECT lo_lseek(fd, -19, 1) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+SELECT lowrite(fd, 'n') FROM lotest_stash_values;
+ lowrite
+---------
+(0 rows)
+
+SELECT lo_tell(fd) FROM lotest_stash_values;
+ lo_tell
+---------
+(0 rows)
+
+SELECT lo_lseek(fd, -156, 2) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+SELECT loread(fd, 35) FROM lotest_stash_values;
+ loread
+--------
+(0 rows)
+
+SELECT lo_close(fd) FROM lotest_stash_values;
+ lo_close
+----------
+(0 rows)
+
+END;
+-- Test resource management
+BEGIN;
+SELECT lo_open(loid, x'40000'::int) from lotest_stash_values;
+ lo_open
+---------
+(0 rows)
+
+ABORT;
+-- Test truncation.
+BEGIN;
+UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
+SELECT lo_truncate(fd, 10) FROM lotest_stash_values;
+ lo_truncate
+-------------
+(0 rows)
+
+SELECT loread(fd, 15) FROM lotest_stash_values;
+ loread
+--------
+(0 rows)
+
+SELECT lo_truncate(fd, 10000) FROM lotest_stash_values;
+ lo_truncate
+-------------
+(0 rows)
+
+SELECT loread(fd, 10) FROM lotest_stash_values;
+ loread
+--------
+(0 rows)
+
+SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+SELECT lo_tell(fd) FROM lotest_stash_values;
+ lo_tell
+---------
+(0 rows)
+
+SELECT lo_truncate(fd, 5000) FROM lotest_stash_values;
+ lo_truncate
+-------------
+(0 rows)
+
+SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+SELECT lo_tell(fd) FROM lotest_stash_values;
+ lo_tell
+---------
+(0 rows)
+
+SELECT lo_close(fd) FROM lotest_stash_values;
+ lo_close
+----------
+(0 rows)
+
+END;
+-- lo_unlink(lobjId oid) returns integer
+-- return value appears to always be 1
+SELECT lo_unlink(loid) from lotest_stash_values;
+ lo_unlink
+-----------
+(0 rows)
+
+TRUNCATE lotest_stash_values;
+INSERT INTO lotest_stash_values (loid) VALUES( lo_import('@abs_srcdir@/data/tenk.data') );
+ERROR: Postgres-XC does not support large object yet
+DETAIL: The feature is not currently supported
+BEGIN;
+UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
+-- with the default BLKSZ, LOBLKSZ = 2048, so this positions us for a block
+-- edge case
+SELECT lo_lseek(fd, 2030, 0) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+-- this should get half of the value from page 0 and half from page 1 of the
+-- large object
+SELECT loread(fd, 36) FROM lotest_stash_values;
+ loread
+--------
+(0 rows)
+
+SELECT lo_tell(fd) FROM lotest_stash_values;
+ lo_tell
+---------
+(0 rows)
+
+SELECT lo_lseek(fd, -26, 1) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+SELECT lowrite(fd, 'abcdefghijklmnop') FROM lotest_stash_values;
+ lowrite
+---------
+(0 rows)
+
+SELECT lo_lseek(fd, 2030, 0) FROM lotest_stash_values;
+ lo_lseek
+----------
+(0 rows)
+
+SELECT loread(fd, 36) FROM lotest_stash_values;
+ loread
+--------
+(0 rows)
+
+SELECT lo_close(fd) FROM lotest_stash_values;
+ lo_close
+----------
+(0 rows)
+
+END;
+SELECT lo_export(loid, '@abs_builddir@/results/lotest.txt') FROM lotest_stash_values;
+ lo_export
+-----------
+(0 rows)
+
+\lo_import '@abs_builddir@/results/lotest.txt'
+ERROR: Postgres-XC does not support large object yet
+DETAIL: The feature is not currently supported
+\set newloid :LASTOID
+-- just make sure \lo_export does not barf
+\lo_export :newloid '@abs_builddir@/results/lotest2.txt'
+ERROR: Postgres-XC does not support large object yet
+DETAIL: The feature is not currently supported
+-- This is a hack to test that export/import are reversible
+-- This uses knowledge about the inner workings of large object mechanism
+-- which should not be used outside it. This makes it a HACK
+SELECT pageno, data FROM pg_largeobject WHERE loid = (SELECT loid from lotest_stash_values)
+EXCEPT
+SELECT pageno, data FROM pg_largeobject WHERE loid = :newloid;
+ pageno | data
+--------+------
+(0 rows)
+
+SELECT lo_unlink(loid) FROM lotest_stash_values;
+ lo_unlink
+-----------
+(0 rows)
+
+\lo_unlink :newloid
+ERROR: Postgres-XC does not support large object yet
+DETAIL: The feature is not currently supported
+TRUNCATE lotest_stash_values;