Skip to content

Commit c5cf711

Browse files
committed
postgres: support postgis point data type
Similar to the support we have for mysql's spatial `point` data type, add support for postgis's `point`. Note: this is different from postgres's built-in geometric data types. Release-Note-Core: Add support for replicating postgis `geometry(point)` data type. Fixes: REA-5721 Change-Id: I66a4fc0b1928f93f62e347253d9112960d2add9c Reviewed-on: https://gerrit.readyset.name/c/readyset/+/9420 Tested-by: Buildkite CI Reviewed-by: Michael Zink <michael.z@readyset.io>
1 parent 8de0399 commit c5cf711

File tree

15 files changed

+138
-24
lines changed

15 files changed

+138
-24
lines changed

data-generator/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ pub fn value_of_type(typ: &SqlType) -> DfValue {
544544
SqlType::Array(_) => unimplemented!(),
545545
SqlType::Other(_) => unimplemented!(),
546546
SqlType::Point => unimplemented!(),
547+
SqlType::PostgisPoint => unimplemented!(),
547548
}
548549
}
549550

@@ -684,6 +685,7 @@ where
684685
SqlType::Array(_) => unimplemented!(),
685686
SqlType::Other(_) => unimplemented!(),
686687
SqlType::Point => unimplemented!(),
688+
SqlType::PostgisPoint => unimplemented!(),
687689
}
688690
}
689691

@@ -829,5 +831,6 @@ pub fn unique_value_of_type(typ: &SqlType, idx: u32) -> DfValue {
829831
SqlType::Array(_) => unimplemented!(),
830832
SqlType::Other(_) => unimplemented!(),
831833
SqlType::Point => unimplemented!(),
834+
SqlType::PostgisPoint => unimplemented!(),
832835
}
833836
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
statement ok
2+
create extension postgis;
3+
4+
statement ok
5+
create table locations (id int primary key, loc geometry(point));
6+
7+
statement ok
8+
insert into locations values
9+
(1, ST_PointFromText('POINT(1 2)')),
10+
(2, ST_PointFromText('POINT(8.123 9.3145732)'));
11+
12+
sleep 1000
13+
14+
query B nosort
15+
select loc from locations where id = 1
16+
----
17+
0x0101000000000000000000F03F0000000000000040
18+
19+
query B nosort
20+
select loc from locations where id = 2
21+
----
22+
0x0101000000E5D022DBF93E204069650CBD0FA12240
23+
24+
25+
26+
# now test tables that explicitly set the SRID
27+
28+
statement ok
29+
create table locations2 (id int primary key, loc geometry(point, 4326));
30+
31+
statement ok
32+
insert into locations2 values
33+
(1, ST_PointFromText('POINT(1 2)', 4326)),
34+
(2, ST_PointFromText('POINT(8.123 9.3145732)', 4326));
35+
36+
query B nosort
37+
select loc from locations2 where id = 1
38+
----
39+
0x0101000020E6100000000000000000F03F0000000000000040
40+
41+
query B nosort
42+
select loc from locations2 where id = 2
43+
----
44+
0x0101000020E6100000E5D022DBF93E204069650CBD0FA12240

nom-sql/src/sql_type.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,22 @@ fn type_identifier_part3(
466466
)),
467467
|_| SqlType::Point,
468468
),
469+
// look for the postgis syntax of "geometry(point, 4326)"
470+
map(
471+
tuple((
472+
tag_no_case("geometry"),
473+
tuple((
474+
whitespace0,
475+
tag("("),
476+
whitespace0,
477+
tag_no_case("point"),
478+
opt(tuple((tag(","), whitespace0, digit1))),
479+
whitespace0,
480+
tag(")"),
481+
)),
482+
)),
483+
|_| SqlType::PostgisPoint,
484+
),
469485
map(other_type(dialect), SqlType::Other),
470486
))(i)
471487
}
@@ -714,6 +730,17 @@ mod tests {
714730
SqlType::MediumInt(None)
715731
);
716732
}
733+
#[test]
734+
fn point_type() {
735+
let res = test_parse!(type_identifier(Dialect::MySQL), b"point");
736+
assert_eq!(res, SqlType::Point);
737+
}
738+
739+
#[test]
740+
fn point_type_with_srid() {
741+
let res = test_parse!(type_identifier(Dialect::MySQL), b"point srid 4326");
742+
assert_eq!(res, SqlType::Point);
743+
}
717744
}
718745

