diff options
| -rw-r--r-- | doc-xc/src/sgml/lobj.sgmlin | 10 | ||||
| -rw-r--r-- | doc-xc/src/sgml/ref/#create_user_mapping.sgmlin# | 132 | ||||
| -rw-r--r-- | doc-xc/src/sgml/ref/alter_large_object.sgmlin | 12 | ||||
| -rw-r--r-- | doc-xc/src/sgml/ref/create_user_mapping.sgmlin | 2 | ||||
| -rw-r--r-- | src/backend/libpq/be-fsstubs.c | 105 | ||||
| -rw-r--r-- | src/test/regress/output/largeobject_3.source | 264 |
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; |
