aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2010-07-25 23:21:22 +0000
committerRobert Haas <rhaas@postgresql.org>2010-07-25 23:21:22 +0000
commita3b012b560f8871e9c24abb24e28cabc6d3c92ea (patch)
tree26b6d7f182580269737c3d7c11365c933332e21f /src
parentedff75bef809629c197c27b23f57baa36330d12e (diff)
downloadpostgresql-a3b012b560f8871e9c24abb24e28cabc6d3c92ea.tar.gz
postgresql-a3b012b560f8871e9c24abb24e28cabc6d3c92ea.zip
CREATE TABLE IF NOT EXISTS.
Reviewed by Bernd Helmle.
Diffstat (limited to 'src')
-rw-r--r--src/backend/bootstrap/bootparse.y5
-rw-r--r--src/backend/catalog/heap.c25
-rw-r--r--src/backend/catalog/toasting.c6
-rw-r--r--src/backend/commands/cluster.c6
-rw-r--r--src/backend/commands/sequence.c4
-rw-r--r--src/backend/commands/tablecmds.c14
-rw-r--r--src/backend/commands/typecmds.c8
-rw-r--r--src/backend/commands/view.c9
-rw-r--r--src/backend/executor/execMain.c6
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/equalfuncs.c3
-rw-r--r--src/backend/nodes/outfuncs.c3
-rw-r--r--src/backend/parser/gram.y35
-rw-r--r--src/backend/tcop/utility.c9
-rw-r--r--src/include/catalog/heap.h5
-rw-r--r--src/include/nodes/parsenodes.h3
-rw-r--r--src/test/regress/expected/create_table.out6
-rw-r--r--src/test/regress/expected/typed_table.out2
-rw-r--r--src/test/regress/sql/create_table.sql5
-rw-r--r--src/test/regress/sql/typed_table.sql1
20 files changed, 130 insertions, 28 deletions
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 9cc68501ffc..70cad329153 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.105 2010/02/07 20:48:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.106 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -245,7 +245,8 @@ Boot_CreateStmt:
ONCOMMIT_NOOP,
(Datum) 0,
false,
- true);
+ true,
+ false);
elog(DEBUG4, "relation created with oid %u", id);
}
do_end();
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 47e0c9b9cf5..a0268f7177a 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.373 2010/04/05 01:09:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.374 2010/07/25 23:21:21 rhaas Exp $
*
*
* INTERFACE ROUTINES
@@ -903,11 +903,13 @@ heap_create_with_catalog(const char *relname,
OnCommitAction oncommit,
Datum reloptions,
bool use_user_acl,
- bool allow_system_table_mods)
+ bool allow_system_table_mods,
+ bool if_not_exists)
{
Relation pg_class_desc;
Relation new_rel_desc;
Acl *relacl;
+ Oid existing_relid;
Oid old_type_oid;
Oid new_type_oid;
Oid new_array_oid = InvalidOid;
@@ -921,10 +923,27 @@ heap_create_with_catalog(const char *relname,
CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
- if (get_relname_relid(relname, relnamespace))
+ /*
+ * If the relation already exists, it's an error, unless the user specifies
+ * "IF NOT EXISTS". In that case, we just print a notice and do nothing
+ * further.
+ */
+ existing_relid = get_relname_relid(relname, relnamespace);
+ if (existing_relid != InvalidOid)
+ {
+ if (if_not_exists)
+ {
+ ereport(NOTICE,
+ (errcode(ERRCODE_DUPLICATE_TABLE),
+ errmsg("relation \"%s\" already exists, skipping",
+ relname)));
+ heap_close(pg_class_desc, RowExclusiveLock);
+ return InvalidOid;
+ }
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("relation \"%s\" already exists", relname)));
+ }
/*
* Since we are going to create a rowtype as well, also check for
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 86e7daa1a03..6f658321b4f 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.32 2010/02/26 02:00:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.33 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -223,7 +223,9 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
ONCOMMIT_NOOP,
reloptions,
false,
- true);
+ true,
+ false);
+ Assert(toast_relid != InvalidOid);
/* make the toast relation visible, else index creation will fail */
CommandCounterIncrement();
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 7a1b8e885be..ce99b55a637 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.203 2010/04/28 16:10:41 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.204 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -687,7 +687,9 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
ONCOMMIT_NOOP,
reloptions,
false,
- true);
+ true,
+ false);
+ Assert(OIDNewHeap != InvalidOid);
ReleaseSysCache(tuple);
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index fc2446997a7..0f06bba8039 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.168 2010/02/20 21:24:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.169 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -203,8 +203,10 @@ DefineSequence(CreateSeqStmt *seq)
stmt->options = list_make1(defWithOids(false));
stmt->oncommit = ONCOMMIT_NOOP;
stmt->tablespacename = NULL;
+ stmt->if_not_exists = false;
seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
+ Assert(seqoid != InvalidOid);
rel = heap_open(seqoid, AccessExclusiveLock);
tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c5981d4e5b2..2fdce989c01 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.333 2010/07/23 20:04:18 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.334 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -548,8 +548,18 @@ DefineRelation(CreateStmt *stmt, char relkind)
stmt->oncommit,
reloptions,
true,
- allowSystemTableMods);
+ allowSystemTableMods,
+ stmt->if_not_exists);
+ /*
+ * If heap_create_with_catalog returns InvalidOid, it means that the user
+ * specified "IF NOT EXISTS" and the relation already exists. In that
+ * case we do nothing further.
+ */
+ if (relationId == InvalidOid)
+ return InvalidOid;
+
+ /* Store inheritance information for new rel. */
StoreCatalogInheritance(relationId, inheritOids);
/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 8a85e79ea65..5d94445910c 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.148 2010/02/26 02:00:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.149 2010/07/25 23:21:21 rhaas Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -1506,6 +1506,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
CreateStmt *createStmt = makeNode(CreateStmt);
Oid old_type_oid;
Oid typeNamespace;
+ Oid relid;
if (coldeflist == NIL)
ereport(ERROR,
@@ -1523,6 +1524,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
createStmt->options = list_make1(defWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
+ createStmt->if_not_exists = false;
/*
* Check for collision with an existing type name. If there is one and
@@ -1546,7 +1548,9 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
/*
* Finally create the relation. This also creates the type.
*/
- return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
+ relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
+ Assert(relid != InvalidOid);
+ return relid;
}
/*
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 900def01480..1acf1b802d7 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.120 2010/01/02 16:57:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.121 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -222,6 +222,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
}
else
{
+ Oid relid;
+
/*
* now set the parameters for keys/inheritance etc. All of these are
* uninteresting for views...
@@ -233,13 +235,16 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
createStmt->options = list_make1(defWithOids(false));
createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
+ createStmt->if_not_exists = false;
/*
* finally create the relation (this will error out if there's an
* existing view, so we don't need more code to complain if "replace"
* is false).
*/
- return DefineRelation(createStmt, RELKIND_VIEW);
+ relid = DefineRelation(createStmt, RELKIND_VIEW);
+ Assert(relid != InvalidOid);
+ return relid;
}
}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 87ca2a1b4b8..b21dbf4762b 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.352 2010/07/22 00:47:52 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.353 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2190,7 +2190,9 @@ OpenIntoRel(QueryDesc *queryDesc)
into->onCommit,
reloptions,
true,
- allowSystemTableMods);
+ allowSystemTableMods,
+ false);
+ Assert(intoRelationId != InvalidOid);
FreeTupleDesc(tupdesc);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 8e47403a485..a5862771a90 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.465 2010/07/12 17:01:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.466 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2537,6 +2537,7 @@ _copyCreateStmt(CreateStmt *from)
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(oncommit);
COPY_STRING_FIELD(tablespacename);
+ COPY_SCALAR_FIELD(if_not_exists);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index e97a3ea9daa..7056287c93b 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.385 2010/02/26 02:00:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.386 2010/07/25 23:21:21 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1104,6 +1104,7 @@ _equalCreateStmt(CreateStmt *a, CreateStmt *b)
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(oncommit);
COMPARE_STRING_FIELD(tablespacename);
+ COMPARE_SCALAR_FIELD(if_not_exists);
return true;
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index ff4a9aaeefd..6089ea3e3aa 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.386 2010/07/12 17:01:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.387 2010/07/25 23:21:21 rhaas Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1795,6 +1795,7 @@ _outCreateStmt(StringInfo str, CreateStmt *node)
WRITE_NODE_FIELD(options);
WRITE_ENUM_FIELD(oncommit, OnCommitAction);
WRITE_STRING_FIELD(tablespacename);
+ WRITE_BOOL_FIELD(if_not_exists);
}
static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 122213a134f..07ee2a83496 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.713 2010/06/13 17:43:12 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.714 2010/07/25 23:21:21 rhaas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2212,6 +2212,23 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->options = $9;
n->oncommit = $10;
n->tablespacename = $11;
+ n->if_not_exists = false;
+ $$ = (Node *)n;
+ }
+ | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '('
+ OptTableElementList ')' OptInherit OptWith OnCommitOption
+ OptTableSpace
+ {
+ CreateStmt *n = makeNode(CreateStmt);
+ $7->istemp = $2;
+ n->relation = $7;
+ n->tableElts = $9;
+ n->inhRelations = $11;
+ n->constraints = NIL;
+ n->options = $12;
+ n->oncommit = $13;
+ n->tablespacename = $14;
+ n->if_not_exists = true;
$$ = (Node *)n;
}
| CREATE OptTemp TABLE qualified_name OF any_name
@@ -2227,6 +2244,22 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->options = $8;
n->oncommit = $9;
n->tablespacename = $10;
+ n->if_not_exists = false;
+ $$ = (Node *)n;
+ }
+ | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name
+ OptTypedTableElementList OptWith OnCommitOption OptTableSpace
+ {
+ CreateStmt *n = makeNode(CreateStmt);
+ n->relation = $7;
+ n->tableElts = $10;
+ n->ofTypename = makeTypeNameFromNameList($9);
+ n->ofTypename->location = @9;
+ n->constraints = NIL;
+ n->options = $11;
+ n->oncommit = $12;
+ n->tablespacename = $13;
+ n->if_not_exists = true;
$$ = (Node *)n;
}
;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 33b1aca72dc..db5c6e9c086 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.335 2010/02/26 02:01:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.336 2010/07/25 23:21:22 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -513,6 +513,13 @@ standard_ProcessUtility(Node *parsetree,
RELKIND_RELATION);
/*
+ * If "IF NOT EXISTS" was specified and the relation
+ * already exists, do nothing further.
+ */
+ if (relOid == InvalidOid)
+ continue;
+
+ /*
* Let AlterTableCreateToastTable decide if this one
* needs a secondary relation too.
*/
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 557c311bc22..681239a5c9c 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.98 2010/02/26 02:01:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.99 2010/07/25 23:21:22 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,7 +61,8 @@ extern Oid heap_create_with_catalog(const char *relname,
OnCommitAction oncommit,
Datum reloptions,
bool use_user_acl,
- bool allow_system_table_mods);
+ bool allow_system_table_mods,
+ bool if_not_exists);
extern void heap_drop_with_catalog(Oid relid);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5325f7e924b..17082253669 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.432 2010/02/26 02:01:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.433 2010/07/25 23:21:22 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1375,6 +1375,7 @@ typedef struct CreateStmt
List *options; /* options from WITH clause */
OnCommitAction oncommit; /* what do we do at COMMIT? */
char *tablespacename; /* table space to use, or NULL */
+ bool if_not_exists; /* just do nothing if it already exists? */
} CreateStmt;
/* ----------
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index daecabb5b72..6f65885c82c 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -196,7 +196,11 @@ CREATE TABLE array_index_op_test (
i int4[],
t text[]
);
-CREATE TABLE test_tsvector(
+CREATE TABLE IF NOT EXISTS test_tsvector(
t text,
a tsvector
);
+CREATE TABLE IF NOT EXISTS test_tsvector(
+ t text
+);
+NOTICE: relation "test_tsvector" already exists, skipping
diff --git a/src/test/regress/expected/typed_table.out b/src/test/regress/expected/typed_table.out
index 9b933fdadcb..8bb9a1dd6a7 100644
--- a/src/test/regress/expected/typed_table.out
+++ b/src/test/regress/expected/typed_table.out
@@ -2,6 +2,8 @@ CREATE TABLE ttable1 OF nothing;
ERROR: type "nothing" does not exist
CREATE TYPE person_type AS (id int, name text);
CREATE TABLE persons OF person_type;
+CREATE TABLE IF NOT EXISTS persons OF person_type;
+NOTICE: relation "persons" already exists, skipping
SELECT * FROM persons;
id | name
----+------
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index e43371eed93..f491e8c142f 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -232,8 +232,11 @@ CREATE TABLE array_index_op_test (
t text[]
);
-CREATE TABLE test_tsvector(
+CREATE TABLE IF NOT EXISTS test_tsvector(
t text,
a tsvector
);
+CREATE TABLE IF NOT EXISTS test_tsvector(
+ t text
+);
diff --git a/src/test/regress/sql/typed_table.sql b/src/test/regress/sql/typed_table.sql
index 60cb6d6857e..1afede14b10 100644
--- a/src/test/regress/sql/typed_table.sql
+++ b/src/test/regress/sql/typed_table.sql
@@ -2,6 +2,7 @@ CREATE TABLE ttable1 OF nothing;
CREATE TYPE person_type AS (id int, name text);
CREATE TABLE persons OF person_type;
+CREATE TABLE IF NOT EXISTS persons OF person_type;
SELECT * FROM persons;
\d persons