@@ -1599,7 +1599,7 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
1599
1599
* plpgsql_parse_wordtype The scanner found word%TYPE. word should be
1600
1600
* a pre-existing variable name.
1601
1601
*
1602
- * Returns datatype struct, or NULL if no match found for word.
1602
+ * Returns datatype struct. Throws error if no match found for word.
1603
1603
* ----------
1604
1604
*/
1605
1605
PLpgSQL_type *
@@ -1623,23 +1623,24 @@ plpgsql_parse_wordtype(char *ident)
1623
1623
case PLPGSQL_NSTYPE_REC :
1624
1624
return ((PLpgSQL_rec * ) (plpgsql_Datums [nse -> itemno ]))-> datatype ;
1625
1625
default :
1626
- return NULL ;
1626
+ break ;
1627
1627
}
1628
1628
}
1629
1629
1630
- /*
1631
- * Nothing found - up to now it's a word without any special meaning for
1632
- * us.
1633
- */
1634
- return NULL ;
1630
+ /* No match, complain */
1631
+ ereport ( ERROR ,
1632
+ ( errcode ( ERRCODE_UNDEFINED_OBJECT ),
1633
+ errmsg ( "variable \"%s\" does not exist" , ident )));
1634
+ return NULL ; /* keep compiler quiet */
1635
1635
}
1636
1636
1637
1637
1638
1638
/* ----------
1639
1639
* plpgsql_parse_cwordtype Same lookup for compositeword%TYPE
1640
1640
*
1641
1641
* Here, we allow either a block-qualified variable name, or a reference
1642
- * to a column of some table.
1642
+ * to a column of some table. (If we must throw error, we assume that the
1643
+ * latter case was intended.)
1643
1644
* ----------
1644
1645
*/
1645
1646
PLpgSQL_type *
@@ -1648,12 +1649,11 @@ plpgsql_parse_cwordtype(List *idents)
1648
1649
PLpgSQL_type * dtype = NULL ;
1649
1650
PLpgSQL_nsitem * nse ;
1650
1651
int nnames ;
1651
- const char * fldname ;
1652
+ RangeVar * relvar = NULL ;
1653
+ const char * fldname = NULL ;
1652
1654
Oid classOid ;
1653
- HeapTuple classtup = NULL ;
1654
1655
HeapTuple attrtup = NULL ;
1655
1656
HeapTuple typetup = NULL ;
1656
- Form_pg_class classStruct ;
1657
1657
Form_pg_attribute attrStruct ;
1658
1658
MemoryContext oldCxt ;
1659
1659
@@ -1688,57 +1688,39 @@ plpgsql_parse_cwordtype(List *idents)
1688
1688
/*
1689
1689
* First word could also be a table name
1690
1690
*/
1691
- classOid = RelnameGetRelid ( strVal ( linitial ( idents )));
1692
- if (! OidIsValid ( classOid ))
1693
- goto done ;
1691
+ relvar = makeRangeVar ( NULL ,
1692
+ strVal ( linitial ( idents )),
1693
+ -1 ) ;
1694
1694
fldname = strVal (lsecond (idents ));
1695
1695
}
1696
- else if ( list_length ( idents ) == 3 )
1696
+ else
1697
1697
{
1698
- RangeVar * relvar ;
1699
-
1700
1698
/*
1701
1699
* We could check for a block-qualified reference to a field of a
1702
1700
* record variable, but %TYPE is documented as applying to variables,
1703
1701
* not fields of variables. Things would get rather ambiguous if we
1704
1702
* allowed either interpretation.
1705
1703
*/
1706
- relvar = makeRangeVar (strVal (linitial (idents )),
1707
- strVal (lsecond (idents )),
1708
- -1 );
1709
- /* Can't lock relation - we might not have privileges. */
1710
- classOid = RangeVarGetRelid (relvar , NoLock , true);
1711
- if (!OidIsValid (classOid ))
1712
- goto done ;
1713
- fldname = strVal (lthird (idents ));
1714
- }
1715
- else
1716
- goto done ;
1704
+ List * rvnames ;
1717
1705
1718
- classtup = SearchSysCache1 (RELOID , ObjectIdGetDatum (classOid ));
1719
- if (!HeapTupleIsValid (classtup ))
1720
- goto done ;
1721
- classStruct = (Form_pg_class ) GETSTRUCT (classtup );
1706
+ Assert (list_length (idents ) > 2 );
1707
+ rvnames = list_delete_last (list_copy (idents ));
1708
+ relvar = makeRangeVarFromNameList (rvnames );
1709
+ fldname = strVal (llast (idents ));
1710
+ }
1722
1711
1723
- /*
1724
- * It must be a relation, sequence, view, materialized view, composite
1725
- * type, or foreign table
1726
- */
1727
- if (classStruct -> relkind != RELKIND_RELATION &&
1728
- classStruct -> relkind != RELKIND_SEQUENCE &&
1729
- classStruct -> relkind != RELKIND_VIEW &&
1730
- classStruct -> relkind != RELKIND_MATVIEW &&
1731
- classStruct -> relkind != RELKIND_COMPOSITE_TYPE &&
1732
- classStruct -> relkind != RELKIND_FOREIGN_TABLE &&
1733
- classStruct -> relkind != RELKIND_PARTITIONED_TABLE )
1734
- goto done ;
1712
+ /* Look up relation name. Can't lock it - we might not have privileges. */
1713
+ classOid = RangeVarGetRelid (relvar , NoLock , false);
1735
1714
1736
1715
/*
1737
1716
* Fetch the named table field and its type
1738
1717
*/
1739
1718
attrtup = SearchSysCacheAttName (classOid , fldname );
1740
1719
if (!HeapTupleIsValid (attrtup ))
1741
- goto done ;
1720
+ ereport (ERROR ,
1721
+ (errcode (ERRCODE_UNDEFINED_COLUMN ),
1722
+ errmsg ("column \"%s\" of relation \"%s\" does not exist" ,
1723
+ fldname , relvar -> relname )));
1742
1724
attrStruct = (Form_pg_attribute ) GETSTRUCT (attrtup );
1743
1725
1744
1726
typetup = SearchSysCache1 (TYPEOID ,
@@ -1759,8 +1741,6 @@ plpgsql_parse_cwordtype(List *idents)
1759
1741
MemoryContextSwitchTo (plpgsql_compile_tmp_cxt );
1760
1742
1761
1743
done :
1762
- if (HeapTupleIsValid (classtup ))
1763
- ReleaseSysCache (classtup );
1764
1744
if (HeapTupleIsValid (attrtup ))
1765
1745
ReleaseSysCache (attrtup );
1766
1746
if (HeapTupleIsValid (typetup ))
@@ -1824,16 +1804,12 @@ plpgsql_parse_cwordrowtype(List *idents)
1824
1804
* As above, this is a relation lookup but could be a type lookup if we
1825
1805
* weren't being backwards-compatible about error wording.
1826
1806
*/
1827
- if (list_length (idents ) != 2 )
1828
- return NULL ;
1829
1807
1830
1808
/* Avoid memory leaks in long-term function context */
1831
1809
oldCxt = MemoryContextSwitchTo (plpgsql_compile_tmp_cxt );
1832
1810
1833
1811
/* Look up relation name. Can't lock it - we might not have privileges. */
1834
- relvar = makeRangeVar (strVal (linitial (idents )),
1835
- strVal (lsecond (idents )),
1836
- -1 );
1812
+ relvar = makeRangeVarFromNameList (idents );
1837
1813
classOid = RangeVarGetRelid (relvar , NoLock , false);
1838
1814
1839
1815
/* Some relkinds lack type OIDs */
@@ -1842,7 +1818,7 @@ plpgsql_parse_cwordrowtype(List *idents)
1842
1818
ereport (ERROR ,
1843
1819
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
1844
1820
errmsg ("relation \"%s\" does not have a composite type" ,
1845
- strVal ( lsecond ( idents )) )));
1821
+ relvar -> relname )));
1846
1822
1847
1823
MemoryContextSwitchTo (oldCxt );
1848
1824
0 commit comments