1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.
//! Abstract syntax tree nodes for sqllogictest.
use std::fmt;
/// A location in a file.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Location {
pub file: String,
pub line: usize,
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}:{}", self.file, self.line)
}
}
/// The declared type of an output column in a query.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type {
/// A text column. Indicated by `T`.
Text,
/// An integer column. Indicated by `I`.
Integer,
/// A "real" number column (i.e., floating point). Indicated by `R`.
Real,
/// A boolean column. Indicated by `B`. This is a CockroachDB extension.
Bool,
/// An object ID (OID) column. Indicated by `O`. This is a CockroachDB
/// extension.
Oid,
// Please don't add new types to this enum, unless you are adding support
// for a sqllogictest dialect that has already done so. These type
// indicators are not meant to be assertions about the output type, but
// rather instructions to the test runner about any necessary coercions.
// For example, declaring a column as an `Integer` when the query returns
// a floating-point will cause the runner to truncate the floating-point
// bit.
//
// In other words, `Bool` and `Oid` are unfortunate additions, as either
// can be replaced with `Text` wherever it appears.
}
/// Whether to apply sorting before checking the results of a query.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Sort {
/// Do not sort. Default. Indicated by the `nosort` query option.
No,
/// Sort each column in each row lexicographically. Indicated by the
/// `rowsort` query option.
Row,
/// Sort each value as though they're in one big list. That is, values are
/// sorted with no respect for column or row boundaries. Indicated by the
/// `valuesort` query option.
Value,
}
impl Sort {
/// Returns true if any kind of sorting should happen.
pub fn yes(&self) -> bool {
use Sort::*;
match self {
No => false,
Row | Value => true,
}
}
}
/// A specific assertion about the expected output of a query.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Output {
/// The query should produce the specified values. Note that the values may
/// need to be sorted according to a [`Sort`] before comparison.
Values(Vec<String>),
/// There should be `num_values` results that hash to `md5`. As with
/// `Output::Values`, the values may need to be sorted according to a
/// [`Sort`] before hashing.
Hashed { num_values: usize, md5: String },
}
impl std::fmt::Display for Output {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Output::Values(strings) if strings.len() == 1 => f.write_str(&strings[0]),
_ => write!(f, "{:?}", self),
}
}
}
/// Instructions for assessing the output of a query.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryOutput<'a> {
pub types: Vec<Type>,
pub sort: Sort,
pub label: Option<&'a str>,
pub column_names: Option<Vec<mz_repr::ColumnName>>,
pub mode: Mode,
pub output: Output,
pub output_str: &'a str,
}
/// A single directive in a sqllogictest file.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Record<'a> {
// A `statement` directive.
Statement {
location: Location,
expected_error: Option<&'a str>,
rows_affected: Option<u64>,
sql: &'a str,
},
/// A `query` directive.
Query {
location: Location,
sql: &'a str,
output: Result<QueryOutput<'a>, &'a str>,
},
/// A `simple` directive.
Simple {
location: Location,
conn: Option<&'a str>,
user: Option<&'a str>,
sql: &'a str,
output: Output,
output_str: &'a str,
},
/// A `hash-threshold` directive.
HashThreshold { threshold: u64 },
/// A `halt` directive.
Halt,
/// A `copy` directive.
Copy {
table_name: &'a str,
tsv_path: &'a str,
},
/// A `reset-server` directive
ResetServer,
}
/// Specifies the dialect of a sqllogictest file. Different sqllogictest runners
/// have slightly different behavior.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
/// In `Standard` mode, expected query output is formatted so that every
/// value is always on its own line, like so:
///
///
/// query II
/// SELECT * FROM VALUES (1, 2), (3, 4)
/// ----
/// 1
/// 2
/// 3
/// 4
///
/// Row boundaries are not visually represented, but they can be inferred
/// because the number of columns per row is specified by the `query`
/// directive.
Standard,
/// In `Cockroach` mode, expected query output is formatted so that rows
/// can contain multiple whitespace-separated columns:
///
/// query II
/// SELECT * FROM VALUES (1, 2), (3, 4)
/// ----
/// 1 2
/// 3 4
///
/// This formatting, while easier to parse visually, is thoroughly
/// frustrating when column values contain whitespace, e.g., strings like
/// "one two", as there is no way to know where the column boundaries are.
/// We jump through some hoops to make this work. You might want to
/// refer to this upstream Cockroach commit [0] for additional details.
///
/// [0]: https://github.com/cockroachdb/cockroach/commit/75c3023ec86a76fe6fb60fe1c6f00752b9784801
Cockroach,
}