@@ -1205,14 +1205,63 @@ fn sql_value_to_func_call(
12051205 } )
12061206}
12071207
1208+ /// Returns the canonical order for a function option.
1209+ /// Postgres's canonical order (as seen in pg_dump output) is:
1210+ /// 1. LANGUAGE
1211+ /// 2. WINDOW
1212+ /// 3. IMMUTABLE / STABLE / VOLATILE (volatility)
1213+ /// 4. LEAKPROOF / NOT LEAKPROOF
1214+ /// 5. STRICT / CALLED ON NULL INPUT (strict)
1215+ /// 6. SECURITY DEFINER / SECURITY INVOKER (security)
1216+ /// 7. PARALLEL (parallel)
1217+ /// 8. COST (cost)
1218+ /// 9. ROWS (rows)
1219+ /// 10. SUPPORT (support)
1220+ /// 11. SET options (set)
1221+ /// 12. AS (function body)
1222+ fn option_order ( defname : & str ) -> usize {
1223+ match defname. to_lowercase ( ) . as_str ( ) {
1224+ "language" => 0 ,
1225+ "window" => 1 ,
1226+ "volatility" => 2 ,
1227+ "leakproof" => 3 ,
1228+ "strict" => 4 ,
1229+ "security" => 5 ,
1230+ "parallel" => 6 ,
1231+ "cost" => 7 ,
1232+ "rows" => 8 ,
1233+ "support" => 9 ,
1234+ "set" => 10 ,
1235+ "as" => 11 ,
1236+ _ => 100 , // Unknown options go last
1237+ }
1238+ }
1239+
1240+ /// Sort function options according to Postgres's canonical order.
1241+ fn sort_function_options ( options : & mut [ pgls_query:: protobuf:: Node ] ) {
1242+ options. sort_by_key ( |node| {
1243+ if let Some ( NodeEnum :: DefElem ( def_elem) ) = & node. node {
1244+ option_order ( & def_elem. defname )
1245+ } else {
1246+ 100 // Non-DefElem nodes go last
1247+ }
1248+ } ) ;
1249+ }
1250+
12081251/// Normalize function body strings by trimming whitespace.
12091252///
12101253/// The formatter emits function bodies on separate lines from the dollar-quote delimiters,
12111254/// which adds leading/trailing newlines to the body. This normalization trims these
12121255/// so that semantically equivalent bodies compare equal.
1256+ ///
1257+ /// Also sorts function options to canonical order so that semantically equivalent
1258+ /// option orderings compare equal.
12131259fn normalize_function_body ( node : & mut NodeEnum ) {
12141260 match node {
12151261 NodeEnum :: CreateFunctionStmt ( stmt) => {
1262+ // Sort options to canonical order
1263+ sort_function_options ( & mut stmt. options ) ;
1264+
12161265 for opt in & mut stmt. options {
12171266 if let Some ( NodeEnum :: DefElem ( def) ) = opt. node . as_mut ( )
12181267 && def. defname . eq_ignore_ascii_case ( "as" )
@@ -1242,6 +1291,10 @@ fn normalize_function_body(node: &mut NodeEnum) {
12421291 NodeEnum :: InlineCodeBlock ( block) => {
12431292 block. source_text = block. source_text . trim ( ) . to_string ( ) ;
12441293 }
1294+ NodeEnum :: AlterFunctionStmt ( stmt) => {
1295+ // Sort actions to canonical order
1296+ sort_function_options ( & mut stmt. actions ) ;
1297+ }
12451298 _ => { }
12461299 }
12471300}
0 commit comments