mirror of
https://github.com/github/awesome-copilot.git
synced 2026-03-13 20:55:13 +00:00
Adds the 'Oracle-to-PostgreSQL Migration Expert' Custom Agent, Asociated Skills, and Plugin Manifest (#950)
* 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>
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user