Skip to content

Commit b297ccb

Browse files
committed
Add support for PostgreSQL/Redshift geometric operators
1 parent 322209a commit b297ccb

11 files changed

+1185
-26
lines changed

src/ast/data_type.rs

+29
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ pub enum DataType {
386386
///
387387
/// [bigquery]: https://cloud.google.com/bigquery/docs/user-defined-functions#templated-sql-udf-parameters
388388
AnyType,
389+
/// geometric type
390+
GeometricType(GeometricTypeKind),
389391
}
390392

391393
impl fmt::Display for DataType {
@@ -641,6 +643,7 @@ impl fmt::Display for DataType {
641643
DataType::Trigger => write!(f, "TRIGGER"),
642644
DataType::AnyType => write!(f, "ANY TYPE"),
643645
DataType::Table(fields) => write!(f, "TABLE({})", display_comma_separated(fields)),
646+
DataType::GeometricType(kind) => write!(f, "{}", kind),
644647
}
645648
}
646649
}
@@ -879,3 +882,29 @@ pub enum ArrayElemTypeDef {
879882
/// `Array(Int64)`
880883
Parenthesis(Box<DataType>),
881884
}
885+
886+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
887+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
888+
pub enum GeometricTypeKind {
889+
Point,
890+
Line,
891+
LineSegment,
892+
GeometricBox,
893+
GeometricPath,
894+
Polygon,
895+
Circle,
896+
}
897+
898+
impl fmt::Display for GeometricTypeKind {
899+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
900+
match self {
901+
GeometricTypeKind::Point => write!(f, "point"),
902+
GeometricTypeKind::Line => write!(f, "line"),
903+
GeometricTypeKind::LineSegment => write!(f, "lseg"),
904+
GeometricTypeKind::GeometricBox => write!(f, "box"),
905+
GeometricTypeKind::GeometricPath => write!(f, "path"),
906+
GeometricTypeKind::Polygon => write!(f, "polygon"),
907+
GeometricTypeKind::Circle => write!(f, "circle"),
908+
}
909+
}
910+
}

