@@ -446,6 +446,7 @@ compute_common_attribute(DefElem *defel,
446446 DefElem * * volatility_item ,
447447 DefElem * * strict_item ,
448448 DefElem * * security_item ,
449+ DefElem * * leakproof_item ,
449450 List * * set_items ,
450451 DefElem * * cost_item ,
451452 DefElem * * rows_item )
@@ -471,6 +472,13 @@ compute_common_attribute(DefElem *defel,
471472
472473 * security_item = defel ;
473474 }
475+ else if (strcmp (defel -> defname , "leakproof" ) == 0 )
476+ {
477+ if (* leakproof_item )
478+ goto duplicate_error ;
479+
480+ * leakproof_item = defel ;
481+ }
474482 else if (strcmp (defel -> defname , "set" ) == 0 )
475483 {
476484 * set_items = lappend (* set_items , defel -> arg );
@@ -564,6 +572,7 @@ compute_attributes_sql_style(List *options,
564572 char * volatility_p ,
565573 bool * strict_p ,
566574 bool * security_definer ,
575+ bool * leakproof_p ,
567576 ArrayType * * proconfig ,
568577 float4 * procost ,
569578 float4 * prorows )
@@ -575,6 +584,7 @@ compute_attributes_sql_style(List *options,
575584 DefElem * volatility_item = NULL ;
576585 DefElem * strict_item = NULL ;
577586 DefElem * security_item = NULL ;
587+ DefElem * leakproof_item = NULL ;
578588 List * set_items = NIL ;
579589 DefElem * cost_item = NULL ;
580590 DefElem * rows_item = NULL ;
@@ -611,6 +621,7 @@ compute_attributes_sql_style(List *options,
611621 & volatility_item ,
612622 & strict_item ,
613623 & security_item ,
624+ & leakproof_item ,
614625 & set_items ,
615626 & cost_item ,
616627 & rows_item ))
@@ -653,6 +664,8 @@ compute_attributes_sql_style(List *options,
653664 * strict_p = intVal (strict_item -> arg );
654665 if (security_item )
655666 * security_definer = intVal (security_item -> arg );
667+ if (leakproof_item )
668+ * leakproof_p = intVal (leakproof_item -> arg );
656669 if (set_items )
657670 * proconfig = update_proconfig_value (NULL , set_items );
658671 if (cost_item )
@@ -805,7 +818,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
805818 Oid requiredResultType ;
806819 bool isWindowFunc ,
807820 isStrict ,
808- security ;
821+ security ,
822+ isLeakProof ;
809823 char volatility ;
810824 ArrayType * proconfig ;
811825 float4 procost ;
@@ -828,6 +842,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
828842 isWindowFunc = false;
829843 isStrict = false;
830844 security = false;
845+ isLeakProof = false;
831846 volatility = PROVOLATILE_VOLATILE ;
832847 proconfig = NULL ;
833848 procost = -1 ; /* indicates not set */
@@ -837,7 +852,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
837852 compute_attributes_sql_style (stmt -> options ,
838853 & as_clause , & language ,
839854 & isWindowFunc , & volatility ,
840- & isStrict , & security ,
855+ & isStrict , & security , & isLeakProof ,
841856 & proconfig , & procost , & prorows );
842857
843858 /* Look up the language and validate permissions */
@@ -874,6 +889,16 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
874889
875890 ReleaseSysCache (languageTuple );
876891
892+ /*
893+ * Only superuser is allowed to create leakproof functions because
894+ * it possibly allows unprivileged users to reference invisible tuples
895+ * to be filtered out using views for row-level security.
896+ */
897+ if (isLeakProof && !superuser ())
898+ ereport (ERROR ,
899+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
900+ errmsg ("only superuser can define a leakproof function" )));
901+
877902 /*
878903 * Convert remaining parameters of CREATE to form wanted by
879904 * ProcedureCreate.
@@ -960,6 +985,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
960985 false, /* not an aggregate */
961986 isWindowFunc ,
962987 security ,
988+ isLeakProof ,
963989 isStrict ,
964990 volatility ,
965991 parameterTypes ,
@@ -1238,6 +1264,7 @@ AlterFunction(AlterFunctionStmt *stmt)
12381264 DefElem * volatility_item = NULL ;
12391265 DefElem * strict_item = NULL ;
12401266 DefElem * security_def_item = NULL ;
1267+ DefElem * leakproof_item = NULL ;
12411268 List * set_items = NIL ;
12421269 DefElem * cost_item = NULL ;
12431270 DefElem * rows_item = NULL ;
@@ -1274,6 +1301,7 @@ AlterFunction(AlterFunctionStmt *stmt)
12741301 & volatility_item ,
12751302 & strict_item ,
12761303 & security_def_item ,
1304+ & leakproof_item ,
12771305 & set_items ,
12781306 & cost_item ,
12791307 & rows_item ) == false)
@@ -1286,6 +1314,14 @@ AlterFunction(AlterFunctionStmt *stmt)
12861314 procForm -> proisstrict = intVal (strict_item -> arg );
12871315 if (security_def_item )
12881316 procForm -> prosecdef = intVal (security_def_item -> arg );
1317+ if (leakproof_item )
1318+ {
1319+ if (intVal (leakproof_item -> arg ) && !superuser ())
1320+ ereport (ERROR ,
1321+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1322+ errmsg ("only superuser can define a leakproof function" )));
1323+ procForm -> proleakproof = intVal (leakproof_item -> arg );
1324+ }
12891325 if (cost_item )
12901326 {
12911327 procForm -> procost = defGetNumeric (cost_item );
0 commit comments