Skip to content

Commit cd4d4f9

Browse files
mjgartonsunng87
authored andcommitted
Describe table 0 (#252)
* Improve `pg_get_constraintdef` UDF `pg_get_constraintdef` can optionally take a boolean as a second parameter, so update the UDF to support this. * Implement `pg_partition_ancestors` Add a UDF for `pg_partition_ancestors` * Add tests for describe table in psql Add test for describing an example table (`\d customer`) to ensure we handle it properly. Most of the queries already worked fine (only 2 failed) but I added them all for completeness.
1 parent d7f9ee4 commit cd4d4f9

File tree

2 files changed

+168
-8
lines changed

2 files changed

+168
-8
lines changed

datafusion-pg-catalog/src/pg_catalog.rs

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use datafusion::catalog::{MemTable, SchemaProvider, TableFunctionImpl};
1414
use datafusion::common::utils::SingleRowListArrayBuilder;
1515
use datafusion::datasource::TableProvider;
1616
use datafusion::error::{DataFusionError, Result};
17-
use datafusion::logical_expr::{ColumnarValue, ScalarUDF, Volatility};
17+
use datafusion::logical_expr::{
18+
ColumnarValue, ScalarUDF, ScalarUDFImpl, Signature, TypeSignature, Volatility,
19+
};
1820
use datafusion::physical_plan::streaming::PartitionStream;
1921
use datafusion::prelude::{create_udf, Expr, SessionContext};
2022
use postgres_types::Oid;
@@ -1348,22 +1350,75 @@ pub fn create_pg_stat_get_numscans() -> ScalarUDF {
13481350
}
13491351

13501352
pub fn create_pg_get_constraintdef() -> ScalarUDF {
1353+
#[derive(Debug, PartialEq, Eq, Hash)]
1354+
struct GetConstraintDefUDF {
1355+
signature: Signature,
1356+
}
1357+
1358+
impl GetConstraintDefUDF {
1359+
fn new() -> Self {
1360+
let type_signature = TypeSignature::OneOf(vec![
1361+
TypeSignature::Exact(vec![DataType::Int32]),
1362+
TypeSignature::Exact(vec![DataType::Int32, DataType::Boolean]),
1363+
]);
1364+
1365+
let signature = Signature::new(type_signature, Volatility::Stable);
1366+
GetConstraintDefUDF { signature }
1367+
}
1368+
}
1369+
1370+
impl ScalarUDFImpl for GetConstraintDefUDF {
1371+
fn as_any(&self) -> &dyn std::any::Any {
1372+
self
1373+
}
1374+
1375+
fn name(&self) -> &str {
1376+
"pg_get_constraintdef"
1377+
}
1378+
1379+
fn signature(&self) -> &Signature {
1380+
&self.signature
1381+
}
1382+
1383+
fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
1384+
Ok(DataType::Utf8)
1385+
}
1386+
1387+
fn invoke_with_args(
1388+
&self,
1389+
args: datafusion::logical_expr::ScalarFunctionArgs,
1390+
) -> Result<ColumnarValue> {
1391+
let args = ColumnarValue::values_to_arrays(&args.args)?;
1392+
let oids = &args[0].as_primitive::<Int32Type>();
1393+
1394+
let mut builder = StringBuilder::new();
1395+
for _ in 0..oids.len() {
1396+
builder.append_value("");
1397+
}
1398+
1399+
let array: ArrayRef = Arc::new(builder.finish());
1400+
Ok(ColumnarValue::Array(array))
1401+
}
1402+
}
1403+
1404+
GetConstraintDefUDF::new().into()
1405+
}
1406+
1407+
pub fn create_pg_get_partition_ancestors_udf() -> ScalarUDF {
13511408
let func = move |args: &[ColumnarValue]| {
13521409
let args = ColumnarValue::values_to_arrays(args)?;
1353-
let oids = &args[0].as_primitive::<Int32Type>();
1410+
let string_array = args[0].as_string::<i32>();
13541411

13551412
let mut builder = StringBuilder::new();
1356-
for _ in 0..oids.len() {
1357-
builder.append_value("");
1358-
}
1359-
1413+
string_array.iter().for_each(|i| builder.append_option(i));
13601414
let array: ArrayRef = Arc::new(builder.finish());
1415+
13611416
Ok(ColumnarValue::Array(array))
13621417
};
13631418

13641419
create_udf(
1365-
"pg_get_constraintdef",
1366-
vec![DataType::Int32],
1420+
"pg_partition_ancestors",
1421+
vec![DataType::Utf8],
13671422
DataType::Utf8,
13681423
Volatility::Stable,
13691424
Arc::new(func),
@@ -1425,6 +1480,7 @@ where
14251480
session_context.register_udf(create_pg_total_relation_size_udf());
14261481
session_context.register_udf(create_pg_stat_get_numscans());
14271482
session_context.register_udf(create_pg_get_constraintdef());
1483+
session_context.register_udf(create_pg_get_partition_ancestors_udf());
14281484

14291485
Ok(())
14301486
}

datafusion-postgres/tests/psql.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,110 @@ const PSQL_QUERIES: &[&str] = &[
104104
CASE WHEN pg_catalog.array_length(d.datacl, 1) = 0 THEN '(none)' ELSE pg_catalog.array_to_string(d.datacl, E'\n') END AS "Access privileges"
105105
FROM pg_catalog.pg_database d
106106
ORDER BY 1;"#,
107+
108+
// Queries from describing a table, for example `\d customer`
109+
110+
r#"SELECT c.oid,
111+
n.nspname,
112+
c.relname
113+
FROM pg_catalog.pg_class c
114+
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
115+
WHERE c.relname OPERATOR(pg_catalog.~) '^(customer)$' COLLATE pg_catalog.default
116+
AND pg_catalog.pg_table_is_visible(c.oid)
117+
ORDER BY 2, 3;"#,
118+
119+
r#"SELECT a.attname,
120+
pg_catalog.format_type(a.atttypid, a.atttypmod),
121+
(SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid, true)
122+
FROM pg_catalog.pg_attrdef d
123+
WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),
124+
a.attnotnull,
125+
(SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t
126+
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation,
127+
a.attidentity,
128+
a.attgenerated
129+
FROM pg_catalog.pg_attribute a
130+
WHERE a.attrelid = '16417' AND a.attnum > 0 AND NOT a.attisdropped
131+
ORDER BY a.attnum;"#,
132+
133+
134+
r#"SELECT true as sametable, conname,
135+
pg_catalog.pg_get_constraintdef(r.oid, true) as condef,
136+
conrelid::pg_catalog.regclass AS ontable
137+
FROM pg_catalog.pg_constraint r
138+
WHERE r.conrelid = '16417' AND r.contype = 'f'
139+
AND conparentid = 0
140+
ORDER BY conname;"#,
141+
142+
r#"SELECT conname, conrelid::pg_catalog.regclass AS ontable,
143+
pg_catalog.pg_get_constraintdef(oid, true) AS condef
144+
FROM pg_catalog.pg_constraint c
145+
WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('16417')
146+
UNION ALL VALUES ('16417'::pg_catalog.regclass))
147+
AND contype = 'f' AND conparentid = 0
148+
ORDER BY conname;"#,
149+
150+
r#"SELECT pol.polname, pol.polpermissive,
151+
CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,
152+
pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),
153+
pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),
154+
CASE pol.polcmd
155+
WHEN 'r' THEN 'SELECT'
156+
WHEN 'a' THEN 'INSERT'
157+
WHEN 'w' THEN 'UPDATE'
158+
WHEN 'd' THEN 'DELETE'
159+
END AS cmd
160+
FROM pg_catalog.pg_policy pol
161+
WHERE pol.polrelid = '16417' ORDER BY 1;"#,
162+
163+
r#"SELECT oid, stxrelid::pg_catalog.regclass, stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS nsp, stxname,
164+
pg_catalog.pg_get_statisticsobjdef_columns(oid) AS columns,
165+
'd' = any(stxkind) AS ndist_enabled,
166+
'f' = any(stxkind) AS deps_enabled,
167+
'm' = any(stxkind) AS mcv_enabled,
168+
stxstattarget
169+
FROM pg_catalog.pg_statistic_ext
170+
WHERE stxrelid = '16417'
171+
ORDER BY nsp, stxname;"#,
172+
173+
r#"SELECT pubname
174+
, NULL
175+
, NULL
176+
FROM pg_catalog.pg_publication p
177+
JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid
178+
JOIN pg_catalog.pg_class pc ON pc.relnamespace = pn.pnnspid
179+
WHERE pc.oid ='16417' and pg_catalog.pg_relation_is_publishable('16417')
180+
UNION
181+
SELECT pubname
182+
, pg_get_expr(pr.prqual, c.oid)
183+
, (CASE WHEN pr.prattrs IS NOT NULL THEN
184+
(SELECT string_agg(attname, ', ')
185+
FROM pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,
186+
pg_catalog.pg_attribute
187+
WHERE attrelid = pr.prrelid AND attnum = prattrs[s])
188+
ELSE NULL END) FROM pg_catalog.pg_publication p
189+
JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid
190+
JOIN pg_catalog.pg_class c ON c.oid = pr.prrelid
191+
WHERE pr.prrelid = '16417'
192+
UNION
193+
SELECT pubname
194+
, NULL
195+
, NULL
196+
FROM pg_catalog.pg_publication p
197+
WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('16417')
198+
ORDER BY 1;"#,
199+
200+
r#"SELECT c.oid::pg_catalog.regclass
201+
FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i
202+
WHERE c.oid = i.inhparent AND i.inhrelid = '16417'
203+
AND c.relkind != 'p' AND c.relkind != 'I'
204+
ORDER BY inhseqno;"#,
205+
206+
r#"SELECT c.oid::pg_catalog.regclass, c.relkind, inhdetachpending, pg_catalog.pg_get_expr(c.relpartbound, c.oid)
207+
FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i
208+
WHERE c.oid = i.inhrelid AND i.inhparent = '16417'
209+
ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT', c.oid::pg_catalog.regclass::pg_catalog.text;"#,
210+
107211
];
108212

109213
#[tokio::test]

0 commit comments

Comments
 (0)