From 4d06e86d041b48a2ecd4f45e2ecbbcf69f3454c0 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 30 May 2006 13:40:56 +0000
Subject: [PATCH] Revert patch, needs more work:

---------------------------------------------------------------------------

Add dynamic record inspection to PL/PgSQL, useful for generic triggers:

  tval2 := r.(cname);

or

  columns := r.(*);

Titus von Boxberg
---
 doc/src/sgml/plpgsql.sgml             |  51 +------
 src/pl/plpgsql/src/pl_comp.c          | 134 +---------------
 src/pl/plpgsql/src/pl_exec.c          | 211 ++++----------------------
 src/pl/plpgsql/src/pl_funcs.c         |  12 +-
 src/pl/plpgsql/src/plpgsql.h          |  24 +--
 src/pl/plpgsql/src/scan.l             |   8 +-
 src/test/regress/expected/plpgsql.out |  38 -----
 src/test/regress/sql/plpgsql.sql      |  32 ----
 8 files changed, 38 insertions(+), 472 deletions(-)

diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index ecbfb49f1f2..f0cbbf2896c 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.93 2006/05/30 12:03:12 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.94 2006/05/30 13:40:55 momjian Exp $ -->
 
 <chapter id="plpgsql"> 
   <title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
@@ -879,55 +879,6 @@ SELECT merge_fields(t.*) FROM table1 t WHERE ... ;
     field in it will draw a run-time error.
    </para>
 
-   <para>
-    To obtain the values of the fields the record is made up of,
-    the record variable can be qualified with the column or field
-    name. This can be done either by literally using the column name
-    or the column name for indexing the record can be taken out of a scalar
-    variable. The syntax for this notation is Record_variable.(IndexVariable).
-    To get information about the column field names of the record, 
-    a special expression exists that returns all column names as an array: 
-    RecordVariable.(*) .
-    Thus, the RECORD can be viewed
-    as an associative array that allows for introspection of it's contents.
-    This feature is especially useful for writing generic triggers that
-    operate on records with unknown structure.
-    Here is an example procedure that shows column names and values
-    of the predefined record NEW in a trigger procedure:
-<programlisting>
-
-CREATE OR REPLACE FUNCTION show_associative_records() RETURNS TRIGGER AS $$
-	DECLARE
-		colname		TEXT;
-		colcontent	TEXT;
-		colnames	TEXT[];
-		coln		INT4;
-		coli		INT4;
-	BEGIN
--- obtain an array with all field names of the record
-		colnames := NEW.(*);
-		RAISE NOTICE 'All column names of test record: %', colnames;
--- show field names and contents of record
-		coli := 1;
-		coln := array_upper(colnames,1);
-		RAISE NOTICE 'Number of columns in NEW: %', coln;
-		FOR coli IN 1 .. coln LOOP
-			colname := colnames[coli];
-			colcontent := NEW.(colname);
-			RAISE NOTICE 'column % of NEW: %', quote_ident(colname), quote_literal(colcontent);
-		END LOOP;
--- Do it with a fixed field name:
--- will have to know the column name
-		RAISE NOTICE 'column someint of NEW: %', quote_literal(NEW.someint);
-		RETURN NULL;
-	END;
-$$ LANGUAGE plpgsql;
---CREATE TABLE test_records (someint INT8, somestring TEXT);
---CREATE TRIGGER tr_test_record BEFORE INSERT ON test_records FOR EACH ROW EXECUTE PROCEDURE show_associative_records();
-
-</programlisting>
-   </para>
-
    <para>
     Note that <literal>RECORD</> is not a true data type, only a placeholder.
     One should also realize that when a <application>PL/pgSQL</application>
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index db7bc6bb106..e904a4dfbbe 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.105 2006/05/30 12:03:13 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.106 2006/05/30 13:40:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -884,8 +884,7 @@ plpgsql_parse_dblword(char *word)
 
 				new = palloc(sizeof(PLpgSQL_recfield));
 				new->dtype = PLPGSQL_DTYPE_RECFIELD;
