<phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
- ADD [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ NULL | NOT NULL ]
+ ADD [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable class="PARAMETER">collation</replaceable> ] [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
DROP [ COLUMN ] [ IF EXISTS ] <replaceable class="PARAMETER">column_name</replaceable> [ RESTRICT | CASCADE ]
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable>
+ ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> SET DEFAULT <replaceable class="PARAMETER">expression</replaceable>
+ ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> DROP DEFAULT
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> { SET | DROP } NOT NULL
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> SET ( <replaceable class="PARAMETER">attribute_option</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] )
<para>
This form adds a new column to the foreign table, using the same syntax as
<xref linkend="SQL-CREATEFOREIGNTABLE">.
+ Unlike the case when adding a column to a regular table, nothing happens
+ to the underlying storage: this action simply declares that
+ some new column is now accessible through the foreign table.
</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>SET</literal>/<literal>DROP DEFAULT</literal></term>
+ <listitem>
+ <para>
+ These forms set or remove the default value for a column.
+ Default values only apply in subsequent <command>INSERT</command>
+ or <command>UPDATE</> commands; they do not cause rows already in the
+ table to change.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>SET</literal>/<literal>DROP NOT NULL</literal></term>
<listitem>
<refsynopsisdiv>
<synopsis>
CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> ( [
- { <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ] [ NULL | NOT NULL ] }
+ <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ] [ COLLATE <replaceable>collation</replaceable> ] [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
[, ... ]
] )
SERVER <replaceable class="parameter">server_name</replaceable>
[ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ]
+<phrase>where <replaceable class="PARAMETER">column_constraint</replaceable> is:</phrase>
+
+[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
+{ NOT NULL |
+ NULL |
+ DEFAULT <replaceable>default_expr</replaceable> }
</synopsis>
</refsynopsisdiv>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>DEFAULT
+ <replaceable>default_expr</replaceable></literal></term>
+ <listitem>
+ <para>
+ The <literal>DEFAULT</> clause assigns a default data value for
+ the column whose column definition it appears within. The value
+ is any variable-free expression (subqueries and cross-references
+ to other columns in the current table are not allowed). The
+ data type of the default expression must match the data type of the
+ column.
+ </para>
+
+ <para>
+ The default expression will be used in any insert operation that
+ does not specify a value for the column. If there is no default
+ for a column, then the default is null.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><replaceable class="PARAMETER">server_name</replaceable></term>
<listitem>
<acronym>SQL</acronym> standard; however, much as with
<link linkend="sql-createtable"><command>CREATE TABLE</></link>,
<literal>NULL</> constraints and zero-column foreign tables are permitted.
+ The ability to specify a default value is also a <productname>PostgreSQL</>
+ extension.
</para>
</refsect1>
if (stmt->constraints != NIL && relkind == RELKIND_FOREIGN_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("constraints on foreign tables are not supported")));
+ errmsg("constraints are not supported on foreign tables")));
/*
* Look up the namespace in which we are supposed to create the relation,
{
RawColumnDefault *rawEnt;
- if (relkind == RELKIND_FOREIGN_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("default values on foreign tables are not supported")));
-
Assert(colDef->cooked_default == NULL);
rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
* substitutes default values into INSERTs before it expands
* rules.
*/
- ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW);
+ ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
/* No command-specific prep needed */
pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
{
RawColumnDefault *rawEnt;
- if (relkind == RELKIND_FOREIGN_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("default values on foreign tables are not supported")));
-
rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
rawEnt->attnum = attribute.attnum;
rawEnt->raw_default = copyObject(colDef->raw_default);
%type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
OptTypedTableElementList TypedTableElementList
- OptForeignTableElementList ForeignTableElementList
reloptions opt_reloptions
OptWith opt_distinct opt_definition func_args func_args_list
func_args_with_defaults func_args_with_defaults_list
%type <vsetstmt> set_rest set_rest_more SetResetClause FunctionSetResetClause
%type <node> TableElement TypedTableElement ConstraintElem TableFuncElement
- ForeignTableElement
%type <node> columnDef columnOptions
%type <defelt> def_elem reloption_elem old_aggr_elem
%type <node> def_arg columnElem where_clause where_or_current_clause
CreateForeignTableStmt:
CREATE FOREIGN TABLE qualified_name
- OptForeignTableElementList
+ '(' OptTableElementList ')'
SERVER name create_generic_options
{
CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
$4->relpersistence = RELPERSISTENCE_PERMANENT;
n->base.relation = $4;
- n->base.tableElts = $5;
+ n->base.tableElts = $6;
n->base.inhRelations = NIL;
n->base.if_not_exists = false;
/* FDW-specific data */
- n->servername = $7;
- n->options = $8;
+ n->servername = $9;
+ n->options = $10;
$$ = (Node *) n;
}
| CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name
- OptForeignTableElementList
+ '(' OptTableElementList ')'
SERVER name create_generic_options
{
CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
$7->relpersistence = RELPERSISTENCE_PERMANENT;
n->base.relation = $7;
- n->base.tableElts = $8;
+ n->base.tableElts = $9;
n->base.inhRelations = NIL;
n->base.if_not_exists = true;
/* FDW-specific data */
- n->servername = $10;
- n->options = $11;
+ n->servername = $12;
+ n->options = $13;
$$ = (Node *) n;
}
;
-OptForeignTableElementList:
- '(' ForeignTableElementList ')' { $$ = $2; }
- | '(' ')' { $$ = NIL; }
- ;
-
-ForeignTableElementList:
- ForeignTableElement
- {
- $$ = list_make1($1);
- }
- | ForeignTableElementList ',' ForeignTableElement
- {
- $$ = lappend($1, $3);
- }
- ;
-
-ForeignTableElement:
- columnDef { $$ = $1; }
- ;
-
/*****************************************************************************
*
* QUERY:
RangeVar *relation; /* relation to create */
Relation rel; /* opened/locked rel, if ALTER */
List *inhRelations; /* relations to inherit from */
+ bool isforeign; /* true if CREATE/ALTER FOREIGN TABLE */
bool isalter; /* true if altering existing table */
bool hasoids; /* does relation have an OID column? */
List *columns; /* ColumnDef items */
cxt.pstate = pstate;
if (IsA(stmt, CreateForeignTableStmt))
+ {
cxt.stmtType = "CREATE FOREIGN TABLE";
+ cxt.isforeign = true;
+ }
else
+ {
cxt.stmtType = "CREATE TABLE";
+ cxt.isforeign = false;
+ }
cxt.relation = stmt->relation;
cxt.rel = NULL;
cxt.inhRelations = stmt->inhRelations;
break;
case CONSTR_CHECK:
+ if (cxt->isforeign)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("constraints are not supported on foreign tables"),
+ parser_errposition(cxt->pstate,
+ constraint->location)));
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
break;
case CONSTR_PRIMARY:
case CONSTR_UNIQUE:
+ if (cxt->isforeign)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("constraints are not supported on foreign tables"),
+ parser_errposition(cxt->pstate,
+ constraint->location)));
if (constraint->keys == NIL)
constraint->keys = list_make1(makeString(column->colname));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
break;
case CONSTR_FOREIGN:
-
+ if (cxt->isforeign)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("constraints are not supported on foreign tables"),
+ parser_errposition(cxt->pstate,
+ constraint->location)));
/*
* Fill in the current attribute's name and throw it into the
* list of FK constraints to be processed later.
}
/*
- * Generate ALTER FOREIGN TABLE ALTER COLUMN statement which adds
- * per-column foreign data wrapper options for this column.
+ * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
+ * per-column foreign data wrapper options to this column after creation.
*/
if (column->fdwoptions != NIL)
{
static void
transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
{
+ if (cxt->isforeign)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("constraints are not supported on foreign tables"),
+ parser_errposition(cxt->pstate,
+ constraint->location)));
+
switch (constraint->contype)
{
case CONSTR_PRIMARY:
char *comment;
ParseCallbackState pcbstate;
- setup_parser_errposition_callback(&pcbstate, cxt->pstate, table_like_clause->relation->location);
+ setup_parser_errposition_callback(&pcbstate, cxt->pstate,
+ table_like_clause->relation->location);
+
+ /* we could support LIKE in many cases, but worry about it another day */
+ if (cxt->isforeign)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("LIKE is not supported for foreign tables")));
relation = relation_openrv(table_like_clause->relation, AccessShareLock);
pstate->p_sourcetext = queryString;
cxt.pstate = pstate;
- cxt.stmtType = "ALTER TABLE";
+ if (stmt->relkind == OBJECT_FOREIGN_TABLE)
+ {
+ cxt.stmtType = "ALTER FOREIGN TABLE";
+ cxt.isforeign = true;
+ }
+ else
+ {
+ cxt.stmtType = "ALTER TABLE";
+ cxt.isforeign = false;
+ }
cxt.relation = stmt->relation;
cxt.rel = rel;
cxt.inhRelations = NIL;
^
CREATE FOREIGN TABLE ft1 () SERVER no_server; -- ERROR
ERROR: server "no_server" does not exist
-CREATE FOREIGN TABLE ft1 (c1 serial) SERVER sc; -- ERROR
-ERROR: default values on foreign tables are not supported
CREATE FOREIGN TABLE ft1 () SERVER s0 WITH OIDS; -- ERROR
ERROR: syntax error at or near "WITH OIDS"
LINE 1: CREATE FOREIGN TABLE ft1 () SERVER s0 WITH OIDS;
COMMENT ON COLUMN ft1.c1 IS 'foreign column';
COMMENT ON COLUMN ft1.c1 IS NULL;
ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer;
-ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0; -- ERROR
-ERROR: default values on foreign tables are not supported
+ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0;
ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
-ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; -- ERROR
-ERROR: "ft1" is not a table or view
-ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; -- ERROR
-ERROR: "ft1" is not a table or view
+ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0;
+ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c6 SET NOT NULL;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) USING '0'; -- ERROR
c1 | integer | not null | ("param 1" 'val1') | plain | 10000 |
c2 | text | | (param2 'val2', param3 'val3') | extended | |
c3 | date | | | plain | |
- c4 | integer | | | plain | |
+ c4 | integer | default 0 | | plain | |
+ c5 | integer | | | plain | |
c6 | integer | not null | | plain | |
c7 | integer | | (p1 'v1', p2 'v2') | plain | |
c8 | text | | (p2 'V2') | extended | |
ERROR: cannot alter foreign table "ft1" because column "use_ft1_column_type.x" uses its row type
DROP TABLE use_ft1_column_type;
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- ERROR
-ERROR: "ft1" is not a table
+ERROR: constraints are not supported on foreign tables
+LINE 1: ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c...
+ ^
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR
ERROR: "ft1" is not a table
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT IF EXISTS no_const;
foreign_column_1 | integer | not null | ("param 1" 'val1')
c2 | text | | (param2 'val2', param3 'val3')
c3 | date | |
- c4 | integer | |
+ c4 | integer | default 0 |
+ c5 | integer | |
c6 | integer | not null |
c7 | integer | | (p1 'v1', p2 'v2')
c8 | text | | (p2 'V2')
CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
CREATE FOREIGN TABLE ft1 (); -- ERROR
CREATE FOREIGN TABLE ft1 () SERVER no_server; -- ERROR
-CREATE FOREIGN TABLE ft1 (c1 serial) SERVER sc; -- ERROR
CREATE FOREIGN TABLE ft1 () SERVER s0 WITH OIDS; -- ERROR
CREATE FOREIGN TABLE ft1 (
c1 integer OPTIONS ("param 1" 'val1') NOT NULL,
COMMENT ON COLUMN ft1.c1 IS NULL;
ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer;
-ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0; -- ERROR
+ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0;
ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
-ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; -- ERROR
-ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; -- ERROR
+ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0;
+ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c6 SET NOT NULL;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) USING '0'; -- ERROR