From 97b4e5ad309b169886a218189804cede0a1eed26 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 5 Apr 2002 11:56:55 +0000
Subject: [PATCH] Add INSERT(..., DEFAULT, ).

Rod Taylor
---
 src/backend/nodes/copyfuncs.c        | 14 +++++++++++++-
 src/backend/nodes/equalfuncs.c       | 11 ++++++++++-
 src/backend/parser/analyze.c         | 24 ++++++++++++++++++++----
 src/backend/parser/gram.y            | 27 ++++++++++++++++++++++-----
 src/backend/parser/parse_target.c    | 14 ++++++++++++--
 src/include/nodes/nodes.h            |  3 ++-
 src/include/nodes/parsenodes.h       | 10 +++++++++-
 src/test/regress/expected/insert.out | 20 ++++++++++++++++++++
 src/test/regress/parallel_schedule   |  1 +
 src/test/regress/serial_schedule     |  3 ++-
 src/test/regress/sql/insert.sql      | 12 ++++++++++++
 11 files changed, 123 insertions(+), 16 deletions(-)
 create mode 100644 src/test/regress/expected/insert.out
 create mode 100644 src/test/regress/sql/insert.sql

diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 055e3c371e2..b633b02b79d 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
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.174 2002/03/29 19:06:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.175 2002/04/05 11:56:48 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1947,6 +1947,15 @@ _copyFuncWithArgs(FuncWithArgs *from)
 	return newnode;
 }
 
+static InsertDefault *
+_copyInsertDefault(InsertDefault *from)
+{
+	InsertDefault *newnode = makeNode(InsertDefault);
+
+	return newnode;
+}
+
+
 static ClosePortalStmt *
 _copyClosePortalStmt(ClosePortalStmt *from)
 {
@@ -3055,6 +3064,9 @@ copyObject(void *from)
 		case T_FuncWithArgs:
 			retval = _copyFuncWithArgs(from);
 			break;
+		case T_InsertDefault:
+			retval = _copyInsertDefault(from);
+			break;
 
 		default:
 			elog(ERROR, "copyObject: don't know how to copy node type %d",
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fee607419a5..eceb8cb36f7 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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.122 2002/03/29 19:06:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.123 2002/04/05 11:56:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -773,6 +773,12 @@ _equalFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b)
 		&& equal(a->funcargs, b->funcargs);
 }
 
+static bool
+_equalInsertDefault(InsertDefault *a, InsertDefault *b)
+{
+	return true;
+}
+
 static bool
 _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
 {
@@ -2215,6 +2221,9 @@ equal(void *a, void *b)
 		case T_FuncWithArgs:
 			retval = _equalFuncWithArgs(a, b);
 			break;
+		case T_InsertDefault:
+			retval = _equalInsertDefault(a, b);
+			break;
 
 		default:
 			elog(WARNING, "equal: don't know whether nodes of type %d are equal",
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 080392b97f5..0de9c5bb851 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.226 2002/04/02 06:30:34 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.227 2002/04/05 11:56:51 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -518,13 +518,29 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
 		TargetEntry *tle = (TargetEntry *) lfirst(tl);
 		ResTarget   *col;
 
-		Assert(!tle->resdom->resjunk);
 		if (icolumns == NIL || attnos == NIL)
 			elog(ERROR, "INSERT has more expressions than target columns");
 		col = (ResTarget *) lfirst(icolumns);
-		Assert(IsA(col, ResTarget));
-		updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
+
+		/*
+		 * When the value is to be set to the column default we can simply
+		 * drop it now and handle it later on using methods for missing
+		 * columns.
+		 */
+		if (!IsA(tle, InsertDefault))
+		{
+			Assert(IsA(col, ResTarget));
+			Assert(!tle->resdom->resjunk);
+			updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
 							  col->indirection);
+		}
+		else
+		{
+			icolumns = lremove(icolumns, icolumns);
+			attnos = lremove(attnos, attnos);
+			qry->targetList = lremove(tle, qry->targetList);
+		}
+
 		icolumns = lnext(icolumns);
 		attnos = lnext(attnos);
 	}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 4e2c2e70336..6ba8766e1ac 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.299 2002/04/01 04:35:38 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.300 2002/04/05 11:56:53 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -203,6 +203,7 @@ static bool set_name_needs_quotes(const char *name);
 		from_clause, from_list, opt_array_bounds, qualified_name_list,
 		any_name, any_name_list, expr_list, dotted_name, attrs,
 		target_list, update_target_list, insert_column_list,
+		insert_target_list,
 		def_list, opt_indirection, group_clause, TriggerFuncArgs,
 		select_limit, opt_select_limit
 
@@ -263,7 +264,7 @@ static bool set_name_needs_quotes(const char *name);
 %type <node>	table_ref
 %type <jexpr>	joined_table
 %type <range>	relation_expr
-%type <target>	target_el, update_target_el
+%type <target>	target_el, insert_target_el, update_target_el
 
 %type <typnam>	Typename, SimpleTypename, ConstTypename
 				GenericType, Numeric, Character, ConstDatetime, ConstInterval, Bit
@@ -3504,7 +3505,7 @@ InsertStmt:  INSERT INTO qualified_name insert_rest
 				}
 		;
 
-insert_rest:  VALUES '(' target_list ')'
+insert_rest:  VALUES '(' insert_target_list ')'
 				{
 					$$ = makeNode(InsertStmt);
 					$$->cols = NIL;
@@ -3525,7 +3526,7 @@ insert_rest:  VALUES '(' target_list ')'
 					$$->targetList = NIL;
 					$$->selectStmt = $1;
 				}
