mirror of
https://github.com/github/awesome-copilot.git
synced 2026-03-13 12:45:13 +00:00
* Add the 'Oracle-to-PostgreSQL Migration Expert' Custom Agent, its associated skills, plugin manifest * Update READMEs using 'npm run build' * Resolve PR comments: - Fix BOM characters - Rerun 'npm run build' - Clarify timestampz date kind - Remove consufing text for SELECT INTO exception - Remove dangerous VB.NET example * Update README and refcursor handling documentation for clarity and consistency * Update skills/creating-oracle-to-postgres-master-migration-plan/SKILL.md Add .slnx to discovery of projects Co-authored-by: Aaron Powell <me@aaron-powell.com> --------- Co-authored-by: TCPrimedPaul <paul.delannoy@tc.gc.ca> Co-authored-by: Aaron Powell <me@aaron-powell.com>
191 lines
4.8 KiB
Markdown
191 lines
4.8 KiB
Markdown
# Oracle to PostgreSQL: Parentheses in FROM Clause
|
|
|
|
## Contents
|
|
|
|
- Problem
|
|
- Root Cause
|
|
- Solution Pattern
|
|
- Examples
|
|
- Migration Checklist
|
|
- Common Locations
|
|
- Application Code Examples
|
|
- Error Messages to Watch For
|
|
- Testing Recommendations
|
|
|
|
## Problem
|
|
|
|
Oracle allows optional parentheses around table names in the FROM clause:
|
|
|
|
```sql
|
|
-- Oracle: Both are valid
|
|
SELECT * FROM (TABLE_NAME) WHERE id = 1;
|
|
SELECT * FROM TABLE_NAME WHERE id = 1;
|
|
```
|
|
|
|
PostgreSQL does **not** allow extra parentheses around a single table name in the FROM clause without it being a derived table or subquery. Attempting to use this pattern results in:
|
|
|
|
```
|
|
Npgsql.PostgresException: 42601: syntax error at or near ")"
|
|
```
|
|
|
|
## Root Cause
|
|
|
|
- **Oracle**: Treats `FROM(TABLE_NAME)` as equivalent to `FROM TABLE_NAME`
|
|
- **PostgreSQL**: Parentheses in the FROM clause are only valid for:
|
|
- Subqueries: `FROM (SELECT * FROM table)`
|
|
- Explicit table references that are part of join syntax
|
|
- Common Table Expressions (CTEs)
|
|
- Without a valid SELECT or join context, PostgreSQL raises a syntax error
|
|
|
|
## Solution Pattern
|
|
|
|
Remove the unnecessary parentheses around the table name:
|
|
|
|
```sql
|
|
-- Oracle (problematic in PostgreSQL)
|
|
SELECT col1, col2
|
|
FROM (TABLE_NAME)
|
|
WHERE id = 1;
|
|
|
|
-- PostgreSQL (correct)
|
|
SELECT col1, col2
|
|
FROM TABLE_NAME
|
|
WHERE id = 1;
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Example 1: Simple Table Reference
|
|
|
|
```sql
|
|
-- Oracle
|
|
SELECT employee_id, employee_name
|
|
FROM (EMPLOYEES)
|
|
WHERE department_id = 10;
|
|
|
|
-- PostgreSQL (fixed)
|
|
SELECT employee_id, employee_name
|
|
FROM EMPLOYEES
|
|
WHERE department_id = 10;
|
|
```
|
|
|
|
### Example 2: Join with Parentheses
|
|
|
|
```sql
|
|
-- Oracle (problematic)
|
|
SELECT e.employee_id, d.department_name
|
|
FROM (EMPLOYEES) e
|
|
JOIN (DEPARTMENTS) d ON e.department_id = d.department_id;
|
|
|
|
-- PostgreSQL (fixed)
|
|
SELECT e.employee_id, d.department_name
|
|
FROM EMPLOYEES e
|
|
JOIN DEPARTMENTS d ON e.department_id = d.department_id;
|
|
```
|
|
|
|
### Example 3: Valid Subquery Parentheses (Works in Both)
|
|
|
|
```sql
|
|
-- Both Oracle and PostgreSQL
|
|
SELECT *
|
|
FROM (SELECT employee_id, employee_name FROM EMPLOYEES WHERE department_id = 10) sub;
|
|
```
|
|
|
|
## Migration Checklist
|
|
|
|
When fixing this issue, verify:
|
|
|
|
1. **Identify all problematic FROM clauses**:
|
|
- Search for `FROM (` pattern in SQL
|
|
- Verify the opening parenthesis is immediately after `FROM` followed by a table name
|
|
- Confirm it's **not** a subquery (no SELECT keyword inside)
|
|
|
|
2. **Distinguish valid parentheses**:
|
|
- ✅ `FROM (SELECT ...)` - Valid subquery
|
|
- ✅ `FROM (table_name` followed by a join - Check if JOIN keyword follows
|
|
- ❌ `FROM (TABLE_NAME)` - Invalid, remove parentheses
|
|
|
|
3. **Apply the fix**:
|
|
- Remove the parentheses around the table name
|
|
- Keep parentheses for legitimate subqueries
|
|
|
|
4. **Test thoroughly**:
|
|
- Execute the query in PostgreSQL
|
|
- Verify result set matches original Oracle query
|
|
- Include in integration tests
|
|
|
|
## Common Locations
|
|
|
|
Search for `FROM (` in:
|
|
|
|
- ✅ Stored procedures and functions (DDL scripts)
|
|
- ✅ Application data access layers (DAL classes)
|
|
- ✅ Dynamic SQL builders
|
|
- ✅ Reporting queries
|
|
- ✅ Views and materialized views
|
|
- ✅ Complex queries with multiple joins
|
|
|
|
## Application Code Examples
|
|
|
|
### VB.NET
|
|
|
|
```vb
|
|
' Before (Oracle)
|
|
StrSQL = "SELECT employee_id, NAME " _
|
|
& "FROM (EMPLOYEES) e " _
|
|
& "WHERE e.department_id = 10"
|
|
|
|
' After (PostgreSQL)
|
|
StrSQL = "SELECT employee_id, NAME " _
|
|
& "FROM EMPLOYEES e " _
|
|
& "WHERE e.department_id = 10"
|
|
```
|
|
|
|
### C #
|
|
|
|
```csharp
|
|
// Before (Oracle)
|
|
var sql = "SELECT id, name FROM (USERS) WHERE status = @status";
|
|
|
|
// After (PostgreSQL)
|
|
var sql = "SELECT id, name FROM USERS WHERE status = @status";
|
|
```
|
|
|
|
## Error Messages to Watch For
|
|
|
|
```
|
|
Npgsql.PostgresException: 42601: syntax error at or near ")"
|
|
ERROR: syntax error at or near ")"
|
|
LINE 1: SELECT * FROM (TABLE_NAME) WHERE ...
|
|
^
|
|
```
|
|
|
|
## Testing Recommendations
|
|
|
|
1. **Syntax Verification**: Parse all migrated queries to ensure they run without syntax errors
|
|
|
|
```csharp
|
|
[Fact]
|
|
public void GetEmployees_ExecutesWithoutSyntaxError()
|
|
{
|
|
// Should not throw PostgresException with error code 42601
|
|
var employees = dal.GetEmployees(departmentId: 10);
|
|
Assert.NotEmpty(employees);
|
|
}
|
|
```
|
|
|
|
2. **Result Comparison**: Verify that result sets are identical before and after migration
|
|
3. **Regex-based Search**: Use pattern `FROM\s*\(\s*[A-Za-z_][A-Za-z0-9_]*\s*\)` to identify candidates
|
|
|
|
## Related Files
|
|
|
|
- Reference: [oracle-to-postgres-type-coercion.md](oracle-to-postgres-type-coercion.md) - Other syntax differences
|
|
- PostgreSQL Documentation: [SELECT Statement](https://www.postgresql.org/docs/current/sql-select.html)
|
|
|
|
## Migration Notes
|
|
|
|
- This is a straightforward syntactic fix with no semantic implications
|
|
- No data conversion required
|
|
- Safe to apply automated find-and-replace, but manually verify complex queries
|
|
- Update integration tests to exercise the migrated queries
|