1use std::sync::{Arc, Weak};
16
17use arrow_schema::SchemaRef as ArrowSchemaRef;
18use common_catalog::consts::INFORMATION_SCHEMA_KEY_COLUMN_USAGE_TABLE_ID;
19use common_error::ext::BoxedError;
20use common_recordbatch::adapter::RecordBatchStreamAdapter;
21use common_recordbatch::{RecordBatch, SendableRecordBatchStream};
22use datafusion::execution::TaskContext;
23use datafusion::physical_plan::SendableRecordBatchStream as DfSendableRecordBatchStream;
24use datafusion::physical_plan::stream::RecordBatchStreamAdapter as DfRecordBatchStreamAdapter;
25use datafusion::physical_plan::streaming::PartitionStream as DfPartitionStream;
26use datatypes::prelude::{ConcreteDataType, MutableVector, ScalarVectorBuilder, VectorRef};
27use datatypes::schema::{ColumnSchema, Schema, SchemaRef};
28use datatypes::value::Value;
29use datatypes::vectors::{ConstantVector, StringVector, StringVectorBuilder, UInt32VectorBuilder};
30use futures_util::TryStreamExt;
31use snafu::{OptionExt, ResultExt};
32use store_api::storage::{ScanRequest, TableId};
33
34use crate::CatalogManager;
35use crate::error::{
36 CreateRecordBatchSnafu, InternalSnafu, Result, UpgradeWeakCatalogManagerRefSnafu,
37};
38use crate::system_schema::information_schema::{
39 InformationTable, KEY_COLUMN_USAGE, Predicates, primary_key_encoding_index_type,
40};
41
42pub const CONSTRAINT_SCHEMA: &str = "constraint_schema";
43pub const CONSTRAINT_NAME: &str = "constraint_name";
44pub const TABLE_CATALOG: &str = "table_catalog";
46pub const REAL_TABLE_CATALOG: &str = "real_table_catalog";
48pub const TABLE_SCHEMA: &str = "table_schema";
49pub const TABLE_NAME: &str = "table_name";
50pub const COLUMN_NAME: &str = "column_name";
51pub const ORDINAL_POSITION: &str = "ordinal_position";
52pub const GREPTIME_INDEX_TYPE: &str = "greptime_index_type";
54const INIT_CAPACITY: usize = 42;
55
56pub(crate) const CONSTRAINT_NAME_TIME_INDEX: &str = "TIME INDEX";
58
59pub(crate) const CONSTRAINT_NAME_PRI: &str = "PRIMARY";
61
62pub(crate) const CONSTRAINT_NAME_INVERTED_INDEX: &str = "INVERTED INDEX";
64
65pub(crate) const CONSTRAINT_NAME_FULLTEXT_INDEX: &str = "FULLTEXT INDEX";
67
68pub(crate) const CONSTRAINT_NAME_SKIPPING_INDEX: &str = "SKIPPING INDEX";
70
71#[derive(Debug)]
75pub(super) struct InformationSchemaKeyColumnUsage {
76 schema: SchemaRef,
77 catalog_name: String,
78 catalog_manager: Weak<dyn CatalogManager>,
79}
80
81impl InformationSchemaKeyColumnUsage {
82 pub(super) fn new(catalog_name: String, catalog_manager: Weak<dyn CatalogManager>) -> Self {
83 Self {
84 schema: Self::schema(),
85 catalog_name,
86 catalog_manager,
87 }
88 }
89
90 pub(crate) fn schema() -> SchemaRef {
91 Arc::new(Schema::new(vec![
92 ColumnSchema::new(
93 "constraint_catalog",
94 ConcreteDataType::string_datatype(),
95 false,
96 ),
97 ColumnSchema::new(
98 CONSTRAINT_SCHEMA,
99 ConcreteDataType::string_datatype(),
100 false,
101 ),
102 ColumnSchema::new(CONSTRAINT_NAME, ConcreteDataType::string_datatype(), false),
103 ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), false),
104 ColumnSchema::new(
105 REAL_TABLE_CATALOG,
106 ConcreteDataType::string_datatype(),
107 false,
108 ),
109 ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), false),
110 ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), false),
111 ColumnSchema::new(COLUMN_NAME, ConcreteDataType::string_datatype(), false),
112 ColumnSchema::new(ORDINAL_POSITION, ConcreteDataType::uint32_datatype(), false),
113 ColumnSchema::new(
114 "position_in_unique_constraint",
115 ConcreteDataType::uint32_datatype(),
116 true,
117 ),
118 ColumnSchema::new(
119 "referenced_table_schema",
120 ConcreteDataType::string_datatype(),
121 true,
122 ),
123 ColumnSchema::new(
124 "referenced_table_name",
125 ConcreteDataType::string_datatype(),
126 true,
127 ),
128 ColumnSchema::new(
129 "referenced_column_name",
130 ConcreteDataType::string_datatype(),
131 true,
132 ),
133 ColumnSchema::new(
134 GREPTIME_INDEX_TYPE,
135 ConcreteDataType::string_datatype(),
136 true,
137 ),
138 ]))
139 }
140
141 fn builder(&self) -> InformationSchemaKeyColumnUsageBuilder {
142 InformationSchemaKeyColumnUsageBuilder::new(
143 self.schema.clone(),
144 self.catalog_name.clone(),
145 self.catalog_manager.clone(),
146 )
147 }
148}
149
150impl InformationTable for InformationSchemaKeyColumnUsage {
151 fn table_id(&self) -> TableId {
152 INFORMATION_SCHEMA_KEY_COLUMN_USAGE_TABLE_ID
153 }
154
155 fn table_name(&self) -> &'static str {
156 KEY_COLUMN_USAGE
157 }
158
159 fn schema(&self) -> SchemaRef {
160 self.schema.clone()
161 }
162
163 fn to_stream(&self, request: ScanRequest) -> Result<SendableRecordBatchStream> {
164 let schema = self.schema.arrow_schema().clone();
165 let mut builder = self.builder();
166 let stream = Box::pin(DfRecordBatchStreamAdapter::new(
167 schema,
168 futures::stream::once(async move {
169 builder
170 .make_key_column_usage(Some(request))
171 .await
172 .map(|x| x.into_df_record_batch())
173 .map_err(Into::into)
174 }),
175 ));
176 Ok(Box::pin(
177 RecordBatchStreamAdapter::try_new(stream)
178 .map_err(BoxedError::new)
179 .context(InternalSnafu)?,
180 ))
181 }
182}
183
184struct InformationSchemaKeyColumnUsageBuilder {
188 schema: SchemaRef,
189 catalog_name: String,
190 catalog_manager: Weak<dyn CatalogManager>,
191
192 constraint_catalog: StringVectorBuilder,
193 constraint_schema: StringVectorBuilder,
194 constraint_name: StringVectorBuilder,
195 table_catalog: StringVectorBuilder,
196 real_table_catalog: StringVectorBuilder,
197 table_schema: StringVectorBuilder,
198 table_name: StringVectorBuilder,
199 column_name: StringVectorBuilder,
200 ordinal_position: UInt32VectorBuilder,
201 position_in_unique_constraint: UInt32VectorBuilder,
202 greptime_index_type: StringVectorBuilder,
203}
204
205impl InformationSchemaKeyColumnUsageBuilder {
206 fn new(
207 schema: SchemaRef,
208 catalog_name: String,
209 catalog_manager: Weak<dyn CatalogManager>,
210 ) -> Self {
211 Self {
212 schema,
213 catalog_name,
214 catalog_manager,
215 constraint_catalog: StringVectorBuilder::with_capacity(INIT_CAPACITY),
216 constraint_schema: StringVectorBuilder::with_capacity(INIT_CAPACITY),
217 constraint_name: StringVectorBuilder::with_capacity(INIT_CAPACITY),
218 table_catalog: StringVectorBuilder::with_capacity(INIT_CAPACITY),
219 real_table_catalog: StringVectorBuilder::with_capacity(INIT_CAPACITY),
220 table_schema: StringVectorBuilder::with_capacity(INIT_CAPACITY),
221 table_name: StringVectorBuilder::with_capacity(INIT_CAPACITY),
222 column_name: StringVectorBuilder::with_capacity(INIT_CAPACITY),
223 ordinal_position: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
224 position_in_unique_constraint: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
225 greptime_index_type: StringVectorBuilder::with_capacity(INIT_CAPACITY),
226 }
227 }
228
229 async fn make_key_column_usage(&mut self, request: Option<ScanRequest>) -> Result<RecordBatch> {
231 let catalog_name = self.catalog_name.clone();
232 let catalog_manager = self
233 .catalog_manager
234 .upgrade()
235 .context(UpgradeWeakCatalogManagerRefSnafu)?;
236 let predicates = Predicates::from_scan_request(&request);
237
238 for schema_name in catalog_manager.schema_names(&catalog_name, None).await? {
239 let mut stream = catalog_manager.tables(&catalog_name, &schema_name, None);
240
241 while let Some(table) = stream.try_next().await? {
242 let table_info = table.table_info();
243 let table_name = &table_info.name;
244 let keys = &table_info.meta.primary_key_indices;
245 let schema = table.schema();
246 let primary_key_encoding =
247 primary_key_encoding_index_type(&table_info.meta.options.extra_options);
248
249 for (idx, column) in schema.column_schemas().iter().enumerate() {
250 if column.is_time_index() {
251 self.add_key_column_usage(
252 &predicates,
253 &schema_name,
254 CONSTRAINT_NAME_TIME_INDEX,
255 &catalog_name,
256 &schema_name,
257 table_name,
258 &column.name,
259 1, "",
261 );
262 }
263 if let Some(pk_seq) = keys.iter().position(|k| *k == idx) {
264 self.add_key_column_usage(
265 &predicates,
266 &schema_name,
267 CONSTRAINT_NAME_PRI,
268 &catalog_name,
269 &schema_name,
270 table_name,
271 &column.name,
272 pk_seq as u32 + 1,
273 primary_key_encoding,
274 );
275 }
276 }
277 }
278 }
279
280 self.finish()
281 }
282
283 #[allow(clippy::too_many_arguments)]
286 fn add_key_column_usage(
287 &mut self,
288 predicates: &Predicates,
289 constraint_schema: &str,
290 constraint_name: &str,
291 table_catalog: &str,
292 table_schema: &str,
293 table_name: &str,
294 column_name: &str,
295 ordinal_position: u32,
296 index_types: &str,
297 ) {
298 let row = [
299 (CONSTRAINT_SCHEMA, &Value::from(constraint_schema)),
300 (CONSTRAINT_NAME, &Value::from(constraint_name)),
301 (REAL_TABLE_CATALOG, &Value::from(table_catalog)),
302 (TABLE_SCHEMA, &Value::from(table_schema)),
303 (TABLE_NAME, &Value::from(table_name)),
304 (COLUMN_NAME, &Value::from(column_name)),
305 (ORDINAL_POSITION, &Value::from(ordinal_position)),
306 (GREPTIME_INDEX_TYPE, &Value::from(index_types)),
307 ];
308
309 if !predicates.eval(&row) {
310 return;
311 }
312
313 self.constraint_catalog.push(Some("def"));
314 self.constraint_schema.push(Some(constraint_schema));
315 self.constraint_name.push(Some(constraint_name));
316 self.table_catalog.push(Some("def"));
317 self.real_table_catalog.push(Some(table_catalog));
318 self.table_schema.push(Some(table_schema));
319 self.table_name.push(Some(table_name));
320 self.column_name.push(Some(column_name));
321 self.ordinal_position.push(Some(ordinal_position));
322 self.position_in_unique_constraint.push(None);
323 self.greptime_index_type.push(Some(index_types));
324 }
325
326 fn finish(&mut self) -> Result<RecordBatch> {
327 let rows_num = self.table_catalog.len();
328
329 let null_string_vector = Arc::new(ConstantVector::new(
330 Arc::new(StringVector::from(vec![None as Option<&str>])),
331 rows_num,
332 ));
333 let columns: Vec<VectorRef> = vec![
334 Arc::new(self.constraint_catalog.finish()),
335 Arc::new(self.constraint_schema.finish()),
336 Arc::new(self.constraint_name.finish()),
337 Arc::new(self.table_catalog.finish()),
338 Arc::new(self.real_table_catalog.finish()),
339 Arc::new(self.table_schema.finish()),
340 Arc::new(self.table_name.finish()),
341 Arc::new(self.column_name.finish()),
342 Arc::new(self.ordinal_position.finish()),
343 Arc::new(self.position_in_unique_constraint.finish()),
344 null_string_vector.clone(),
345 null_string_vector.clone(),
346 null_string_vector,
347 Arc::new(self.greptime_index_type.finish()),
348 ];
349 RecordBatch::new(self.schema.clone(), columns).context(CreateRecordBatchSnafu)
350 }
351}
352
353impl DfPartitionStream for InformationSchemaKeyColumnUsage {
354 fn schema(&self) -> &ArrowSchemaRef {
355 self.schema.arrow_schema()
356 }
357
358 fn execute(&self, _: Arc<TaskContext>) -> DfSendableRecordBatchStream {
359 let schema = self.schema.arrow_schema().clone();
360 let mut builder = self.builder();
361 Box::pin(DfRecordBatchStreamAdapter::new(
362 schema,
363 futures::stream::once(async move {
364 builder
365 .make_key_column_usage(None)
366 .await
367 .map(|x| x.into_df_record_batch())
368 .map_err(Into::into)
369 }),
370 ))
371 }
372}