1414
1515#include "catalog/pg_proc.h"
1616#include "catalog/pg_type.h"
17+
18+ #if PG_VERSION_NUM >= 180000
19+
20+ #include "common/hashfn.h"
21+
22+ #endif
23+
1724#include "nodes/makefuncs.h"
1825#include "utils/guc.h"
1926#include "utils/memutils.h"
2330#include "utils/typcache.h"
2431#include "access/heapam.h"
2532
33+
2634static HTAB * plpgsql_check_HashTable = NULL ;
2735
2836bool plpgsql_check_other_warnings = false;
@@ -1353,6 +1361,75 @@ copy_plpgsql_datum(PLpgSQL_checkstate *cstate, PLpgSQL_datum *datum)
13531361 return result ;
13541362}
13551363
1364+ #if PG_VERSION_NUM >= 180000
1365+
1366+ /*
1367+ * cfunc_hash: hash function for cfunc hash table (copy from funccache.c)
1368+ *
1369+ * We need special hash and match functions to deal with the optional
1370+ * presence of a TupleDesc in the hash keys. As long as we have to do
1371+ * that, we might as well also be smart about not comparing unused
1372+ * elements of the argtypes arrays.
1373+ */
1374+ static uint32
1375+ cfunc_hash (const void * key , Size keysize )
1376+ {
1377+ const CachedFunctionHashKey * k = (const CachedFunctionHashKey * ) key ;
1378+ uint32 h ;
1379+
1380+ Assert (keysize == sizeof (CachedFunctionHashKey ));
1381+ /* Hash all the fixed fields except callResultType */
1382+ h = DatumGetUInt32 (hash_any ((const unsigned char * ) k ,
1383+ offsetof(CachedFunctionHashKey , callResultType )));
1384+ /* Incorporate input argument types */
1385+ if (k -> nargs > 0 )
1386+ h = hash_combine (h ,
1387+ DatumGetUInt32 (hash_any ((const unsigned char * ) k -> argtypes ,
1388+ k -> nargs * sizeof (Oid ))));
1389+ /* Incorporate callResultType if present */
1390+ if (k -> callResultType )
1391+ h = hash_combine (h , hashRowType (k -> callResultType ));
1392+ return h ;
1393+ }
1394+
1395+ /*
1396+ * cfunc_match: match function to use with cfunc_hash
1397+ */
1398+ static int
1399+ cfunc_match (const void * key1 , const void * key2 , Size keysize )
1400+ {
1401+ const CachedFunctionHashKey * k1 = (const CachedFunctionHashKey * ) key1 ;
1402+ const CachedFunctionHashKey * k2 = (const CachedFunctionHashKey * ) key2 ;
1403+
1404+ Assert (keysize == sizeof (CachedFunctionHashKey ));
1405+ /* Compare all the fixed fields except callResultType */
1406+ if (memcmp (k1 , k2 , offsetof(CachedFunctionHashKey , callResultType )) != 0 )
1407+ return 1 ; /* not equal */
1408+ /* Compare input argument types (we just verified that nargs matches) */
1409+ if (k1 -> nargs > 0 &&
1410+ memcmp (k1 -> argtypes , k2 -> argtypes , k1 -> nargs * sizeof (Oid )) != 0 )
1411+ return 1 ; /* not equal */
1412+ /* Compare callResultType */
1413+ if (k1 -> callResultType )
1414+ {
1415+ if (k2 -> callResultType )
1416+ {
1417+ if (!equalRowTypes (k1 -> callResultType , k2 -> callResultType ))
1418+ return 1 ; /* not equal */
1419+ }
1420+ else
1421+ return 1 ; /* not equal */
1422+ }
1423+ else
1424+ {
1425+ if (k2 -> callResultType )
1426+ return 1 ; /* not equal */
1427+ }
1428+ return 0 ; /* equal */
1429+ }
1430+
1431+ #endif
1432+
13561433void
13571434plpgsql_check_HashTableInit (void )
13581435{
@@ -1366,18 +1443,24 @@ plpgsql_check_HashTableInit(void)
13661443#if PG_VERSION_NUM >= 180000
13671444
13681445 ctl .keysize = sizeof (CachedFunctionHashKey );
1446+ ctl .entrysize = sizeof (plpgsql_check_HashEnt );
1447+ ctl .hash = cfunc_hash ;
1448+ ctl .match = cfunc_match ;
1449+ plpgsql_check_HashTable = hash_create ("plpgsql_check function cache" ,
1450+ FUNCS_PER_USER ,
1451+ & ctl ,
1452+ HASH_ELEM | HASH_FUNCTION | HASH_COMPARE );
13691453
13701454#else
13711455
13721456 ctl .keysize = sizeof (PLpgSQL_func_hashkey );
1373-
1374- #endif
1375-
13761457 ctl .entrysize = sizeof (plpgsql_check_HashEnt );
13771458 plpgsql_check_HashTable = hash_create ("plpgsql_check function cache" ,
13781459 FUNCS_PER_USER ,
13791460 & ctl ,
13801461 HASH_ELEM | HASH_BLOBS );
1462+ #endif
1463+
13811464}
13821465
13831466/*
@@ -1456,6 +1539,7 @@ plpgsql_check_mark_as_checked(PLpgSQL_function *func)
14561539 hentry -> fn_tid = func -> fn_tid ;
14571540
14581541#endif
1542+
14591543 hentry -> is_checked = true;
14601544 }
14611545}
0 commit comments