From a1212d09a13ea1d1d20dbcd541e2351669f095f9 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 20 Dec 2008 15:51:28 +0000
Subject: [PATCH] Fix various confusions of pointers and OIDs, unsafe
 assumptions about nulls, etc.  I think this will fix the current buildfarm
 issues ...

---
 src/backend/commands/foreigncmds.c | 49 +++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 17 deletions(-)

diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index c9decf953cf..27dd1b92fb8 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.2 2008/12/20 09:40:56 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.3 2008/12/20 15:51:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,8 @@
 /*
  * Convert a DefElem list to the text array format that is used in
  * pg_foreign_data_wrapper, pg_foreign_server, and pg_user_mapping.
+ * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
+ * if the list is empty.
  *
  * Note: The array is usually stored to database without further
  * processing, hence any validation should be done before this
@@ -45,13 +47,13 @@ optionListToArray(List *options)
 {
 	ArrayBuildState    *astate = NULL;
 	ListCell		   *cell;
-	text			   *t;
 
-	foreach (cell, options)
+	foreach(cell, options)
 	{
 		DefElem    *def = lfirst(cell);
-		const char *value = "";
+		const char *value;
 		Size		len;
+		text	   *t;
 
 		value = defGetString(def);
 		len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
@@ -76,6 +78,9 @@ optionListToArray(List *options)
  * The result is converted to array of text suitable for storing in
  * options.
  *
+ * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
+ * if the list is empty.
+ *
  * This is used by CREATE/ALTER of FOREIGN DATA WRAPPER/SERVER/USER
  * MAPPING.  In the ALTER cases, oldOptions is the current text array
  * of options.
@@ -90,15 +95,15 @@ transformGenericOptions(Datum oldOptions,
 	List	 *resultOptions = untransformRelOptions(oldOptions);
 	ListCell *optcell;
 
-	foreach (optcell, optionDefList)
+	foreach(optcell, optionDefList)
 	{
+		OptionDefElem	*od = lfirst(optcell);
 		ListCell	    *cell;
 		ListCell		*prev = NULL;
-		OptionDefElem	*od = lfirst(optcell);
 
 		/*
 		 * Find the element in resultOptions.  We need this for
-		 * validation in all cases.
+		 * validation in all cases.  Also identify the previous element.
 		 */
 		foreach (cell, resultOptions)
 		{
@@ -190,7 +195,6 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
 	HeapTuple	tup;
 	Relation	rel;
 	Oid			fdwId;
-
 	Form_pg_foreign_data_wrapper form;
 
     /* Must be a superuser to change a FDW owner */
@@ -345,7 +349,8 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	 */
 	rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
 
-	MemSet(nulls, false, Natts_pg_foreign_data_wrapper);
+	memset(values, 0, sizeof(values));
+	memset(nulls, false, sizeof(nulls));
 
 	values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
 		DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
@@ -359,7 +364,8 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	 */
 	fdwlib = GetForeignDataWrapperLibrary(stmt->library);
 
-	fdwoptions = transformGenericOptions(0, stmt->options, FdwOpt, NULL,
+	fdwoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
+										 FdwOpt, NULL,
 										 fdwlib->validateOptionList);
 
 	if (PointerIsValid(DatumGetPointer(fdwoptions)))
@@ -447,6 +453,7 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 								tp,
 								Anum_pg_foreign_data_wrapper_fdwlibrary,
 								&isnull);
+		Assert(!isnull);
 		fdwlib = GetForeignDataWrapperLibrary(TextDatumGetCString(datum));
 	}
 
@@ -460,13 +467,15 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 								tp,
 								Anum_pg_foreign_data_wrapper_fdwoptions,
 								&isnull);
+		if (isnull)
+			datum = PointerGetDatum(NULL);
 
 		/* Transform the options */
 		datum = transformGenericOptions(datum, stmt->options, FdwOpt,
 										NULL, fdwlib->validateOptionList);
 
 		if (PointerIsValid(DatumGetPointer(datum)))
-			repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = ObjectIdGetDatum(datum);
+			repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
 		else
 			repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
 
@@ -603,7 +612,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	 */
 	rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
 
-	MemSet(nulls, false, Natts_pg_foreign_server);
+	memset(values, 0, sizeof(values));
+	memset(nulls, false, sizeof(nulls));
 
 	values[Anum_pg_foreign_server_srvname - 1] =
 		DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
@@ -628,7 +638,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	nulls[Anum_pg_foreign_server_srvacl - 1] = true;
 
 	/* Add server options */
-	srvoptions = transformGenericOptions(0, stmt->options, ServerOpt, fdw,
+	srvoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
+										 ServerOpt, fdw,
 										 fdw->lib->validateOptionList);
 
 	if (PointerIsValid(DatumGetPointer(srvoptions)))
@@ -722,6 +733,8 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 								tp,
 								Anum_pg_foreign_server_srvoptions,
 								&isnull);
+		if (isnull)
+			datum = PointerGetDatum(NULL);
 
 		/* Prepare the options array */
 		datum = transformGenericOptions(datum, stmt->options, ServerOpt,
@@ -868,13 +881,15 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	 */
 	rel = heap_open(UserMappingRelationId, RowExclusiveLock);
 
-	MemSet(nulls, false, Natts_pg_user_mapping);
+	memset(values, 0, sizeof(values));
+	memset(nulls, false, sizeof(nulls));
 
 	values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
 	values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
 
 	/* Add user options */
-	useoptions = transformGenericOptions(0, stmt->options, UserMappingOpt,
+	useoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
+										 UserMappingOpt,
 										 fdw, fdw->lib->validateOptionList);
 
 	if (PointerIsValid(DatumGetPointer(useoptions)))
@@ -931,12 +946,10 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
 						  ObjectIdGetDatum(srv->serverid),
 						  0, 0);
 	if (!OidIsValid(umId))
-	{
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				errmsg("user mapping \"%s\" does not exist for the server",
 					MappingUserName(useId))));
-	}
 
 	/*
 	 * Must be owner of the server to alter user mapping.
@@ -972,6 +985,8 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
 								tp,
 								Anum_pg_user_mapping_umoptions,
 								&isnull);
+		if (isnull)
+			datum = PointerGetDatum(NULL);
 
 		/* Prepare the options array */
 		datum = transformGenericOptions(datum, stmt->options, UserMappingOpt,
-- 
GitLab