Skip to content

Commit a0066cf

Browse files
authored
Merge branch 'pg13-pg14-base' into pg14-pg15-transformer
2 parents c0c7190 + 727f67a commit a0066cf

26 files changed

+5034
-353
lines changed

packages/transform/STATUS-15-16.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,57 @@
1-
not started — see previous status docs for format style.
1+
# PostgreSQL v15-to-v16 AST Transformer Status
2+
3+
## Current Status: **IN PROGRESS** 🟡
4+
- **Test Pass Rate**: 184/258 tests passing (71.3% success rate)
5+
- **Branch**: `pg15-pg16-transformer`
6+
- **PR**: [#175](https://github.com/launchql/pgsql-parser/pull/175)
7+
8+
## Progress Summary
9+
Started from a basic skeleton transformer and systematically implemented node wrapping and transformation logic across all node types. Made significant progress improving test pass rate from initial ~30% to current 71.3%.
10+
11+
## Key Achievements
12+
- ✅ Implemented comprehensive node transformation methods for 100+ node types
13+
- ✅ Fixed node wrapping issues across SelectStmt, InsertStmt, UpdateStmt, DeleteStmt
14+
- ✅ Resolved PartitionSpec strategy mapping in CreateStmt method
15+
- ✅ Added proper Array handling to transform method for nested node processing
16+
- ✅ Established stable baseline of 184/258 tests passing locally
17+
18+
## Current Challenge: Negative Integer Transformation
19+
**Root Issue**: PG15 produces `"ival": {}` (empty objects) where PG16 expects `"ival": {"ival": -3}` for negative integers in A_Const nodes.
20+
21+
**Analysis Completed**:
22+
- Created detailed debug scripts to analyze transformation flow
23+
- Identified that A_Const method calls `this.transform()` on empty ival objects
24+
- Empty objects `{}` don't get routed to Integer method due to missing node wrapper structure
25+
- Need targeted fix that distinguishes between zero values (should remain empty) and negative values (need nested structure)
26+
27+
**Attempted Solutions**:
28+
- ❌ Broad A_Const fix (transforms all empty ival objects) - caused test pass rate to drop to 144/258
29+
- ❌ Context-based detection (constraint/ALTER TABLE contexts) - caused test pass rate to drop to 174/258
30+
- ✅ Successfully reverted to stable 184/258 baseline after testing approaches
31+
- 🔄 Dual-parse approach explored but @pgsql/parser returns empty objects for all SQL queries
32+
33+
## Debug Tools Created
34+
- `debug_transformation_flow_detailed.js` - Analyzes exact transformation flow for negative integers
35+
- `debug_sql_value_analysis.js` - Compares PG15 vs PG16 behavior across test cases
36+
- `debug_ival_contexts.js` - Analyzes empty ival contexts across different SQL scenarios
37+
- `debug_alternative_approach.js` - Explores alternative detection methods beyond context analysis
38+
- `debug_insert_negative.js` - Tests specific INSERT statement with negative value
39+
- `debug_zero_vs_negative.js` - Compares zero vs negative value handling
40+
- `debug_context_analysis.js` - Analyzes context-dependent transformation patterns
41+
42+
## Next Steps
43+
1. Investigate alternative approaches beyond context-based and dual-parse methods
44+
2. Consider advanced pattern matching or heuristic detection for negative integer cases
45+
3. Explore selective transformation targeting only high-confidence scenarios
46+
4. Verify specific failing test cases like `alter_table-234.sql`
47+
5. Continue systematic improvement of remaining 74 failing tests
48+
49+
## Test Categories
50+
- **Passing (184)**: Basic node transformations, most SQL constructs
51+
- **Failing (74)**: Primarily negative integer transformations, some complex nested structures
52+
53+
## Technical Notes
54+
- Following patterns from v13-to-v14 transformer as reference
55+
- Focus only on v15-to-v16 transformer per user instructions
56+
- Ignoring CI failures per user directive, focusing on local test improvements
57+
- Maintaining systematic approach to avoid regressions

packages/transform/STATUS-16-17.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,47 @@
1-
not started — see previous status docs for format style.
1+
# PostgreSQL 16-to-17 AST Transformer Status
2+
3+
## Current Status: 98.8% Complete (255/258 tests passing)
4+
5+
### Test Results (Confirmed: June 28, 2025)
6+
- **Total tests**: 258
7+
- **Passing**: 255 (98.8%)
8+
- **Failing**: 3 (1.2%)
9+
10+
### Progress Summary
11+
-**Core transformer implementation**: Complete
12+
-**Basic AST node transformations**: Complete
13+
-**Domain creation contexts**: Fixed
14+
-**SELECT statement contexts**: Fixed
15+
- ⚠️ **Complex nested contexts**: 3 remaining failures
16+
17+
### Remaining Test Failures
18+
1. **pretty-misc.test.ts**: JSON TypeCast prefix handling
19+
- Issue: Transformer adding pg_catalog prefix when expected output has none
20+
- Context: WITH clauses containing A_Expr with JSON TypeCasts
21+
- Status: Logic needs to be reversed - remove prefixes instead of adding them
22+
23+
2. **misc-quotes_etc.test.ts**: String escaping issue
24+
- Issue: \v character handling difference between PG16/PG17
25+
- Expected: `\v` → Received: `v`
26+
- Status: Likely parser-level difference, not transformer issue
27+
28+
3. **latest-postgres-create_am.test.ts**: CREATE ACCESS METHOD syntax
29+
- Issue: `syntax error at or near "DEFAULT"`
30+
- Status: PG16 parser limitation - syntax not supported in PG16
31+
32+
### Key Insights
33+
- **JSON prefix logic**: Test failures show expected output does NOT want pg_catalog prefixes
34+
- **String escaping**: PG16/PG17 parser difference in escape sequence handling
35+
- **CREATE ACCESS METHOD**: PG16 parser doesn't support this PG17 syntax feature
36+
37+
### Technical Details
38+
- **Branch**: pg16-pg17-transformer
39+
- **PR**: #177 (https://github.com/launchql/pgsql-parser/pull/177)
40+
- **Last test run**: June 28, 2025 20:47 UTC
41+
- **Current approach**: Context-aware transformation based on parent node types
42+
43+
### Next Steps to Achieve 100%
44+
1. **Remove JSON pg_catalog prefix logic entirely** from TypeCast method
45+
2. **Investigate String method** for \v character handling
46+
3. **Document CREATE ACCESS METHOD limitation** as expected PG16 parser constraint
47+
4. **Final test run** to confirm 258/258 success rate

packages/transform/TODO.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# TODO: Transform Package Improvements
2+
3+
## Type Safety Improvements
4+
5+
### Add Return Type Annotations to Transformer Methods
6+
- **Priority**: High
7+
- **Description**: Add proper TypeScript return type annotations to all transformer methods in v15-to-v16.ts (and other transformers)
8+
- **Benefit**: Would catch structural issues like double-wrapping at compile time instead of runtime
9+
- **Example**:
10+
```typescript
11+
TypeName(node: PG15.TypeName, context: TransformerContext): { TypeName: PG16.TypeName } {
12+
// implementation
13+
}
14+
```
15+
- **Impact**: Prevents bugs like the double-wrapping issue we encountered where `{"TypeName": {"TypeName": {...}}}` was produced instead of `{"TypeName": {...}}`
16+
17+
### Improve Type Definitions
18+
- Add stricter typing for node transformation methods
19+
- Consider using mapped types for consistent return type patterns
20+
- Add compile-time validation for node wrapping consistency
21+
22+
## Testing Improvements
23+
- Add unit tests for individual transformer methods
24+
- Create focused test cases for edge cases like empty Integer nodes
25+
- Improve error messages in transformation mismatches
26+
27+
## Documentation
28+
- Document transformation patterns and conventions
29+
- Add examples of proper node wrapping
30+
- Document debugging strategies for transformation issues
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const fs = require('fs');
2+
3+
function analyze15To16CIFailures() {
4+
const logFile = '/home/ubuntu/full_outputs/gh_run_view_log_fail_1751134577.6148772.txt';
5+
6+
try {
7+
const content = fs.readFileSync(logFile, 'utf8');
8+
9+
const lines = content.split('\n');
10+
const failures15to16 = [];
11+
let currentFailure = null;
12+
let isIn15to16 = false;
13+
14+
for (let i = 0; i < lines.length; i++) {
15+
const line = lines[i];
16+
17+
if (line.includes('FAIL __tests__/kitchen-sink/15-16/')) {
18+
isIn15to16 = true;
19+
if (currentFailure) {
20+
failures15to16.push(currentFailure);
21+
}
22+
currentFailure = {
23+
testFile: line.split('FAIL ')[1],
24+
errors: [],
25+
fullContext: []
26+
};
27+
} else if (line.includes('FAIL __tests__/kitchen-sink/') && !line.includes('15-16')) {
28+
isIn15to16 = false;
29+
if (currentFailure && isIn15to16) {
30+
failures15to16.push(currentFailure);
31+
currentFailure = null;
32+
}
33+
}
34+
35+
if (isIn15to16 && currentFailure) {
36+
currentFailure.fullContext.push(line);
37+
38+
if (line.includes('- Expected') || line.includes('+ Received') ||
39+
line.includes('ival') || line.includes('Integer')) {
40+
const errorContext = lines.slice(Math.max(0, i-3), i+7).join('\n');
41+
currentFailure.errors.push(errorContext);
42+
}
43+
}
44+
}
45+
46+
if (currentFailure && isIn15to16) {
47+
failures15to16.push(currentFailure);
48+
}
49+
50+
console.log('=== 15-16 CI FAILURE ANALYSIS ===');
51+
console.log(`Total 15-16 failures found: ${failures15to16.length}`);
52+
53+
const errorPatterns = {
54+
'ival_empty_to_nested': 0,
55+
'integer_wrapping': 0,
56+
'negative_integer': 0,
57+
'missing_node_wrapping': 0
58+
};
59+
60+
failures15to16.forEach(f => {
61+
f.errors.forEach(error => {
62+
if (error.includes('ival') && error.includes('{}') && error.includes('ival":')) {
63+
errorPatterns.ival_empty_to_nested++;
64+
}
65+
if (error.includes('Integer') && error.includes('+') && error.includes('-')) {
66+
errorPatterns.integer_wrapping++;
67+
}
68+
if (error.includes('-3') || error.includes('negative')) {
69+
errorPatterns.negative_integer++;
70+
}
71+
if (error.includes('+ ') && error.includes('Object {')) {
72+
errorPatterns.missing_node_wrapping++;
73+
}
74+
});
75+
});
76+
77+
console.log('\n=== 15-16 ERROR PATTERNS ===');
78+
Object.entries(errorPatterns).forEach(([pattern, count]) => {
79+
console.log(`${pattern}: ${count} occurrences`);
80+
});
81+
82+
console.log('\n=== DETAILED 15-16 FAILURES ===');
83+
failures15to16.slice(0, 3).forEach((f, i) => {
84+
console.log(`\n--- Failure ${i+1}: ${f.testFile} ---`);
85+
if (f.errors.length > 0) {
86+
console.log(f.errors[0].substring(0, 800));
87+
} else {
88+
console.log('No specific error patterns found, showing context:');
89+
console.log(f.fullContext.slice(-20).join('\n').substring(0, 800));
90+
}
91+
console.log('...\n');
92+
});
93+
94+
console.log('\n=== COMPARISON WITH LOCAL FAILURES ===');
95+
console.log('CI shows 148 failures in 15-16 transformer');
96+
console.log('Local shows 74 failures in 15-16 transformer');
97+
console.log('Difference suggests CI may be testing additional scenarios or environment differences');
98+
99+
} catch (error) {
100+
console.error('Error analyzing CI failures:', error.message);
101+
}
102+
}
103+
104+
analyze15To16CIFailures();
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
const fs = require('fs');
2+
3+
function analyzeCIFailures() {
4+
const logFile = '/home/ubuntu/full_outputs/gh_run_view_log_fail_1751134169.160914.txt';
5+
6+
try {
7+
const content = fs.readFileSync(logFile, 'utf8');
8+
9+
const lines = content.split('\n');
10+
const failures = [];
11+
let currentFailure = null;
12+
13+
for (let i = 0; i < lines.length; i++) {
14+
const line = lines[i];
15+
16+
if (line.includes('FAIL __tests__/kitchen-sink/')) {
17+
const match = line.match(/FAIL __tests__\/kitchen-sink\/(\d+-\d+)\//);
18+
if (match) {
19+
if (currentFailure) {
20+
failures.push(currentFailure);
21+
}
22+
currentFailure = {
23+
transformer: match[1],
24+
testFile: line.split('FAIL ')[1],
25+
errors: []
26+
};
27+
}
28+
}
29+
30+
if (currentFailure && (line.includes('- Expected') || line.includes('+ Received'))) {
31+
const errorContext = lines.slice(Math.max(0, i-5), i+10).join('\n');
32+
currentFailure.errors.push(errorContext);
33+
}
34+
}
35+
36+
if (currentFailure) {
37+
failures.push(currentFailure);
38+
}
39+
40+
console.log('=== CI FAILURE ANALYSIS ===');
41+
console.log(`Total failures found: ${failures.length}`);
42+
43+
const transformerCounts = {};
44+
failures.forEach(f => {
45+
transformerCounts[f.transformer] = (transformerCounts[f.transformer] || 0) + 1;
46+
});
47+
48+
console.log('\n=== FAILURES BY TRANSFORMER ===');
49+
Object.entries(transformerCounts).forEach(([transformer, count]) => {
50+
console.log(`${transformer}: ${count} failures`);
51+
});
52+
53+
const errorPatterns = {
54+
'str_to_sval': 0,
55+
'missing_wrapping': 0,
56+
'ival_issues': 0
57+
};
58+
59+
failures.forEach(f => {
60+
f.errors.forEach(error => {
61+
if (error.includes('"str":') && error.includes('"sval":')) {
62+
errorPatterns.str_to_sval++;
63+
}
64+
if (error.includes('+ ') && error.includes('Object {')) {
65+
errorPatterns.missing_wrapping++;
66+
}
67+
if (error.includes('ival')) {
68+
errorPatterns.ival_issues++;
69+
}
70+
});
71+
});
72+
73+
console.log('\n=== ERROR PATTERNS ===');
74+
Object.entries(errorPatterns).forEach(([pattern, count]) => {
75+
console.log(`${pattern}: ${count} occurrences`);
76+
});
77+
78+
const my_failures = failures.filter(f => f.transformer === '15-16').slice(0, 3);
79+
console.log('\n=== SAMPLE 15-16 FAILURES ===');
80+
my_failures.forEach((f, i) => {
81+
console.log(`\n--- Failure ${i+1}: ${f.testFile} ---`);
82+
if (f.errors.length > 0) {
83+
console.log(f.errors[0].substring(0, 500) + '...');
84+
}
85+
});
86+
87+
} catch (error) {
88+
console.error('Error analyzing CI failures:', error.message);
89+
}
90+
}
91+
92+
analyzeCIFailures();

0 commit comments

Comments
 (0)