## Coverage Report

#### Created: 2024-10-13 08:39

    /Users/andrewlamb/Software/datafusion/datafusion/expr/src/logical_plan/ddl.rs

    Line
    Count
    Source (jump to first uncovered line)
    1
    // Licensed to the Apache Software Foundation (ASF) under one
    2
    // or more contributor license agreements.  See the NOTICE file
    3
    // distributed with this work for additional information
    4
    // regarding copyright ownership.  The ASF licenses this file
    5
    // to you under the Apache License, Version 2.0 (the
    6
    // "License"); you may not use this file except in compliance
    7
    // with the License.  You may obtain a copy of the License at
    8
    //
    9
    //   http://www.apache.org/licenses/LICENSE-2.0
    10
    //
    11
    // Unless required by applicable law or agreed to in writing,
    12
    // software distributed under the License is distributed on an
    13
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14
    // KIND, either express or implied.  See the License for the
    15
    // specific language governing permissions and limitations
    16
    // under the License.
    17
    18
    use crate::{Expr, LogicalPlan, SortExpr, Volatility};
    19
    use std::cmp::Ordering;
    20
    use std::collections::HashMap;
    21
    use std::sync::Arc;
    22
    use std::{
    23
        fmt::{self, Display},
    24
        hash::{Hash, Hasher},
    25
    };
    26
    27
    use crate::expr::Sort;
    28
    use arrow::datatypes::DataType;
    29
    use datafusion_common::{Constraints, DFSchemaRef, SchemaReference, TableReference};
    30
    use sqlparser::ast::Ident;
    31
    32
    /// Various types of DDL  (CREATE / DROP) catalog manipulation
    33
    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
    34
    pub enum DdlStatement {
    35
        /// Creates an external table.
    36
        CreateExternalTable(CreateExternalTable),
    37
        /// Creates an in memory table.
    38
        CreateMemoryTable(CreateMemoryTable),
    39
        /// Creates a new view.
    40
        CreateView(CreateView),
    41
        /// Creates a new catalog schema.
    42
        CreateCatalogSchema(CreateCatalogSchema),
    43
        /// Creates a new catalog (aka "Database").
    44
        CreateCatalog(CreateCatalog),
    45
        /// Creates a new index.
    46
        CreateIndex(CreateIndex),
    47
        /// Drops a table.
    48
        DropTable(DropTable),
    49
        /// Drops a view.
    50
        DropView(DropView),
    51
        /// Drops a catalog schema
    52
        DropCatalogSchema(DropCatalogSchema),
    53
        /// Create function statement
    54
        CreateFunction(CreateFunction),
    55
        /// Drop function statement
    56
        DropFunction(DropFunction),
    57
    }
    58
    59
    impl DdlStatement {
    60
        /// Get a reference to the logical plan's schema
    61
    0
        pub fn schema(&self) -> &DFSchemaRef {
    62
    0
            match self {
    63
    0
                DdlStatement::CreateExternalTable(CreateExternalTable { schema, .. }) => {
    64
    0
                    schema
    65
                }
    66
    0
                DdlStatement::CreateMemoryTable(CreateMemoryTable { input, .. })
    67
    0
                | DdlStatement::CreateView(CreateView { input, .. }) => input.schema(),
    68
    0
                DdlStatement::CreateCatalogSchema(CreateCatalogSchema { schema, .. }) => {
    69
    0
                    schema
    70
                }
    71
    0
                DdlStatement::CreateCatalog(CreateCatalog { schema, .. }) => schema,
    72
    0
                DdlStatement::CreateIndex(CreateIndex { schema, .. }) => schema,
    73
    0
                DdlStatement::DropTable(DropTable { schema, .. }) => schema,
    74
    0
                DdlStatement::DropView(DropView { schema, .. }) => schema,
    75
    0
                DdlStatement::DropCatalogSchema(DropCatalogSchema { schema, .. }) => schema,
    76
    0
                DdlStatement::CreateFunction(CreateFunction { schema, .. }) => schema,
    77
    0
                DdlStatement::DropFunction(DropFunction { schema, .. }) => schema,
    78
            }
    79
    0
        }
    80
    81
        /// Return a descriptive string describing the type of this
    82
        /// [`DdlStatement`]
    83
    0
        pub fn name(&self) -> &str {
    84
    0
            match self {
    85
    0
                DdlStatement::CreateExternalTable(_) => "CreateExternalTable",
    86
    0
                DdlStatement::CreateMemoryTable(_) => "CreateMemoryTable",
    87
    0
                DdlStatement::CreateView(_) => "CreateView",
    88
    0
                DdlStatement::CreateCatalogSchema(_) => "CreateCatalogSchema",
    89
    0
                DdlStatement::CreateCatalog(_) => "CreateCatalog",
    90
    0
                DdlStatement::CreateIndex(_) => "CreateIndex",
    91
    0
                DdlStatement::DropTable(_) => "DropTable",
    92
    0
                DdlStatement::DropView(_) => "DropView",
    93
    0
                DdlStatement::DropCatalogSchema(_) => "DropCatalogSchema",
    94
    0
                DdlStatement::CreateFunction(_) => "CreateFunction",
    95
    0
                DdlStatement::DropFunction(_) => "DropFunction",
    96
            }
    97
    0
        }
    98
    99
        /// Return all inputs for this plan
    100
    0
        pub fn inputs(&self) -> Vec<&LogicalPlan> {
    101
    0
            match self {
    102
    0
                DdlStatement::CreateExternalTable(_) => vec![],
    103
    0
                DdlStatement::CreateCatalogSchema(_) => vec![],
    104
    0
                DdlStatement::CreateCatalog(_) => vec![],
    105
    0
                DdlStatement::CreateMemoryTable(CreateMemoryTable { input, .. }) => {
    106
    0
                    vec![input]
    107
                }
    108
    0
                DdlStatement::CreateView(CreateView { input, .. }) => vec![input],
    109
    0
                DdlStatement::CreateIndex(_) => vec![],
    110
    0
                DdlStatement::DropTable(_) => vec![],
    111
    0
                DdlStatement::DropView(_) => vec![],
    112
    0
                DdlStatement::DropCatalogSchema(_) => vec![],
    113
    0
                DdlStatement::CreateFunction(_) => vec![],
    114
    0
                DdlStatement::DropFunction(_) => vec![],
    115
            }
    116
    0
        }
    117
    118
        /// Return a `format`able structure with the a human readable
    119
        /// description of this LogicalPlan node per node, not including
    120
        /// children.
    121
        ///
    122
        /// See [crate::LogicalPlan::display] for an example
    123
    0
        pub fn display(&self) -> impl fmt::Display + '_ {
    124
            struct Wrapper<'a>(&'a DdlStatement);
    125
            impl<'a> Display for Wrapper<'a> {
    126
    0
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    127
    0
                    match self.0 {
    128
                        DdlStatement::CreateExternalTable(CreateExternalTable {
    129
    0
                            ref name,
    130
    0
                            constraints,
    131
    0
                            ..
    132
    0
                        }) => {
    133
    0
                            write!(f, "CreateExternalTable: {name:?}{constraints}")
    134
                        }
    135
                        DdlStatement::CreateMemoryTable(CreateMemoryTable {
    136
    0
                            name,
    137
    0
                            constraints,
    138
    0
                            ..
    139
    0
                        }) => {
    140
    0
                            write!(f, "CreateMemoryTable: {name:?}{constraints}")
    141
                        }
    142
    0
                        DdlStatement::CreateView(CreateView { name, .. }) => {
    143
    0
                            write!(f, "CreateView: {name:?}")
    144
                        }
    145
                        DdlStatement::CreateCatalogSchema(CreateCatalogSchema {
    146
    0
                            schema_name,
    147
    0
                            ..
    148
    0
                        }) => {
    149
    0
                            write!(f, "CreateCatalogSchema: {schema_name:?}")
    150
                        }
    151
                        DdlStatement::CreateCatalog(CreateCatalog {
    152
    0
                            catalog_name, ..
    153
    0
                        }) => {
    154
    0
                            write!(f, "CreateCatalog: {catalog_name:?}")
    155
                        }
    156
    0
                        DdlStatement::CreateIndex(CreateIndex { name, .. }) => {
    157
    0
                            write!(f, "CreateIndex: {name:?}")
    158
                        }
    159
                        DdlStatement::DropTable(DropTable {
    160
    0
                            name, if_exists, ..
    161
    0
                        }) => {
    162
    0
                            write!(f, "DropTable: {name:?} if not exist:={if_exists}")
    163
                        }
    164
                        DdlStatement::DropView(DropView {
    165
    0
                            name, if_exists, ..
    166
    0
                        }) => {
    167
    0
                            write!(f, "DropView: {name:?} if not exist:={if_exists}")
    168
                        }
    169
                        DdlStatement::DropCatalogSchema(DropCatalogSchema {
    170
    0
                            name,
    171
    0
                            if_exists,
    172
    0
                            cascade,
    173
    0
                            ..
    174
    0
                        }) => {
    175
    0
                            write!(f, "DropCatalogSchema: {name:?} if not exist:={if_exists} cascade:={cascade}")
    176
                        }
    177
    0
                        DdlStatement::CreateFunction(CreateFunction { name, .. }) => {
    178
    0
                            write!(f, "CreateFunction: name {name:?}")
    179
                        }
    180
    0
                        DdlStatement::DropFunction(DropFunction { name, .. }) => {
    181
    0
                            write!(f, "CreateFunction: name {name:?}")
    182
                        }
    183
                    }
    184
    0
                }
    185
            }
    186
    0
            Wrapper(self)
    187
    0
        }
    188
    }
    189
    190
    /// Creates an external table.
    191
    #[derive(Debug, Clone, PartialEq, Eq)]
    192
    pub struct CreateExternalTable {
    193
        /// The table schema
    194
        pub schema: DFSchemaRef,
    195
        /// The table name
    196
        pub name: TableReference,
    197
        /// The physical location
    198
        pub location: String,
    199
        /// The file type of physical file
    200
        pub file_type: String,
    201
        /// Partition Columns
    202
        pub table_partition_cols: Vec<String>,
    203
        /// Option to not error if table already exists
    204
        pub if_not_exists: bool,
    205
        /// SQL used to create the table, if available
    206
        pub definition: Option<String>,
    207
        /// Order expressions supplied by user
    208
        pub order_exprs: Vec<Vec<Sort>>,
    209
        /// Whether the table is an infinite streams
    210
        pub unbounded: bool,
    211
        /// Table(provider) specific options
    212
        pub options: HashMap<String, String>,
    213
        /// The list of constraints in the schema, such as primary key, unique, etc.
    214
        pub constraints: Constraints,
    215
        /// Default values for columns
    216
        pub column_defaults: HashMap<String, Expr>,
    217
    }
    218
    219
    // Hashing refers to a subset of fields considered in PartialEq.
    220
    impl Hash for CreateExternalTable {
    221
    0
        fn hash<H: Hasher>(&self, state: &mut H) {
    222
    0
            self.schema.hash(state);
    223
    0
            self.name.hash(state);
    224
    0
            self.location.hash(state);
    225
    0
            self.file_type.hash(state);
    226
    0
            self.table_partition_cols.hash(state);
    227
    0
            self.if_not_exists.hash(state);
    228
    0
            self.definition.hash(state);
    229
    0
            self.order_exprs.hash(state);
    230
    0
            self.unbounded.hash(state);
    231
    0
            self.options.len().hash(state); // HashMap is not hashable
    232
    0
        }
    233
    }
    234
    235
    // Manual implementation needed because of `schema`, `options`, and `column_defaults` fields.
    236
    // Comparison excludes these fields.
    237
    impl PartialOrd for CreateExternalTable {
    238
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    239
            #[derive(PartialEq, PartialOrd)]
    240
            struct ComparableCreateExternalTable<'a> {
    241
                /// The table name
    242
                pub name: &'a TableReference,
    243
                /// The physical location
    244
                pub location: &'a String,
    245
                /// The file type of physical file
    246
                pub file_type: &'a String,
    247
                /// Partition Columns
    248
                pub table_partition_cols: &'a Vec<String>,
    249
                /// Option to not error if table already exists
    250
                pub if_not_exists: &'a bool,
    251
                /// SQL used to create the table, if available
    252
                pub definition: &'a Option<String>,
    253
                /// Order expressions supplied by user
    254
                pub order_exprs: &'a Vec<Vec<Sort>>,
    255
                /// Whether the table is an infinite streams
    256
                pub unbounded: &'a bool,
    257
                /// The list of constraints in the schema, such as primary key, unique, etc.
    258
                pub constraints: &'a Constraints,
    259
            }
    260
    0
            let comparable_self = ComparableCreateExternalTable {
    261
    0
                name: &self.name,
    262
    0
                location: &self.location,
    263
    0
                file_type: &self.file_type,
    264
    0
                table_partition_cols: &self.table_partition_cols,
    265
    0
                if_not_exists: &self.if_not_exists,
    266
    0
                definition: &self.definition,
    267
    0
                order_exprs: &self.order_exprs,
    268
    0
                unbounded: &self.unbounded,
    269
    0
                constraints: &self.constraints,
    270
    0
            };
    271
    0
            let comparable_other = ComparableCreateExternalTable {
    272
    0
                name: &other.name,
    273
    0
                location: &other.location,
    274
    0
                file_type: &other.file_type,
    275
    0
                table_partition_cols: &other.table_partition_cols,
    276
    0
                if_not_exists: &other.if_not_exists,
    277
    0
                definition: &other.definition,
    278
    0
                order_exprs: &other.order_exprs,
    279
    0
                unbounded: &other.unbounded,
    280
    0
                constraints: &other.constraints,
    281
    0
            };
    282
    0
            comparable_self.partial_cmp(&comparable_other)
    283
    0
        }
    284
    }
    285
    286
    /// Creates an in memory table.
    287
    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
    288
    pub struct CreateMemoryTable {
    289
        /// The table name
    290
        pub name: TableReference,
    291
        /// The list of constraints in the schema, such as primary key, unique, etc.
    292
        pub constraints: Constraints,
    293
        /// The logical plan
    294
        pub input: Arc<LogicalPlan>,
    295
        /// Option to not error if table already exists
    296
        pub if_not_exists: bool,
    297
        /// Option to replace table content if table already exists
    298
        pub or_replace: bool,
    299
        /// Default values for columns
    300
        pub column_defaults: Vec<(String, Expr)>,
    301
    }
    302
    303
    /// Creates a view.
    304
    #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
    305
    pub struct CreateView {
    306
        /// The table name
    307
        pub name: TableReference,
    308
        /// The logical plan
    309
        pub input: Arc<LogicalPlan>,
    310
        /// Option to not error if table already exists
    311
        pub or_replace: bool,
    312
        /// SQL used to create the view, if available
    313
        pub definition: Option<String>,
    314
    }
    315
    316
    /// Creates a catalog (aka "Database").
    317
    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    318
    pub struct CreateCatalog {
    319
        /// The catalog name
    320
        pub catalog_name: String,
    321
        /// Do nothing (except issuing a notice) if a schema with the same name already exists
    322
        pub if_not_exists: bool,
    323
        /// Empty schema
    324
        pub schema: DFSchemaRef,
    325
    }
    326
    327
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    328
    impl PartialOrd for CreateCatalog {
    329
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    330
    0
            match self.catalog_name.partial_cmp(&other.catalog_name) {
    331
    0
                Some(Ordering::Equal) => self.if_not_exists.partial_cmp(&other.if_not_exists),
    332
    0
                cmp => cmp,
    333
            }
    334
    0
        }
    335
    }
    336
    337
    /// Creates a schema.
    338
    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    339
    pub struct CreateCatalogSchema {
    340
        /// The table schema
    341
        pub schema_name: String,
    342
        /// Do nothing (except issuing a notice) if a schema with the same name already exists
    343
        pub if_not_exists: bool,
    344
        /// Empty schema
    345
        pub schema: DFSchemaRef,
    346
    }
    347
    348
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    349
    impl PartialOrd for CreateCatalogSchema {
    350
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    351
    0
            match self.schema_name.partial_cmp(&other.schema_name) {
    352
    0
                Some(Ordering::Equal) => self.if_not_exists.partial_cmp(&other.if_not_exists),
    353
    0
                cmp => cmp,
    354
            }
    355
    0
        }
    356
    }
    357
    358
    /// Drops a table.
    359
    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    360
    pub struct DropTable {
    361
        /// The table name
    362
        pub name: TableReference,
    363
        /// If the table exists
    364
        pub if_exists: bool,
    365
        /// Dummy schema
    366
        pub schema: DFSchemaRef,
    367
    }
    368
    369
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    370
    impl PartialOrd for DropTable {
    371
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    372
    0
            match self.name.partial_cmp(&other.name) {
    373
    0
                Some(Ordering::Equal) => self.if_exists.partial_cmp(&other.if_exists),
    374
    0
                cmp => cmp,
    375
            }
    376
    0
        }
    377
    }
    378
    379
    /// Drops a view.
    380
    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    381
    pub struct DropView {
    382
        /// The view name
    383
        pub name: TableReference,
    384
        /// If the view exists
    385
        pub if_exists: bool,
    386
        /// Dummy schema
    387
        pub schema: DFSchemaRef,
    388
    }
    389
    390
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    391
    impl PartialOrd for DropView {
    392
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    393
    0
            match self.name.partial_cmp(&other.name) {
    394
    0
                Some(Ordering::Equal) => self.if_exists.partial_cmp(&other.if_exists),
    395
    0
                cmp => cmp,
    396
            }
    397
    0
        }
    398
    }
    399
    400
    /// Drops a schema
    401
    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    402
    pub struct DropCatalogSchema {
    403
        /// The schema name
    404
        pub name: SchemaReference,
    405
        /// If the schema exists
    406
        pub if_exists: bool,
    407
        /// Whether drop should cascade
    408
        pub cascade: bool,
    409
        /// Dummy schema
    410
        pub schema: DFSchemaRef,
    411
    }
    412
    413
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    414
    impl PartialOrd for DropCatalogSchema {
    415
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    416
    0
            match self.name.partial_cmp(&other.name) {
    417
    0
                Some(Ordering::Equal) => match self.if_exists.partial_cmp(&other.if_exists) {
    418
    0
                    Some(Ordering::Equal) => self.cascade.partial_cmp(&other.cascade),
    419
    0
                    cmp => cmp,
    420
                },
    421
    0
                cmp => cmp,
    422
            }
    423
    0
        }
    424
    }
    425
    426
    /// Arguments passed to `CREATE FUNCTION`
    427
    ///
    428
    /// Note this meant to be the same as from sqlparser's [`sqlparser::ast::Statement::CreateFunction`]
    429
    #[derive(Clone, PartialEq, Eq, Hash, Debug)]
    430
    pub struct CreateFunction {
    431
        // TODO: There is open question should we expose sqlparser types or redefine them here?
    432
        //       At the moment it make more sense to expose sqlparser types and leave
    433
        //       user to convert them as needed
    434
        pub or_replace: bool,
    435
        pub temporary: bool,
    436
        pub name: String,
    437
        pub args: Option<Vec<OperateFunctionArg>>,
    438
        pub return_type: Option<DataType>,
    439
        pub params: CreateFunctionBody,
    440
        /// Dummy schema
    441
        pub schema: DFSchemaRef,
    442
    }
    443
    444
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    445
    impl PartialOrd for CreateFunction {
    446
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    447
            #[derive(PartialEq, PartialOrd)]
    448
            struct ComparableCreateFunction<'a> {
    449
                pub or_replace: &'a bool,
    450
                pub temporary: &'a bool,
    451
                pub name: &'a String,
    452
                pub args: &'a Option<Vec<OperateFunctionArg>>,
    453
                pub return_type: &'a Option<DataType>,
    454
                pub params: &'a CreateFunctionBody,
    455
            }
    456
    0
            let comparable_self = ComparableCreateFunction {
    457
    0
                or_replace: &self.or_replace,
    458
    0
                temporary: &self.temporary,
    459
    0
                name: &self.name,
    460
    0
                args: &self.args,
    461
    0
                return_type: &self.return_type,
    462
    0
                params: &self.params,
    463
    0
            };
    464
    0
            let comparable_other = ComparableCreateFunction {
    465
    0
                or_replace: &other.or_replace,
    466
    0
                temporary: &other.temporary,
    467
    0
                name: &other.name,
    468
    0
                args: &other.args,
    469
    0
                return_type: &other.return_type,
    470
    0
                params: &other.params,
    471
    0
            };
    472
    0
            comparable_self.partial_cmp(&comparable_other)
    473
    0
        }
    474
    }
    475
    476
    #[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
    477
    pub struct OperateFunctionArg {
    478
        // TODO: figure out how to support mode
    479
        // pub mode: Option<ArgMode>,
    480
        pub name: Option<Ident>,
    481
        pub data_type: DataType,
    482
        pub default_expr: Option<Expr>,
    483
    }
    484
    #[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
    485
    pub struct CreateFunctionBody {
    486
        /// LANGUAGE lang_name
    487
        pub language: Option<Ident>,
    488
        /// IMMUTABLE | STABLE | VOLATILE
    489
        pub behavior: Option<Volatility>,
    490
        /// RETURN or AS function body
    491
        pub function_body: Option<Expr>,
    492
    }
    493
    494
    #[derive(Clone, PartialEq, Eq, Hash, Debug)]
    495
    pub struct DropFunction {
    496
        pub name: String,
    497
        pub if_exists: bool,
    498
        pub schema: DFSchemaRef,
    499
    }
    500
    501
    impl PartialOrd for DropFunction {
    502
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    503
    0
            match self.name.partial_cmp(&other.name) {
    504
    0
                Some(Ordering::Equal) => self.if_exists.partial_cmp(&other.if_exists),
    505
    0
                cmp => cmp,
    506
            }
    507
    0
        }
    508
    }
    509
    510
    #[derive(Clone, PartialEq, Eq, Hash, Debug)]
    511
    pub struct CreateIndex {
    512
        pub name: Option<String>,
    513
        pub table: TableReference,
    514
        pub using: Option<String>,
    515
        pub columns: Vec<SortExpr>,
    516
        pub unique: bool,
    517
        pub if_not_exists: bool,
    518
        pub schema: DFSchemaRef,
    519
    }
    520
    521
    // Manual implementation needed because of `schema` field. Comparison excludes this field.
    522
    impl PartialOrd for CreateIndex {
    523
    0
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    524
            #[derive(PartialEq, PartialOrd)]
    525
            struct ComparableCreateIndex<'a> {
    526
                pub name: &'a Option<String>,
    527
                pub table: &'a TableReference,
    528
                pub using: &'a Option<String>,
    529
                pub columns: &'a Vec<SortExpr>,
    530
                pub unique: &'a bool,
    531
                pub if_not_exists: &'a bool,
    532
            }
    533
    0
            let comparable_self = ComparableCreateIndex {
    534
    0
                name: &self.name,
    535
    0
                table: &self.table,
    536
    0
                using: &self.using,
    537
    0
                columns: &self.columns,
    538
    0
                unique: &self.unique,
    539
    0
                if_not_exists: &self.if_not_exists,
    540
    0
            };
    541
    0
            let comparable_other = ComparableCreateIndex {
    542
    0
                name: &other.name,
    543
    0
                table: &other.table,
    544
    0
                using: &other.using,
    545
    0
                columns: &other.columns,
    546
    0
                unique: &other.unique,
    547
    0
                if_not_exists: &other.if_not_exists,
    548
    0
            };
    549
    0
            comparable_self.partial_cmp(&comparable_other)
    550
    0
        }
    551
    }
    552
    553
    #[cfg(test)]
    554
    mod test {
    555
        use crate::{CreateCatalog, DdlStatement, DropView};
    556
        use datafusion_common::{DFSchema, DFSchemaRef, TableReference};
    557
        use std::cmp::Ordering;
    558
    559
        #[test]
    560
        fn test_partial_ord() {
    561
            let catalog = DdlStatement::CreateCatalog(CreateCatalog {
    562
                catalog_name: "name".to_string(),
    563
                if_not_exists: false,
    564
                schema: DFSchemaRef::new(DFSchema::empty()),
    565
            });
    566
            let catalog_2 = DdlStatement::CreateCatalog(CreateCatalog {
    567
                catalog_name: "name".to_string(),
    568
                if_not_exists: true,
    569
                schema: DFSchemaRef::new(DFSchema::empty()),
    570
            });
    571
    572
            assert_eq!(catalog.partial_cmp(&catalog_2), Some(Ordering::Less));
    573
    574
            let drop_view = DdlStatement::DropView(DropView {
    575
                name: TableReference::from("table"),
    576
                if_exists: false,
    577
                schema: DFSchemaRef::new(DFSchema::empty()),
    578
            });
    579
    580
            assert_eq!(drop_view.partial_cmp(&catalog), Some(Ordering::Greater));
    581
        }
    582
    }