src/ast/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ use crate::ast::helpers::stmt_data_loading::{
9393
#[cfg(feature = "visitor")]
9494
pub use visitor::*;
9595

96+
pub use self::data_type::GeometricTypeKind;
97+
9698
mod data_type;
9799
mod dcl;
98100
mod ddl;
@@ -1533,7 +1535,15 @@ impl fmt::Display for Expr {
15331535
Expr::UnaryOp { op, expr } => {
15341536
if op == &UnaryOperator::PGPostfixFactorial {
15351537
write!(f, "{expr}{op}")
1536-
} else if op == &UnaryOperator::Not {
1538+
} else if matches!(
1539+
op,
1540+
UnaryOperator::Not
1541+
| UnaryOperator::NumOfPoints
1542+
| UnaryOperator::LenOrCircumference
1543+
| UnaryOperator::Center
1544+
| UnaryOperator::IsHorizontal
1545+
| UnaryOperator::IsVertical
1546+
) {
15371547
write!(f, "{op} {expr}")
15381548
} else {
15391549
write!(f, "{op}{expr}")

src/ast/operator.rs

+84
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@ pub enum UnaryOperator {
5353
PGAbs,
5454
/// Unary logical not operator: e.g. `! false` (Hive-specific)
5555
BangNot,
56+
/// `#` Number of points in path or polygon (PostgreSQL/Redshift geometric operator)
57+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
58+
NumOfPoints,
59+
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
60+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
61+
LenOrCircumference,
62+
/// `@@` Center (PostgreSQL/Redshift geometric operator)
63+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
64+
Center,
65+
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
66+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
67+
IsHorizontal,
68+
/// `?|` Is vertical? (PostgreSQL/Redshift geometric operator)
69+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
70+
IsVertical,
5671
}
5772

5873
impl fmt::Display for UnaryOperator {
@@ -68,6 +83,11 @@ impl fmt::Display for UnaryOperator {
6883
UnaryOperator::PGPrefixFactorial => "!!",
6984
UnaryOperator::PGAbs => "@",
7085
UnaryOperator::BangNot => "!",
86+
UnaryOperator::NumOfPoints => "#",
87+
UnaryOperator::LenOrCircumference => "@-@",
88+
UnaryOperator::Center => "@@",
89+
UnaryOperator::IsHorizontal => "?-",
90+
UnaryOperator::IsVertical => "?|",
7191
})
7292
}
7393
}
@@ -253,6 +273,54 @@ pub enum BinaryOperator {
253273
/// Specifies a test for an overlap between two datetime periods:
254274
/// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#overlaps-predicate>
255275
Overlaps,
276+
/// `##` Point of closest proximity (PostgreSQL/Redshift geometric operator)
277+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
278+
DoubleHash,
279+
/// `<->` Distance between (PostgreSQL/Redshift geometric operator)
280+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
281+
LtDashGt,
282+
/// `&<` Overlaps to left? (PostgreSQL/Redshift geometric operator)
283+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
284+
AndLt,
285+
/// `&>` Overlaps to right? (PostgreSQL/Redshift geometric operator)
286+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
287+
AndGt,
288+
/// `<<|` Is strictly below? (PostgreSQL/Redshift geometric operator)
289+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
290+
LtLtPipe,
291+
/// `|>>` Is strictly above? (PostgreSQL/Redshift geometric operator)
292+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
293+
PipeGtGt,
294+
/// `&<|` Does not extend above? (PostgreSQL/Redshift geometric operator)
295+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
296+
AndLtPipe,
297+
/// `|&>` Does not extend below? (PostgreSQL/Redshift geometric operator)
298+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
299+
PipeAndGt,
300+
/// `<^` Is below? (PostgreSQL/Redshift geometric operator)
301+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
302+
LtCaret,
303+
/// `>^` Is above? (PostgreSQL/Redshift geometric operator)
304+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
305+
GtCaret,
306+
/// `?#` Intersects? (PostgreSQL/Redshift geometric operator)
307+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
308+
QuestionHash,
309+
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
310+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
311+
QuestionDash,
312+
/// `?-|` Is perpendicular? (PostgreSQL/Redshift geometric operator)
313+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
314+
QuestionDashPipe,
315+
/// `?||` Are Parallel? (PostgreSQL/Redshift geometric operator)
316+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
317+
QuestionDoublePipe,
318+
/// `@` Contained or on? (PostgreSQL/Redshift geometric operator)
319+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
320+
At,
321+
/// `~=` Same as? (PostgreSQL/Redshift geometric operator)
322+
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
323+
TildeEq,
256324
}
257325

258326
impl fmt::Display for BinaryOperator {
@@ -310,6 +378,22 @@ impl fmt::Display for BinaryOperator {
310378
write!(f, "OPERATOR({})", display_separated(idents, "."))
311379
}
312380
BinaryOperator::Overlaps => f.write_str("OVERLAPS"),
381+
BinaryOperator::DoubleHash => f.write_str("##"),
382+
BinaryOperator::LtDashGt => f.write_str("<->"),
383+
BinaryOperator::AndLt => f.write_str("&<"),
384+
BinaryOperator::AndGt => f.write_str("&>"),
385+
BinaryOperator::LtLtPipe => f.write_str("<<|"),
386+
BinaryOperator::PipeGtGt => f.write_str("|>>"),
387+
BinaryOperator::AndLtPipe => f.write_str("&<|"),
388+
BinaryOperator::PipeAndGt => f.write_str("|&>"),
389+
BinaryOperator::LtCaret => f.write_str("<^"),
390+
BinaryOperator::GtCaret => f.write_str(">^"),
391+
BinaryOperator::QuestionHash => f.write_str("?#"),
392+
BinaryOperator::QuestionDash => f.write_str("?-"),
393+
BinaryOperator::QuestionDashPipe => f.write_str("?-|"),
394+
BinaryOperator::QuestionDoublePipe => f.write_str("?||"),
395+
BinaryOperator::At => f.write_str("@"),
396+
BinaryOperator::TildeEq => f.write_str("~="),
313397
}
314398
}
315399
}

src/dialect/mod.rs

