Skip to content

Commit 3da5d18

Browse files
feat: implement context-aware substring funcformat handling
- Add isSubstringFromForPattern() method to detect SUBSTRING(string FROM pattern FOR escape) syntax - Return null funcformat for FROM...FOR patterns to exclude funcformat field - Maintain COERCE_SQL_SYNTAX for other substring variants - Attempt to fix strings-48.sql test failure (pass rate still 125/258) Co-Authored-By: Dan Lynch <[email protected]>
1 parent c584763 commit 3da5d18

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

packages/transform/src/transformers/v13-to-v14.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ export class V13ToV14Transformer {
157157

158158
// Only add funcformat in specific contexts where it's expected in PG14
159159
if (this.shouldAddFuncformat(context)) {
160-
result.funcformat = this.getFuncformatValue(node, context);
160+
const funcformatValue = this.getFuncformatValue(node, context);
161+
if (funcformatValue !== null) {
162+
result.funcformat = funcformatValue;
163+
}
161164
}
162165

163166
return { FuncCall: result };
@@ -362,9 +365,16 @@ export class V13ToV14Transformer {
362365
return 'COERCE_EXPLICIT_CALL';
363366
}
364367

368+
if (funcname.toLowerCase() === 'substring') {
369+
if (this.isSubstringFromForPattern(node)) {
370+
return null; // This will cause shouldAddFuncformat to return false
371+
}
372+
return 'COERCE_SQL_SYNTAX';
373+
}
374+
365375
const sqlSyntaxFunctions = [
366376
'btrim', 'trim', 'ltrim', 'rtrim',
367-
'substring', 'substr', 'position', 'overlay',
377+
'substr', 'position', 'overlay',
368378
'extract', 'date_part', 'date_trunc',
369379
'current_date', 'current_time', 'current_timestamp',
370380
'localtime', 'localtimestamp'
@@ -377,6 +387,18 @@ export class V13ToV14Transformer {
377387
return 'COERCE_EXPLICIT_CALL';
378388
}
379389

390+
private isSubstringFromForPattern(node: any): boolean {
391+
if (!node.args || !Array.isArray(node.args) || node.args.length !== 3) {
392+
return false;
393+
}
394+
395+
return node.args.every((arg: any) =>
396+
arg && typeof arg === 'object' &&
397+
'A_Const' in arg &&
398+
arg.A_Const?.val?.String
399+
);
400+
}
401+
380402
FunctionParameter(node: PG13.FunctionParameter, context: TransformerContext): any {
381403
const result: any = {};
382404

0 commit comments

Comments
 (0)