-				new->fieldindex.fieldname = pstrdup(cp[1]);
-				new->fieldindex_flag = RECFIELD_USE_FIELDNAME;
+				new->fieldname = pstrdup(cp[1]);
 				new->recparentno = ns->itemno;
 
 				plpgsql_adddatum((PLpgSQL_datum *) new);
@@ -991,8 +990,7 @@ plpgsql_parse_tripword(char *word)
 
 				new = palloc(sizeof(PLpgSQL_recfield));
 				new->dtype = PLPGSQL_DTYPE_RECFIELD;
-				new->fieldindex.fieldname = pstrdup(cp[2]);
-				new->fieldindex_flag = RECFIELD_USE_FIELDNAME;
+				new->fieldname = pstrdup(cp[2]);
 				new->recparentno = ns->itemno;
 
 				plpgsql_adddatum((PLpgSQL_datum *) new);
@@ -1440,132 +1438,6 @@ plpgsql_parse_dblwordrowtype(char *word)
 	return T_DTYPE;
 }
 
-/* ----------
- * plpgsql_parse_recindex
- * lookup associative index into record
- * ----------
- */
-int
-plpgsql_parse_recindex(char *word)
-{
-	PLpgSQL_nsitem *ns1, *ns2;
-	char		*cp[2];
-	int		ret = T_ERROR;
-	char		*fieldvar;
-	int		fl;
-
-	/* Do case conversion and word separation */
-	plpgsql_convert_ident(word, cp, 2);
-	Assert(cp[1] != NULL);
-
-	/* cleanup the "(identifier)" string to "identifier" */
-	fieldvar = cp[1];
-	Assert(*fieldvar == '(');
-	++fieldvar;	/* get rid of ( */
-
-	fl = strlen(fieldvar);
-	Assert(fieldvar[fl-1] == ')');
-	fieldvar[fl-1] = 0; /* get rid of ) */
-
-	/*
-	 * Lookup the first word
-	 */
-	ns1 = plpgsql_ns_lookup(cp[0], NULL);
-	if ( ns1 == NULL )
-	{
-		pfree(cp[0]);
-		pfree(cp[1]);
-		return T_ERROR;
-	}
-
-	ns2 = plpgsql_ns_lookup(fieldvar, NULL);
-	pfree(cp[0]);
-	pfree(cp[1]);
-	if ( ns2 == NULL )	/* name lookup failed */
-		return T_ERROR;
-
-	switch (ns1->itemtype)
-	{
-		case PLPGSQL_NSTYPE_REC:
-			{
-				/*
-				 * First word is a record name, so second word must be an
-				 * variable holding the field name in this record.
-				 */
-				if ( ns2->itemtype == PLPGSQL_NSTYPE_VAR ) {
-					PLpgSQL_recfield *new;
-
-					new = palloc(sizeof(PLpgSQL_recfield));
-					new->dtype = PLPGSQL_DTYPE_RECFIELD;
-					new->fieldindex.indexvar_no = ns2->itemno;
-					new->fieldindex_flag = RECFIELD_USE_INDEX_VAR;
-					new->recparentno = ns1->itemno;
-
-					plpgsql_adddatum((PLpgSQL_datum *) new);
-
-					plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
-					ret =  T_SCALAR;
-				} 
-				break;
-			}
-		default:
-			break;
-	}
-	return ret;
-} 
-
-
-/* ----------
- * plpgsql_parse_recfieldnames
- * create fieldnames of a record
- * ----------
- */
-int
-plpgsql_parse_recfieldnames(char *word)
-{
-	PLpgSQL_nsitem	*ns1;
-	char		*cp[2];
-	int		ret = T_ERROR;
-
-	/* Do case conversion and word separation */
-	plpgsql_convert_ident(word, cp, 2);
-
-	/*
-	 * Lookup the first word
-	 */
-	ns1 = plpgsql_ns_lookup(cp[0], NULL);
-	if ( ns1 == NULL )
-	{
-		pfree(cp[0]);
-		pfree(cp[1]);
-		return T_ERROR;
-	}
-
-	pfree(cp[0]);
-	pfree(cp[1]);
-
-	switch (ns1->itemtype)
-	{
-		case PLPGSQL_NSTYPE_REC:
-			{
-				PLpgSQL_recfieldproperties *new;
-
-				new = palloc(sizeof(PLpgSQL_recfieldproperties));
-				new->dtype = PLPGSQL_DTYPE_RECFIELDNAMES;
-				new->recparentno = ns1->itemno;
-				new->save_fieldnames = NULL;
-				plpgsql_adddatum((PLpgSQL_datum *) new);
-				plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
-				ret =  T_SCALAR;	/* ??? */
-				break;
-			}
-		default:
-			break;
-	}
-	return ret;
-}
-
-
 /*
  * plpgsql_build_variable - build a datum-array entry of a given
  * datatype
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 07f1211f4e5..b27849c8913 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.168 2006/05/30 12:03:13 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.169 2006/05/30 13:40:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -741,7 +741,7 @@ copy_plpgsql_datum(PLpgSQL_datum *datum)
 		case PLPGSQL_DTYPE_RECFIELD:
 		case PLPGSQL_DTYPE_ARRAYELEM:
 		case PLPGSQL_DTYPE_TRIGARG:
-		case PLPGSQL_DTYPE_RECFIELDNAMES:
+
 			/*
 			 * These datum records are read-only at runtime, so no need to
 			 * copy them
@@ -851,7 +851,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
 			case PLPGSQL_DTYPE_RECFIELD:
 			case PLPGSQL_DTYPE_ARRAYELEM:
-			case PLPGSQL_DTYPE_RECFIELDNAMES:
 				break;
 
 			default:
@@ -2180,8 +2179,6 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
 static void
 exec_eval_cleanup(PLpgSQL_execstate *estate)
 {
-	int		i;
-	ArrayType	*a;
 	/* Clear result of a full SPI_execute */
 	if (estate->eval_tuptable != NULL)
 		SPI_freetuptable(estate->eval_tuptable);
