diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
new file mode 100644
index 6869366..4acf824
*** a/doc/src/sgml/spi.sgml
--- b/doc/src/sgml/spi.sgml
*************** Oid SPI_gettypeid(TupleDesc <parameter>r
*** 3186,3191 ****
--- 3186,3257 ----
  
  <!-- *********************************************** -->
  
+ <refentry id="spi-spi-gettypmod">
+  <refmeta>
+   <refentrytitle>SPI_gettypmod</refentrytitle>
+   <manvolnum>3</manvolnum>
+  </refmeta>
+ 
+  <refnamediv>
+   <refname>SPI_gettypmod</refname>
+   <refpurpose>return the type-specific data of the specified column</refpurpose>
+  </refnamediv>
+ 
+  <indexterm><primary>SPI_gettypmod</primary></indexterm>
+ 
+  <refsynopsisdiv>
+ <synopsis>
+ int4 SPI_gettypmod(TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnumber</parameter>)
+ </synopsis>
+  </refsynopsisdiv>
+ 
+  <refsect1>
+   <title>Description</title>
+ 
+   <para>
+    <function>SPI_gettypmod</function> returns the type-specific data supplied
+    at table creation time.  For example: the max length of a varchar field.
+   </para>
+  </refsect1>
+ 
+  <refsect1>
+   <title>Arguments</title>
+ 
+   <variablelist>
+    <varlistentry>
+     <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term>
+     <listitem>
+      <para>
+       input row description
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>int <parameter>colnumber</parameter></literal></term>
+     <listitem>
+      <para>
+       column number (count starts at 1)
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </refsect1>
+ 
+  <refsect1>
+   <title>Return Value</title>
+ 
+   <para>
+    The type-specific data supplied at table creation time of the specified
+    column or <symbol>InvalidOid</symbol> on error.  On error,
+    <varname>SPI_result</varname> is set to
+    <symbol>SPI_ERROR_NOATTRIBUTE</symbol>.
+   </para>
+  </refsect1>
+ </refentry>
+ 
+ <!-- *********************************************** -->
+ 
  <refentry id="spi-spi-getrelname">
   <refmeta>
    <refentrytitle>SPI_getrelname</refentrytitle>
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
new file mode 100644
index de8d59a..86c1cee
*** a/src/backend/executor/spi.c
--- b/src/backend/executor/spi.c
*************** SPI_gettypeid(TupleDesc tupdesc, int fnu
*** 958,963 ****
--- 958,981 ----
  		return (SystemAttributeDefinition(fnumber, true))->atttypid;
  }
  
+ int32
+ SPI_gettypmod(TupleDesc tupdesc, int fnumber)
+ {
+ 	SPI_result = 0;
+ 
+ 	if (fnumber > tupdesc->natts || fnumber == 0 ||
+ 		fnumber <= FirstLowInvalidHeapAttributeNumber)
+ 	{
+ 		SPI_result = SPI_ERROR_NOATTRIBUTE;
+ 		return -1;
+ 	}
+ 
+ 	if (fnumber > 0)
+ 		return tupdesc->attrs[fnumber - 1]->atttypmod;
+ 	else
+ 		return (SystemAttributeDefinition(fnumber, true))->atttypmod;
+ }
+ 
  char *
  SPI_getrelname(Relation rel)
  {
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
new file mode 100644
index d4f1272..cfd95fe
*** a/src/include/executor/spi.h
--- b/src/include/executor/spi.h
*************** extern char *SPI_getvalue(HeapTuple tupl
*** 116,121 ****
--- 116,122 ----
  extern Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull);
  extern char *SPI_gettype(TupleDesc tupdesc, int fnumber);
  extern Oid	SPI_gettypeid(TupleDesc tupdesc, int fnumber);
+ extern int32 SPI_gettypmod(TupleDesc tupdesc, int fnumber);
  extern char *SPI_getrelname(Relation rel);
  extern char *SPI_getnspname(Relation rel);
  extern void *SPI_palloc(Size size);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
new file mode 100644
index 591a432..73ab354
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** exec_eval_datum(PLpgSQL_execstate *estat
*** 4386,4396 ****
  							 errmsg("record \"%s\" has no field \"%s\"",
  									rec->refname, recfield->fieldname)));
  				*typeid = SPI_gettypeid(rec->tupdesc, fno);
! 				/* XXX there's no SPI_gettypmod, for some reason */
! 				if (fno > 0)
! 					*typetypmod = rec->tupdesc->attrs[fno - 1]->atttypmod;
! 				else
! 					*typetypmod = -1;
  				*value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
  				break;
  			}
--- 4386,4392 ----
  							 errmsg("record \"%s\" has no field \"%s\"",
  									rec->refname, recfield->fieldname)));
  				*typeid = SPI_gettypeid(rec->tupdesc, fno);
! 				*typetypmod = SPI_gettypeid(rec->tupdesc, fno);
  				*value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
  				break;
  			}
*************** exec_get_datum_type_info(PLpgSQL_execsta
*** 4563,4573 ****
  							 errmsg("record \"%s\" has no field \"%s\"",
  									rec->refname, recfield->fieldname)));
  				*typeid = SPI_gettypeid(rec->tupdesc, fno);
! 				/* XXX there's no SPI_gettypmod, for some reason */
! 				if (fno > 0)
! 					*typmod = rec->tupdesc->attrs[fno - 1]->atttypmod;
! 				else
! 					*typmod = -1;
  				/* XXX there's no SPI_getcollation either */
  				if (fno > 0)
  					*collation = rec->tupdesc->attrs[fno - 1]->attcollation;
--- 4559,4565 ----
  							 errmsg("record \"%s\" has no field \"%s\"",
  									rec->refname, recfield->fieldname)));
  				*typeid = SPI_gettypeid(rec->tupdesc, fno);
! 				*typmod = SPI_gettypmod(rec->tupdesc, fno);
  				/* XXX there's no SPI_getcollation either */
  				if (fno > 0)
  					*collation = rec->tupdesc->attrs[fno - 1]->attcollation;
