1use std::sync::{Arc, Weak};
16
17use arrow_schema::SchemaRef as ArrowSchemaRef;
18use common_catalog::consts::{
19 INFORMATION_SCHEMA_COLUMNS_TABLE_ID, SEMANTIC_TYPE_FIELD, SEMANTIC_TYPE_PRIMARY_KEY,
20 SEMANTIC_TYPE_TIME_INDEX,
21};
22use common_error::ext::BoxedError;
23use common_recordbatch::adapter::RecordBatchStreamAdapter;
24use common_recordbatch::{RecordBatch, SendableRecordBatchStream};
25use datafusion::execution::TaskContext;
26use datafusion::physical_plan::SendableRecordBatchStream as DfSendableRecordBatchStream;
27use datafusion::physical_plan::stream::RecordBatchStreamAdapter as DfRecordBatchStreamAdapter;
28use datafusion::physical_plan::streaming::PartitionStream as DfPartitionStream;
29use datatypes::prelude::{ConcreteDataType, DataType, MutableVector};
30use datatypes::scalars::ScalarVectorBuilder;
31use datatypes::schema::{ColumnSchema, Schema, SchemaRef};
32use datatypes::value::Value;
33use datatypes::vectors::{
34 Int64Vector, Int64VectorBuilder, StringVector, StringVectorBuilder, VectorRef,
35};
36use futures::TryStreamExt;
37use snafu::{OptionExt, ResultExt};
38use sql::statements;
39use store_api::storage::{ScanRequest, TableId};
40
41use crate::CatalogManager;
42use crate::error::{
43 CreateRecordBatchSnafu, InternalSnafu, Result, UpgradeWeakCatalogManagerRefSnafu,
44};
45use crate::information_schema::Predicates;
46use crate::system_schema::SystemTable;
47use crate::system_schema::information_schema::{
48 COLUMNS, InformationSchemaTableScope, InformationTable,
49};
50
51#[derive(Debug)]
52pub(super) struct InformationSchemaColumns {
53 schema: SchemaRef,
54 catalog_name: String,
55 catalog_manager: Weak<dyn CatalogManager>,
56}
57
58pub const TABLE_CATALOG: &str = "table_catalog";
59pub const TABLE_SCHEMA: &str = "table_schema";
60pub const TABLE_NAME: &str = "table_name";
61pub const COLUMN_NAME: &str = "column_name";
62pub const REGION_ID: &str = "region_id";
63pub const PEER_ID: &str = "peer_id";
64const ORDINAL_POSITION: &str = "ordinal_position";
65const CHARACTER_MAXIMUM_LENGTH: &str = "character_maximum_length";
66const CHARACTER_OCTET_LENGTH: &str = "character_octet_length";
67const NUMERIC_PRECISION: &str = "numeric_precision";
68const NUMERIC_SCALE: &str = "numeric_scale";
69const DATETIME_PRECISION: &str = "datetime_precision";
70const CHARACTER_SET_NAME: &str = "character_set_name";
71pub const COLLATION_NAME: &str = "collation_name";
72pub const COLUMN_KEY: &str = "column_key";
73pub const EXTRA: &str = "extra";
74pub const PRIVILEGES: &str = "privileges";
75const GENERATION_EXPRESSION: &str = "generation_expression";
76pub const GREPTIME_DATA_TYPE: &str = "greptime_data_type";
78pub const DATA_TYPE: &str = "data_type";
79pub const SEMANTIC_TYPE: &str = "semantic_type";
80pub const COLUMN_DEFAULT: &str = "column_default";
81pub const IS_NULLABLE: &str = "is_nullable";
82const COLUMN_TYPE: &str = "column_type";
83pub const COLUMN_COMMENT: &str = "column_comment";
84const SRS_ID: &str = "srs_id";
85const INIT_CAPACITY: usize = 42;
86
87const MAX_STRING_LENGTH: i64 = 2147483647;
89const UTF8_CHARSET_NAME: &str = "utf8";
90const UTF8_COLLATE_NAME: &str = "utf8_bin";
91const PRI_COLUMN_KEY: &str = "PRI";
92const TIME_INDEX_COLUMN_KEY: &str = "TIME INDEX";
93const DEFAULT_PRIVILEGES: &str = "select,insert";
94const EMPTY_STR: &str = "";
95const YES: &str = "YES";
96const NO: &str = "NO";
97
98impl InformationSchemaColumns {
99 pub(super) fn new(catalog_name: String, catalog_manager: Weak<dyn CatalogManager>) -> Self {
100 Self {
101 schema: Self::schema(),
102 catalog_name,
103 catalog_manager,
104 }
105 }
106
107 fn schema() -> SchemaRef {
108 Arc::new(Schema::new(vec![
109 ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), false),
110 ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), false),
111 ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), false),
112 ColumnSchema::new(COLUMN_NAME, ConcreteDataType::string_datatype(), false),
113 ColumnSchema::new(ORDINAL_POSITION, ConcreteDataType::int64_datatype(), false),
114 ColumnSchema::new(
115 CHARACTER_MAXIMUM_LENGTH,
116 ConcreteDataType::int64_datatype(),
117 true,
118 ),
119 ColumnSchema::new(
120 CHARACTER_OCTET_LENGTH,
121 ConcreteDataType::int64_datatype(),
122 true,
123 ),
124 ColumnSchema::new(NUMERIC_PRECISION, ConcreteDataType::int64_datatype(), true),
125 ColumnSchema::new(NUMERIC_SCALE, ConcreteDataType::int64_datatype(), true),
126 ColumnSchema::new(DATETIME_PRECISION, ConcreteDataType::int64_datatype(), true),
127 ColumnSchema::new(
128 CHARACTER_SET_NAME,
129 ConcreteDataType::string_datatype(),
130 true,
131 ),
132 ColumnSchema::new(COLLATION_NAME, ConcreteDataType::string_datatype(), true),
133 ColumnSchema::new(COLUMN_KEY, ConcreteDataType::string_datatype(), false),
134 ColumnSchema::new(EXTRA, ConcreteDataType::string_datatype(), false),
135 ColumnSchema::new(PRIVILEGES, ConcreteDataType::string_datatype(), false),
136 ColumnSchema::new(
137 GENERATION_EXPRESSION,
138 ConcreteDataType::string_datatype(),
139 false,
140 ),
141 ColumnSchema::new(
142 GREPTIME_DATA_TYPE,
143 ConcreteDataType::string_datatype(),
144 false,
145 ),
146 ColumnSchema::new(DATA_TYPE, ConcreteDataType::string_datatype(), false),
147 ColumnSchema::new(SEMANTIC_TYPE, ConcreteDataType::string_datatype(), false),
148 ColumnSchema::new(COLUMN_DEFAULT, ConcreteDataType::string_datatype(), true),
149 ColumnSchema::new(IS_NULLABLE, ConcreteDataType::string_datatype(), false),
150 ColumnSchema::new(COLUMN_TYPE, ConcreteDataType::string_datatype(), false),
151 ColumnSchema::new(COLUMN_COMMENT, ConcreteDataType::string_datatype(), true),
152 ColumnSchema::new(SRS_ID, ConcreteDataType::int64_datatype(), true),
153 ]))
154 }
155
156 fn builder(&self) -> InformationSchemaColumnsBuilder {
157 InformationSchemaColumnsBuilder::new(
158 self.schema.clone(),
159 self.catalog_name.clone(),
160 self.catalog_manager.clone(),
161 )
162 }
163}
164
165impl InformationTable for InformationSchemaColumns {
166 fn scope(&self) -> InformationSchemaTableScope {
167 InformationSchemaTableScope::Catalog
168 }
169}
170
171impl SystemTable for InformationSchemaColumns {
172 fn table_id(&self) -> TableId {
173 INFORMATION_SCHEMA_COLUMNS_TABLE_ID
174 }
175
176 fn table_name(&self) -> &'static str {
177 COLUMNS
178 }
179
180 fn schema(&self) -> SchemaRef {
181 self.schema.clone()
182 }
183
184 fn to_stream(&self, request: ScanRequest) -> Result<SendableRecordBatchStream> {
185 let schema = self.schema.arrow_schema().clone();
186 let mut builder = self.builder();
187 let stream = Box::pin(DfRecordBatchStreamAdapter::new(
188 schema,
189 futures::stream::once(async move {
190 builder
191 .make_columns(Some(request))
192 .await
193 .map(|x| x.into_df_record_batch())
194 .map_err(Into::into)
195 }),
196 ));
197 Ok(Box::pin(
198 RecordBatchStreamAdapter::try_new(stream)
199 .map_err(BoxedError::new)
200 .context(InternalSnafu)?,
201 ))
202 }
203}
204
205struct InformationSchemaColumnsBuilder {
206 schema: SchemaRef,
207 catalog_name: String,
208 catalog_manager: Weak<dyn CatalogManager>,
209
210 catalog_names: StringVectorBuilder,
211 schema_names: StringVectorBuilder,
212 table_names: StringVectorBuilder,
213 column_names: StringVectorBuilder,
214 ordinal_positions: Int64VectorBuilder,
215 character_maximum_lengths: Int64VectorBuilder,
216 character_octet_lengths: Int64VectorBuilder,
217 numeric_precisions: Int64VectorBuilder,
218 numeric_scales: Int64VectorBuilder,
219 datetime_precisions: Int64VectorBuilder,
220 character_set_names: StringVectorBuilder,
221 collation_names: StringVectorBuilder,
222 column_keys: StringVectorBuilder,
223 greptime_data_types: StringVectorBuilder,
224 data_types: StringVectorBuilder,
225 semantic_types: StringVectorBuilder,
226 column_defaults: StringVectorBuilder,
227 is_nullables: StringVectorBuilder,
228 column_types: StringVectorBuilder,
229 column_comments: StringVectorBuilder,
230}
231
232impl InformationSchemaColumnsBuilder {
233 fn new(
234 schema: SchemaRef,
235 catalog_name: String,
236 catalog_manager: Weak<dyn CatalogManager>,
237 ) -> Self {
238 Self {
239 schema,
240 catalog_name,
241 catalog_manager,
242 catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
243 schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
244 table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
245 column_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
246 ordinal_positions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
247 character_maximum_lengths: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
248 character_octet_lengths: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
249 numeric_precisions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
250 numeric_scales: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
251 datetime_precisions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
252 character_set_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
253 collation_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
254 column_keys: StringVectorBuilder::with_capacity(INIT_CAPACITY),
255 greptime_data_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
256 data_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
257 semantic_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
258 column_defaults: StringVectorBuilder::with_capacity(INIT_CAPACITY),
259 is_nullables: StringVectorBuilder::with_capacity(INIT_CAPACITY),
260 column_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
261 column_comments: StringVectorBuilder::with_capacity(INIT_CAPACITY),
262 }
263 }
264
265 async fn make_columns(&mut self, request: Option<ScanRequest>) -> Result<RecordBatch> {
267 let catalog_name = self.catalog_name.clone();
268 let catalog_manager = self
269 .catalog_manager
270 .upgrade()
271 .context(UpgradeWeakCatalogManagerRefSnafu)?;
272 let predicates = Predicates::from_scan_request(&request);
273
274 for schema_name in catalog_manager.schema_names(&catalog_name, None).await? {
275 let mut stream = catalog_manager.tables(&catalog_name, &schema_name, None);
276
277 while let Some(table) = stream.try_next().await? {
278 let keys = &table.table_info().meta.primary_key_indices;
279 let schema = table.schema();
280
281 for (idx, column) in schema.column_schemas().iter().enumerate() {
282 let semantic_type = if column.is_time_index() {
283 SEMANTIC_TYPE_TIME_INDEX
284 } else if keys.contains(&idx) {
285 SEMANTIC_TYPE_PRIMARY_KEY
286 } else {
287 SEMANTIC_TYPE_FIELD
288 };
289
290 self.add_column(
291 &predicates,
292 idx,
293 &catalog_name,
294 &schema_name,
295 &table.table_info().name,
296 semantic_type,
297 column,
298 );
299 }
300 }
301 }
302
303 self.finish()
304 }
305
306 #[allow(clippy::too_many_arguments)]
307 fn add_column(
308 &mut self,
309 predicates: &Predicates,
310 index: usize,
311 catalog_name: &str,
312 schema_name: &str,
313 table_name: &str,
314 semantic_type: &str,
315 column_schema: &ColumnSchema,
316 ) {
317 let data_type = statements::concrete_data_type_to_sql_data_type(&column_schema.data_type)
319 .map(|dt| dt.to_string().to_lowercase())
320 .unwrap_or_else(|_| column_schema.data_type.name());
321
322 let column_key = match semantic_type {
323 SEMANTIC_TYPE_PRIMARY_KEY => PRI_COLUMN_KEY,
324 SEMANTIC_TYPE_TIME_INDEX => TIME_INDEX_COLUMN_KEY,
325 _ => EMPTY_STR,
326 };
327
328 let row = [
329 (TABLE_CATALOG, &Value::from(catalog_name)),
330 (TABLE_SCHEMA, &Value::from(schema_name)),
331 (TABLE_NAME, &Value::from(table_name)),
332 (COLUMN_NAME, &Value::from(column_schema.name.as_str())),
333 (DATA_TYPE, &Value::from(data_type.as_str())),
334 (SEMANTIC_TYPE, &Value::from(semantic_type)),
335 (ORDINAL_POSITION, &Value::from((index + 1) as i64)),
336 (COLUMN_KEY, &Value::from(column_key)),
337 ];
338
339 if !predicates.eval(&row) {
340 return;
341 }
342
343 self.catalog_names.push(Some(catalog_name));
344 self.schema_names.push(Some(schema_name));
345 self.table_names.push(Some(table_name));
346 self.column_names.push(Some(&column_schema.name));
347 self.ordinal_positions.push(Some((index + 1) as i64));
349
350 if column_schema.data_type.is_string() {
351 self.character_maximum_lengths.push(Some(MAX_STRING_LENGTH));
352 self.character_octet_lengths.push(Some(MAX_STRING_LENGTH));
353 self.numeric_precisions.push(None);
354 self.numeric_scales.push(None);
355 self.datetime_precisions.push(None);
356 self.character_set_names.push(Some(UTF8_CHARSET_NAME));
357 self.collation_names.push(Some(UTF8_COLLATE_NAME));
358 } else if column_schema.data_type.is_numeric() || column_schema.data_type.is_decimal() {
359 self.character_maximum_lengths.push(None);
360 self.character_octet_lengths.push(None);
361
362 self.numeric_precisions.push(
363 column_schema
364 .data_type
365 .numeric_precision()
366 .map(|x| x as i64),
367 );
368 self.numeric_scales
369 .push(column_schema.data_type.numeric_scale().map(|x| x as i64));
370
371 self.datetime_precisions.push(None);
372 self.character_set_names.push(None);
373 self.collation_names.push(None);
374 } else {
375 self.character_maximum_lengths.push(None);
376 self.character_octet_lengths.push(None);
377 self.numeric_precisions.push(None);
378 self.numeric_scales.push(None);
379
380 match &column_schema.data_type {
381 ConcreteDataType::Timestamp(ts_type) => {
382 self.datetime_precisions
383 .push(Some(ts_type.precision() as i64));
384 }
385 ConcreteDataType::Time(time_type) => {
386 self.datetime_precisions
387 .push(Some(time_type.precision() as i64));
388 }
389 _ => self.datetime_precisions.push(None),
390 }
391
392 self.character_set_names.push(None);
393 self.collation_names.push(None);
394 }
395
396 self.column_keys.push(Some(column_key));
397 self.greptime_data_types
398 .push(Some(&column_schema.data_type.name()));
399 self.data_types.push(Some(&data_type));
400 self.semantic_types.push(Some(semantic_type));
401 self.column_defaults.push(
402 column_schema
403 .default_constraint()
404 .map(|s| format!("{}", s))
405 .as_deref(),
406 );
407 if column_schema.is_nullable() {
408 self.is_nullables.push(Some(YES));
409 } else {
410 self.is_nullables.push(Some(NO));
411 }
412 self.column_types.push(Some(&data_type));
413 let column_comment = column_schema.column_comment().map(|x| x.as_ref());
414 self.column_comments.push(column_comment);
415 }
416
417 fn finish(&mut self) -> Result<RecordBatch> {
418 let rows_num = self.collation_names.len();
419
420 let privileges = Arc::new(StringVector::from(vec![DEFAULT_PRIVILEGES; rows_num]));
421 let empty_string = Arc::new(StringVector::from(vec![EMPTY_STR; rows_num]));
422 let srs_ids = Arc::new(Int64Vector::from(vec![None; rows_num]));
423
424 let columns: Vec<VectorRef> = vec![
425 Arc::new(self.catalog_names.finish()),
426 Arc::new(self.schema_names.finish()),
427 Arc::new(self.table_names.finish()),
428 Arc::new(self.column_names.finish()),
429 Arc::new(self.ordinal_positions.finish()),
430 Arc::new(self.character_maximum_lengths.finish()),
431 Arc::new(self.character_octet_lengths.finish()),
432 Arc::new(self.numeric_precisions.finish()),
433 Arc::new(self.numeric_scales.finish()),
434 Arc::new(self.datetime_precisions.finish()),
435 Arc::new(self.character_set_names.finish()),
436 Arc::new(self.collation_names.finish()),
437 Arc::new(self.column_keys.finish()),
438 empty_string.clone(),
439 privileges,
440 empty_string,
441 Arc::new(self.greptime_data_types.finish()),
442 Arc::new(self.data_types.finish()),
443 Arc::new(self.semantic_types.finish()),
444 Arc::new(self.column_defaults.finish()),
445 Arc::new(self.is_nullables.finish()),
446 Arc::new(self.column_types.finish()),
447 Arc::new(self.column_comments.finish()),
448 srs_ids,
449 ];
450
451 RecordBatch::new(self.schema.clone(), columns).context(CreateRecordBatchSnafu)
452 }
453}
454
455impl DfPartitionStream for InformationSchemaColumns {
456 fn schema(&self) -> &ArrowSchemaRef {
457 self.schema.arrow_schema()
458 }
459
460 fn execute(&self, _: Arc<TaskContext>) -> DfSendableRecordBatchStream {
461 let schema = self.schema.arrow_schema().clone();
462 let mut builder = self.builder();
463 Box::pin(DfRecordBatchStreamAdapter::new(
464 schema,
465 futures::stream::once(async move {
466 builder
467 .make_columns(None)
468 .await
469 .map(|x| x.into_df_record_batch())
470 .map_err(Into::into)
471 }),
472 ))
473 }
474}