Skip to content

Commit 2f88587

Browse files
CodingAnarchyclaude
andcommitted
fix: Fix PostgreSQL migration 014 CREATE FUNCTION syntax error
This release fixes a critical bug in PostgreSQL migration 014 that was causing "syntax error at or near 'RETURNS'" errors in production. ## Root Cause The sqlparser library was dropping empty parentheses `()` from CREATE FUNCTION statements when reformatting parsed SQL. PostgreSQL requires these parentheses even when functions have no parameters. ## Key Fixes ### Migration Parser Enhancement - Enhanced `parse_sql_statements` to detect CREATE FUNCTION statements - Added automatic restoration of missing parentheses before RETURNS clause - Fixed syntax: `CREATE FUNCTION name()` instead of `CREATE FUNCTION name` ### Enhanced Test Coverage - Updated `test_migration_014_sql_parsing` to explicitly verify parentheses preservation - Added assertions to ensure function names include required parentheses - Validates complete SQL syntax correctness after sqlparser formatting ### Version Update - Bumped version to 1.15.3 - Updated CHANGELOG.md with detailed fix description ## Impact - Migration 014 now executes successfully in production environments - Resolves CREATE FUNCTION syntax errors in PostgreSQL migrations - Maintains backward compatibility with existing migration behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 75260d8 commit 2f88587

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.15.3] - 2025-01-25
11+
12+
### Fixed
13+
- **🔧 PostgreSQL Migration 014 Function Syntax Fix**
14+
- Fixed critical bug where sqlparser was dropping empty parentheses from CREATE FUNCTION statements
15+
- PostgreSQL requires `()` after function names even when there are no parameters
16+
- Migration 014 was failing with "syntax error at or near 'RETURNS'" due to missing parentheses
17+
- Added automatic restoration of missing parentheses when sqlparser formats CREATE FUNCTION statements
18+
- Enhanced test coverage to explicitly verify parentheses preservation in function declarations
19+
- This fix ensures migration 014 executes correctly in production environments
20+
1021
## [1.15.2] - 2025-01-25
1122

1223
### Fixed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
resolver = "2"
1010

1111
[workspace.package]
12-
version = "1.15.2"
12+
version = "1.15.3"
1313
edition = "2024"
1414
license = "MIT"
1515
repository = "https://github.com/CodingAnarchy/hammerwork"

src/migrations/postgres.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,32 @@ fn parse_sql_statements(
1818
match Parser::parse_sql(&dialect, sql) {
1919
Ok(statements) => {
2020
// Convert parsed statements back to SQL strings
21-
Ok(statements.iter().map(|stmt| format!("{};", stmt)).collect())
21+
Ok(statements
22+
.iter()
23+
.map(|stmt| {
24+
let mut sql_string = format!("{}", stmt);
25+
26+
// Fix sqlparser bug: it drops empty parentheses from CREATE FUNCTION
27+
// PostgreSQL requires () even when there are no parameters
28+
if let sqlparser::ast::Statement::CreateFunction { args, .. } = stmt {
29+
if args.is_none() {
30+
// Find function name and add () after it if missing
31+
// The pattern is: "CREATE ... FUNCTION name RETURNS"
32+
if let Some(returns_pos) = sql_string.find(" RETURNS ") {
33+
// Check if there's already () before RETURNS
34+
let before_returns = &sql_string[..returns_pos];
35+
if !before_returns.ends_with("()") && !before_returns.ends_with(")")
36+
{
37+
// Insert () before RETURNS
38+
sql_string.insert_str(returns_pos, "()");
39+
}
40+
}
41+
}
42+
}
43+
44+
format!("{};", sql_string)
45+
})
46+
.collect())
2247
}
2348
Err(_) => {
2449
// If parsing fails, try to split manually while respecting SQL syntax
@@ -432,6 +457,37 @@ CREATE TRIGGER trigger_update_hammerwork_queue_pause_updated_at
432457
"Migration 014 SQL should parse successfully with sqlparser-rs: {:?}",
433458
result
434459
);
460+
461+
// CRITICAL: Verify that the parentheses are preserved/restored in the CREATE FUNCTION statement
462+
let parsed_statements = result.unwrap();
463+
assert_eq!(
464+
parsed_statements.len(),
465+
5,
466+
"Should parse 5 statements from migration 014 with sqlparser"
467+
);
468+
469+
// Find the CREATE FUNCTION statement
470+
let create_function_stmt = parsed_statements
471+
.iter()
472+
.find(|stmt| stmt.contains("CREATE OR REPLACE FUNCTION"))
473+
.expect("Should find CREATE FUNCTION statement");
474+
475+
// Verify the function name has parentheses - this is critical for PostgreSQL
476+
assert!(
477+
create_function_stmt.contains("update_hammerwork_queue_pause_updated_at()"),
478+
"Function name must include parentheses even with no parameters. Statement: {}",
479+
create_function_stmt
480+
);
481+
482+
// Also verify the statement is syntactically correct
483+
assert!(
484+
create_function_stmt.contains("RETURNS TRIGGER"),
485+
"Statement should contain RETURNS TRIGGER"
486+
);
487+
assert!(
488+
create_function_stmt.contains("LANGUAGE plpgsql"),
489+
"Statement should contain LANGUAGE plpgsql"
490+
);
435491
}
436492

437493
#[test]

0 commit comments

Comments
 (0)