Skip to main content

tests_integration/
grpc.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod flight;
16mod network;
17
18use api::v1::QueryRequest;
19use api::v1::greptime_request::Request;
20use api::v1::query_request::Query;
21use common_query::OutputData;
22use common_recordbatch::RecordBatches;
23use frontend::instance::Instance;
24use servers::query_handler::grpc::GrpcQueryHandler;
25use session::context::QueryContext;
26
27#[allow(unused)]
28async fn query_and_expect(instance: &Instance, sql: &str, expected: &str) {
29    let request = Request::Query(QueryRequest {
30        query: Some(Query::Sql(sql.to_string())),
31    });
32    let output = GrpcQueryHandler::do_query(instance, request, QueryContext::arc())
33        .await
34        .unwrap();
35    let OutputData::Stream(stream) = output.data else {
36        unreachable!()
37    };
38    let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
39    let actual = recordbatches.pretty_print().unwrap();
40    assert_eq!(actual, expected, "actual: {}", actual);
41}
42
43#[cfg(test)]
44mod test {
45    use std::collections::HashMap;
46    use std::sync::Arc;
47
48    use api::v1::column::Values;
49    use api::v1::column_data_type_extension::TypeExt;
50    use api::v1::ddl_request::Expr as DdlExpr;
51    use api::v1::greptime_request::Request;
52    use api::v1::query_request::Query;
53    use api::v1::region::QueryRequest as RegionQueryRequest;
54    use api::v1::{
55        AddColumn, AddColumns, AlterTableExpr, Column, ColumnDataType, ColumnDataTypeExtension,
56        ColumnDef, CreateDatabaseExpr, CreateTableExpr, DdlRequest, DeleteRequest, DeleteRequests,
57        DropTableExpr, InsertIntoPlan, InsertRequest, InsertRequests, QueryRequest, SemanticType,
58        VectorTypeExtension, alter_table_expr,
59    };
60    use auth::{
61        DefaultPermissionChecker, Identity, Password, PermissionCheckerRef, UserProvider,
62        static_user_provider_from_option,
63    };
64    use client::OutputData;
65    use common_base::Plugins;
66    use common_catalog::consts::MITO_ENGINE;
67    use common_meta::rpc::router::region_distribution;
68    use common_query::Output;
69    use common_query::logical_plan::breakup_insert_plan;
70    use common_recordbatch::RecordBatches;
71    use frontend::instance::Instance;
72    use query::parser::QueryLanguageParser;
73    use query::query_engine::DefaultSerializer;
74    use rstest::rstest;
75    use rstest_reuse::apply;
76    use servers::query_handler::grpc::GrpcQueryHandler;
77    use session::context::{QueryContext, QueryContextBuilder};
78    use store_api::mito_engine_options::TWCS_TIME_WINDOW;
79    use store_api::storage::RegionId;
80    use substrait::{DFLogicalSubstraitConvertor, SubstraitPlan};
81
82    use super::*;
83    use crate::standalone::GreptimeDbStandaloneBuilder;
84    use crate::test_util::execute_sql_and_expect;
85    use crate::tests;
86    use crate::tests::MockDistributedInstance;
87    use crate::tests::test_util::{MockInstance, both_instances_cases, distributed, standalone};
88
89    #[tokio::test(flavor = "multi_thread")]
90    async fn test_distributed_handle_ddl_request() {
91        common_telemetry::init_default_ut_logging();
92        let instance =
93            tests::create_distributed_instance("test_distributed_handle_ddl_request").await;
94
95        test_handle_ddl_request(instance.frontend().as_ref()).await;
96
97        verify_table_is_dropped(&instance).await;
98    }
99
100    #[tokio::test(flavor = "multi_thread")]
101    async fn test_standalone_handle_ddl_request() {
102        let standalone = GreptimeDbStandaloneBuilder::new("test_standalone_handle_ddl_request")
103            .build()
104            .await;
105        let instance = standalone.fe_instance();
106
107        test_handle_ddl_request(instance.as_ref()).await;
108    }
109
110    #[tokio::test(flavor = "multi_thread")]
111    async fn test_distributed_handle_multi_ddl_request() {
112        common_telemetry::init_default_ut_logging();
113        let instance =
114            tests::create_distributed_instance("test_distributed_handle_multi_ddl_request").await;
115
116        test_handle_multi_ddl_request(instance.frontend().as_ref()).await;
117
118        verify_table_is_dropped(&instance).await;
119    }
120
121    #[tokio::test(flavor = "multi_thread")]
122    async fn test_standalone_handle_multi_ddl_request() {
123        let standalone =
124            GreptimeDbStandaloneBuilder::new("test_standalone_handle_multi_ddl_request")
125                .build()
126                .await;
127        let instance = standalone.fe_instance();
128
129        test_handle_multi_ddl_request(instance.as_ref()).await;
130    }
131
132    async fn query(instance: &Instance, request: Request) -> Output {
133        GrpcQueryHandler::do_query(instance, request, QueryContext::arc())
134            .await
135            .unwrap()
136    }
137
138    #[tokio::test(flavor = "multi_thread")]
139    async fn test_grpc_insert_into_plan_rejects_readonly_user() {
140        let plugins = Plugins::new();
141        plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
142
143        let standalone =
144            GreptimeDbStandaloneBuilder::new("test_grpc_insert_into_plan_rejects_readonly_user")
145                .with_plugin(plugins)
146                .build()
147                .await;
148        let instance = standalone.fe_instance();
149        let table_name = "grpc_insert_into_plan_auth";
150
151        create_table(
152            instance,
153            format!("CREATE TABLE {table_name} (host STRING, val DOUBLE, ts TIMESTAMP TIME INDEX)"),
154        )
155        .await;
156
157        let stmt = QueryLanguageParser::parse_sql(
158            &format!("INSERT INTO {table_name} VALUES ('readonly-bypass', 42.0, 1000)"),
159            &QueryContext::arc(),
160        )
161        .unwrap();
162        let plan = instance
163            .statement_executor()
164            .plan(&stmt, QueryContext::arc())
165            .await
166            .unwrap();
167        let (table_name, insert_plan) = breakup_insert_plan(&plan, "greptime", "public").unwrap();
168        let logical_plan = DFLogicalSubstraitConvertor
169            .encode(&insert_plan, DefaultSerializer)
170            .unwrap()
171            .to_vec();
172
173        let request = Request::Query(QueryRequest {
174            query: Some(Query::InsertIntoPlan(InsertIntoPlan {
175                table_name: Some(table_name),
176                logical_plan,
177            })),
178        });
179        let ctx = QueryContext::arc();
180        let provider =
181            static_user_provider_from_option("static_user_provider:cmd:readonly:ro=readonly_pwd")
182                .unwrap();
183        let readonly_user = provider
184            .authenticate(
185                Identity::UserId("readonly", None),
186                Password::PlainText("readonly_pwd".to_string().into()),
187            )
188            .await
189            .unwrap();
190        ctx.set_current_user(readonly_user);
191
192        let err = GrpcQueryHandler::do_query(instance.as_ref(), request, ctx)
193            .await
194            .unwrap_err();
195        let err_msg = format!("{err:?}");
196        assert!(
197            err_msg.contains("not authorized"),
198            "unexpected error: {err_msg}"
199        );
200
201        query_and_expect(
202            instance,
203            "SELECT count(*) FROM grpc_insert_into_plan_auth",
204            "\
205+----------+
206| count(*) |
207+----------+
208| 0        |
209+----------+",
210        )
211        .await;
212    }
213
214    async fn test_handle_multi_ddl_request(instance: &Instance) {
215        let request = Request::Ddl(DdlRequest {
216            expr: Some(DdlExpr::CreateDatabase(CreateDatabaseExpr {
217                catalog_name: "greptime".to_string(),
218                schema_name: "database_created_through_grpc".to_string(),
219                create_if_not_exists: true,
220                options: Default::default(),
221            })),
222        });
223        let output = query(instance, request).await;
224        assert!(matches!(output.data, OutputData::AffectedRows(1)));
225
226        let request = Request::Ddl(DdlRequest {
227            expr: Some(DdlExpr::CreateTable(CreateTableExpr {
228                catalog_name: "greptime".to_string(),
229                schema_name: "database_created_through_grpc".to_string(),
230                table_name: "table_created_through_grpc".to_string(),
231                column_defs: vec![
232                    ColumnDef {
233                        name: "a".to_string(),
234                        data_type: ColumnDataType::String as _,
235                        is_nullable: true,
236                        default_constraint: vec![],
237                        semantic_type: SemanticType::Field as i32,
238                        ..Default::default()
239                    },
240                    ColumnDef {
241                        name: "ts".to_string(),
242                        data_type: ColumnDataType::TimestampMillisecond as _,
243                        is_nullable: false,
244                        default_constraint: vec![],
245                        semantic_type: SemanticType::Timestamp as i32,
246                        ..Default::default()
247                    },
248                ],
249                time_index: "ts".to_string(),
250                engine: MITO_ENGINE.to_string(),
251                ..Default::default()
252            })),
253        });
254        let output = query(instance, request).await;
255        assert!(matches!(output.data, OutputData::AffectedRows(0)));
256
257        let request = Request::Ddl(DdlRequest {
258            expr: Some(DdlExpr::AlterTable(AlterTableExpr {
259                catalog_name: "greptime".to_string(),
260                schema_name: "database_created_through_grpc".to_string(),
261                table_name: "table_created_through_grpc".to_string(),
262                kind: Some(alter_table_expr::Kind::AddColumns(AddColumns {
263                    add_columns: vec![
264                        AddColumn {
265                            column_def: Some(ColumnDef {
266                                name: "b".to_string(),
267                                data_type: ColumnDataType::Int32 as _,
268                                is_nullable: true,
269                                default_constraint: vec![],
270                                semantic_type: SemanticType::Field as i32,
271                                ..Default::default()
272                            }),
273                            location: None,
274                            add_if_not_exists: true,
275                        },
276                        AddColumn {
277                            column_def: Some(ColumnDef {
278                                name: "a".to_string(),
279                                data_type: ColumnDataType::String as _,
280                                is_nullable: true,
281                                default_constraint: vec![],
282                                semantic_type: SemanticType::Field as i32,
283                                ..Default::default()
284                            }),
285                            location: None,
286                            add_if_not_exists: true,
287                        },
288                    ],
289                })),
290            })),
291        });
292        let output = query(instance, request).await;
293        assert!(matches!(output.data, OutputData::AffectedRows(0)));
294
295        let request = Request::Ddl(DdlRequest {
296            expr: Some(DdlExpr::AlterTable(AlterTableExpr {
297                catalog_name: "greptime".to_string(),
298                schema_name: "database_created_through_grpc".to_string(),
299                table_name: "table_created_through_grpc".to_string(),
300                kind: Some(alter_table_expr::Kind::AddColumns(AddColumns {
301                    add_columns: vec![
302                        AddColumn {
303                            column_def: Some(ColumnDef {
304                                name: "c".to_string(),
305                                data_type: ColumnDataType::Int32 as _,
306                                is_nullable: true,
307                                default_constraint: vec![],
308                                semantic_type: SemanticType::Field as i32,
309                                ..Default::default()
310                            }),
311                            location: None,
312                            add_if_not_exists: true,
313                        },
314                        AddColumn {
315                            column_def: Some(ColumnDef {
316                                name: "d".to_string(),
317                                data_type: ColumnDataType::Int32 as _,
318                                is_nullable: true,
319                                default_constraint: vec![],
320                                semantic_type: SemanticType::Field as i32,
321                                ..Default::default()
322                            }),
323                            location: None,
324                            add_if_not_exists: true,
325                        },
326                    ],
327                })),
328            })),
329        });
330        let output = query(instance, request).await;
331        assert!(matches!(output.data, OutputData::AffectedRows(0)));
332
333        let request = Request::Query(QueryRequest {
334            query: Some(Query::Sql("INSERT INTO database_created_through_grpc.table_created_through_grpc (a, b, c, d, ts) VALUES ('s', 1, 1, 1, 1672816466000)".to_string()))
335        });
336        let output = query(instance, request).await;
337        assert!(matches!(output.data, OutputData::AffectedRows(1)));
338
339        let sql = "SELECT ts, a, b FROM database_created_through_grpc.table_created_through_grpc";
340        let expected = "\
341+---------------------+---+---+
342| ts                  | a | b |
343+---------------------+---+---+
344| 2023-01-04T07:14:26 | s | 1 |
345+---------------------+---+---+";
346        query_and_expect(instance, sql, expected).await;
347
348        let request = Request::Ddl(DdlRequest {
349            expr: Some(DdlExpr::DropTable(DropTableExpr {
350                catalog_name: "greptime".to_string(),
351                schema_name: "database_created_through_grpc".to_string(),
352                table_name: "table_created_through_grpc".to_string(),
353                ..Default::default()
354            })),
355        });
356        let output = query(instance, request).await;
357        assert!(matches!(output.data, OutputData::AffectedRows(0)));
358    }
359
360    async fn test_handle_ddl_request(instance: &Instance) {
361        let request = Request::Ddl(DdlRequest {
362            expr: Some(DdlExpr::CreateDatabase(CreateDatabaseExpr {
363                catalog_name: "greptime".to_string(),
364                schema_name: "database_created_through_grpc".to_string(),
365                create_if_not_exists: true,
366                options: Default::default(),
367            })),
368        });
369        let output = query(instance, request).await;
370        assert!(matches!(output.data, OutputData::AffectedRows(1)));
371
372        let request = Request::Ddl(DdlRequest {
373            expr: Some(DdlExpr::CreateTable(CreateTableExpr {
374                catalog_name: "greptime".to_string(),
375                schema_name: "database_created_through_grpc".to_string(),
376                table_name: "table_created_through_grpc".to_string(),
377                column_defs: vec![
378                    ColumnDef {
379                        name: "a".to_string(),
380                        data_type: ColumnDataType::String as _,
381                        is_nullable: true,
382                        default_constraint: vec![],
383                        semantic_type: SemanticType::Field as i32,
384                        ..Default::default()
385                    },
386                    ColumnDef {
387                        name: "ts".to_string(),
388                        data_type: ColumnDataType::TimestampMillisecond as _,
389                        is_nullable: false,
390                        default_constraint: vec![],
391                        semantic_type: SemanticType::Timestamp as i32,
392                        ..Default::default()
393                    },
394                ],
395                time_index: "ts".to_string(),
396                engine: MITO_ENGINE.to_string(),
397                ..Default::default()
398            })),
399        });
400        let output = query(instance, request).await;
401        assert!(matches!(output.data, OutputData::AffectedRows(0)));
402
403        let request = Request::Ddl(DdlRequest {
404            expr: Some(DdlExpr::AlterTable(AlterTableExpr {
405                catalog_name: "greptime".to_string(),
406                schema_name: "database_created_through_grpc".to_string(),
407                table_name: "table_created_through_grpc".to_string(),
408                kind: Some(alter_table_expr::Kind::AddColumns(AddColumns {
409                    add_columns: vec![AddColumn {
410                        column_def: Some(ColumnDef {
411                            name: "b".to_string(),
412                            data_type: ColumnDataType::Int32 as _,
413                            is_nullable: true,
414                            default_constraint: vec![],
415                            semantic_type: SemanticType::Field as i32,
416                            ..Default::default()
417                        }),
418                        location: None,
419                        add_if_not_exists: false,
420                    }],
421                })),
422            })),
423        });
424        let output = query(instance, request).await;
425        assert!(matches!(output.data, OutputData::AffectedRows(0)));
426
427        let request = Request::Query(QueryRequest {
428            query: Some(Query::Sql("INSERT INTO database_created_through_grpc.table_created_through_grpc (a, b, ts) VALUES ('s', 1, 1672816466000)".to_string()))
429        });
430        let output = query(instance, request).await;
431        assert!(matches!(output.data, OutputData::AffectedRows(1)));
432
433        let sql = "SELECT ts, a, b FROM database_created_through_grpc.table_created_through_grpc";
434        let expected = "\
435+---------------------+---+---+
436| ts                  | a | b |
437+---------------------+---+---+
438| 2023-01-04T07:14:26 | s | 1 |
439+---------------------+---+---+";
440        query_and_expect(instance, sql, expected).await;
441
442        let request = Request::Ddl(DdlRequest {
443            expr: Some(DdlExpr::DropTable(DropTableExpr {
444                catalog_name: "greptime".to_string(),
445                schema_name: "database_created_through_grpc".to_string(),
446                table_name: "table_created_through_grpc".to_string(),
447                ..Default::default()
448            })),
449        });
450        let output = query(instance, request).await;
451        assert!(matches!(output.data, OutputData::AffectedRows(0)));
452    }
453
454    async fn verify_table_is_dropped(instance: &MockDistributedInstance) {
455        assert!(
456            instance
457                .frontend()
458                .catalog_manager()
459                .table(
460                    "greptime",
461                    "database_created_through_grpc",
462                    "table_created_through_grpc",
463                    None,
464                )
465                .await
466                .unwrap()
467                .is_none()
468        );
469    }
470
471    #[tokio::test(flavor = "multi_thread")]
472    async fn test_distributed_insert_delete_and_query() {
473        common_telemetry::init_default_ut_logging();
474
475        let instance =
476            tests::create_distributed_instance("test_distributed_insert_delete_and_query").await;
477        let frontend = instance.frontend();
478        let frontend = frontend.as_ref();
479
480        let table_name = "my_dist_table";
481        let sql = format!(
482            r"
483CREATE TABLE {table_name} (
484    a INT,
485    b STRING,
486    c JSON,
487    d VECTOR(3),
488    ts TIMESTAMP,
489    TIME INDEX (ts),
490    PRIMARY KEY (a, b, c)
491) PARTITION ON COLUMNS(a) (
492    a < 10,
493    a >= 10 AND a < 20,
494    a >= 20 AND a < 50,
495    a >= 50
496)"
497        );
498        create_table(frontend, sql).await;
499
500        test_insert_delete_and_query_on_existing_table(frontend, table_name).await;
501
502        verify_data_distribution(
503            &instance,
504            table_name,
505            HashMap::from([
506                (
507                    0u32,
508                    "\
509+---------------------+---+-------------------+
510| ts                  | a | b                 |
511+---------------------+---+-------------------+
512| 2023-01-01T07:26:12 | 1 | ts: 1672557972000 |
513| 2023-01-01T07:26:15 | 4 | ts: 1672557975000 |
514| 2023-01-01T07:26:16 | 5 | ts: 1672557976000 |
515| 2023-01-01T07:26:17 |   | ts: 1672557977000 |
516+---------------------+---+-------------------+",
517                ),
518                (
519                    1u32,
520                    "\
521+---------------------+----+-------------------+
522| ts                  | a  | b                 |
523+---------------------+----+-------------------+
524| 2023-01-01T07:26:18 | 11 | ts: 1672557978000 |
525+---------------------+----+-------------------+",
526                ),
527                (
528                    2u32,
529                    "\
530+---------------------+----+-------------------+
531| ts                  | a  | b                 |
532+---------------------+----+-------------------+
533| 2023-01-01T07:26:20 | 20 | ts: 1672557980000 |
534| 2023-01-01T07:26:21 | 21 | ts: 1672557981000 |
535| 2023-01-01T07:26:23 | 23 | ts: 1672557983000 |
536+---------------------+----+-------------------+",
537                ),
538                (
539                    3u32,
540                    "\
541+---------------------+----+-------------------+
542| ts                  | a  | b                 |
543+---------------------+----+-------------------+
544| 2023-01-01T07:26:24 | 50 | ts: 1672557984000 |
545| 2023-01-01T07:26:25 | 51 | ts: 1672557985000 |
546+---------------------+----+-------------------+",
547                ),
548            ]),
549        )
550        .await;
551
552        test_insert_delete_and_query_on_auto_created_table(frontend).await;
553
554        // Auto created table has only one region.
555        verify_data_distribution(
556            &instance,
557            "auto_created_table",
558            HashMap::from([(
559                0u32,
560                "\
561+---------------------+---+---+
562| ts                  | a | b |
563+---------------------+---+---+
564| 2023-01-01T07:26:16 |   |   |
565| 2023-01-01T07:26:17 | 6 |   |
566| 2023-01-01T07:26:18 |   | x |
567| 2023-01-01T07:26:20 |   | z |
568+---------------------+---+---+",
569            )]),
570        )
571        .await;
572    }
573
574    #[tokio::test(flavor = "multi_thread")]
575    async fn test_standalone_insert_and_query() {
576        common_telemetry::init_default_ut_logging();
577        let standalone = GreptimeDbStandaloneBuilder::new("test_standalone_insert_and_query")
578            .build()
579            .await;
580        let instance = standalone.fe_instance();
581
582        let table_name = "my_table";
583        let sql = format!(
584            "CREATE TABLE {table_name} (a INT, b STRING, c JSON, ts TIMESTAMP, TIME INDEX (ts), PRIMARY KEY (a, b, c))"
585        );
586        create_table(instance, sql).await;
587
588        test_insert_delete_and_query_on_existing_table(instance, table_name).await;
589
590        test_insert_delete_and_query_on_auto_created_table(instance).await
591    }
592
593    async fn create_table(frontend: &Instance, sql: String) {
594        let request = Request::Query(QueryRequest {
595            query: Some(Query::Sql(sql)),
596        });
597        let output = query(frontend, request).await;
598        assert!(matches!(output.data, OutputData::AffectedRows(0)));
599    }
600
601    async fn test_insert_delete_and_query_on_existing_table(instance: &Instance, table_name: &str) {
602        let timestamp_millisecond_values = vec![
603            1672557972000,
604            1672557973000,
605            1672557974000,
606            1672557975000,
607            1672557976000,
608            1672557977000,
609            1672557978000,
610            1672557979000,
611            1672557980000,
612            1672557981000,
613            1672557982000,
614            1672557983000,
615            1672557984000,
616            1672557985000,
617            1672557986000,
618            1672557987000,
619        ];
620        let json_strings = vec![
621            r#"{ "id": 1, "name": "Alice", "age": 30, "active": true }"#.to_string(),
622            r#"{ "id": 2, "name": "Bob", "balance": 1234.56, "active": false }"#.to_string(),
623            r#"{ "id": 3, "tags": ["rust", "testing", "json"], "age": 28 }"#.to_string(),
624            r#"{ "id": 4, "metadata": { "created_at": "2024-10-30T12:00:00Z", "status": "inactive" } }"#.to_string(),
625            r#"{ "id": 5, "name": null, "phone": "+1234567890" }"#.to_string(),
626            r#"{ "id": 6, "height": 5.9, "weight": 72.5, "active": true }"#.to_string(),
627            r#"{ "id": 7, "languages": ["English", "Spanish"], "age": 29 }"#.to_string(),
628            r#"{ "id": 8, "contact": { "email": "hank@example.com", "phone": "+0987654321" } }"#.to_string(),
629            r#"{ "id": 9, "preferences": { "notifications": true, "theme": "dark" } }"#.to_string(),
630            r#"{ "id": 10, "scores": [88, 92, 76], "active": false }"#.to_string(),
631            r#"{ "id": 11, "birthday": "1996-07-20", "location": { "city": "New York", "zip": "10001" } }"#.to_string(),
632            r#"{ "id": 12, "subscription": { "type": "premium", "expires": "2025-01-01" } }"#.to_string(),
633            r#"{ "id": 13, "settings": { "volume": 0.8, "brightness": 0.6 }, "active": true }"#.to_string(),
634            r#"{ "id": 14, "notes": ["first note", "second note"], "priority": 1 }"#.to_string(),
635            r#"{ "id": 15, "transactions": [{ "amount": 500, "date": "2024-01-01" }, { "amount": -200, "date": "2024-02-01" }] }"#.to_string(),
636            r#"{ "id": 16, "transactions": [{ "amount": 500, "date": "2024-01-01" }] }"#.to_string(),
637        ];
638        let vector_values = [
639            [1.0f32, 2.0, 3.0],
640            [4.0, 5.0, 6.0],
641            [7.0, 8.0, 9.0],
642            [10.0, 11.0, 12.0],
643            [13.0, 14.0, 15.0],
644            [16.0, 17.0, 18.0],
645            [19.0, 20.0, 21.0],
646            [22.0, 23.0, 24.0],
647            [25.0, 26.0, 27.0],
648            [28.0, 29.0, 30.0],
649            [31.0, 32.0, 33.0],
650            [34.0, 35.0, 36.0],
651            [37.0, 38.0, 39.0],
652            [40.0, 41.0, 42.0],
653            [43.0, 44.0, 45.0],
654            [46.0, 47.0, 48.0],
655        ]
656        .iter()
657        .map(|x| x.iter().flat_map(|&f| f.to_le_bytes()).collect::<Vec<u8>>())
658        .collect::<Vec<_>>();
659
660        let insert = InsertRequest {
661            table_name: table_name.to_string(),
662            columns: vec![
663                Column {
664                    column_name: "a".to_string(),
665                    values: Some(Values {
666                        i32_values: vec![1, 2, 3, 4, 5, 11, 12, 20, 21, 22, 23, 50, 51, 52, 53],
667                        ..Default::default()
668                    }),
669                    null_mask: vec![32, 0],
670                    semantic_type: SemanticType::Tag as i32,
671                    datatype: ColumnDataType::Int32 as i32,
672                    ..Default::default()
673                },
674                Column {
675                    column_name: "b".to_string(),
676                    values: Some(Values {
677                        string_values: timestamp_millisecond_values
678                            .iter()
679                            .map(|x| format!("ts: {x}"))
680                            .collect(),
681                        ..Default::default()
682                    }),
683                    semantic_type: SemanticType::Tag as i32,
684                    datatype: ColumnDataType::String as i32,
685                    ..Default::default()
686                },
687                Column {
688                    column_name: "c".to_string(),
689                    values: Some(Values {
690                        string_values: json_strings,
691                        ..Default::default()
692                    }),
693                    semantic_type: SemanticType::Tag as i32,
694                    datatype: ColumnDataType::Json as i32,
695                    ..Default::default()
696                },
697                Column {
698                    column_name: "d".to_string(),
699                    values: Some(Values {
700                        binary_values: vector_values.clone(),
701                        ..Default::default()
702                    }),
703                    semantic_type: SemanticType::Field as i32,
704                    datatype: ColumnDataType::Vector as i32,
705                    datatype_extension: Some(ColumnDataTypeExtension {
706                        type_ext: Some(TypeExt::VectorType(VectorTypeExtension { dim: 3 })),
707                    }),
708                    ..Default::default()
709                },
710                Column {
711                    column_name: "ts".to_string(),
712                    values: Some(Values {
713                        timestamp_millisecond_values,
714                        ..Default::default()
715                    }),
716                    semantic_type: SemanticType::Timestamp as i32,
717                    datatype: ColumnDataType::TimestampMillisecond as i32,
718                    ..Default::default()
719                },
720            ],
721            row_count: 16,
722        };
723        let output = query(
724            instance,
725            Request::Inserts(InsertRequests {
726                inserts: vec![insert],
727            }),
728        )
729        .await;
730        assert!(matches!(output.data, OutputData::AffectedRows(16)));
731
732        let request = Request::Query(QueryRequest {
733            query: Some(Query::Sql(format!(
734                "SELECT ts, a, b, json_to_string(c) as c, d FROM {table_name} ORDER BY ts"
735            ))),
736        });
737        let output = query(instance, request.clone()).await;
738        let OutputData::Stream(stream) = output.data else {
739            unreachable!()
740        };
741        let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
742        let expected = r#"+---------------------+----+-------------------+---------------------------------------------------------------------------------------------------+--------------------------+
743| ts                  | a  | b                 | c                                                                                                 | d                        |
744+---------------------+----+-------------------+---------------------------------------------------------------------------------------------------+--------------------------+
745| 2023-01-01T07:26:12 | 1  | ts: 1672557972000 | {"active":true,"age":30,"id":1,"name":"Alice"}                                                    | 0000803f0000004000004040 |
746| 2023-01-01T07:26:13 | 2  | ts: 1672557973000 | {"active":false,"balance":1234.56,"id":2,"name":"Bob"}                                            | 000080400000a0400000c040 |
747| 2023-01-01T07:26:14 | 3  | ts: 1672557974000 | {"age":28,"id":3,"tags":["rust","testing","json"]}                                                | 0000e0400000004100001041 |
748| 2023-01-01T07:26:15 | 4  | ts: 1672557975000 | {"id":4,"metadata":{"created_at":"2024-10-30T12:00:00Z","status":"inactive"}}                     | 000020410000304100004041 |
749| 2023-01-01T07:26:16 | 5  | ts: 1672557976000 | {"id":5,"name":null,"phone":"+1234567890"}                                                        | 000050410000604100007041 |
750| 2023-01-01T07:26:17 |    | ts: 1672557977000 | {"active":true,"height":5.9,"id":6,"weight":72.5}                                                 | 000080410000884100009041 |
751| 2023-01-01T07:26:18 | 11 | ts: 1672557978000 | {"age":29,"id":7,"languages":["English","Spanish"]}                                               | 000098410000a0410000a841 |
752| 2023-01-01T07:26:19 | 12 | ts: 1672557979000 | {"contact":{"email":"hank@example.com","phone":"+0987654321"},"id":8}                             | 0000b0410000b8410000c041 |
753| 2023-01-01T07:26:20 | 20 | ts: 1672557980000 | {"id":9,"preferences":{"notifications":true,"theme":"dark"}}                                      | 0000c8410000d0410000d841 |
754| 2023-01-01T07:26:21 | 21 | ts: 1672557981000 | {"active":false,"id":10,"scores":[88,92,76]}                                                      | 0000e0410000e8410000f041 |
755| 2023-01-01T07:26:22 | 22 | ts: 1672557982000 | {"birthday":"1996-07-20","id":11,"location":{"city":"New York","zip":"10001"}}                    | 0000f8410000004200000442 |
756| 2023-01-01T07:26:23 | 23 | ts: 1672557983000 | {"id":12,"subscription":{"expires":"2025-01-01","type":"premium"}}                                | 0000084200000c4200001042 |
757| 2023-01-01T07:26:24 | 50 | ts: 1672557984000 | {"active":true,"id":13,"settings":{"brightness":0.6,"volume":0.8}}                                | 000014420000184200001c42 |
758| 2023-01-01T07:26:25 | 51 | ts: 1672557985000 | {"id":14,"notes":["first note","second note"],"priority":1}                                       | 000020420000244200002842 |
759| 2023-01-01T07:26:26 | 52 | ts: 1672557986000 | {"id":15,"transactions":[{"amount":500,"date":"2024-01-01"},{"amount":-200,"date":"2024-02-01"}]} | 00002c420000304200003442 |
760| 2023-01-01T07:26:27 | 53 | ts: 1672557987000 | {"id":16,"transactions":[{"amount":500,"date":"2024-01-01"}]}                                     | 0000384200003c4200004042 |
761+---------------------+----+-------------------+---------------------------------------------------------------------------------------------------+--------------------------+"#;
762        similar_asserts::assert_eq!(recordbatches.pretty_print().unwrap(), expected);
763
764        // Checks if the encoded vector values are as expected.
765        let hex_repr_of_vector_values = vector_values.iter().map(hex::encode).collect::<Vec<_>>();
766        assert_eq!(
767            hex_repr_of_vector_values,
768            vec![
769                "0000803f0000004000004040",
770                "000080400000a0400000c040",
771                "0000e0400000004100001041",
772                "000020410000304100004041",
773                "000050410000604100007041",
774                "000080410000884100009041",
775                "000098410000a0410000a841",
776                "0000b0410000b8410000c041",
777                "0000c8410000d0410000d841",
778                "0000e0410000e8410000f041",
779                "0000f8410000004200000442",
780                "0000084200000c4200001042",
781                "000014420000184200001c42",
782                "000020420000244200002842",
783                "00002c420000304200003442",
784                "0000384200003c4200004042",
785            ]
786        );
787
788        let new_grpc_delete_request = |a, b, c, d, ts, row_count| DeleteRequest {
789            table_name: table_name.to_string(),
790            key_columns: vec![
791                Column {
792                    column_name: "a".to_string(),
793                    semantic_type: SemanticType::Tag as i32,
794                    values: Some(Values {
795                        i32_values: a,
796                        ..Default::default()
797                    }),
798                    datatype: ColumnDataType::Int32 as i32,
799                    ..Default::default()
800                },
801                Column {
802                    column_name: "b".to_string(),
803                    semantic_type: SemanticType::Tag as i32,
804                    values: Some(Values {
805                        string_values: b,
806                        ..Default::default()
807                    }),
808                    datatype: ColumnDataType::String as i32,
809                    ..Default::default()
810                },
811                Column {
812                    column_name: "c".to_string(),
813                    values: Some(Values {
814                        string_values: c,
815                        ..Default::default()
816                    }),
817                    semantic_type: SemanticType::Tag as i32,
818                    datatype: ColumnDataType::Json as i32,
819                    ..Default::default()
820                },
821                Column {
822                    column_name: "d".to_string(),
823                    values: Some(Values {
824                        binary_values: d,
825                        ..Default::default()
826                    }),
827                    semantic_type: SemanticType::Field as i32,
828                    datatype: ColumnDataType::Vector as i32,
829                    datatype_extension: Some(ColumnDataTypeExtension {
830                        type_ext: Some(TypeExt::VectorType(VectorTypeExtension { dim: 3 })),
831                    }),
832                    ..Default::default()
833                },
834                Column {
835                    column_name: "ts".to_string(),
836                    semantic_type: SemanticType::Timestamp as i32,
837                    values: Some(Values {
838                        timestamp_millisecond_values: ts,
839                        ..Default::default()
840                    }),
841                    datatype: ColumnDataType::TimestampMillisecond as i32,
842                    ..Default::default()
843                },
844            ],
845            row_count,
846        };
847        let delete1 = new_grpc_delete_request(
848            vec![2, 12, 22, 52],
849            vec![
850                "ts: 1672557973000".to_string(),
851                "ts: 1672557979000".to_string(),
852                "ts: 1672557982000".to_string(),
853                "ts: 1672557986000".to_string(),
854            ],
855            vec![
856                r#"{ "id": 2, "name": "Bob", "balance": 1234.56, "active": false }"#.to_string(),
857                r#"{ "id": 8, "contact": { "email": "hank@example.com", "phone": "+0987654321" } }"#.to_string(),
858                r#"{ "id": 11, "birthday": "1996-07-20", "location": { "city": "New York", "zip": "10001" } }"#.to_string(),
859                r#"{ "id": 15, "transactions": [{ "amount": 500, "date": "2024-01-01" }, { "amount": -200, "date": "2024-02-01" }] }"#.to_string(),
860            ],
861            vec![
862                [4.0f32, 5.0, 6.0].iter().flat_map(|f| f.to_le_bytes()).collect::<Vec<u8>>(),
863                [22.0f32, 23.0, 24.0].iter().flat_map(|f| f.to_le_bytes()).collect::<Vec<u8>>(),
864                [31.0f32, 32.0, 33.0].iter().flat_map(|f| f.to_le_bytes()).collect::<Vec<u8>>(),
865                [43.0f32, 44.0, 45.0].iter().flat_map(|f| f.to_le_bytes()).collect::<Vec<u8>>(),
866            ],
867            vec![1672557973000, 1672557979000, 1672557982000, 1672557986000],
868            4,
869        );
870        let delete2 = new_grpc_delete_request(
871            vec![3, 53],
872            vec![
873                "ts: 1672557974000".to_string(),
874                "ts: 1672557987000".to_string(),
875            ],
876            vec![
877                r#"{ "id": 3, "tags": ["rust", "testing", "json"], "age": 28 }"#.to_string(),
878                r#"{ "id": 16, "transactions": [{ "amount": 500, "date": "2024-01-01" }] }"#
879                    .to_string(),
880            ],
881            vec![
882                [7.0f32, 8.0, 9.0]
883                    .iter()
884                    .flat_map(|f| f.to_le_bytes())
885                    .collect::<Vec<u8>>(),
886                [46.0f32, 47.0, 48.0]
887                    .iter()
888                    .flat_map(|f| f.to_le_bytes())
889                    .collect::<Vec<u8>>(),
890            ],
891            vec![1672557974000, 1672557987000],
892            2,
893        );
894        let output = query(
895            instance,
896            Request::Deletes(DeleteRequests {
897                deletes: vec![delete1, delete2],
898            }),
899        )
900        .await;
901        assert!(matches!(output.data, OutputData::AffectedRows(6)));
902
903        let output = query(instance, request).await;
904        let OutputData::Stream(stream) = output.data else {
905            unreachable!()
906        };
907        let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
908        let expected = r#"+---------------------+----+-------------------+-------------------------------------------------------------------------------+--------------------------+
909| ts                  | a  | b                 | c                                                                             | d                        |
910+---------------------+----+-------------------+-------------------------------------------------------------------------------+--------------------------+
911| 2023-01-01T07:26:12 | 1  | ts: 1672557972000 | {"active":true,"age":30,"id":1,"name":"Alice"}                                | 0000803f0000004000004040 |
912| 2023-01-01T07:26:15 | 4  | ts: 1672557975000 | {"id":4,"metadata":{"created_at":"2024-10-30T12:00:00Z","status":"inactive"}} | 000020410000304100004041 |
913| 2023-01-01T07:26:16 | 5  | ts: 1672557976000 | {"id":5,"name":null,"phone":"+1234567890"}                                    | 000050410000604100007041 |
914| 2023-01-01T07:26:17 |    | ts: 1672557977000 | {"active":true,"height":5.9,"id":6,"weight":72.5}                             | 000080410000884100009041 |
915| 2023-01-01T07:26:18 | 11 | ts: 1672557978000 | {"age":29,"id":7,"languages":["English","Spanish"]}                           | 000098410000a0410000a841 |
916| 2023-01-01T07:26:20 | 20 | ts: 1672557980000 | {"id":9,"preferences":{"notifications":true,"theme":"dark"}}                  | 0000c8410000d0410000d841 |
917| 2023-01-01T07:26:21 | 21 | ts: 1672557981000 | {"active":false,"id":10,"scores":[88,92,76]}                                  | 0000e0410000e8410000f041 |
918| 2023-01-01T07:26:23 | 23 | ts: 1672557983000 | {"id":12,"subscription":{"expires":"2025-01-01","type":"premium"}}            | 0000084200000c4200001042 |
919| 2023-01-01T07:26:24 | 50 | ts: 1672557984000 | {"active":true,"id":13,"settings":{"brightness":0.6,"volume":0.8}}            | 000014420000184200001c42 |
920| 2023-01-01T07:26:25 | 51 | ts: 1672557985000 | {"id":14,"notes":["first note","second note"],"priority":1}                   | 000020420000244200002842 |
921+---------------------+----+-------------------+-------------------------------------------------------------------------------+--------------------------+"#;
922        similar_asserts::assert_eq!(recordbatches.pretty_print().unwrap(), expected);
923    }
924
925    async fn verify_data_distribution(
926        instance: &MockDistributedInstance,
927        table_name: &str,
928        expected_distribution: HashMap<u32, &str>,
929    ) {
930        let table = instance
931            .frontend()
932            .catalog_manager()
933            .table("greptime", "public", table_name, None)
934            .await
935            .unwrap()
936            .unwrap();
937        let table_id = table.table_info().ident.table_id;
938        let table_route_value = instance
939            .table_metadata_manager()
940            .table_route_manager()
941            .table_route_storage()
942            .get(table_id)
943            .await
944            .unwrap()
945            .unwrap();
946
947        let region_to_dn_map = region_distribution(
948            table_route_value
949                .region_routes()
950                .expect("physical table route"),
951        )
952        .iter()
953        .map(|(k, v)| (v.leader_regions[0], *k))
954        .collect::<HashMap<u32, u64>>();
955        assert!(region_to_dn_map.len() <= instance.datanodes().len());
956
957        let stmt = QueryLanguageParser::parse_sql(
958            &format!("SELECT ts, a, b FROM {table_name} ORDER BY ts"),
959            &QueryContext::arc(),
960        )
961        .unwrap();
962        let plan = instance
963            .frontend()
964            .statement_executor()
965            .plan(&stmt, QueryContext::arc())
966            .await
967            .unwrap();
968        let plan = DFLogicalSubstraitConvertor
969            .encode(&plan, DefaultSerializer)
970            .unwrap();
971
972        for (region, dn) in region_to_dn_map.iter() {
973            let region_server = instance.datanodes().get(dn).unwrap().region_server();
974
975            let region_id = RegionId::new(table_id, *region);
976
977            let stream = region_server
978                .handle_remote_read(
979                    RegionQueryRequest {
980                        region_id: region_id.as_u64(),
981                        plan: plan.to_vec(),
982                        ..Default::default()
983                    },
984                    QueryContext::arc(),
985                )
986                .await
987                .unwrap();
988
989            let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
990            let actual = recordbatches.pretty_print().unwrap();
991
992            let expected = expected_distribution.get(region).unwrap();
993            assert_eq!(&actual, expected);
994        }
995    }
996
997    async fn test_insert_delete_and_query_on_auto_created_table(instance: &Instance) {
998        let insert = InsertRequest {
999            table_name: "auto_created_table".to_string(),
1000            columns: vec![
1001                Column {
1002                    column_name: "a".to_string(),
1003                    values: Some(Values {
1004                        i32_values: vec![4, 6],
1005                        ..Default::default()
1006                    }),
1007                    null_mask: vec![2],
1008                    semantic_type: SemanticType::Field as i32,
1009                    datatype: ColumnDataType::Int32 as i32,
1010                    ..Default::default()
1011                },
1012                Column {
1013                    column_name: "c".to_string(),
1014                    values: Some(Values {
1015                        string_values: vec![
1016                            r#"{ "id": 1, "name": "Alice", "age": 30, "active": true }"#
1017                                .to_string(),
1018                            r#"{ "id": 2, "name": "Bob", "balance": 1234.56, "active": false }"#
1019                                .to_string(),
1020                        ],
1021                        ..Default::default()
1022                    }),
1023                    null_mask: vec![2],
1024                    semantic_type: SemanticType::Field as i32,
1025                    datatype: ColumnDataType::Json as i32,
1026                    ..Default::default()
1027                },
1028                Column {
1029                    column_name: "ts".to_string(),
1030                    values: Some(Values {
1031                        timestamp_millisecond_values: vec![
1032                            1672557975000,
1033                            1672557976000,
1034                            1672557977000,
1035                        ],
1036                        ..Default::default()
1037                    }),
1038                    semantic_type: SemanticType::Timestamp as i32,
1039                    datatype: ColumnDataType::TimestampMillisecond as i32,
1040                    ..Default::default()
1041                },
1042            ],
1043            row_count: 3,
1044        };
1045
1046        // Test auto create not existed table upon insertion.
1047        let request = Request::Inserts(InsertRequests {
1048            inserts: vec![insert],
1049        });
1050        let output = query(instance, request).await;
1051        assert!(matches!(output.data, OutputData::AffectedRows(3)));
1052
1053        let insert = InsertRequest {
1054            table_name: "auto_created_table".to_string(),
1055            columns: vec![
1056                Column {
1057                    column_name: "b".to_string(),
1058                    values: Some(Values {
1059                        string_values: vec!["x".to_string(), "z".to_string()],
1060                        ..Default::default()
1061                    }),
1062                    null_mask: vec![2],
1063                    semantic_type: SemanticType::Field as i32,
1064                    datatype: ColumnDataType::String as i32,
1065                    ..Default::default()
1066                },
1067                Column {
1068                    column_name: "ts".to_string(),
1069                    values: Some(Values {
1070                        timestamp_millisecond_values: vec![
1071                            1672557978000,
1072                            1672557979000,
1073                            1672557980000,
1074                        ],
1075                        ..Default::default()
1076                    }),
1077                    semantic_type: SemanticType::Timestamp as i32,
1078                    datatype: ColumnDataType::TimestampMillisecond as i32,
1079                    ..Default::default()
1080                },
1081            ],
1082            row_count: 3,
1083        };
1084
1085        // Test auto add not existed column upon insertion.
1086        let request = Request::Inserts(InsertRequests {
1087            inserts: vec![insert],
1088        });
1089        let output = query(instance, request).await;
1090        assert!(matches!(output.data, OutputData::AffectedRows(3)));
1091
1092        let request = Request::Query(QueryRequest {
1093            query: Some(Query::Sql(
1094                "SELECT ts, a, b, json_to_string(c) as c FROM auto_created_table order by ts"
1095                    .to_string(),
1096            )),
1097        });
1098        let output = query(instance, request.clone()).await;
1099        let OutputData::Stream(stream) = output.data else {
1100            unreachable!()
1101        };
1102        let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
1103        let expected = r#"+---------------------+---+---+--------------------------------------------------------+
1104| ts                  | a | b | c                                                      |
1105+---------------------+---+---+--------------------------------------------------------+
1106| 2023-01-01T07:26:15 | 4 |   | {"active":true,"age":30,"id":1,"name":"Alice"}         |
1107| 2023-01-01T07:26:16 |   |   |                                                        |
1108| 2023-01-01T07:26:17 | 6 |   | {"active":false,"balance":1234.56,"id":2,"name":"Bob"} |
1109| 2023-01-01T07:26:18 |   | x |                                                        |
1110| 2023-01-01T07:26:19 |   |   |                                                        |
1111| 2023-01-01T07:26:20 |   | z |                                                        |
1112+---------------------+---+---+--------------------------------------------------------+"#;
1113        similar_asserts::assert_eq!(recordbatches.pretty_print().unwrap(), expected);
1114
1115        let delete = DeleteRequest {
1116            table_name: "auto_created_table".to_string(),
1117            key_columns: vec![Column {
1118                column_name: "ts".to_string(),
1119                values: Some(Values {
1120                    timestamp_millisecond_values: vec![1672557975000, 1672557979000],
1121                    ..Default::default()
1122                }),
1123                semantic_type: SemanticType::Timestamp as i32,
1124                datatype: ColumnDataType::TimestampMillisecond as i32,
1125                ..Default::default()
1126            }],
1127            row_count: 2,
1128        };
1129
1130        let output = query(
1131            instance,
1132            Request::Deletes(DeleteRequests {
1133                deletes: vec![delete],
1134            }),
1135        )
1136        .await;
1137        assert!(matches!(output.data, OutputData::AffectedRows(2)));
1138
1139        let output = query(instance, request).await;
1140        let OutputData::Stream(stream) = output.data else {
1141            unreachable!()
1142        };
1143        let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
1144        let expected = r#"+---------------------+---+---+--------------------------------------------------------+
1145| ts                  | a | b | c                                                      |
1146+---------------------+---+---+--------------------------------------------------------+
1147| 2023-01-01T07:26:16 |   |   |                                                        |
1148| 2023-01-01T07:26:17 | 6 |   | {"active":false,"balance":1234.56,"id":2,"name":"Bob"} |
1149| 2023-01-01T07:26:18 |   | x |                                                        |
1150| 2023-01-01T07:26:20 |   | z |                                                        |
1151+---------------------+---+---+--------------------------------------------------------+"#;
1152        similar_asserts::assert_eq!(recordbatches.pretty_print().unwrap(), expected);
1153    }
1154
1155    #[tokio::test(flavor = "multi_thread")]
1156    async fn test_promql_query() {
1157        let standalone = GreptimeDbStandaloneBuilder::new("test_standalone_promql_query")
1158            .build()
1159            .await;
1160        let instance = standalone.fe_instance();
1161
1162        let table_name = "my_table";
1163        let sql = format!(
1164            "CREATE TABLE {table_name} (h string, a double, ts TIMESTAMP, TIME INDEX (ts), PRIMARY KEY(h))"
1165        );
1166        create_table(instance, sql).await;
1167
1168        let insert = InsertRequest {
1169            table_name: table_name.to_string(),
1170            columns: vec![
1171                Column {
1172                    column_name: "h".to_string(),
1173                    values: Some(Values {
1174                        string_values: vec![
1175                            "t".to_string(),
1176                            "t".to_string(),
1177                            "t".to_string(),
1178                            "t".to_string(),
1179                            "t".to_string(),
1180                            "t".to_string(),
1181                            "t".to_string(),
1182                            "t".to_string(),
1183                        ],
1184                        ..Default::default()
1185                    }),
1186                    semantic_type: SemanticType::Tag as i32,
1187                    datatype: ColumnDataType::String as i32,
1188                    ..Default::default()
1189                },
1190                Column {
1191                    column_name: "a".to_string(),
1192                    values: Some(Values {
1193                        f64_values: vec![1f64, 11f64, 20f64, 22f64, 50f64, 55f64, 99f64],
1194                        ..Default::default()
1195                    }),
1196                    null_mask: vec![4],
1197                    semantic_type: SemanticType::Field as i32,
1198                    datatype: ColumnDataType::Float64 as i32,
1199                    ..Default::default()
1200                },
1201                Column {
1202                    column_name: "ts".to_string(),
1203                    values: Some(Values {
1204                        timestamp_millisecond_values: vec![
1205                            1672557972000,
1206                            1672557973000,
1207                            1672557974000,
1208                            1672557975000,
1209                            1672557976000,
1210                            1672557977000,
1211                            1672557978000,
1212                            1672557979000,
1213                        ],
1214                        ..Default::default()
1215                    }),
1216                    semantic_type: SemanticType::Timestamp as i32,
1217                    datatype: ColumnDataType::TimestampMillisecond as i32,
1218                    ..Default::default()
1219                },
1220            ],
1221            row_count: 8,
1222        };
1223
1224        let request = Request::Inserts(InsertRequests {
1225            inserts: vec![insert],
1226        });
1227        let output = query(instance, request).await;
1228        assert!(matches!(output.data, OutputData::AffectedRows(8)));
1229
1230        let request = Request::Query(QueryRequest {
1231            query: Some(Query::PromRangeQuery(api::v1::PromRangeQuery {
1232                query: "my_table".to_owned(),
1233                start: "1672557973".to_owned(),
1234                end: "1672557978".to_owned(),
1235                step: "1s".to_owned(),
1236                lookback: "5m".to_string(),
1237            })),
1238        });
1239        let output = query(instance, request).await;
1240        let OutputData::Stream(stream) = output.data else {
1241            unreachable!()
1242        };
1243        let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
1244        let expected = "\
1245+---+------+---------------------+
1246| h | a    | ts                  |
1247+---+------+---------------------+
1248| t | 11.0 | 2023-01-01T07:26:13 |
1249| t |      | 2023-01-01T07:26:14 |
1250| t | 20.0 | 2023-01-01T07:26:15 |
1251| t | 22.0 | 2023-01-01T07:26:16 |
1252| t | 50.0 | 2023-01-01T07:26:17 |
1253| t | 55.0 | 2023-01-01T07:26:18 |
1254+---+------+---------------------+";
1255        assert_eq!(recordbatches.pretty_print().unwrap(), expected);
1256    }
1257
1258    #[apply(both_instances_cases)]
1259    async fn test_extra_external_table_options(instance: Arc<dyn MockInstance>) {
1260        common_telemetry::init_default_ut_logging();
1261        let frontend = instance.frontend();
1262        let instance = frontend.as_ref();
1263
1264        let insert = InsertRequest {
1265            table_name: "auto_created_table".to_string(),
1266            columns: vec![
1267                Column {
1268                    column_name: "a".to_string(),
1269                    values: Some(Values {
1270                        i32_values: vec![4, 6],
1271                        ..Default::default()
1272                    }),
1273                    null_mask: vec![2],
1274                    semantic_type: SemanticType::Field as i32,
1275                    datatype: ColumnDataType::Int32 as i32,
1276                    ..Default::default()
1277                },
1278                Column {
1279                    column_name: "c".to_string(),
1280                    values: Some(Values {
1281                        string_values: vec![
1282                            r#"{ "id": 1, "name": "Alice", "age": 30, "active": true }"#
1283                                .to_string(),
1284                            r#"{ "id": 2, "name": "Bob", "balance": 1234.56, "active": false }"#
1285                                .to_string(),
1286                        ],
1287                        ..Default::default()
1288                    }),
1289                    null_mask: vec![2],
1290                    semantic_type: SemanticType::Field as i32,
1291                    datatype: ColumnDataType::Json as i32,
1292                    ..Default::default()
1293                },
1294                Column {
1295                    column_name: "ts".to_string(),
1296                    values: Some(Values {
1297                        timestamp_millisecond_values: vec![
1298                            1672557975000,
1299                            1672557976000,
1300                            1672557977000,
1301                        ],
1302                        ..Default::default()
1303                    }),
1304                    semantic_type: SemanticType::Timestamp as i32,
1305                    datatype: ColumnDataType::TimestampMillisecond as i32,
1306                    ..Default::default()
1307                },
1308            ],
1309            row_count: 3,
1310        };
1311        let request = Request::Inserts(InsertRequests {
1312            inserts: vec![insert],
1313        });
1314
1315        let ctx = Arc::new(
1316            QueryContextBuilder::default()
1317                .set_extension(TWCS_TIME_WINDOW.to_string(), "1d".to_string())
1318                .build(),
1319        );
1320        let output = GrpcQueryHandler::do_query(instance, request, ctx)
1321            .await
1322            .unwrap();
1323        assert!(matches!(output.data, OutputData::AffectedRows(3)));
1324
1325        let sql = "show create table auto_created_table";
1326        let expected = r#"+--------------------+---------------------------------------------------+
1327| Table              | Create Table                                      |
1328+--------------------+---------------------------------------------------+
1329| auto_created_table | CREATE TABLE IF NOT EXISTS "auto_created_table" ( |
1330|                    |   "a" INT NULL,                                   |
1331|                    |   "c" JSON NULL,                                  |
1332|                    |   "ts" TIMESTAMP(3) NOT NULL,                     |
1333|                    |   TIME INDEX ("ts")                               |
1334|                    | )                                                 |
1335|                    |                                                   |
1336|                    | ENGINE=mito                                       |
1337|                    | WITH(                                             |
1338|                    |   'comment' = 'Created on insertion',             |
1339|                    |   'compaction.twcs.time_window' = '1d',           |
1340|                    |   'compaction.type' = 'twcs'                      |
1341|                    | )                                                 |
1342+--------------------+---------------------------------------------------+"#;
1343        execute_sql_and_expect(&frontend, sql, expected).await;
1344    }
1345}