-		| '(' insert_column_list ')' VALUES '(' target_list ')'
+		| '(' insert_column_list ')' VALUES '(' insert_target_list ')'
 				{
 					$$ = makeNode(InsertStmt);
 					$$->cols = $2;
@@ -5244,7 +5245,6 @@ c_expr:  columnref
 					s->val.type = T_String;
 					s->val.val.str = "now";
 					s->typename = makeTypeName(xlateSqlType("text"));
-
 					d = makeTypeName(xlateSqlType("timetz"));
 					if (($3 < 0) || ($3 > 13))
 						elog(ERROR,"CURRENT_TIME(%d) precision must be between %d and %d",
@@ -5721,6 +5721,23 @@ update_target_el:  ColId opt_indirection '=' a_expr
 				}
 		;
 
+insert_target_list:  insert_target_list ',' insert_target_el
+				{	$$ = lappend($1, $3);  }
+		| insert_target_el
+				{	$$ = makeList1($1);  }
+		;
+
+insert_target_el:  target_el	{	$$ = $1;  }
+				| DEFAULT		{	
+									InsertDefault *def = makeNode(InsertDefault);
+									$$ = makeNode(ResTarget);
+									$$->name = NULL;
+									$$->indirection = NULL;
+									$$->val = (Node *)def;
+								}
+				;
+
+
 /*****************************************************************************
  *
  *	Names and constants
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 3ffef8e617a..e8e82a45c3b 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.81 2002/04/02 08:51:52 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.82 2002/04/05 11:56:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,9 +175,19 @@ transformTargetList(ParseState *pstate, List *targetlist)
 														false));
 			}
 		}
+		else if (IsA(res->val, InsertDefault))
+		{
+			InsertDefault *newnode = makeNode(InsertDefault);
+
+			/*
+			 * If this is a DEFAULT element, we make a junk entry
+			 * which will get dropped on return to transformInsertStmt().
+			 */
+			p_target = lappend(p_target, newnode);
+		}
 		else
 		{
-			/* Everything else but ColumnRef */
+			/* Everything else but ColumnRef and InsertDefault */
 			p_target = lappend(p_target,
 							   transformTargetEntry(pstate,
 													res->val,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 34510c0d792..ff03eb12284 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.103 2002/03/22 02:56:36 tgl Exp $
+ * $Id: nodes.h,v 1.104 2002/04/05 11:56:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -229,6 +229,7 @@ typedef enum NodeTag
 	T_PrivGrantee,
 	T_FuncWithArgs,
 	T_PrivTarget,
+	T_InsertDefault,
 
 	/*
 	 * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 4cccc6a7d2a..e2b0d9f38f3 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.167 2002/04/01 04:35:40 tgl Exp $
+ * $Id: parsenodes.h,v 1.168 2002/04/05 11:56:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -359,6 +359,14 @@ typedef struct ResTarget
 								 * assign */
 } ResTarget;
 
+/*
+ * Empty node used as a marker for Default Columns
+ */
+typedef struct InsertDefault
+{
+	NodeTag		type;
+} InsertDefault;
+
 /*
  * SortGroupBy - for ORDER BY clause
  */
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
new file mode 100644
index 00000000000..f0688762f57
--- /dev/null
+++ b/src/test/regress/expected/insert.out
@@ -0,0 +1,20 @@
+--
+-- insert with DEFAULT in the target_list
+--
+create table inserttest (col1 int4, col2 int4 NOT NULL, col3 text default 'testing');
+insert into inserttest (col1, col2, col3) values (DEFAULT, DEFAULT, DEFAULT);
+ERROR:  ExecAppend: Fail to add null value in not null attribute col2
+insert into inserttest (col2, col3) values (3, DEFAULT);
+insert into inserttest (col1, col2, col3) values (DEFAULT, 5, DEFAULT);
+insert into inserttest values (DEFAULT, 5, 'test');
+insert into inserttest values (DEFAULT, 7);
+select * from inserttest;
+ col1 | col2 |  col3   
+------+------+---------
+      |    3 | testing
+      |    5 | testing
+      |    5 | test
+      |    7 | testing
+(4 rows)
+
+drop table inserttest;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index cd9d2d5260a..c28d4c66eb4 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -21,6 +21,7 @@ test: horology
 # ----------
 # These four each depend on the previous one
 # ----------
+test: insert
 test: create_function_1
 test: create_type
 test: create_table
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index c56b3561c2f..58a9a3b9449 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -1,4 +1,4 @@
-# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.8 2002/03/19 02:18:24 momjian Exp $
+# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.9 2002/04/05 11:56:55 momjian Exp $
 # This should probably be in an order similar to parallel_schedule.
 test: boolean
 test: char
@@ -37,6 +37,7 @@ test: type_sanity
 test: opr_sanity
 test: geometry
 test: horology
+test: insert
 test: create_function_1
 test: create_type
 test: create_table
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
new file mode 100644
index 00000000000..5d42c87649f
--- /dev/null
+++ b/src/test/regress/sql/insert.sql
@@ -0,0 +1,12 @@
+--
+-- insert with DEFAULT in the target_list
+--
+create table inserttest (col1 int4, col2 int4 NOT NULL, col3 text default 'testing');
+insert into inserttest (col1, col2, col3) values (DEFAULT, DEFAULT, DEFAULT);
+insert into inserttest (col2, col3) values (3, DEFAULT);
+insert into inserttest (col1, col2, col3) values (DEFAULT, 5, DEFAULT);
+insert into inserttest values (DEFAULT, 5, 'test');
+insert into inserttest values (DEFAULT, 7);
+
+select * from inserttest;
+drop table inserttest;
-- 
GitLab