Skip to content

Commit 06260dd

Browse files
committed
add pg_collation to pg_catalog
1 parent b279611 commit 06260dd

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed

rust/cubesql/cubesql/src/compile/engine/information_schema/postgres/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ mod pg_type;
5858
mod pg_user;
5959
mod pg_user_mapping;
6060
mod pg_views;
61+
mod pg_collation;
6162
mod role_column_grants;
6263
mod role_table_grants;
6364
mod testing_blocking;
@@ -109,6 +110,7 @@ pub use pg_type::*;
109110
pub use pg_user::*;
110111
pub use pg_user_mapping::*;
111112
pub use pg_views::*;
113+
pub use pg_collation::*;
112114
pub use role_column_grants::*;
113115
pub use role_table_grants::*;
114116
pub use sql_implementation_info::*;
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
use std::sync::Arc;
2+
3+
use async_trait::async_trait;
4+
5+
use datafusion::{
6+
arrow::{
7+
array::{Array, ArrayRef, BooleanBuilder, Int32Builder, StringBuilder, UInt32Builder},
8+
datatypes::{DataType, Field, Schema},
9+
record_batch::RecordBatch,
10+
},
11+
datasource::{datasource::TableProviderFilterPushDown, TableProvider},
12+
error::Result,
13+
logical_plan::Expr,
14+
physical_plan::{memory::MemoryExec, ExecutionPlan},
15+
};
16+
17+
use crate::compile::engine::information_schema::postgres::PG_NAMESPACE_CATALOG_OID;
18+
19+
struct PgCollation {
20+
oid: u32,
21+
collname: &'static str,
22+
collnamespace: u32,
23+
collowner: u32,
24+
collprovider: String,
25+
collisdeterministic: bool,
26+
collencoding: i32,
27+
collcollate: Option<String>,
28+
collctype: Option<String>,
29+
// Column `colliculocale` renamed to `colllocale` since PostgreSQL 17.
30+
// Support both columns for backward-compatibility.
31+
// Reference: https://pgpedia.info/p/pg_collation.html
32+
colliculocale: Option<String>,
33+
colllocale: Option<String>,
34+
collicurules: Option<String>,
35+
collversion: Option<String>,
36+
}
37+
38+
struct PgCatalogCollationBuilder {
39+
oid: UInt32Builder,
40+
collname: StringBuilder,
41+
collnamespace: UInt32Builder,
42+
collowner: UInt32Builder,
43+
collprovider: StringBuilder,
44+
collisdeterministic: BooleanBuilder,
45+
collencoding: Int32Builder,
46+
colliculocale: StringBuilder,
47+
collcollate: StringBuilder,
48+
collctype: StringBuilder,
49+
colllocale: StringBuilder,
50+
collicurules: StringBuilder,
51+
collversion: StringBuilder,
52+
}
53+
54+
impl PgCatalogCollationBuilder {
55+
fn new() -> Self {
56+
let capacity = 5;
57+
Self {
58+
oid: UInt32Builder::new(capacity),
59+
collname: StringBuilder::new(capacity),
60+
collnamespace: UInt32Builder::new(capacity),
61+
collowner: UInt32Builder::new(capacity),
62+
collprovider: StringBuilder::new(capacity),
63+
collisdeterministic: BooleanBuilder::new(capacity),
64+
collencoding: Int32Builder::new(capacity),
65+
colliculocale: StringBuilder::new(capacity),
66+
collcollate: StringBuilder::new(capacity),
67+
collctype: StringBuilder::new(capacity),
68+
colllocale: StringBuilder::new(capacity),
69+
collicurules: StringBuilder::new(capacity),
70+
collversion: StringBuilder::new(capacity),
71+
}
72+
}
73+
fn add_collation(&mut self, coll: &PgCollation) {
74+
self.oid.append_value(coll.oid).unwrap();
75+
self.collname.append_value(coll.collname).unwrap();
76+
self.collnamespace.append_value(coll.collnamespace).unwrap();
77+
self.collowner.append_value(coll.collowner).unwrap();
78+
self.collprovider
79+
.append_value(coll.collprovider.clone())
80+
.unwrap();
81+
self.collisdeterministic
82+
.append_value(coll.collisdeterministic)
83+
.unwrap();
84+
self.collencoding.append_value(coll.collencoding).unwrap();
85+
self.colliculocale
86+
.append_option(coll.colliculocale.clone())
87+
.unwrap();
88+
self.collcollate
89+
.append_option(coll.collcollate.clone())
90+
.unwrap();
91+
self.collctype
92+
.append_option(coll.collctype.clone())
93+
.unwrap();
94+
self.collicurules
95+
.append_option(coll.collicurules.clone())
96+
.unwrap();
97+
self.colllocale
98+
.append_option(coll.colllocale.clone())
99+
.unwrap();
100+
self.collversion
101+
.append_option(coll.collversion.clone())
102+
.unwrap();
103+
}
104+
105+
fn finish(mut self) -> Vec<Arc<dyn Array>> {
106+
let columns: Vec<Arc<dyn Array>> = vec![
107+
Arc::new(self.oid.finish()),
108+
Arc::new(self.collname.finish()),
109+
Arc::new(self.collnamespace.finish()),
110+
Arc::new(self.collowner.finish()),
111+
Arc::new(self.collprovider.finish()),
112+
Arc::new(self.collisdeterministic.finish()),
113+
Arc::new(self.collencoding.finish()),
114+
Arc::new(self.colliculocale.finish()),
115+
Arc::new(self.collcollate.finish()),
116+
Arc::new(self.collctype.finish()),
117+
Arc::new(self.collicurules.finish()),
118+
Arc::new(self.colllocale.finish()),
119+
Arc::new(self.collversion.finish()),
120+
];
121+
columns
122+
}
123+
}
124+
125+
pub struct PgCatalogCollationProvider {
126+
data: Arc<Vec<ArrayRef>>,
127+
}
128+
129+
impl PgCatalogCollationProvider {
130+
pub fn new() -> Self {
131+
// See https://github.com/postgres/postgres/blob/REL_16_4/src/include/catalog/pg_collation.h
132+
let mut builder = PgCatalogCollationBuilder::new();
133+
134+
// Initial contents of the pg_collation system catalog.
135+
// See https://github.com/postgres/postgres/blob/REL_16_4/src/include/catalog/pg_collation.dat
136+
builder.add_collation(&PgCollation {
137+
oid: 100,
138+
collname: "default",
139+
collnamespace: PG_NAMESPACE_CATALOG_OID,
140+
collowner: 10,
141+
collprovider: "d".to_string(),
142+
collisdeterministic: true,
143+
collencoding: -1,
144+
collcollate: None,
145+
colliculocale: None,
146+
collctype: None,
147+
colllocale: None,
148+
collicurules: None,
149+
collversion: None,
150+
});
151+
builder.add_collation(&PgCollation {
152+
oid: 950,
153+
collname: "C",
154+
collnamespace: PG_NAMESPACE_CATALOG_OID,
155+
collowner: 10,
156+
collprovider: "c".to_string(),
157+
collisdeterministic: true,
158+
collencoding: -1,
159+
collcollate: Some("C".to_string()),
160+
colliculocale: Some("C".to_string()),
161+
collctype: Some("C".to_string()),
162+
colllocale: None,
163+
collicurules: None,
164+
collversion: None,
165+
});
166+
builder.add_collation(&PgCollation {
167+
oid: 951,
168+
collname: "POSIX",
169+
collnamespace: PG_NAMESPACE_CATALOG_OID,
170+
collowner: 10,
171+
collprovider: "c".to_string(),
172+
collisdeterministic: true,
173+
collencoding: -1,
174+
collcollate: Some("POSIX".to_string()),
175+
colliculocale: Some("POSIX".to_string()),
176+
collctype: Some("POSIX".to_string()),
177+
colllocale: None,
178+
collicurules: None,
179+
collversion: None,
180+
});
181+
builder.add_collation(&PgCollation {
182+
oid: 962,
183+
collname: "usc_basic",
184+
collnamespace: PG_NAMESPACE_CATALOG_OID,
185+
collowner: 10,
186+
collprovider: "c".to_string(),
187+
collisdeterministic: true,
188+
collencoding: 6,
189+
collcollate: Some("C".to_string()),
190+
colliculocale: Some("C".to_string()),
191+
collctype: Some("C".to_string()),
192+
colllocale: None,
193+
collicurules: None,
194+
collversion: None,
195+
});
196+
builder.add_collation(&PgCollation {
197+
oid: 963,
198+
collname: "unicode",
199+
collnamespace: PG_NAMESPACE_CATALOG_OID,
200+
collowner: 10,
201+
collprovider: "i".to_string(),
202+
collisdeterministic: true,
203+
collencoding: -1,
204+
collcollate: None,
205+
colliculocale: None,
206+
collctype: None,
207+
colllocale: Some("und".to_string()),
208+
collicurules: None,
209+
collversion: Some("153.121".to_string()),
210+
});
211+
Self {
212+
data: Arc::new(builder.finish()),
213+
}
214+
}
215+
}
216+
217+
#[async_trait]
218+
impl TableProvider for PgCatalogCollationProvider {
219+
fn as_any(&self) -> &dyn std::any::Any {
220+
self
221+
}
222+
fn schema(&self) -> datafusion::arrow::datatypes::SchemaRef {
223+
Arc::new(Schema::new(vec![
224+
Field::new("oid", DataType::UInt32, false),
225+
Field::new("collname", DataType::Utf8, false),
226+
Field::new("collnamespace", DataType::UInt32, false),
227+
]))
228+
}
229+
async fn scan(
230+
&self,
231+
projection: &Option<Vec<usize>>,
232+
_filters: &[Expr],
233+
// limit can be used to reduce the amount scanned
234+
// from the datasource as a performance optimization.
235+
// If set, it contains the amount of rows needed by the `LogicalPlan`,
236+
// The datasource should return *at least* this number of rows if available.
237+
_limit: Option<usize>,
238+
) -> Result<Arc<dyn ExecutionPlan>> {
239+
let batch = RecordBatch::try_new(self.schema(), self.data.to_vec())?;
240+
Ok(Arc::new(MemoryExec::try_new(
241+
&[vec![batch]],
242+
self.schema(),
243+
projection.clone(),
244+
)?))
245+
}
246+
fn supports_filter_pushdown(&self, _filter: &Expr) -> Result<TableProviderFilterPushDown> {
247+
Ok(TableProviderFilterPushDown::Unsupported)
248+
}
249+
}

0 commit comments

Comments
 (0)