Skip to content

Add support for PostgreSQL/Redshift geometric operators #1723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/ast/data_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ pub enum DataType {
///
/// [bigquery]: https://cloud.google.com/bigquery/docs/user-defined-functions#templated-sql-udf-parameters
AnyType,
/// geometric type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we include a link to the postgres docs here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

///
/// [Postgres]: https://www.postgresql.org/docs/9.5/functions-geometry.html
GeometricType(GeometricTypeKind),
}

impl fmt::Display for DataType {
Expand Down Expand Up @@ -639,6 +643,7 @@ impl fmt::Display for DataType {
DataType::Trigger => write!(f, "TRIGGER"),
DataType::AnyType => write!(f, "ANY TYPE"),
DataType::Table(fields) => write!(f, "TABLE({})", display_comma_separated(fields)),
DataType::GeometricType(kind) => write!(f, "{}", kind),
}
}
}
Expand Down Expand Up @@ -915,3 +920,34 @@ pub enum ArrayElemTypeDef {
/// `Array(Int64)`
Parenthesis(Box<DataType>),
}

/// Represents different types of geometric shapes which are commonly used in
/// PostgreSQL/Redshift for spatial operations and geometry-related computations.
///
/// [Postgres]: https://www.postgresql.org/docs/9.5/functions-geometry.html
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a short description to this struct with a link to the docs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum GeometricTypeKind {
Point,
Line,
LineSegment,
GeometricBox,
GeometricPath,
Polygon,
Circle,
}

