mirror of
https://github.com/github/awesome-copilot.git
synced 2026-03-13 20:55: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>
146 lines
4.2 KiB
Markdown
146 lines
4.2 KiB
Markdown
# Oracle to PostgreSQL: TO_CHAR() Numeric Conversions
|
|
|
|
## Contents
|
|
|
|
- Problem
|
|
- Root Cause
|
|
- Solution Patterns — CAST, format string, concatenation
|
|
- Migration Checklist
|
|
- Application Code Review
|
|
- Testing Recommendations
|
|
- Common Locations
|
|
- Error Messages to Watch For
|
|
|
|
## Problem
|
|
|
|
Oracle allows `TO_CHAR()` to convert numeric types to strings without a format specifier:
|
|
|
|
```sql
|
|
-- Oracle: Works fine
|
|
SELECT TO_CHAR(vessel_id) FROM vessels;
|
|
SELECT TO_CHAR(fiscal_year) FROM certificates;
|
|
```
|
|
|
|
PostgreSQL requires a format string when using `TO_CHAR()` with numeric types, otherwise it raises:
|
|
|
|
```
|
|
42883: function to_char(numeric) does not exist
|
|
```
|
|
|
|
## Root Cause
|
|
|
|
- **Oracle**: `TO_CHAR(number)` without a format mask implicitly converts the number to a string using default formatting
|
|
- **PostgreSQL**: `TO_CHAR()` always requires an explicit format string for numeric types (e.g., `'999999'`, `'FM999999'`)
|
|
|
|
## Solution Patterns
|
|
|
|
### Pattern 1: Use CAST (Recommended)
|
|
|
|
The cleanest migration approach is to replace `TO_CHAR(numeric_column)` with `CAST(numeric_column AS TEXT)`:
|
|
|
|
```sql
|
|
-- Oracle
|
|
SELECT TO_CHAR(vessel_id) AS vessel_item FROM vessels;
|
|
|
|
-- PostgreSQL (preferred)
|
|
SELECT CAST(vessel_id AS TEXT) AS vessel_item FROM vessels;
|
|
```
|
|
|
|
**Advantages:**
|
|
|
|
- More idiomatic in PostgreSQL
|
|
- Clearer intent
|
|
- No format string needed
|
|
|
|
### Pattern 2: Provide Format String
|
|
|
|
If you need specific numeric formatting, use an explicit format mask:
|
|
|
|
```sql
|
|
-- PostgreSQL with format
|
|
SELECT TO_CHAR(vessel_id, 'FM999999') AS vessel_item FROM vessels;
|
|
SELECT TO_CHAR(amount, 'FM999999.00') AS amount_text FROM payments;
|
|
```
|
|
|
|
**Format masks:**
|
|
|
|
- `'FM999999'`: Fixed-width integer (FM = Fill Mode, removes leading spaces)
|
|
- `'FM999999.00'`: Decimal with 2 places
|
|
- `'999,999.00'`: With thousand separators
|
|
|
|
### Pattern 3: String Concatenation
|
|
|
|
For simple concatenation where numeric conversion is implicit:
|
|
|
|
```sql
|
|
-- Oracle
|
|
WHERE TO_CHAR(fiscal_year) = '2024'
|
|
|
|
-- PostgreSQL (using concatenation)
|
|
WHERE fiscal_year::TEXT = '2024'
|
|
-- or
|
|
WHERE CAST(fiscal_year AS TEXT) = '2024'
|
|
```
|
|
|
|
## Migration Checklist
|
|
|
|
When migrating SQL containing `TO_CHAR()`:
|
|
|
|
1. **Identify all TO_CHAR() calls**: Search for `TO_CHAR\(` in SQL strings, stored procedures, and application queries
|
|
2. **Check the argument type**:
|
|
- **DATE/TIMESTAMP**: Keep `TO_CHAR()` with format string (e.g., `TO_CHAR(date_col, 'YYYY-MM-DD')`)
|
|
- **NUMERIC/INTEGER**: Replace with `CAST(... AS TEXT)` or add format string
|
|
3. **Test the output**: Verify that the string representation matches expectations (no unexpected spaces, decimals, etc.)
|
|
4. **Update comparison logic**: If comparing numeric-to-string, ensure consistent types on both sides
|
|
|
|
## Application Code Review
|
|
|
|
### C# Example
|
|
|
|
```csharp
|
|
// Before (Oracle)
|
|
var sql = "SELECT TO_CHAR(id) AS id_text FROM entities WHERE TO_CHAR(status) = @status";
|
|
|
|
// After (PostgreSQL)
|
|
var sql = "SELECT CAST(id AS TEXT) AS id_text FROM entities WHERE CAST(status AS TEXT) = @status";
|
|
```
|
|
|
|
## Testing Recommendations
|
|
|
|
1. **Unit Tests**: Verify numeric-to-string conversions return expected values
|
|
|
|
```csharp
|
|
[Fact]
|
|
public void GetVesselNumbers_ReturnsVesselIdsAsStrings()
|
|
{
|
|
var results = dal.GetVesselNumbers(certificateType);
|
|
Assert.All(results, item => Assert.True(int.TryParse(item.DISPLAY_MEMBER, out _)));
|
|
}
|
|
```
|
|
|
|
2. **Integration Tests**: Ensure queries with `CAST()` execute without errors
|
|
3. **Comparison Tests**: Verify WHERE clauses with numeric-to-string comparisons filter correctly
|
|
|
|
## Common Locations
|
|
|
|
Search for `TO_CHAR` in:
|
|
|
|
- ✅ Stored procedures and functions (DDL scripts)
|
|
- ✅ Application data access layers (DAL classes)
|
|
- ✅ Dynamic SQL builders
|
|
- ✅ Reporting queries
|
|
- ✅ ORM/Entity Framework raw SQL
|
|
|
|
## Error Messages to Watch For
|
|
|
|
```
|
|
Npgsql.PostgresException: 42883: function to_char(numeric) does not exist
|
|
Npgsql.PostgresException: 42883: function to_char(integer) does not exist
|
|
Npgsql.PostgresException: 42883: function to_char(bigint) does not exist
|
|
```
|
|
|
|
## See Also
|
|
|
|
- [oracle-to-postgres-type-coercion.md](oracle-to-postgres-type-coercion.md) - Related type conversion issues
|
|
- PostgreSQL Documentation: [Data Type Formatting Functions](https://www.postgresql.org/docs/current/functions-formatting.html)
|