719746
mod postgres {
@@ -780,15 +807,17 @@ mod tests {
780807
}
781808

782809
#[test]
783-
fn point_type() {
784-
let res = test_parse!(type_identifier(Dialect::PostgreSQL), b"point");
785-
assert_eq!(res, SqlType::Point);
810+
fn geometry_point_type() {
811+
let res = test_parse!(type_identifier(Dialect::PostgreSQL), b"geometry(point)");
812+
assert_eq!(res, SqlType::PostgisPoint);
786813
}
787-
788814
#[test]
789-
fn point_type_with_srid() {
790-
let res = test_parse!(type_identifier(Dialect::PostgreSQL), b"point srid 4326");
791-
assert_eq!(res, SqlType::Point);
815+
fn geometry_point_type_with_srid() {
816+
let res = test_parse!(
817+
type_identifier(Dialect::PostgreSQL),
818+
b"geometry(point, 4326)"
819+
);
820+
assert_eq!(res, SqlType::PostgisPoint);
792821
}
793822

794823
#[test]

readyset-data/src/float.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ pub(crate) fn coerce_f64(val: f64, to_ty: &DfType, from_ty: &DfType) -> ReadySet
176176
| DfType::VarBit(_)
177177
| DfType::Array(_)
178178
| DfType::Row
179-
| DfType::Point => Err(err("not allowed")),
179+
| DfType::Point
180+
| DfType::PostgisPoint => Err(err("not allowed")),
180181
}
181182
}
182183

@@ -284,6 +285,7 @@ pub(crate) fn coerce_decimal(
284285
| DfType::VarBit(_)
285286
| DfType::Array(_)
286287
| DfType::Point
288+
| DfType::PostgisPoint
287289
| DfType::Row => Err(ReadySetError::DfValueConversionError {
288290
src_type: "Decimal".to_string(),
289291
target_type: to_ty.to_string(),

readyset-data/src/integer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ where
206206
| DfType::VarBit(_)
207207
| DfType::Array(_)
208208
| DfType::Row
209-
| DfType::Point => Err(ReadySetError::DfValueConversionError {
209+
| DfType::Point
210+
| DfType::PostgisPoint => Err(ReadySetError::DfValueConversionError {
210211
src_type: from_ty.to_string(),
211212
target_type: to_ty.to_string(),
212213
details: "Not allowed".to_string(),

readyset-data/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,8 @@ impl<'a> FromSql<'a> for DfValue {
22132213
<&str>::from_sql(ty, raw)?,
22142214
Collation::Citext,
22152215
)),
2216+
// catch the postgis geometry types, and just pass through
2217+
ref ty if ty.name() == "geometry" => mk_from_sql!(Vec<u8>),
22162218
ref ty => Ok(DfValue::PassThrough(Arc::new(PassThrough {
22172219
ty: ty.clone(),
22182220
format: PassThroughFormat::Binary,
@@ -2580,7 +2582,8 @@ mod arbitrary {
25802582
| Some(DfType::Uuid)
25812583
| Some(DfType::Inet)
25822584
| Some(DfType::Row)
2583-
| Some(DfType::Point) => Just(DfValue::None).boxed(),
2585+
| Some(DfType::Point)
2586+
| Some(DfType::PostgisPoint) => Just(DfValue::None).boxed(),
25842587
}
25852588
}
25862589
}

readyset-data/src/text.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,11 @@ pub(crate) trait TextCoerce: Sized + Clone + Into<DfValue> {
597597
}
598598
}
599599

600-
DfType::Bit(_) | DfType::VarBit(_) | DfType::Row | DfType::Point => {
601-
Err(Self::coerce_err(to_ty, "Not allowed"))
602-
}
600+
DfType::Bit(_)
601+
| DfType::VarBit(_)
602+
| DfType::Row
603+
| DfType::Point
604+
| DfType::PostgisPoint => Err(Self::coerce_err(to_ty, "Not allowed")),
603605
}
604606
}
605607
}

readyset-data/src/timestamp.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,8 @@ impl TimestampTz {
568568
| DfType::VarBit(_)
569569
| DfType::Array(_)
570570
| DfType::Row
571-
| DfType::Point => Err(ReadySetError::DfValueConversionError {
571+
| DfType::Point
572+
| DfType::PostgisPoint => Err(ReadySetError::DfValueConversionError {
572573
src_type: "DfValue::TimestampTz".to_string(),
573574
target_type: format!("{:?}", to_ty),
574575
details: "Not allowed".to_string(),

readyset-data/src/type.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,13 @@ pub enum DfType {
206206
Jsonb,
207207

208208
/// [MySQL `point`](https://dev.mysql.com/doc/refman/8.4/en/gis-class-point.html)
209-
/// Note: We aren't supporting the old, legacy `point`/geometry data types that
210-
/// are native to postgres. Instead, we'll support the postgis spatial types.
211209
Point,
210+
211+
/// [PostGIS `point`](https://postgis.net/docs/manual-3.5/using_postgis_dbmanagement.html#Point)
212+
///
213+
/// This "postgis"-specific type is meant to distinguish it from the native `point` type in
214+
/// PostgreSQL.
215+
PostgisPoint,
212216
}
213217

214218
/// Defaults.
@@ -323,6 +327,7 @@ impl DfType {
323327
Inet => unsupported!("Unsupported type: Inet"),
324328
Citext => Self::Text(Collation::Citext),
325329
Point => Self::Point,
330+
PostgisPoint => Self::PostgisPoint,
326331
Other(ref id) => resolve_custom_type(id.clone()).ok_or_else(|| {
327332
let id_upper = format!("{}", id.display_unquoted()).to_uppercase();
328333
unsupported_err!("Unsupported type: {}", id_upper)
@@ -383,7 +388,8 @@ impl DfType {
383388
| DfType::Enum { .. }
384389
| DfType::Json
385390
| DfType::Jsonb
386-
| DfType::Point => PgTypeCategory::UserDefined,
391+
| DfType::Point
392+
| DfType::PostgisPoint => PgTypeCategory::UserDefined,
387393
}
388394
}
389395

@@ -829,6 +835,7 @@ impl fmt::Display for DfType {
829835
}
830836
Self::Numeric { prec, scale } => write!(f, "{kind:?}({prec}, {scale})"),
831837
Self::Point => write!(f, "Point"),
838+
Self::PostgisPoint => write!(f, "Postgis Geometry(Point)"),
832839
}
833840
}
834841
}

readyset-e2e-tests/tests/types_mysql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ fn arbitrary_mysql_value_for_type(sql_type: SqlType) -> impl Strategy<Value = Va
318318
SqlType::Signed | SqlType::Unsigned | SqlType::UnsignedInteger | SqlType::SignedInteger => {
319319
unimplemented!("This type is only valid in `CAST` and can't be used as a Column Def")
320320
}
321-
SqlType::Point => unimplemented!("Points aren't implemented yet"),
321+
SqlType::Point | SqlType::PostgisPoint => unimplemented!("Points aren't implemented yet"),
322322
}
323323
}
324324

0 commit comments

Comments
 (0)