impl fmt::Display for GeometricTypeKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GeometricTypeKind::Point => write!(f, "point"),
GeometricTypeKind::Line => write!(f, "line"),
GeometricTypeKind::LineSegment => write!(f, "lseg"),
GeometricTypeKind::GeometricBox => write!(f, "box"),
GeometricTypeKind::GeometricPath => write!(f, "path"),
GeometricTypeKind::Polygon => write!(f, "polygon"),
GeometricTypeKind::Circle => write!(f, "circle"),
}
}
}
12 changes: 11 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ use crate::ast::helpers::stmt_data_loading::{
#[cfg(feature = "visitor")]
pub use visitor::*;

pub use self::data_type::GeometricTypeKind;

mod data_type;
mod dcl;
mod ddl;
Expand Down Expand Up @@ -1533,7 +1535,15 @@ impl fmt::Display for Expr {
Expr::UnaryOp { op, expr } => {
if op == &UnaryOperator::PGPostfixFactorial {
write!(f, "{expr}{op}")
} else if op == &UnaryOperator::Not {
} else if matches!(
op,
UnaryOperator::Not
| UnaryOperator::Hash
| UnaryOperator::AtDashAt
| UnaryOperator::DoubleAt
| UnaryOperator::QuestionDash
| UnaryOperator::QuestionPipe
) {
write!(f, "{op} {expr}")
} else {
write!(f, "{op}{expr}")
Expand Down
84 changes: 84 additions & 0 deletions src/ast/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ pub enum UnaryOperator {
PGAbs,
/// Unary logical not operator: e.g. `! false` (Hive-specific)
BangNot,
/// `#` Number of points in path or polygon (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
Hash,
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AtDashAt,
/// `@@` Center (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
DoubleAt,
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDash,
/// `?|` Is vertical? (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionPipe,
}

impl fmt::Display for UnaryOperator {
Expand All @@ -68,6 +83,11 @@ impl fmt::Display for UnaryOperator {
UnaryOperator::PGPrefixFactorial => "!!",
UnaryOperator::PGAbs => "@",
UnaryOperator::BangNot => "!",
UnaryOperator::Hash => "#",
UnaryOperator::AtDashAt => "@-@",
UnaryOperator::DoubleAt => "@@",
UnaryOperator::QuestionDash => "?-",
UnaryOperator::QuestionPipe => "?|",
})
}
}
Expand Down Expand Up @@ -253,6 +273,54 @@ pub enum BinaryOperator {
/// Specifies a test for an overlap between two datetime periods:
/// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#overlaps-predicate>
Overlaps,
/// `##` Point of closest proximity (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
DoubleHash,
/// `<->` Distance between (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
LtDashGt,
/// `&<` Overlaps to left? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AndLt,
/// `&>` Overlaps to right? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AndGt,
/// `<<|` Is strictly below? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
LtLtPipe,
/// `|>>` Is strictly above? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
PipeGtGt,
/// `&<|` Does not extend above? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AndLtPipe,
/// `|&>` Does not extend below? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
PipeAndGt,
/// `<^` Is below? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
LtCaret,
/// `>^` Is above? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
GtCaret,
/// `?#` Intersects? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionHash,
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDash,
/// `?-|` Is perpendicular? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDashPipe,
/// `?||` Are Parallel? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDoublePipe,
/// `@` Contained or on? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
At,
/// `~=` Same as? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
TildeEq,
}

impl fmt::Display for BinaryOperator {
Expand Down Expand Up @@ -310,6 +378,22 @@ impl fmt::Display for BinaryOperator {
write!(f, "OPERATOR({})", display_separated(idents, "."))
}
BinaryOperator::Overlaps => f.write_str("OVERLAPS"),
BinaryOperator::DoubleHash => f.write_str("##"),
BinaryOperator::LtDashGt => f.write_str("<->"),
BinaryOperator::AndLt => f.write_str("&<"),
BinaryOperator::AndGt => f.write_str("&>"),
BinaryOperator::LtLtPipe => f.write_str("<<|"),
BinaryOperator::PipeGtGt => f.write_str("|>>"),
BinaryOperator::AndLtPipe => f.write_str("&<|"),
BinaryOperator::PipeAndGt => f.write_str("|&>"),
BinaryOperator::LtCaret => f.write_str("<^"),
BinaryOperator::GtCaret => f.write_str(">^"),
BinaryOperator::QuestionHash => f.write_str("?#"),
BinaryOperator::QuestionDash => f.write_str("?-"),
BinaryOperator::QuestionDashPipe => f.write_str("?-|"),
BinaryOperator::QuestionDoublePipe => f.write_str("?||"),
BinaryOperator::At => f.write_str("@"),
BinaryOperator::TildeEq => f.write_str("~="),
}
}
}
36 changes: 29 additions & 7 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,18 +591,34 @@ pub trait Dialect: Debug + Any {
| Token::ExclamationMarkDoubleTilde
| Token::ExclamationMarkDoubleTildeAsterisk
| Token::Spaceship => Ok(p!(Eq)),
Token::Pipe => Ok(p!(Pipe)),
Token::Pipe
| Token::QuestionMarkDash
| Token::DoubleSharp
| Token::Overlap
| Token::AmpersandLeftAngleBracket
| Token::AmpersandRightAngleBracket
| Token::QuestionMarkDashVerticalBar
| Token::AmpersandLeftAngleBracketVerticalBar
| Token::VerticalBarAmpersandRightAngleBracket
| Token::TwoWayArrow
| Token::LeftAngleBracketCaret
| Token::RightAngleBracketCaret
| Token::QuestionMarkSharp
| Token::QuestionMarkDoubleVerticalBar
| Token::QuestionPipe
| Token::TildeEqual
| Token::AtSign
| Token::ShiftLeftVerticalBar
| Token::VerticalBarShiftRight => Ok(p!(Pipe)),
Token::Caret | Token::Sharp | Token::ShiftRight | Token::ShiftLeft => Ok(p!(Caret)),
Token::Ampersand => Ok(p!(Ampersand)),
Token::Plus | Token::Minus => Ok(p!(PlusMinus)),
Token::Mul | Token::Div | Token::DuckIntDiv | Token::Mod | Token::StringConcat => {
Ok(p!(MulDivModOp))
}
Token::DoubleColon
| Token::ExclamationMark
| Token::LBracket
| Token::Overlap
| Token::CaretAt => Ok(p!(DoubleColon)),
Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
Ok(p!(DoubleColon))
}
Token::Arrow
| Token::LongArrow
| Token::HashArrow
Expand All @@ -614,7 +630,6 @@ pub trait Dialect: Debug + Any {
| Token::AtAt
| Token::Question
| Token::QuestionAnd
| Token::QuestionPipe
| Token::CustomBinaryOperator(_) => Ok(p!(PgOther)),
_ => Ok(self.prec_unknown()),
}
Expand Down Expand Up @@ -912,6 +927,13 @@ pub trait Dialect: Debug + Any {
fn supports_array_typedef_size(&self) -> bool {
false
}
/// Returns true if the dialect supports geometric types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a link to the postgres docs here (and maybe an example sql)? it would help folks with context on what we mean by geometric types

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

///
/// Postgres: <https://www.postgresql.org/docs/9.5/functions-geometry.html>
/// e.g. @@ circle '((0,0),10)'
fn supports_geometric_types(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ impl Dialect for PostgreSqlDialect {
fn supports_array_typedef_size(&self) -> bool {
true
}

fn supports_geometric_types(&self) -> bool {
true
}
}

pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/redshift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ impl Dialect for RedshiftSqlDialect {
fn supports_string_escape_constant(&self) -> bool {
true
}

fn supports_geometric_types(&self) -> bool {
true
}
}
6 changes: 6 additions & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ define_keywords!(
BOOL,
BOOLEAN,
BOTH,
BOX,
BROWSE,
BTREE,
BUCKET,
Expand Down Expand Up @@ -175,6 +176,7 @@ define_keywords!(
CHARSET,
CHAR_LENGTH,
CHECK,
CIRCLE,
CLEAR,
CLOB,
CLONE,
Expand Down Expand Up @@ -478,6 +480,7 @@ define_keywords!(
LIKE,
LIKE_REGEX,
LIMIT,
LINE,
LINES,
LIST,
LISTEN,
Expand All @@ -499,6 +502,7 @@ define_keywords!(
LOWER,
LOW_PRIORITY,
LS,
LSEG,
MACRO,
MANAGE,
MANAGED,
Expand Down Expand Up @@ -653,7 +657,9 @@ define_keywords!(
PLACING,
PLAN,
PLANS,
POINT,
POLICY,
POLYGON,
POOL,
PORTION,
POSITION,
Expand Down
Loading