+26-7
Original file line numberDiff line numberDiff line change
@@ -591,18 +591,34 @@ pub trait Dialect: Debug + Any {
591591
| Token::ExclamationMarkDoubleTilde
592592
| Token::ExclamationMarkDoubleTildeAsterisk
593593
| Token::Spaceship => Ok(p!(Eq)),
594-
Token::Pipe => Ok(p!(Pipe)),
594+
Token::Pipe
595+
| Token::QuestionMarkDash
596+
| Token::DoubleSharp
597+
| Token::Overlap
598+
| Token::AmpersandLeftAngleBracket
599+
| Token::AmpersandRightAngleBracket
600+
| Token::QuestionMarkDashVerticalBar
601+
| Token::AmpersandLeftAngleBracketVerticalBar
602+
| Token::VerticalBarAmpersandRightAngleBracket
603+
| Token::TwoWayArrow
604+
| Token::LeftAngleBracketCaret
605+
| Token::RightAngleBracketCaret
606+
| Token::QuestionMarkSharp
607+
| Token::QuestionMarkDoubleVerticalBar
608+
| Token::QuestionPipe
609+
| Token::TildeEqual
610+
| Token::AtSign
611+
| Token::ShiftLeftVerticalBar
612+
| Token::VerticalBarShiftRight => Ok(p!(Pipe)),
595613
Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
596614
Token::Ampersand => Ok(p!(Ampersand)),
597615
Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
598616
Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
599617
Ok(p!(MulDivModOp))
600618
}
601-
Token::DoubleColon
602-
| Token::ExclamationMark
603-
| Token::LBracket
604-
| Token::Overlap
605-
| Token::CaretAt => Ok(p!(DoubleColon)),
619+
Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
620+
Ok(p!(DoubleColon))
621+
}
606622
Token::Arrow
607623
| Token::LongArrow
608624
| Token::HashArrow
@@ -614,7 +630,6 @@ pub trait Dialect: Debug + Any {
614630
| Token::AtAt
615631
| Token::Question
616632
| Token::QuestionAnd
617-
| Token::QuestionPipe
618633
| Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
619634
_ => Ok(self.prec_unknown()),
620635
}
@@ -912,6 +927,10 @@ pub trait Dialect: Debug + Any {
912927
fn supports_array_typedef_size(&self) -> bool {
913928
false
914929
}
930+
/// Returns true if the dialect supports geometric types.
931+
fn supports_geometric_types(&self) -> bool {
932+
false
933+
}
915934
}
916935

917936
/// This represents the operators for which precedence must be defined

src/dialect/postgresql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ impl Dialect for PostgreSqlDialect {
258258
fn supports_array_typedef_size(&self) -> bool {
259259
true
260260
}
261+
262+
fn supports_geometric_types(&self) -> bool {
263+
true
264+
}
261265
}
262266

263267
pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> {

src/dialect/redshift.rs

+4
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,8 @@ impl Dialect for RedshiftSqlDialect {
113113
fn supports_string_escape_constant(&self) -> bool {
114114
true
115115
}
116+
117+
fn supports_geometric_types(&self) -> bool {
118+
true
119+
}
116120
}

src/keywords.rs

+26
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ use serde::{Deserialize, Serialize};
3333
#[cfg(feature = "visitor")]
3434
use sqlparser_derive::{Visit, VisitMut};
3535

36+
use crate::ast::GeometricTypeKind;
37+
3638
/// Defines a string constant for a single keyword: `kw_def!(SELECT);`
3739
/// expands to `pub const SELECT = "SELECT";`
3840
macro_rules! kw_def {
@@ -141,6 +143,7 @@ define_keywords!(
141143
BOOL,
142144
BOOLEAN,
143145
BOTH,
146+
BOX,
144147
BROWSE,
145148
BTREE,
146149
BUCKET,
@@ -175,6 +178,7 @@ define_keywords!(
175178
CHARSET,
176179
CHAR_LENGTH,
177180
CHECK,
181+
CIRCLE,
178182
CLEAR,
179183
CLOB,
180184
CLONE,
@@ -478,6 +482,7 @@ define_keywords!(
478482
LIKE,
479483
LIKE_REGEX,
480484
LIMIT,
485+
LINE,
481486
LINES,
482487
LIST,
483488
LISTEN,
@@ -499,6 +504,7 @@ define_keywords!(
499504
LOWER,
500505
LOW_PRIORITY,
501506
LS,
507+
LSEG,
502508
MACRO,
503509
MANAGE,
504510
MANAGED,
@@ -653,7 +659,9 @@ define_keywords!(
653659
PLACING,
654660
PLAN,
655661
PLANS,
662+
POINT,
656663
POLICY,
664+
POLYGON,
657665
POOL,
658666
PORTION,
659667
POSITION,
@@ -1081,3 +1089,21 @@ pub const RESERVED_FOR_IDENTIFIER: &[Keyword] = &[
10811089
Keyword::STRUCT,
10821090
Keyword::TRIM,
10831091
];
1092+
1093+
/// Defines a compile time lookup table that maps `Keyword`s to their
1094+
/// corresponding `GeometricTypeKind`.
1095+
macro_rules! define_geometric_type_map {
1096+
($($keyword:ident => $kind:ident),* $(,)?) => {
1097+
&[$( (Keyword::$keyword, GeometricTypeKind::$kind) ),*]
1098+
};
1099+
}
1100+
1101+
pub(crate) const GEOMETRIC_TYPE_LOOKUP: &[(Keyword, GeometricTypeKind)] = define_geometric_type_map! {
1102+
BOX => GeometricBox,
1103+
CIRCLE => Circle,
1104+
LINE => Line,
1105+
LSEG => LineSegment,
1106+
PATH => GeometricPath,
1107+
POINT => Point,
1108+
POLYGON => Polygon,
1109+
};

0 commit comments

Comments
 (0)