Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
6b603e67
Commit
6b603e67
authored
Nov 15, 2002
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add DOMAIN check constraints.
Rod Taylor
parent
2986aa6a
Changes
29
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
641 additions
and
147 deletions
+641
-147
doc/src/sgml/ref/create_domain.sgml
doc/src/sgml/ref/create_domain.sgml
+1
-11
src/backend/catalog/heap.c
src/backend/catalog/heap.c
+7
-5
src/backend/catalog/pg_constraint.c
src/backend/catalog/pg_constraint.c
+64
-10
src/backend/commands/tablecmds.c
src/backend/commands/tablecmds.c
+10
-6
src/backend/commands/typecmds.c
src/backend/commands/typecmds.c
+169
-30
src/backend/executor/execQual.c
src/backend/executor/execQual.c
+41
-5
src/backend/nodes/copyfuncs.c
src/backend/nodes/copyfuncs.c
+31
-1
src/backend/nodes/equalfuncs.c
src/backend/nodes/equalfuncs.c
+25
-2
src/backend/nodes/outfuncs.c
src/backend/nodes/outfuncs.c
+29
-1
src/backend/nodes/readfuncs.c
src/backend/nodes/readfuncs.c
+49
-1
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/clauses.c
+12
-1
src/backend/parser/analyze.c
src/backend/parser/analyze.c
+2
-2
src/backend/parser/gram.y
src/backend/parser/gram.y
+8
-2
src/backend/parser/keywords.c
src/backend/parser/keywords.c
+2
-1
src/backend/parser/parse_clause.c
src/backend/parser/parse_clause.c
+6
-6
src/backend/parser/parse_coerce.c
src/backend/parser/parse_coerce.c
+53
-3
src/backend/parser/parse_expr.c
src/backend/parser/parse_expr.c
+34
-23
src/backend/parser/parse_node.c
src/backend/parser/parse_node.c
+3
-3
src/backend/parser/parse_target.c
src/backend/parser/parse_target.c
+2
-2
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/ruleutils.c
+7
-1
src/include/catalog/indexing.h
src/include/catalog/indexing.h
+4
-1
src/include/catalog/pg_constraint.h
src/include/catalog/pg_constraint.h
+14
-5
src/include/nodes/execnodes.h
src/include/nodes/execnodes.h
+8
-1
src/include/nodes/nodes.h
src/include/nodes/nodes.h
+3
-1
src/include/nodes/parsenodes.h
src/include/nodes/parsenodes.h
+18
-1
src/include/optimizer/var.h
src/include/optimizer/var.h
+2
-1
src/include/parser/parse_expr.h
src/include/parser/parse_expr.h
+3
-2
src/test/regress/expected/domain.out
src/test/regress/expected/domain.out
+20
-12
src/test/regress/sql/domain.sql
src/test/regress/sql/domain.sql
+14
-7
No files found.
doc/src/sgml/ref/create_domain.sgml
View file @
6b603e67
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.
6 2002/09/20 03:39:1
5 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.
7 2002/11/15 02:50:0
5 momjian Exp $
PostgreSQL documentation
-->
...
...
@@ -200,16 +200,6 @@ CREATE TABLE countrylist (id INT4, country country_code);
</para>
</refsect1>
<refsect1 id="SQL-CREATEDOMAIN-compatibility">
<title>Compatibility</title>
<para>
SQL99 defines CREATE DOMAIN, but says that the only allowed constraint
type is CHECK constraints. CHECK constraints for domains are not yet
supported by <productname>PostgreSQL</productname>.
</para>
</refsect1>
<refsect1 id="SQL-CREATEDOMAIN-see-also">
<title>See Also</title>
...
...
src/backend/catalog/heap.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.23
4 2002/11/11 22:19:21 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.23
5 2002/11/15 02:50:05 momjian
Exp $
*
*
* INTERFACE ROUTINES
...
...
@@ -1500,7 +1500,8 @@ AddRelationRawConstraints(Relation rel,
ccname
=
cdef
->
name
;
/* Check against pre-existing constraints */
if
(
ConstraintNameIsUsed
(
RelationGetRelid
(
rel
),
if
(
ConstraintNameIsUsed
(
CONSTRAINT_RELATION
,
RelationGetRelid
(
rel
),
RelationGetNamespace
(
rel
),
ccname
))
elog
(
ERROR
,
"constraint
\"
%s
\"
already exists for relation
\"
%s
\"
"
,
...
...
@@ -1534,7 +1535,8 @@ AddRelationRawConstraints(Relation rel,
* pre-existing constraints, nor with any auto-generated
* names so far.
*/
ccname
=
GenerateConstraintName
(
RelationGetRelid
(
rel
),
ccname
=
GenerateConstraintName
(
CONSTRAINT_RELATION
,
RelationGetRelid
(
rel
),
RelationGetNamespace
(
rel
),
&
constr_name_ctr
);
...
...
@@ -1565,7 +1567,7 @@ AddRelationRawConstraints(Relation rel,
/*
* Transform raw parsetree to executable expression.
*/
expr
=
transformExpr
(
pstate
,
cdef
->
raw_expr
);
expr
=
transformExpr
(
pstate
,
cdef
->
raw_expr
,
NULL
);
/*
* Make sure it yields a boolean result.
...
...
@@ -1694,7 +1696,7 @@ cookDefault(ParseState *pstate,
/*
* Transform raw parsetree to executable expression.
*/
expr
=
transformExpr
(
pstate
,
raw_default
);
expr
=
transformExpr
(
pstate
,
raw_default
,
NULL
);
/*
* Make sure default expr does not refer to any vars.
...
...
src/backend/catalog/pg_constraint.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.
7 2002/09/22 00:37:09 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.
8 2002/11/15 02:50:05 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -190,6 +190,19 @@ CreateConstraintEntry(const char *constraintName,
}
}
if
(
OidIsValid
(
domainId
))
{
/*
* Register auto dependency from constraint to owning domain
*/
ObjectAddress
domobject
;
domobject
.
classId
=
RelOid_pg_type
;
domobject
.
objectId
=
domainId
;
recordDependencyOn
(
&
conobject
,
&
domobject
,
DEPENDENCY_AUTO
);
}
if
(
OidIsValid
(
foreignRelId
))
{
/*
...
...
@@ -262,7 +275,7 @@ CreateConstraintEntry(const char *constraintName,
* this test is not very meaningful.
*/
bool
ConstraintNameIsUsed
(
Oid
relId
,
Oid
rel
Namespace
,
const
char
*
cname
)
ConstraintNameIsUsed
(
CONSTRAINTCATEGORY
conCat
,
Oid
objId
,
Oid
obj
Namespace
,
const
char
*
cname
)
{
bool
found
;
Relation
conDesc
;
...
...
@@ -280,7 +293,7 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
ScanKeyEntryInitialize
(
&
skey
[
1
],
0x0
,
Anum_pg_constraint_connamespace
,
F_OIDEQ
,
ObjectIdGetDatum
(
rel
Namespace
));
ObjectIdGetDatum
(
obj
Namespace
));
conscan
=
systable_beginscan
(
conDesc
,
ConstraintNameNspIndex
,
true
,
SnapshotNow
,
2
,
skey
);
...
...
@@ -289,7 +302,12 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
{
Form_pg_constraint
con
=
(
Form_pg_constraint
)
GETSTRUCT
(
tup
);
if
(
con
->
conrelid
==
relId
)
if
(
conCat
==
CONSTRAINT_RELATION
&&
con
->
conrelid
==
objId
)
{
found
=
true
;
break
;
}
else
if
(
conCat
==
CONSTRAINT_DOMAIN
&&
con
->
contypid
==
objId
)
{
found
=
true
;
break
;
...
...
@@ -314,7 +332,7 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
* someone else might choose the same name concurrently!
*/
char
*
GenerateConstraintName
(
Oid
relId
,
Oid
rel
Namespace
,
int
*
counter
)
GenerateConstraintName
(
CONSTRAINTCATEGORY
conCat
,
Oid
objId
,
Oid
obj
Namespace
,
int
*
counter
)
{
bool
found
;
Relation
conDesc
;
...
...
@@ -347,7 +365,7 @@ GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
ScanKeyEntryInitialize
(
&
skey
[
1
],
0x0
,
Anum_pg_constraint_connamespace
,
F_OIDEQ
,
ObjectIdGetDatum
(
rel
Namespace
));
ObjectIdGetDatum
(
obj
Namespace
));
conscan
=
systable_beginscan
(
conDesc
,
ConstraintNameNspIndex
,
true
,
SnapshotNow
,
2
,
skey
);
...
...
@@ -356,7 +374,12 @@ GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
{
Form_pg_constraint
con
=
(
Form_pg_constraint
)
GETSTRUCT
(
tup
);
if
(
con
->
conrelid
==
relId
)
if
(
conCat
==
CONSTRAINT_RELATION
&&
con
->
conrelid
==
objId
)
{
found
=
true
;
break
;
}
else
if
(
conCat
==
CONSTRAINT_DOMAIN
&&
con
->
contypid
==
objId
)
{
found
=
true
;
break
;
...
...
@@ -415,10 +438,13 @@ RemoveConstraintById(Oid conId)
con
=
(
Form_pg_constraint
)
GETSTRUCT
(
tup
);
/*
* If the constraint is for a relation, open and exclusive-lock the
* relation it's for.
* If the constraint is for a relation, open and exclusive-lock
* the relation it's for.
*
* If the constraint is for a domain, open and lock the pg_type entry
* tye constraint is used on.
*
* XXX not clear what we should lock, if anything, for
other
constraints.
* XXX not clear what we should lock, if anything, for
assert
constraints.
*/
if
(
OidIsValid
(
con
->
conrelid
))
{
...
...
@@ -463,6 +489,34 @@ RemoveConstraintById(Oid conId)
/* Keep lock on constraint's rel until end of xact */
heap_close
(
rel
,
NoLock
);
}
/* Lock the domain row in pg_type */
else
if
(
OidIsValid
(
con
->
contypid
))
{
Relation
typRel
;
HeapTuple
typTup
;
ScanKeyData
typKey
[
1
];
SysScanDesc
typScan
;
typRel
=
heap_openr
(
TypeRelationName
,
RowExclusiveLock
);
ScanKeyEntryInitialize
(
&
typKey
[
0
],
0x0
,
Anum_pg_constraint_contypid
,
F_OIDEQ
,
ObjectIdGetDatum
(
con
->
contypid
));
typScan
=
systable_beginscan
(
typRel
,
TypeOidIndex
,
true
,
SnapshotNow
,
1
,
typKey
);
typTup
=
systable_getnext
(
typScan
);
if
(
!
HeapTupleIsValid
(
typTup
))
elog
(
ERROR
,
"RemoveConstraintById: Type %d does not exist"
,
con
->
contypid
);
systable_endscan
(
typScan
);
/* Keep lock on domain type until end of xact */
heap_close
(
typRel
,
NoLock
);
}
/* Fry the constraint itself */
simple_heap_delete
(
conDesc
,
&
tup
->
t_self
);
...
...
src/backend/commands/tablecmds.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.5
3 2002/11/11 22:19:21 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.5
4 2002/11/15 02:50:05 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -2632,14 +2632,16 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
*/
if
(
constr
->
name
)
{
if
(
ConstraintNameIsUsed
(
RelationGetRelid
(
rel
),
if
(
ConstraintNameIsUsed
(
CONSTRAINT_RELATION
,
RelationGetRelid
(
rel
),
RelationGetNamespace
(
rel
),
constr
->
name
))
elog
(
ERROR
,
"constraint
\"
%s
\"
already exists for relation
\"
%s
\"
"
,
constr
->
name
,
RelationGetRelationName
(
rel
));
}
else
constr
->
name
=
GenerateConstraintName
(
RelationGetRelid
(
rel
),
constr
->
name
=
GenerateConstraintName
(
CONSTRAINT_RELATION
,
RelationGetRelid
(
rel
),
RelationGetNamespace
(
rel
),
&
counter
);
...
...
@@ -2668,7 +2670,8 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
*/
if
(
fkconstraint
->
constr_name
)
{
if
(
ConstraintNameIsUsed
(
RelationGetRelid
(
rel
),
if
(
ConstraintNameIsUsed
(
CONSTRAINT_RELATION
,
RelationGetRelid
(
rel
),
RelationGetNamespace
(
rel
),
fkconstraint
->
constr_name
))
elog
(
ERROR
,
"constraint
\"
%s
\"
already exists for relation
\"
%s
\"
"
,
...
...
@@ -2676,7 +2679,8 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
RelationGetRelationName
(
rel
));
}
else
fkconstraint
->
constr_name
=
GenerateConstraintName
(
RelationGetRelid
(
rel
),
fkconstraint
->
constr_name
=
GenerateConstraintName
(
CONSTRAINT_RELATION
,
RelationGetRelid
(
rel
),
RelationGetNamespace
(
rel
),
&
counter
);
...
...
@@ -2734,7 +2738,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
/*
* Convert the A_EXPR in raw_expr into an EXPR
*/
expr
=
transformExpr
(
pstate
,
constr
->
raw_expr
);
expr
=
transformExpr
(
pstate
,
constr
->
raw_expr
,
NULL
);
/*
* Make sure it yields a boolean result.
...
...
src/backend/commands/typecmds.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.1
6 2002/11/11 22:19:22 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.1
7 2002/11/15 02:50:06 momjian
Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
...
...
@@ -36,10 +36,17 @@
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "miscadmin.h"
#include "nodes/nodes.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
...
...
@@ -407,6 +414,7 @@ DefineDomain(CreateDomainStmt *stmt)
Oid
basetypeoid
;
Oid
domainoid
;
Form_pg_type
baseType
;
int
counter
=
0
;
/* Convert list of names to a name and namespace */
domainNamespace
=
QualifiedNameGetCreationNamespace
(
stmt
->
domainname
,
...
...
@@ -484,17 +492,21 @@ DefineDomain(CreateDomainStmt *stmt)
basetypelem
=
baseType
->
typelem
;
/*
* Run through constraints manually to avoid the additional processing
* conducted by DefineRelation() and friends.
*
* Besides, we don't want any constraints to be cooked. We'll do that
* when the table is created via MergeDomainAttributes().
* Run through constraints manually to avoid the additional
* processing conducted by DefineRelation() and friends.
*/
foreach
(
listptr
,
schema
)
{
Constraint
*
colDef
=
lfirst
(
listptr
);
Node
*
newConstraint
=
lfirst
(
listptr
);
Constraint
*
colDef
;
ParseState
*
pstate
;
/* Prior to processing, confirm that it is not a foreign key constraint */
if
(
nodeTag
(
newConstraint
)
==
T_FkConstraint
)
elog
(
ERROR
,
"CREATE DOMAIN / FOREIGN KEY constraints not supported"
);
colDef
=
(
Constraint
*
)
newConstraint
;
switch
(
colDef
->
contype
)
{
/*
...
...
@@ -556,8 +568,8 @@ DefineDomain(CreateDomainStmt *stmt)
elog
(
ERROR
,
"CREATE DOMAIN / PRIMARY KEY indexes not supported"
);
break
;
/* Check constraints are handled after domain creation */
case
CONSTR_CHECK
:
elog
(
ERROR
,
"DefineDomain: CHECK Constraints not supported"
);
break
;
case
CONSTR_ATTR_DEFERRABLE
:
...
...
@@ -598,6 +610,133 @@ DefineDomain(CreateDomainStmt *stmt)
typNDims
,
/* Array dimensions for base type */
typNotNull
);
/* Type NOT NULL */
/*
* Process constraints which refer to the domain ID returned by TypeCreate
*/
foreach
(
listptr
,
schema
)
{
Constraint
*
constr
=
lfirst
(
listptr
);
ParseState
*
pstate
;
switch
(
constr
->
contype
)
{
case
CONSTR_CHECK
:
{
Node
*
expr
;
char
*
ccsrc
;
char
*
ccbin
;
ConstraintTestValue
*
domVal
;
/*
* Assign or validate constraint name
*/
if
(
constr
->
name
)
{
if
(
ConstraintNameIsUsed
(
CONSTRAINT_DOMAIN
,
domainoid
,
domainNamespace
,
constr
->
name
))
elog
(
ERROR
,
"constraint
\"
%s
\"
already exists for domain
\"
%s
\"
"
,
constr
->
name
,
domainName
);
}
else
constr
->
name
=
GenerateConstraintName
(
CONSTRAINT_DOMAIN
,
domainoid
,
domainNamespace
,
&
counter
);
/*
* Convert the A_EXPR in raw_expr into an
* EXPR
*/
pstate
=
make_parsestate
(
NULL
);
/*
* We want to have the domain VALUE node type filled in so
* that proper casting can occur.
*/
domVal
=
makeNode
(
ConstraintTestValue
);
domVal
->
typeId
=
basetypeoid
;
domVal
->
typeMod
=
stmt
->
typename
->
typmod
;
expr
=
transformExpr
(
pstate
,
constr
->
raw_expr
,
domVal
);
/*
* Domains don't allow var clauses
*/
if
(
contain_var_clause
(
expr
))
elog
(
ERROR
,
"cannot use column references in domain CHECK clause"
);
/*
* Make sure it yields a boolean result.
*/
expr
=
coerce_to_boolean
(
expr
,
"CHECK"
);
/*
* Make sure no outside relations are
* referred to.
*/
if
(
length
(
pstate
->
p_rtable
)
!=
0
)
elog
(
ERROR
,
"Relations cannot be referenced in domain CHECK constraint"
);
/*
* No subplans or aggregates, either...
*/
if
(
contain_subplans
(
expr
))
elog
(
ERROR
,
"cannot use subselect in CHECK constraint expression"
);
if
(
contain_agg_clause
(
expr
))
elog
(
ERROR
,
"cannot use aggregate function in CHECK constraint expression"
);
/*
* Might as well try to reduce any constant expressions.
*/
expr
=
eval_const_expressions
(
expr
);
/*
* Must fix opids in operator clauses.
*/
fix_opids
(
expr
);
ccbin
=
nodeToString
(
expr
);
/*
* Deparse it. Since VARNOs aren't allowed in domain
* constraints, relation context isn't required as anything
* other than a shell.
*/
ccsrc
=
deparse_expression
(
expr
,
deparse_context_for
(
domainName
,
InvalidOid
),
false
,
false
);
/* Write the constraint */
CreateConstraintEntry
(
constr
->
name
,
/* Constraint Name */
domainNamespace
,
/* namespace */
CONSTRAINT_CHECK
,
/* Constraint Type */
false
,
/* Is Deferrable */
false
,
/* Is Deferred */
InvalidOid
,
/* not a relation constraint */
NULL
,
0
,
domainoid
,
/* domain constraint */
InvalidOid
,
/* Foreign key fields */
NULL
,
0
,
' '
,
' '
,
' '
,
InvalidOid
,
expr
,
/* Tree form check constraint */
ccbin
,
/* Binary form check constraint */
ccsrc
);
/* Source form check constraint */
}
break
;
default:
break
;
}
}
/*
* Add any dependencies needed for the default expression.
*/
...
...
src/backend/executor/execQual.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.10
8 2002/09/04 20:31:17
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.10
9 2002/11/15 02:50:06
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -72,6 +72,9 @@ static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
static
Datum
ExecEvalConstraintTest
(
ConstraintTest
*
constraint
,
ExprContext
*
econtext
,
bool
*
isNull
,
ExprDoneCond
*
isDone
);
static
Datum
ExecEvalConstraintTestValue
(
ConstraintTestValue
*
conVal
,
ExprContext
*
econtext
,
bool
*
isNull
,
ExprDoneCond
*
isDone
);
/*----------
...
...
@@ -1551,6 +1554,23 @@ ExecEvalBooleanTest(BooleanTest *btest,
}
}
/*
* ExecEvalConstraintTestValue
*
* Return the value stored by constraintTest.
*/
static
Datum
ExecEvalConstraintTestValue
(
ConstraintTestValue
*
conVal
,
ExprContext
*
econtext
,
bool
*
isNull
,
ExprDoneCond
*
isDone
)
{
/*
* If the Datum hasn't been set, then it's ExecEvalConstraintTest
* hasn't been called.
*/
*
isNull
=
econtext
->
domainValue_isNull
;
return
econtext
->
domainValue_datum
;
}
/*
* ExecEvalConstraintTest
*
...
...
@@ -1571,11 +1591,22 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
case
CONSTR_TEST_NOTNULL
:
if
(
*
isNull
)
elog
(
ERROR
,
"Domain %s does not allow NULL values"
,
constraint
->
name
);
constraint
->
dom
name
);
break
;
case
CONSTR_TEST_CHECK
:
/* TODO: Add CHECK Constraints to domains */
elog
(
ERROR
,
"Domain CHECK Constraints not yet implemented"
);
{
Datum
conResult
;
/* Var with attnum == UnassignedAttrNum uses the result */
econtext
->
domainValue_datum
=
result
;
econtext
->
domainValue_isNull
=
*
isNull
;
conResult
=
ExecEvalExpr
(
constraint
->
check_expr
,
econtext
,
isNull
,
isDone
);
if
(
!
DatumGetBool
(
conResult
))
elog
(
ERROR
,
"Domain %s constraint %s failed"
,
constraint
->
name
,
constraint
->
domname
);
}
break
;
default:
elog
(
ERROR
,
"ExecEvalConstraintTest: Constraint type unknown"
);
...
...
@@ -1777,7 +1808,12 @@ ExecEvalExpr(Node *expression,
isNull
,
isDone
);
break
;
case
T_ConstraintTestValue
:
retDatum
=
ExecEvalConstraintTestValue
((
ConstraintTestValue
*
)
expression
,
econtext
,
isNull
,
isDone
);
break
;
default:
elog
(
ERROR
,
"ExecEvalExpr: unknown expression type %d"
,
nodeTag
(
expression
));
...
...
src/backend/nodes/copyfuncs.c
View file @
6b603e67
...
...
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.21
7 2002/11/11 22:19:22 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.21
8 2002/11/15 02:50:06 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -1056,11 +1056,35 @@ _copyConstraintTest(ConstraintTest *from)
newnode
->
testtype
=
from
->
testtype
;
if
(
from
->
name
)
newnode
->
name
=
pstrdup
(
from
->
name
);
if
(
from
->
domname
)
newnode
->
domname
=
pstrdup
(
from
->
domname
);
Node_Copy
(
from
,
newnode
,
check_expr
);
return
newnode
;
}
static
ConstraintTestValue
*
_copyConstraintTestValue
(
ConstraintTestValue
*
from
)
{
ConstraintTestValue
*
newnode
=
makeNode
(
ConstraintTestValue
);
/*
* copy remainder of node
*/
newnode
->
typeId
=
from
->
typeId
;
newnode
->
typeMod
=
from
->
typeMod
;
return
newnode
;
}
static
DomainConstraintValue
*
_copyDomainConstraintValue
(
DomainConstraintValue
*
from
)
{
DomainConstraintValue
*
newnode
=
makeNode
(
DomainConstraintValue
);
return
newnode
;
}
static
ArrayRef
*
_copyArrayRef
(
ArrayRef
*
from
)
{
...
...
@@ -3252,6 +3276,9 @@ copyObject(void *from)
case
T_ConstraintTest
:
retval
=
_copyConstraintTest
(
from
);
break
;
case
T_ConstraintTestValue
:
retval
=
_copyConstraintTestValue
(
from
);
break
;
case
T_FkConstraint
:
retval
=
_copyFkConstraint
(
from
);
break
;
...
...
@@ -3264,6 +3291,9 @@ copyObject(void *from)
case
T_InsertDefault
:
retval
=
_copyInsertDefault
(
from
);
break
;
case
T_DomainConstraintValue
:
retval
=
_copyDomainConstraintValue
(
from
);
break
;
default:
elog
(
ERROR
,
"copyObject: don't know how to copy node type %d"
,
...
...
src/backend/nodes/equalfuncs.c
View file @
6b603e67
...
...
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.16
3 2002/11/11 22:19:22 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.16
4 2002/11/15 02:50:06 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -1971,15 +1971,32 @@ _equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
return
false
;
if
(
!
equalstr
(
a
->
name
,
b
->
name
))
return
false
;
if
(
!
equalstr
(
a
->
domname
,
b
->
domname
))
return
false
;
if
(
!
equal
(
a
->
check_expr
,
b
->
check_expr
))
return
false
;
return
true
;
}
static
bool
_equalConstraintTestValue
(
ConstraintTestValue
*
a
,
ConstraintTestValue
*
b
)
{
if
(
a
->
typeId
!=
b
->
typeId
)
return
false
;
if
(
a
->
typeMod
!=
b
->
typeMod
)
return
false
;
return
true
;
}
static
bool
_equalDomainConstraintValue
(
DomainConstraintValue
*
a
,
DomainConstraintValue
*
b
)
{
return
true
;
}
/*
* Stuff from pg_list.h
*/
static
bool
_equalValue
(
Value
*
a
,
Value
*
b
)
{
...
...
@@ -2438,6 +2455,9 @@ equal(void *a, void *b)
case
T_ConstraintTest
:
retval
=
_equalConstraintTest
(
a
,
b
);
break
;
case
T_ConstraintTestValue
:
retval
=
_equalConstraintTestValue
(
a
,
b
);
break
;
case
T_FkConstraint
:
retval
=
_equalFkConstraint
(
a
,
b
);
break
;
...
...
@@ -2450,6 +2470,9 @@ equal(void *a, void *b)
case
T_InsertDefault
:
retval
=
_equalInsertDefault
(
a
,
b
);
break
;
case
T_DomainConstraintValue
:
retval
=
_equalDomainConstraintValue
(
a
,
b
);
break
;
default:
elog
(
WARNING
,
"equal: don't know whether nodes of type %d are equal"
,
...
...
src/backend/nodes/outfuncs.c
View file @
6b603e67
...
...
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.1
79 2002/11/11 22:19:22 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.1
80 2002/11/15 02:50:07 momjian
Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
...
...
@@ -1525,10 +1525,32 @@ _outConstraintTest(StringInfo str, ConstraintTest *node)
appendStringInfo
(
str
,
" :testtype %d :name "
,
(
int
)
node
->
testtype
);
_outToken
(
str
,
node
->
name
);
appendStringInfo
(
str
,
" :domain "
);
_outToken
(
str
,
node
->
domname
);
appendStringInfo
(
str
,
" :check_expr "
);
_outNode
(
str
,
node
->
check_expr
);
}
/*
* ConstraintTestValue
*/
static
void
_outConstraintTestValue
(
StringInfo
str
,
ConstraintTestValue
*
node
)
{
appendStringInfo
(
str
,
" CONSTRAINTTESTVALUE :typeid %u :typemod %d "
,
node
->
typeId
,
node
->
typeMod
);
}
/*
* DomainConstraintValue
*/
static
void
_outDomainConstraintValue
(
StringInfo
str
,
DomainConstraintValue
*
node
)
{
appendStringInfo
(
str
,
" DOMAINCONSTRAINTVALUE "
);
}
/*
* _outNode -
* converts a Node into ascii string and append it to 'str'
...
...
@@ -1796,9 +1818,15 @@ _outNode(StringInfo str, void *obj)
case
T_ConstraintTest
:
_outConstraintTest
(
str
,
obj
);
break
;
case
T_ConstraintTestValue
:
_outConstraintTestValue
(
str
,
obj
);
break
;
case
T_FuncCall
:
_outFuncCall
(
str
,
obj
);
break
;
case
T_DomainConstraintValue
:
_outDomainConstraintValue
(
str
,
obj
);
break
;
default:
elog
(
WARNING
,
"_outNode: don't know how to print type %d "
,
...
...
src/backend/nodes/readfuncs.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.13
6 2002/11/06 00:00:44 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.13
7 2002/11/15 02:50:07 momjian
Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
...
...
@@ -949,12 +949,56 @@ _readConstraintTest(void)
token
=
pg_strtok
(
&
length
);
/* now read it */
local_node
->
name
=
nullable_string
(
token
,
length
);
token
=
pg_strtok
(
&
length
);
/* get :domname */
token
=
pg_strtok
(
&
length
);
/* get domname */
local_node
->
domname
=
nullable_string
(
token
,
length
);
token
=
pg_strtok
(
&
length
);
/* eat :check_expr */
local_node
->
check_expr
=
nodeRead
(
true
);
/* now read it */
return
local_node
;
}
/* ----------------
* _readConstraintTestValue
*
* ConstraintTestValue is a subclass of Node
* ----------------
*/
static
ConstraintTestValue
*
_readConstraintTestValue
(
void
)
{
ConstraintTestValue
*
local_node
;
char
*
token
;
int
length
;
local_node
=
makeNode
(
ConstraintTestValue
);
token
=
pg_strtok
(
&
length
);
/* eat :typeid */
token
=
pg_strtok
(
&
length
);
/* get typeid */
local_node
->
typeId
=
atooid
(
token
);
token
=
pg_strtok
(
&
length
);
/* eat :typemod */
token
=
pg_strtok
(
&
length
);
/* get typemod */
local_node
->
typeMod
=
atoi
(
token
);
return
local_node
;
}
/* ----------------
* _readDomainConstraintValue
*
* DomainConstraintValue is a subclass of Node
* ----------------
*/
static
DomainConstraintValue
*
_readDomainConstraintValue
(
void
)
{
DomainConstraintValue
*
local_node
;
local_node
=
makeNode
(
DomainConstraintValue
);
return
local_node
;
}
/* ----------------
* _readVar
*
...
...
@@ -2300,6 +2344,10 @@ parsePlanString(void)
return_value
=
_readBooleanTest
();
else
if
(
length
==
14
&&
strncmp
(
token
,
"CONSTRAINTTEST"
,
length
)
==
0
)
return_value
=
_readConstraintTest
();
else
if
(
length
==
21
&&
strncmp
(
token
,
"DOMAINCONSTRAINTVALUE"
,
length
)
==
0
)
return_value
=
_readDomainConstraintValue
();
else
if
(
length
==
19
&&
strncmp
(
token
,
"CONSTRAINTTESTVALUE"
,
length
)
==
0
)
return_value
=
_readConstraintTestValue
();
else
elog
(
ERROR
,
"badly formatted planstring
\"
%.10s
\"
..."
,
token
);
...
...
src/backend/optimizer/util/clauses.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.11
0 2002/11/06 22:31:24 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.11
1 2002/11/15 02:50:07 momjian
Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
...
...
@@ -1926,6 +1926,8 @@ expression_tree_walker(Node *node,
if
(
walker
(((
ConstraintTest
*
)
node
)
->
arg
,
context
))
return
true
;
return
walker
(((
ConstraintTest
*
)
node
)
->
check_expr
,
context
);
case
T_ConstraintTestValue
:
break
;
case
T_SubLink
:
{
SubLink
*
sublink
=
(
SubLink
*
)
node
;
...
...
@@ -2310,6 +2312,15 @@ expression_tree_mutator(Node *node,
return
(
Node
*
)
newnode
;
}
break
;
case
T_ConstraintTestValue
:
{
ConstraintTestValue
*
ctest
=
(
ConstraintTestValue
*
)
node
;
ConstraintTestValue
*
newnode
;
FLATCOPY
(
newnode
,
ctest
,
ConstraintTestValue
);
return
(
Node
*
)
newnode
;
}
break
;
case
T_SubLink
:
{
/*
...
...
src/backend/parser/analyze.c
View file @
6b603e67
...
...
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.25
3 2002/10/21 22:06:19 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.25
4 2002/11/15 02:50:07 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -2401,7 +2401,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
Oid
expected_type_id
,
given_type_id
;
expr
=
transformExpr
(
pstate
,
expr
);
expr
=
transformExpr
(
pstate
,
expr
,
NULL
);
/* Cannot contain subselects or aggregates */
if
(
contain_subplans
(
expr
))
...
...
src/backend/parser/gram.y
View file @
6b603e67
...
...
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.37
7 2002/11/13 00:44
:08 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.37
8 2002/11/15 02:50
:08 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
...
...
@@ -393,7 +393,7 @@ static void doNegateFloat(Value *v);
UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USAGE USER USING
VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
VACUUM VALID VALIDATOR VALUE
VALUE
S VARCHAR VARYING
VERBOSE VERSION VIEW VOLATILE
WHEN WHERE WITH WITHOUT WORK WRITE
...
...
@@ -6406,6 +6406,11 @@ c_expr: columnref { $$ = (Node *) $1; }
n->subselect = $2;
$$ = (Node *)n;
}
| VALUE
{
DomainConstraintValue *n = makeNode(DomainConstraintValue);
$$ = (Node *)n;
}
;
/*
...
...
@@ -7315,6 +7320,7 @@ reserved_keyword:
| UNIQUE
| USER
| USING
| VALUE
| WHEN
| WHERE
;
...
...
src/backend/parser/keywords.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.13
0 2002/11/13 00:44:09
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.13
1 2002/11/15 02:50:08
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -314,6 +314,7 @@ static const ScanKeyword ScanKeywords[] = {
{
"vacuum"
,
VACUUM
},
{
"valid"
,
VALID
},
{
"validator"
,
VALIDATOR
},
{
"value"
,
VALUE
},
{
"values"
,
VALUES
},
{
"varchar"
,
VARCHAR
},
{
"varying"
,
VARYING
},
...
...
src/backend/parser/parse_clause.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.9
8 2002/09/18 21:35:22 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.9
9 2002/11/15 02:50:08 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -283,7 +283,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
* transformJoinOnClause() does. Just invoke transformExpr() to fix
* up the operators, and we're done.
*/
result
=
transformExpr
(
pstate
,
result
);
result
=
transformExpr
(
pstate
,
result
,
NULL
);
result
=
coerce_to_boolean
(
result
,
"JOIN/USING"
);
...
...
@@ -317,7 +317,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
pstate
->
p_namespace
=
makeList2
(
j
->
larg
,
j
->
rarg
);
/* This part is just like transformWhereClause() */
result
=
transformExpr
(
pstate
,
j
->
quals
);
result
=
transformExpr
(
pstate
,
j
->
quals
,
NULL
);
result
=
coerce_to_boolean
(
result
,
"JOIN/ON"
);
...
...
@@ -478,7 +478,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
save_namespace
=
pstate
->
p_namespace
;
pstate
->
p_namespace
=
NIL
;
funcexpr
=
transformExpr
(
pstate
,
r
->
funccallnode
);
funcexpr
=
transformExpr
(
pstate
,
r
->
funccallnode
,
NULL
);
pstate
->
p_namespace
=
save_namespace
;
...
...
@@ -961,7 +961,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
if
(
clause
==
NULL
)
return
NULL
;
qual
=
transformExpr
(
pstate
,
clause
);
qual
=
transformExpr
(
pstate
,
clause
,
NULL
);
qual
=
coerce_to_boolean
(
qual
,
"WHERE"
);
...
...
@@ -1104,7 +1104,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
* willing to match a resjunk target here, though the above cases must
* ignore resjunk targets.
*/
expr
=
transformExpr
(
pstate
,
node
);
expr
=
transformExpr
(
pstate
,
node
,
NULL
);
foreach
(
tl
,
tlist
)
{
...
...
src/backend/parser/parse_coerce.c
View file @
6b603e67
...
...
@@ -8,13 +8,18 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.8
5 2002/10/24 22:09:00 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.8
6 2002/11/15 02:50:09 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
...
...
@@ -405,8 +410,14 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
for
(;;)
{
HeapTuple
tup
;
HeapTuple
conTup
;
Form_pg_type
typTup
;
ScanKeyData
key
[
1
];
int
nkeys
=
0
;
SysScanDesc
scan
;
Relation
conRel
;
tup
=
SearchSysCache
(
TYPEOID
,
ObjectIdGetDatum
(
typeId
),
0
,
0
,
0
);
...
...
@@ -419,7 +430,45 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
if
(
typTup
->
typnotnull
&&
notNull
==
NULL
)
notNull
=
pstrdup
(
NameStr
(
typTup
->
typname
));
/* TODO: Add CHECK Constraints to domains */
/* Add CHECK Constraints to domains */
conRel
=
heap_openr
(
ConstraintRelationName
,
RowShareLock
);
ScanKeyEntryInitialize
(
&
key
[
nkeys
++
],
0x0
,
Anum_pg_constraint_contypid
,
F_OIDEQ
,
ObjectIdGetDatum
(
typeId
));
scan
=
systable_beginscan
(
conRel
,
ConstraintTypidIndex
,
true
,
SnapshotNow
,
nkeys
,
key
);
while
(
HeapTupleIsValid
(
conTup
=
systable_getnext
(
scan
)))
{
Datum
val
;
bool
isNull
;
ConstraintTest
*
r
=
makeNode
(
ConstraintTest
);
Form_pg_constraint
c
=
(
Form_pg_constraint
)
GETSTRUCT
(
conTup
);
/* Not expecting conbin to be NULL, but we'll test for it anyway */
val
=
fastgetattr
(
conTup
,
Anum_pg_constraint_conbin
,
conRel
->
rd_att
,
&
isNull
);
if
(
isNull
)
elog
(
ERROR
,
"coerce_type_constraints: domain %s constraint %s has NULL conbin"
,
NameStr
(
typTup
->
typname
),
NameStr
(
c
->
conname
));
r
->
arg
=
arg
;
r
->
testtype
=
CONSTR_TEST_CHECK
;
r
->
name
=
NameStr
(
c
->
conname
);
r
->
domname
=
NameStr
(
typTup
->
typname
);
r
->
check_expr
=
stringToNode
(
MemoryContextStrdup
(
CacheMemoryContext
,
DatumGetCString
(
DirectFunctionCall1
(
textout
,
val
))));
arg
=
(
Node
*
)
r
;
}
systable_endscan
(
scan
);
heap_close
(
conRel
,
RowShareLock
);
if
(
typTup
->
typtype
!=
'd'
)
{
...
...
@@ -452,7 +501,8 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
r
->
arg
=
arg
;
r
->
testtype
=
CONSTR_TEST_NOTNULL
;
r
->
name
=
notNull
;
r
->
name
=
"NOT NULL"
;
r
->
domname
=
notNull
;
r
->
check_expr
=
NULL
;
arg
=
(
Node
*
)
r
;
...
...
src/backend/parser/parse_expr.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.1
29 2002/09/18 21:35:22 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.1
30 2002/11/15 02:50:09 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -20,6 +20,7 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/params.h"
#include "optimizer/clauses.h"
#include "parser/analyze.h"
#include "parser/gramparse.h"
#include "parser/parse.h"
...
...
@@ -83,7 +84,7 @@ parse_expr_init(void)
* input and output of transformExpr; see SubLink for example.
*/
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
)
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
,
ConstraintTestValue
*
domVal
)
{
Node
*
result
=
NULL
;
...
...
@@ -152,7 +153,7 @@ transformExpr(ParseState *pstate, Node *expr)
ExprFieldSelect
*
efs
=
(
ExprFieldSelect
*
)
expr
;
List
*
fields
;
result
=
transformExpr
(
pstate
,
efs
->
arg
);
result
=
transformExpr
(
pstate
,
efs
->
arg
,
domVal
);
/* handle qualification, if any */
foreach
(
fields
,
efs
->
fields
)
{
...
...
@@ -169,7 +170,7 @@ transformExpr(ParseState *pstate, Node *expr)
case
T_TypeCast
:
{
TypeCast
*
tc
=
(
TypeCast
*
)
expr
;
Node
*
arg
=
transformExpr
(
pstate
,
tc
->
arg
);
Node
*
arg
=
transformExpr
(
pstate
,
tc
->
arg
,
domVal
);
result
=
typecast_expression
(
arg
,
tc
->
typename
);
break
;
...
...
@@ -204,14 +205,14 @@ transformExpr(ParseState *pstate, Node *expr)
n
->
arg
=
a
->
lexpr
;
result
=
transformExpr
(
pstate
,
(
Node
*
)
n
);
(
Node
*
)
n
,
domVal
);
}
else
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
);
a
->
lexpr
,
domVal
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
);
a
->
rexpr
,
domVal
);
result
=
(
Node
*
)
make_op
(
a
->
name
,
lexpr
,
...
...
@@ -222,9 +223,9 @@ transformExpr(ParseState *pstate, Node *expr)
case
AND
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
);
a
->
lexpr
,
domVal
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
);
a
->
rexpr
,
domVal
);
Expr
*
expr
=
makeNode
(
Expr
);
lexpr
=
coerce_to_boolean
(
lexpr
,
"AND"
);
...
...
@@ -239,9 +240,9 @@ transformExpr(ParseState *pstate, Node *expr)
case
OR
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
);
a
->
lexpr
,
domVal
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
);
a
->
rexpr
,
domVal
);
Expr
*
expr
=
makeNode
(
Expr
);
lexpr
=
coerce_to_boolean
(
lexpr
,
"OR"
);
...
...
@@ -256,7 +257,7 @@ transformExpr(ParseState *pstate, Node *expr)
case
NOT
:
{
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
);
a
->
rexpr
,
domVal
);
Expr
*
expr
=
makeNode
(
Expr
);
rexpr
=
coerce_to_boolean
(
rexpr
,
"NOT"
);
...
...
@@ -270,9 +271,9 @@ transformExpr(ParseState *pstate, Node *expr)
case
DISTINCT
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
);
a
->
lexpr
,
domVal
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
);
a
->
rexpr
,
domVal
);
result
=
(
Node
*
)
make_op
(
a
->
name
,
lexpr
,
...
...
@@ -293,7 +294,7 @@ transformExpr(ParseState *pstate, Node *expr)
* Will result in a boolean constant node.
*/
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
);
a
->
lexpr
,
domVal
);
ltype
=
exprType
(
lexpr
);
foreach
(
telem
,
(
List
*
)
a
->
rexpr
)
...
...
@@ -317,7 +318,7 @@ transformExpr(ParseState *pstate, Node *expr)
n
->
val
.
val
.
str
=
(
matched
?
"t"
:
"f"
);
n
->
typename
=
SystemTypeName
(
"bool"
);
result
=
transformExpr
(
pstate
,
(
Node
*
)
n
);
result
=
transformExpr
(
pstate
,
(
Node
*
)
n
,
domVal
);
}
break
;
}
...
...
@@ -331,7 +332,7 @@ transformExpr(ParseState *pstate, Node *expr)
/* transform the list of arguments */
foreach
(
args
,
fn
->
args
)
lfirst
(
args
)
=
transformExpr
(
pstate
,
(
Node
*
)
lfirst
(
args
));
(
Node
*
)
lfirst
(
args
)
,
domVal
);
result
=
ParseFuncOrColumn
(
pstate
,
fn
->
funcname
,
fn
->
args
,
...
...
@@ -405,7 +406,7 @@ transformExpr(ParseState *pstate, Node *expr)
List
*
elist
;
foreach
(
elist
,
left_list
)
lfirst
(
elist
)
=
transformExpr
(
pstate
,
lfirst
(
elist
));
lfirst
(
elist
)
=
transformExpr
(
pstate
,
lfirst
(
elist
)
,
domVal
);
Assert
(
IsA
(
sublink
->
oper
,
A_Expr
));
op
=
((
A_Expr
*
)
sublink
->
oper
)
->
name
;
...
...
@@ -504,7 +505,7 @@ transformExpr(ParseState *pstate, Node *expr)
warg
=
(
Node
*
)
makeSimpleA_Expr
(
OP
,
"="
,
c
->
arg
,
warg
);
}
neww
->
expr
=
transformExpr
(
pstate
,
warg
);
neww
->
expr
=
transformExpr
(
pstate
,
warg
,
domVal
);
neww
->
expr
=
coerce_to_boolean
(
neww
->
expr
,
"CASE/WHEN"
);
...
...
@@ -520,7 +521,7 @@ transformExpr(ParseState *pstate, Node *expr)
n
->
val
.
type
=
T_Null
;
warg
=
(
Node
*
)
n
;
}
neww
->
result
=
transformExpr
(
pstate
,
warg
);
neww
->
result
=
transformExpr
(
pstate
,
warg
,
domVal
);
newargs
=
lappend
(
newargs
,
neww
);
typeids
=
lappendi
(
typeids
,
exprType
(
neww
->
result
));
...
...
@@ -544,7 +545,7 @@ transformExpr(ParseState *pstate, Node *expr)
n
->
val
.
type
=
T_Null
;
defresult
=
(
Node
*
)
n
;
}
newc
->
defresult
=
transformExpr
(
pstate
,
defresult
);
newc
->
defresult
=
transformExpr
(
pstate
,
defresult
,
domVal
);
/*
* Note: default result is considered the most significant
...
...
@@ -580,7 +581,7 @@ transformExpr(ParseState *pstate, Node *expr)
{
NullTest
*
n
=
(
NullTest
*
)
expr
;
n
->
arg
=
transformExpr
(
pstate
,
n
->
arg
);
n
->
arg
=
transformExpr
(
pstate
,
n
->
arg
,
domVal
);
/* the argument can be any type, so don't coerce it */
result
=
expr
;
break
;
...
...
@@ -617,7 +618,7 @@ transformExpr(ParseState *pstate, Node *expr)
clausename
=
NULL
;
/* keep compiler quiet */
}
b
->
arg
=
transformExpr
(
pstate
,
b
->
arg
);
b
->
arg
=
transformExpr
(
pstate
,
b
->
arg
,
domVal
);
b
->
arg
=
coerce_to_boolean
(
b
->
arg
,
clausename
);
...
...
@@ -625,6 +626,13 @@ transformExpr(ParseState *pstate, Node *expr)
break
;
}
case
T_DomainConstraintValue
:
{
result
=
(
Node
*
)
copyObject
(
domVal
);
break
;
}
/*********************************************
* Quietly accept node types that may be presented when we are
* called on an already-transformed tree.
...
...
@@ -936,6 +944,9 @@ exprType(Node *expr)
case
T_ConstraintTest
:
type
=
exprType
(((
ConstraintTest
*
)
expr
)
->
arg
);
break
;
case
T_ConstraintTestValue
:
type
=
((
ConstraintTestValue
*
)
expr
)
->
typeId
;
break
;
default:
elog
(
ERROR
,
"exprType: Do not know how to get type for %d node"
,
nodeTag
(
expr
));
...
...
src/backend/parser/parse_node.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.7
2 2002/11/13 00:39:47
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.7
3 2002/11/15 02:50:09
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -277,7 +277,7 @@ transformArraySubscripts(ParseState *pstate,
{
if
(
ai
->
lidx
)
{
subexpr
=
transformExpr
(
pstate
,
ai
->
lidx
);
subexpr
=
transformExpr
(
pstate
,
ai
->
lidx
,
NULL
);
/* If it's not int4 already, try to coerce */
subexpr
=
coerce_to_target_type
(
subexpr
,
exprType
(
subexpr
),
INT4OID
,
-
1
,
...
...
@@ -299,7 +299,7 @@ transformArraySubscripts(ParseState *pstate,
}
lowerIndexpr
=
lappend
(
lowerIndexpr
,
subexpr
);
}
subexpr
=
transformExpr
(
pstate
,
ai
->
uidx
);
subexpr
=
transformExpr
(
pstate
,
ai
->
uidx
,
NULL
);
/* If it's not int4 already, try to coerce */
subexpr
=
coerce_to_target_type
(
subexpr
,
exprType
(
subexpr
),
INT4OID
,
-
1
,
...
...
src/backend/parser/parse_target.c
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.9
1 2002/09/28 20:00:19 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.9
2 2002/11/15 02:50:09 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -56,7 +56,7 @@ transformTargetEntry(ParseState *pstate,
/* Transform the node if caller didn't do it already */
if
(
expr
==
NULL
)
expr
=
transformExpr
(
pstate
,
node
);
expr
=
transformExpr
(
pstate
,
node
,
NULL
);
if
(
IsA
(
expr
,
RangeVar
))
elog
(
ERROR
,
"You can't use relation names alone in the target list, try relation.*."
);
...
...
src/backend/utils/adt/ruleutils.c
View file @
6b603e67
...
...
@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.12
4 2002/09/19 23:40:56 tgl
Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.12
5 2002/11/15 02:50:09 momjian
Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
...
...
@@ -2226,6 +2226,12 @@ get_rule_expr(Node *node, deparse_context *context,
}
break
;
case
T_ConstraintTestValue
:
{
appendStringInfo
(
buf
,
"VALUE"
);
}
break
;
case
T_SubLink
:
get_sublink_expr
(
node
,
context
);
break
;
...
...
src/include/catalog/indexing.h
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: indexing.h,v 1.7
6 2002/10/18 20:33:57 tgl
Exp $
* $Id: indexing.h,v 1.7
7 2002/11/15 02:50:10 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -40,6 +40,7 @@
#define ConstraintNameNspIndex "pg_constraint_conname_nsp_index"
#define ConstraintOidIndex "pg_constraint_oid_index"
#define ConstraintRelidIndex "pg_constraint_conrelid_index"
#define ConstraintTypidIndex "pg_constraint_contypid_index"
#define ConversionDefaultIndex "pg_conversion_default_index"
#define ConversionNameNspIndex "pg_conversion_name_nsp_index"
#define ConversionOidIndex "pg_conversion_oid_index"
...
...
@@ -129,6 +130,8 @@ DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index on pg_class using btree(relname
DECLARE_INDEX
(
pg_constraint_conname_nsp_index
on
pg_constraint
using
btree
(
conname
name_ops
,
connamespace
oid_ops
));
/* This following index is not used for a cache and is not unique */
DECLARE_INDEX
(
pg_constraint_conrelid_index
on
pg_constraint
using
btree
(
conrelid
oid_ops
));
/* This following index is not used for a cache and is not unique */
DECLARE_INDEX
(
pg_constraint_contypid_index
on
pg_constraint
using
btree
(
contypid
oid_ops
));
DECLARE_UNIQUE_INDEX
(
pg_constraint_oid_index
on
pg_constraint
using
btree
(
oid
oid_ops
));
DECLARE_UNIQUE_INDEX
(
pg_conversion_default_index
on
pg_conversion
using
btree
(
connamespace
oid_ops
,
conforencoding
int4_ops
,
contoencoding
int4_ops
,
oid
oid_ops
));
DECLARE_UNIQUE_INDEX
(
pg_conversion_name_nsp_index
on
pg_conversion
using
btree
(
conname
name_ops
,
connamespace
oid_ops
));
...
...
src/include/catalog/pg_constraint.h
View file @
6b603e67
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_constraint.h,v 1.
4 2002/09/22 00:37:09 tgl
Exp $
* $Id: pg_constraint.h,v 1.
5 2002/11/15 02:50:10 momjian
Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -140,6 +140,15 @@ typedef FormData_pg_constraint *Form_pg_constraint;
* the FKCONSTR_MATCH_xxx constants defined in parsenodes.h.
*/
/*
* Used for constraint support functions where the
* and conrelid, contypid columns being looked up
*/
typedef
enum
CONSTRAINTCATEGORY
{
CONSTRAINT_RELATION
,
CONSTRAINT_DOMAIN
,
CONSTRAINT_ASSERTION
}
CONSTRAINTCATEGORY
;
/*
* prototypes for functions in pg_constraint.c
...
...
@@ -166,9 +175,9 @@ extern Oid CreateConstraintEntry(const char *constraintName,
extern
void
RemoveConstraintById
(
Oid
conId
);
extern
bool
ConstraintNameIsUsed
(
Oid
relId
,
Oid
rel
Namespace
,
extern
bool
ConstraintNameIsUsed
(
CONSTRAINTCATEGORY
conCat
,
Oid
objId
,
Oid
obj
Namespace
,
const
char
*
cname
);
extern
char
*
GenerateConstraintName
(
Oid
relId
,
Oid
rel
Namespace
,
extern
char
*
GenerateConstraintName
(
CONSTRAINTCATEGORY
conCat
,
Oid
objId
,
Oid
obj
Namespace
,
int
*
counter
);
extern
bool
ConstraintNameIsGenerated
(
const
char
*
cname
);
...
...
src/include/nodes/execnodes.h
View file @
6b603e67
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execnodes.h,v 1.7
7 2002/11/06 22:31:24 tgl
Exp $
* $Id: execnodes.h,v 1.7
8 2002/11/15 02:50:10 momjian
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -113,6 +113,13 @@ typedef struct ExprContext
Datum
*
ecxt_aggvalues
;
/* precomputed values for Aggref nodes */
bool
*
ecxt_aggnulls
;
/* null flags for Aggref nodes */
/*
* Carry the domain value through the executor for application
* in a domain constraint
*/
Datum
domainValue_datum
;
bool
domainValue_isNull
;
/* Functions to call back when ExprContext is shut down */
ExprContext_CB
*
ecxt_callbacks
;
}
ExprContext
;
...
...
src/include/nodes/nodes.h
View file @
6b603e67
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.12
2 2002/11/10 02:17:25
momjian Exp $
* $Id: nodes.h,v 1.12
3 2002/11/15 02:50:10
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -171,6 +171,7 @@ typedef enum NodeTag
T_ViewStmt
,
T_LoadStmt
,
T_CreateDomainStmt
,
T_DomainConstraintValue
,
T_CreatedbStmt
,
T_DropdbStmt
,
T_VacuumStmt
,
...
...
@@ -231,6 +232,7 @@ typedef enum NodeTag
T_NullTest
,
T_BooleanTest
,
T_ConstraintTest
,
T_ConstraintTestValue
,
T_CaseExpr
,
T_CaseWhen
,
T_FkConstraint
,
...
...
src/include/nodes/parsenodes.h
View file @
6b603e67
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.21
3 2002/11/13 00:44:09
momjian Exp $
* $Id: parsenodes.h,v 1.21
4 2002/11/15 02:50:12
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -285,9 +285,26 @@ typedef struct ConstraintTest
Node
*
arg
;
/* input expression */
ConstraintTestType
testtype
;
/* test type */
char
*
name
;
/* name of constraint (for error msgs) */
char
*
domname
;
/* name of domain (for error messages) */
Node
*
check_expr
;
/* for CHECK test, a boolean expression */
}
ConstraintTest
;
/*
* Placeholder node for the value to be processed by a domains
* check constraint.
*/
typedef
struct
DomainConstraintValue
{
NodeTag
type
;
}
DomainConstraintValue
;
typedef
struct
ConstraintTestValue
{
NodeTag
type
;
Oid
typeId
;
int32
typeMod
;
}
ConstraintTestValue
;
/*
* ColumnDef - column definition (used in various creates)
*
...
...
src/include/optimizer/var.h
View file @
6b603e67
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: var.h,v 1.2
1 2002/06/20 20:29:5
1 momjian Exp $
* $Id: var.h,v 1.2
2 2002/11/15 02:50:2
1 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -22,6 +22,7 @@ extern bool contain_var_reference(Node *node, int varno, int varattno,
int
levelsup
);
extern
bool
contain_whole_tuple_var
(
Node
*
node
,
int
varno
,
int
levelsup
);
extern
bool
contain_var_clause
(
Node
*
node
);
extern
bool
contain_var_tuple_clause
(
Node
*
node
);
extern
List
*
pull_var_clause
(
Node
*
node
,
bool
includeUpperVars
);
extern
Node
*
flatten_join_alias_vars
(
Node
*
node
,
List
*
rtable
,
bool
force
);
...
...
src/include/parser/parse_expr.h
View file @
6b603e67
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_expr.h,v 1.2
8 2002/06/20 20:29:5
1 momjian Exp $
* $Id: parse_expr.h,v 1.2
9 2002/11/15 02:50:2
1 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -21,7 +21,8 @@
extern
int
max_expr_depth
;
extern
bool
Transform_null_equals
;
extern
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
);
extern
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
,
ConstraintTestValue
*
domVal
);
extern
Oid
exprType
(
Node
*
expr
);
extern
int32
exprTypmod
(
Node
*
expr
);
extern
bool
exprIsLengthCoercion
(
Node
*
expr
,
int32
*
coercedTypmod
);
...
...
src/test/regress/expected/domain.out
View file @
6b603e67
...
...
@@ -103,35 +103,43 @@ drop domain domainint4arr restrict;
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15);
create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
, col5 dcheck CHECK (col5 IN ('c', 'd'))
);
INSERT INTO nulltest DEFAULT VALUES;
ERROR: Domain dnotnull does not allow NULL values
INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good
insert into nulltest values ('a', 'b', 'c', 'd', NULL);
ERROR: Domain $1 constraint dcheck failed
insert into nulltest values ('a', 'b', 'c', 'd', 'a');
ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
ERROR: Domain dnotnull does not allow NULL values
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
INSERT INTO nulltest values ('a', NULL, 'c', 'd'
, 'c'
);
ERROR: Domain dnotnull does not allow NULL values
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
INSERT INTO nulltest values ('a', 'b', NULL, 'd'
, 'c'
);
ERROR: ExecInsert: Fail to add null value in not null attribute col3
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
INSERT INTO nulltest values ('a', 'b', 'c', NULL
, 'd'
); -- Good
-- Test copy
COPY nulltest FROM stdin; --fail
ERROR: copy: line 1,
CopyFrom: Fail to add null value in not null attribute col3
ERROR: copy: line 1,
Domain $1 constraint dcheck failed
lost synchronization with server, resetting connection
SET autocommit TO 'on';
-- Last row is bad
COPY nulltest FROM stdin;
ERROR: copy: line 3, CopyFrom: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
lost synchronization with server, resetting connection
select * from nulltest;
col1 | col2 | col3 | col4
------+------+------+------
a | b | c | d
a | b | c |
a | b | c |
(3 rows)
col1 | col2 | col3 | col4 | col5
------+------+------+------+------
a | b | c | d | c
a | b | c | | d
(2 rows)
-- Test out coerced (casted) constraints
SELECT cast('1' as dnotnull);
...
...
src/test/regress/sql/domain.sql
View file @
6b603e67
...
...
@@ -83,29 +83,36 @@ drop domain domaintextarr restrict;
create
domain
dnotnull
varchar
(
15
)
NOT
NULL
;
create
domain
dnull
varchar
(
15
);
create
domain
dcheck
varchar
(
15
)
NOT
NULL
CHECK
(
VALUE
=
'a'
OR
VALUE
=
'c'
OR
VALUE
=
'd'
);
create
table
nulltest
(
col1
dnotnull
,
col2
dnotnull
NULL
-- NOT NULL in the domain cannot be overridden
,
col3
dnull
NOT
NULL
,
col4
dnull
,
col5
dcheck
CHECK
(
col5
IN
(
'c'
,
'd'
))
);
INSERT
INTO
nulltest
DEFAULT
VALUES
;
INSERT
INTO
nulltest
values
(
'a'
,
'b'
,
'c'
,
'd'
);
-- Good
INSERT
INTO
nulltest
values
(
NULL
,
'b'
,
'c'
,
'd'
);
INSERT
INTO
nulltest
values
(
'a'
,
NULL
,
'c'
,
'd'
);
INSERT
INTO
nulltest
values
(
'a'
,
'b'
,
NULL
,
'd'
);
INSERT
INTO
nulltest
values
(
'a'
,
'b'
,
'c'
,
NULL
);
-- Good
INSERT
INTO
nulltest
values
(
'a'
,
'b'
,
'c'
,
'd'
,
'c'
);
-- Good
insert
into
nulltest
values
(
'a'
,
'b'
,
'c'
,
'd'
,
NULL
);
insert
into
nulltest
values
(
'a'
,
'b'
,
'c'
,
'd'
,
'a'
);
INSERT
INTO
nulltest
values
(
NULL
,
'b'
,
'c'
,
'd'
,
'd'
);
INSERT
INTO
nulltest
values
(
'a'
,
NULL
,
'c'
,
'd'
,
'c'
);
INSERT
INTO
nulltest
values
(
'a'
,
'b'
,
NULL
,
'd'
,
'c'
);
INSERT
INTO
nulltest
values
(
'a'
,
'b'
,
'c'
,
NULL
,
'd'
);
-- Good
-- Test copy
COPY
nulltest
FROM
stdin
;
--fail
a
b
\
N
d
a
b
\
N
d
\
N
\
.
SET
autocommit
TO
'on'
;
-- Last row is bad
COPY
nulltest
FROM
stdin
;
a
b
c
\
N
a
b
c
\
N
c
a
b
c
\
N
d
a
b
c
\
N
a
\
.
select
*
from
nulltest
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment