Skip to content

Commit 339239d

Browse files
authored
Add support for PostgreSQL/Redshift geometric operators (#1723)
1 parent 97f0be6 commit 339239d

11 files changed

+809
-26
lines changed

src/ast/data_type.rs

+36
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ 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+
///
391+
/// [Postgres]: https://www.postgresql.org/docs/9.5/functions-geometry.html
392+
GeometricType(GeometricTypeKind),
389393
}
390394

391395
impl fmt::Display for DataType {
@@ -639,6 +643,7 @@ impl fmt::Display for DataType {
639643
DataType::Trigger => write!(f, "TRIGGER"),
640644
DataType::AnyType => write!(f, "ANY TYPE"),
641645
DataType::Table(fields) => write!(f, "TABLE({})", display_comma_separated(fields)),
646+
DataType::GeometricType(kind) => write!(f, "{}", kind),
642647
}
643648
}
644649
}
@@ -915,3 +920,34 @@ pub enum ArrayElemTypeDef {
915920
/// `Array(Int64)`
916921
Parenthesis(Box<DataType>),
917922
}
923+
924+
/// Represents different types of geometric shapes which are commonly used in
925+
/// PostgreSQL/Redshift for spatial operations and geometry-related computations.
926+
///
927+
/// [Postgres]: https://www.postgresql.org/docs/9.5/functions-geometry.html
928+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
929+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
930+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
931+
pub enum GeometricTypeKind {
932+
Point,
933+
Line,
934+
LineSegment,
935+
GeometricBox,
936+
GeometricPath,
937+
Polygon,
938+
Circle,
939+
}
940+
941+
impl fmt::Display for GeometricTypeKind {
942+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943+
match self {
944+
GeometricTypeKind::Point => write!(f, "point"),
945+
GeometricTypeKind::Line => write!(f, "line"),
946+
GeometricTypeKind::LineSegment => write!(f, "lseg"),
947+
GeometricTypeKind::GeometricBox => write!(f, "box"),
948+
GeometricTypeKind::GeometricPath => write!(f, "path"),
949+
GeometricTypeKind::Polygon => write!(f, "polygon"),
950+
GeometricTypeKind::Circle => write!(f, "circle"),
951+
}
952+
}
953+
}

src/ast/mod.rs

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

98+
pub use self::data_type::GeometricTypeKind;
99+
98100
mod data_type;
99101
mod dcl;
100102
mod ddl;
@@ -1513,7 +1515,15 @@ impl fmt::Display for Expr {
15131515
Expr::UnaryOp { op, expr } => {
15141516
if op == &UnaryOperator::PGPostfixFactorial {
15151517
write!(f, "{expr}{op}")
1516-
} else if op == &UnaryOperator::Not {
1518+
} else if matches!(
1519+
op,
1520+
UnaryOperator::Not
1521+
| UnaryOperator::Hash
1522+
| UnaryOperator::AtDashAt
1523+
| UnaryOperator::DoubleAt
1524+
| UnaryOperator::QuestionDash
1525+
| UnaryOperator::QuestionPipe
1526+
) {
15171527
write!(f, "{op} {expr}")
15181528
} else {
15191529
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+
Hash,
59+
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
60+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
61+
AtDashAt,
62+
/// `@@` Center (PostgreSQL/Redshift geometric operator)
63+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
64+
DoubleAt,
65+
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
66+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
67+
QuestionDash,
68+
/// `?|` Is vertical? (PostgreSQL/Redshift geometric operator)
69+
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
70+
QuestionPipe,
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::Hash => "#",
87+
UnaryOperator::AtDashAt => "@-@",
88+
UnaryOperator::DoubleAt => "@@",
89+
UnaryOperator::QuestionDash => "?-",
90+
UnaryOperator::QuestionPipe => "?|",
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

+29-7
Original file line numberDiff line numberDiff line change
@@ -599,18 +599,34 @@ pub trait Dialect: Debug + Any {
599599
| Token::ExclamationMarkDoubleTilde
600600
| Token::ExclamationMarkDoubleTildeAsterisk
601601
| Token::Spaceship => Ok(p!(Eq)),
602-
Token::Pipe => Ok(p!(Pipe)),
602+
Token::Pipe
603+
| Token::QuestionMarkDash
604+
| Token::DoubleSharp
605+
| Token::Overlap
606+
| Token::AmpersandLeftAngleBracket
607+
| Token::AmpersandRightAngleBracket
608+
| Token::QuestionMarkDashVerticalBar
609+
| Token::AmpersandLeftAngleBracketVerticalBar
610+
| Token::VerticalBarAmpersandRightAngleBracket
611+
| Token::TwoWayArrow
612+
| Token::LeftAngleBracketCaret
613+
| Token::RightAngleBracketCaret
614+
| Token::QuestionMarkSharp
615+
| Token::QuestionMarkDoubleVerticalBar
616+
| Token::QuestionPipe
617+
| Token::TildeEqual
618+
| Token::AtSign
619+
| Token::ShiftLeftVerticalBar
620+
| Token::VerticalBarShiftRight => Ok(p!(Pipe)),
603621
Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
604622
Token::Ampersand => Ok(p!(Ampersand)),
605623
Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
606624
Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
607625
Ok(p!(MulDivModOp))
608626
}
609-
Token::DoubleColon
610-
| Token::ExclamationMark
611-
| Token::LBracket
612-
| Token::Overlap
613-
| Token::CaretAt => Ok(p!(DoubleColon)),
627+
Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
628+
Ok(p!(DoubleColon))
629+
}
614630
Token::Arrow
615631
| Token::LongArrow
616632
| Token::HashArrow
@@ -622,7 +638,6 @@ pub trait Dialect: Debug + Any {
622638
| Token::AtAt
623639
| Token::Question
624640
| Token::QuestionAnd
625-
| Token::QuestionPipe
626641
| Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
627642
_ => Ok(self.prec_unknown()),
628643
}
@@ -921,6 +936,13 @@ pub trait Dialect: Debug + Any {
921936
fn supports_array_typedef_size(&self) -> bool {
922937
false
923938
}
939+
/// Returns true if the dialect supports geometric types.
940+
///
941+
/// Postgres: <https://www.postgresql.org/docs/9.5/functions-geometry.html>
942+
/// e.g. @@ circle '((0,0),10)'
943+
fn supports_geometric_types(&self) -> bool {
944+
false
945+
}
924946
}
925947

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

src/dialect/postgresql.rs

+4
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,8 @@ impl Dialect for PostgreSqlDialect {
250250
fn supports_array_typedef_size(&self) -> bool {
251251
true
252252
}
253+
254+
fn supports_geometric_types(&self) -> bool {
255+
true
256+
}
253257
}

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

+6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ define_keywords!(
141141
BOOL,
142142
BOOLEAN,
143143
BOTH,
144+
BOX,
144145
BROWSE,
145146
BTREE,
146147
BUCKET,
@@ -175,6 +176,7 @@ define_keywords!(
175176
CHARSET,
176177
CHAR_LENGTH,
177178
CHECK,
179+
CIRCLE,
178180
CLEAR,
179181
CLOB,
180182
CLONE,
@@ -478,6 +480,7 @@ define_keywords!(
478480
LIKE,
479481
LIKE_REGEX,
480482
LIMIT,
483+
LINE,
481484
LINES,
482485
LIST,
483486
LISTEN,
@@ -499,6 +502,7 @@ define_keywords!(
499502
LOWER,
500503
LOW_PRIORITY,
501504
LS,
505+
LSEG,
502506
MACRO,
503507
MANAGE,
504508
MANAGED,
@@ -653,7 +657,9 @@ define_keywords!(
653657
PLACING,
654658
PLAN,
655659
PLANS,
660+
POINT,
656661
POLICY,
662+
POLYGON,
657663
POOL,
658664
PORTION,
659665
POSITION,

0 commit comments

Comments
 (0)