@@ -2190,14 +2187,6 @@ exec_eval_cleanup(PLpgSQL_execstate *estate)
 	/* Clear result of exec_eval_simple_expr (but keep the econtext) */
 	if (estate->eval_econtext != NULL)
 		ResetExprContext(estate->eval_econtext);
-	for ( i = 0; i < estate->ndatums; ++i ) {
-		if ( estate->datums[i]->dtype == PLPGSQL_DTYPE_RECFIELDNAMES ) {
-			a = ((PLpgSQL_recfieldproperties *)(estate->datums[i]))->save_fieldnames;
-			if ( a )
-				pfree(a);
-			((PLpgSQL_recfieldproperties *)(estate->datums[i]))->save_fieldnames = NULL;
-		}
-	}
 }
 
 
@@ -3167,7 +3156,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
 				 */
 				PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
 				PLpgSQL_rec *rec;
-				int			fno = 0;
+				int			fno;
 				HeapTuple	newtup;
 				int			natts;
 				int			i;
@@ -3196,35 +3185,12 @@ exec_assign_value(PLpgSQL_execstate *estate,
 				 * Get the number of the records field to change and the
 				 * number of attributes in the tuple.
 				 */
-				if ( recfield->fieldindex_flag == RECFIELD_USE_FIELDNAME ) {
-					fno = SPI_fnumber(rec->tupdesc, recfield->fieldindex.fieldname);
-					if (fno == SPI_ERROR_NOATTRIBUTE)
-						ereport(ERROR,
-								(errcode(ERRCODE_UNDEFINED_COLUMN),
-								 errmsg("record \"%s\" has no field \"%s\"",
-										rec->refname, recfield->fieldindex.fieldname)));
-				}
-				else if ( recfield->fieldindex_flag == RECFIELD_USE_INDEX_VAR ) {
-					PLpgSQL_var * idxvar = (PLpgSQL_var *) (estate->datums[recfield->fieldindex.indexvar_no]);
-					char * fname = convert_value_to_string(idxvar->value, idxvar->datatype->typoid);
-					if ( fname == NULL )
-						ereport(ERROR,
-								(errcode(ERRCODE_UNDEFINED_COLUMN),
-								errmsg("record \"%s\": cannot evaluate variable to record index string",
-										rec->refname)));
-					fno = SPI_fnumber(rec->tupdesc, fname);
-					pfree(fname);
-					if (fno == SPI_ERROR_NOATTRIBUTE)
-						ereport(ERROR,
-								(errcode(ERRCODE_UNDEFINED_COLUMN),
-								 errmsg("record \"%s\" has no field \"%s\"",
-										rec->refname, fname)));
-				}
-				else
+				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
+				if (fno == SPI_ERROR_NOATTRIBUTE)
 					ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_COLUMN),
