PG->Fabric (T-SQL): date_part with a typed text field literal drops the field -> DATEPART(DAY)
8<------------------------------------------------------------------------------8<
Description
When the first argument of date_part is a typed text literal ('year'::text, as emitted
by PostgreSQL's own deparser pg_get_viewdef/pg_get_querydef), the Fabric transpiler discards
the field name and emits DATEPART(DAY, …) regardless of the requested field. A bare literal
('year') is preserved. Because tools that round-trip through the PostgreSQL deparser always
produce the typed form, every date_part(<field>, d) silently returns the day-of-month.
Root cause (pointer)
The date_part -> DATEPART mapping only recognises a bare string literal as the field
argument; a Cast(StringLiteral, TEXT) node is not unwrapped, so the field is lost and the
emitter falls back to its DAY default.
Affected constructs
date_part('year'::text, d), date_part('month'::text, d), date_part('quarter'::text, d),
date_part('week'::text, d), date_part('dow'::text, d) — all collapse to DATEPART(DAY, d).
(EXTRACT(field FROM d) is unaffected — it maps correctly.)
Repro
Cargo.toml:
[package]
name = "datepart_typed_repro"
version = "0.1.0"
edition = "2021"
[dependencies]
polyglot-sql = "0.5.15"
src/main.rs:
use polyglot_sql::{Dialect, DialectType, TranspileOptions};
fn go(sql: &str) {
let d = Dialect::get(DialectType::PostgreSQL).unwrap();
match d.transpile_with(sql, DialectType::Fabric, TranspileOptions::strict()) {
Ok(out) => println!("IN : {sql}\nOUT: {}\n", out.join("; ")),
Err(e) => println!("IN : {sql}\nERR: {e}\n"),
}
}
fn main() {
// typed literal (what pg_get_viewdef emits) -> field dropped, defaults to DAY
go("SELECT date_part('year'::text, f1) FROM date_tbl");
go("SELECT date_part('month'::text, f1) FROM date_tbl");
go("SELECT date_part('dow'::text, f1) FROM date_tbl");
// bare literal -> field preserved (for contrast)
go("SELECT date_part('year', f1) FROM date_tbl");
}
Captured output (polyglot-sql 0.5.15):
IN : SELECT date_part('year'::text, f1) FROM date_tbl
OUT: SELECT DATEPART(DAY, f1) FROM date_tbl
IN : SELECT date_part('month'::text, f1) FROM date_tbl
OUT: SELECT DATEPART(DAY, f1) FROM date_tbl
IN : SELECT date_part('dow'::text, f1) FROM date_tbl
OUT: SELECT DATEPART(DAY, f1) FROM date_tbl
IN : SELECT date_part('year', f1) FROM date_tbl
OUT: SELECT DATEPART(year, f1) FROM date_tbl
Expected
REWRITE: unwrap the ::text cast on the field literal and preserve the mapped datepart —
date_part('year'::text, d) -> DATEPART(year, d) (same as the bare form). If the field is
not mappable, REJECT rather than silently defaulting to DAY.
Notes
Sibling of the other PG->Fabric date/time reports (#281 exotic dateparts, #282 date_trunc,
#292 umbrella). This one is specifically the typed-literal field is dropped -> DAY path.
PG->Fabric (T-SQL): date_part with a typed text field literal drops the field -> DATEPART(DAY)
8<------------------------------------------------------------------------------8<
Description
When the first argument of
date_partis a typed text literal ('year'::text, as emittedby PostgreSQL's own deparser
pg_get_viewdef/pg_get_querydef), the Fabric transpiler discardsthe field name and emits
DATEPART(DAY, …)regardless of the requested field. A bare literal(
'year') is preserved. Because tools that round-trip through the PostgreSQL deparser alwaysproduce the typed form, every
date_part(<field>, d)silently returns the day-of-month.Root cause (pointer)
The
date_part->DATEPARTmapping only recognises a bare string literal as the fieldargument; a
Cast(StringLiteral, TEXT)node is not unwrapped, so the field is lost and theemitter falls back to its
DAYdefault.Affected constructs
date_part('year'::text, d),date_part('month'::text, d),date_part('quarter'::text, d),date_part('week'::text, d),date_part('dow'::text, d)— all collapse toDATEPART(DAY, d).(EXTRACT(field FROM d) is unaffected — it maps correctly.)
Repro
Cargo.toml:
src/main.rs:
Captured output (polyglot-sql 0.5.15):
Expected
REWRITE: unwrap the
::textcast on the field literal and preserve the mapped datepart —date_part('year'::text, d)->DATEPART(year, d)(same as the bare form). If the field isnot mappable, REJECT rather than silently defaulting to DAY.
Notes
Sibling of the other PG->Fabric date/time reports (#281 exotic dateparts, #282 date_trunc,
#292 umbrella). This one is specifically the typed-literal field is dropped -> DAY path.