-						errmsg("record \"%s\": internal error",
-									rec->refname)));
+							(errcode(ERRCODE_UNDEFINED_COLUMN),
+							 errmsg("record \"%s\" has no field \"%s\"",
+									rec->refname, recfield->fieldname)));
 				fno--;
 				natts = rec->tupdesc->natts;
 
@@ -3544,7 +3510,7 @@ exec_eval_datum(PLpgSQL_execstate *estate,
 			{
 				PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
 				PLpgSQL_rec *rec;
-				int			fno = 0;
+				int			fno;
 
 				rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
 				if (!HeapTupleIsValid(rec->tup))
@@ -3553,125 +3519,22 @@ exec_eval_datum(PLpgSQL_execstate *estate,
 						   errmsg("record \"%s\" is not assigned yet",
 								  rec->refname),
 						   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
- 				if ( recfield->fieldindex_flag == RECFIELD_USE_FIELDNAME ) {
- 					fno = SPI_fnumber(rec->tupdesc, recfield->fieldindex.fieldname);
- 					if (fno == SPI_ERROR_NOATTRIBUTE)
- 						ereport(ERROR,
- 								(errcode(ERRCODE_UNDEFINED_COLUMN),
- 								 errmsg("record \"%s\" has no field \"%s\"",
- 										rec->refname, recfield->fieldindex.fieldname)));
- 				}
- 				else if ( recfield->fieldindex_flag == RECFIELD_USE_INDEX_VAR ) {
- 					PLpgSQL_var * idxvar = (PLpgSQL_var *) (estate->datums[recfield->fieldindex.indexvar_no]);
- 					char * fname = convert_value_to_string(idxvar->value, idxvar->datatype->typoid);
- 					if ( fname == NULL )
- 						ereport(ERROR,
- 								(errcode(ERRCODE_UNDEFINED_COLUMN),
- 								errmsg("record \"%s\": cannot evaluate variable to record index string",
- 										rec->refname)));
- 					fno = SPI_fnumber(rec->tupdesc, fname);
- 					pfree(fname);
- 					if (fno == SPI_ERROR_NOATTRIBUTE)
- 						ereport(ERROR,
- 								(errcode(ERRCODE_UNDEFINED_COLUMN),
- 								 errmsg("record \"%s\" has no field \"%s\"",
- 										rec->refname, fname)));
- 				}
- 				else
- 					ereport(ERROR,
- 						(errcode(ERRCODE_UNDEFINED_COLUMN),
- 						errmsg("record \"%s\": internal error",
- 								rec->refname)));
- 
- 				/* Do not allow typeids to become "narrowed" by InvalidOids 
- 				causing specialized typeids from the tuple restricting the destination */
- 				if ( expectedtypeid != InvalidOid && expectedtypeid != SPI_gettypeid(rec->tupdesc, fno) ) {
- 					Datum cval = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
- 					cval =   exec_simple_cast_value(cval,
- 									SPI_gettypeid(rec->tupdesc, fno),
- 									expectedtypeid,
- 									-1,
- 									*isnull);
- 
- 					*value = cval;
- 					*typeid = expectedtypeid;
- 					/* ereport(ERROR,
- 							(errcode(ERRCODE_DATATYPE_MISMATCH),
- 							 errmsg("type of \"%s\" does not match that when preparing the plan",
- 									rec->refname)));
- 					*/
- 				} 
- 				else { /* expected typeid matches */
- 					*value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
- 					*typeid = SPI_gettypeid(rec->tupdesc, fno);
- 				} 
- 				break;
- 			}
- 
- 		case PLPGSQL_DTYPE_RECFIELDNAMES:
- 			/* Construct array datum from record field names */
- 			{
- 				Oid			arraytypeid,
- 							arrayelemtypeid = TEXTOID;
- 				int16			arraytyplen,
- 							elemtyplen;
- 				bool			elemtypbyval;
- 				char			elemtypalign;
- 				ArrayType		*arrayval;
- 				PLpgSQL_recfieldproperties * recfp = (PLpgSQL_recfieldproperties *) datum;
- 				PLpgSQL_rec		*rec = (PLpgSQL_rec *) (estate->datums[recfp->recparentno]);
- 				int			fc, tfc = 0;
- 				Datum			*arrayelems;
- 				char			*fieldname;
- 
- 				if (!HeapTupleIsValid(rec->tup))
- 					ereport(ERROR,
- 					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- 					   errmsg("record \"%s\" is not assigned yet",
- 							  rec->refname),
- 					   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
- 				arrayelems = palloc(sizeof(Datum) * rec->tupdesc->natts);
- 				arraytypeid = get_array_type(arrayelemtypeid);
- 				arraytyplen = get_typlen(arraytypeid);
- 				get_typlenbyvalalign(arrayelemtypeid,
- 						     &elemtyplen,
- 						     &elemtypbyval,
- 						     &elemtypalign);
- 
- 				if ( expectedtypeid != InvalidOid && expectedtypeid != arraytypeid )
- 					ereport(ERROR,
- 							(errcode(ERRCODE_DATATYPE_MISMATCH),
- 							 errmsg("type of \"%s\" does not match array type when preparing the plan",
- 									rec->refname)));
- 				for ( fc = 0; fc < rec->tupdesc->natts; ++fc ) {
- 					fieldname = SPI_fname(rec->tupdesc, fc+1);
- 					if ( fieldname ) {
- 						arrayelems[fc] = DirectFunctionCall1(textin, CStringGetDatum(fieldname));
- 						pfree(fieldname);
- 						++tfc;
- 					} 
- 				} 
- 				arrayval = construct_array(arrayelems, tfc,
- 							 arrayelemtypeid,
- 							 elemtyplen,
- 							 elemtypbyval,
- 							 elemtypalign);
- 
- 
- 				/* construct_array copies data; free temp elem array */
- 				for ( fc = 0; fc < tfc; ++fc )
- 					pfree(DatumGetPointer(arrayelems[fc]));
- 				pfree(arrayelems);
- 				*value = PointerGetDatum(arrayval);
- 				*typeid = arraytypeid;
- 				*isnull = false;
- 				/* need to save the pointer because otherwise it does not get freed */
- 				if ( recfp->save_fieldnames )
- 					pfree(recfp->save_fieldnames);
- 				recfp->save_fieldnames = arrayval;
- 				break;
- 			}
- 
+				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
+				if (fno == SPI_ERROR_NOATTRIBUTE)
+					ereport(ERROR,
+							(errcode(ERRCODE_UNDEFINED_COLUMN),
+							 errmsg("record \"%s\" has no field \"%s\"",
+									rec->refname, recfield->fieldname)));
+				*typeid = SPI_gettypeid(rec->tupdesc, fno);
+				*value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
+				if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							 errmsg("type of \"%s.%s\" does not match that when preparing the plan",
+									rec->refname, recfield->fieldname)));
+				break;
+			}
+
 		case PLPGSQL_DTYPE_TRIGARG:
 			{
 				PLpgSQL_trigarg *trigarg = (PLpgSQL_trigarg *) datum;
@@ -3769,29 +3632,7 @@ exec_eval_expr(PLpgSQL_execstate *estate,
 	 */
 	if (expr->plan == NULL)
 		exec_prepare_plan(estate, expr);
-	else {
-		/*
-		 * check for any subexpressions with varying type in the expression 
-		 * currently (July 05), this is a record field of a record indexed by a variable
-		 */
-		int			i;
-		PLpgSQL_datum		*d;
-		PLpgSQL_recfield	*rf;
-		for ( i = 0; i < expr->nparams; ++i ) {
-			d = estate->datums[expr->params[i]];
-			if ( d->dtype == PLPGSQL_DTYPE_RECFIELD ) {
-				rf = (PLpgSQL_recfield *)d;
-				if ( rf->fieldindex_flag == RECFIELD_USE_INDEX_VAR )
-					break;
-			}
-		}
-		if ( i < expr->nparams ) { /* expr may change it's type */
-			/* now discard the plan and get new one */
-			SPI_freeplan(expr->plan);
-			expr->plan = NULL;
-			exec_prepare_plan(estate, expr);
-		}
-	}
+
 	/*
 	 * If this is a simple expression, bypass SPI and use the executor
 	 * directly
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index c2905055bdf..9420ab15cf3 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.51 2006/05/30 12:03:13 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.52 2006/05/30 13:40:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1044,13 +1044,9 @@ plpgsql_dumptree(PLpgSQL_function *func)
 				printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
 				break;
 			case PLPGSQL_DTYPE_RECFIELD:
-				if ( ((PLpgSQL_recfield *) d)->fieldindex_flag == RECFIELD_USE_FIELDNAME )
-					printf("RECFIELD %-16s of REC %d\n",
-						   ((PLpgSQL_recfield *) d)->fieldindex.fieldname,
-						   ((PLpgSQL_recfield *) d)->recparentno);
-				else
-					printf("RECFIELD Variable of REC %d\n",
-						   ((PLpgSQL_recfield *) d)->recparentno);
+				printf("RECFIELD %-16s of REC %d\n",
+					   ((PLpgSQL_recfield *) d)->fieldname,
+					   ((PLpgSQL_recfield *) d)->recparentno);
 				break;
 			case PLPGSQL_DTYPE_ARRAYELEM:
 				printf("ARRAYELEM of VAR %d subscript ",
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 4a46597f095..86fea3ca465 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.73 2006/05/30 12:03:13 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.74 2006/05/30 13:40:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,8 +52,7 @@ enum
 	PLPGSQL_DTYPE_RECFIELD,
 	PLPGSQL_DTYPE_ARRAYELEM,
 	PLPGSQL_DTYPE_EXPR,
-	PLPGSQL_DTYPE_TRIGARG,
-	PLPGSQL_DTYPE_RECFIELDNAMES
+	PLPGSQL_DTYPE_TRIGARG
 };
 
 /* ----------
@@ -252,25 +251,10 @@ typedef struct
 {								/* Field in record */
 	int			dtype;
 	int			rfno;
-	union {
-		char	*fieldname;
-		int	indexvar_no;		/* dno of variable holding index string */
-	} fieldindex;
-	enum {
-		RECFIELD_USE_FIELDNAME,
-		RECFIELD_USE_INDEX_VAR,
-	}	fieldindex_flag;
+	char	   *fieldname;
 	int			recparentno;	/* dno of parent record */
 } PLpgSQL_recfield;
 
-typedef struct
-{								/* Field in record */
-	int			dtype;
-	int			rfno;
-	int			recparentno;			/* dno of parent record */
-	ArrayType *		save_fieldnames;
-} PLpgSQL_recfieldproperties;
-
 
 typedef struct
 {								/* Element of array variable */
@@ -677,8 +661,6 @@ extern int	plpgsql_parse_dblwordtype(char *word);
 extern int	plpgsql_parse_tripwordtype(char *word);
 extern int	plpgsql_parse_wordrowtype(char *word);
 extern int	plpgsql_parse_dblwordrowtype(char *word);
-extern int	plpgsql_parse_recfieldnames(char *word);
-extern int	plpgsql_parse_recindex(char *word);
 extern PLpgSQL_type *plpgsql_parse_datatype(const char *string);
 extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
 extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index 5202058f4c6..dfc2b942ecb 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.48 2006/05/30 12:03:13 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.49 2006/05/30 13:40:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -222,12 +222,6 @@ dump			{ return O_DUMP;			}
 {param}{space}*\.{space}*{identifier}{space}*%ROWTYPE	{
 	plpgsql_error_lineno = plpgsql_scanner_lineno();
 	return plpgsql_parse_dblwordrowtype(yytext); }
-{identifier}{space}*\.\(\*\)		{
-	plpgsql_error_lineno = plpgsql_scanner_lineno();
-	return plpgsql_parse_recfieldnames(yytext); }
-{identifier}{space}*\.\({identifier}\)		{
-	plpgsql_error_lineno = plpgsql_scanner_lineno();
-	return plpgsql_parse_recindex(yytext); }
 
 {digit}+		{ return T_NUMBER;			}
 
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index e20d76c0aeb..6e6597dadb2 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2725,44 +2725,6 @@ end;
 $$ language plpgsql;
 ERROR:  end label "outer_label" specified for unlabelled block
 CONTEXT:  compile of PL/pgSQL function "end_label4" near line 5
--- check introspective records
-create table ritest (i INT4, t TEXT);
-insert into ritest (i, t) VALUES (1, 'sometext');
-create function test_record() returns void as $$
-declare
-  cname text;
-  tval  text;
-  ival  int4;
-  tval2 text;
-  ival2 int4;
-  columns text[];
-  r     RECORD;
-begin
-  SELECT INTO r * FROM ritest WHERE i = 1;
-  ival := r.i;
-  tval := r.t;
-  RAISE NOTICE 'ival=%, tval=%', ival, tval;
-  cname := 'i';
-  ival2 := r.(cname);
-  cname :='t';
-  tval2 := r.(cname);
-  RAISE NOTICE 'ival2=%, tval2=%', ival2, tval2;
-  columns := r.(*);
-  RAISE NOTICE 'fieldnames=%', columns;
-  RETURN;
-end;
-$$ language plpgsql;
-select test_record();
-NOTICE:  ival=1, tval=sometext
-NOTICE:  ival2=1, tval2=sometext
-NOTICE:  fieldnames={i,t}
- test_record 
--------------
- 
- (1 row)
-
-drop table ritest;
-drop function test_record();
 -- using list of scalars in fori and fore stmts
 create function for_vect() returns void as $proc$
 <<lbl>>declare a integer; b varchar; c varchar; r record;
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 05460629860..19e145be65f 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -2281,38 +2281,6 @@ begin
 end;
 $$ language plpgsql;
 
--- check introspective records
-create table ritest (i INT4, t TEXT);
-insert into ritest (i, t) VALUES (1, 'sometext');
-create function test_record() returns void as $$
-declare
-  cname text;
-  tval  text;
-  ival  int4;
-  tval2 text;
-  ival2 int4;
-  columns text[];
-  r     RECORD;
-begin
-  SELECT INTO r * FROM ritest WHERE i = 1;
-  ival := r.i;
-  tval := r.t;
-  RAISE NOTICE 'ival=%, tval=%', ival, tval;
-  cname := 'i';
-  ival2 := r.(cname);
-  cname :='t';
-  tval2 := r.(cname);
-  RAISE NOTICE 'ival2=%, tval2=%', ival2, tval2;
-  columns := r.(*);
-  RAISE NOTICE 'fieldnames=%', columns;
-  RETURN;
-end;
-$$ language plpgsql;
-select test_record();
-drop table ritest;
-drop function test_record();
-
-
 -- using list of scalars in fori and fore stmts
 create function for_vect() returns void as $proc$
 <<lbl>>declare a integer; b varchar; c varchar; r record;
-- 
GitLab