Skip to content

Commit c0431ce

Browse files
committed
readyset-data: Add DfType::Point
Add a new `DfType` to support an initial spatial data type, which is `Point`. This CL also adds basic MySQL support in replicator (snapshot, replication). A logictest is provided to test the output is correct (matches the upstream's output). It is expected, though, that real-world queries will use one of the `ST_*` spatial functions to select the data; those functions are inplemented in a follow-up CL. Fixes: REA-5697 Release-Core-Note: Basic support for `Point` spatial type in mysql. Change-Id: If79e5385ec32d9f58be601c0366312b4ddfad6a6 Reviewed-on: https://gerrit.readyset.name/c/readyset/+/9320 Reviewed-by: Michael Zink <michael.z@readyset.io> Tested-by: Buildkite CI
1 parent 0510157 commit c0431ce

File tree

17 files changed

+132
-8
lines changed

17 files changed

+132
-8
lines changed

data-generator/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ pub fn value_of_type(typ: &SqlType) -> DfValue {
475475
SqlType::Interval { .. } => unimplemented!(),
476476
SqlType::Array(_) => unimplemented!(),
477477
SqlType::Other(_) => unimplemented!(),
478+
SqlType::Point => unimplemented!(),
478479
}
479480
}
480481

@@ -614,6 +615,7 @@ where
614615
SqlType::Interval { .. } => unimplemented!(),
615616
SqlType::Array(_) => unimplemented!(),
616617
SqlType::Other(_) => unimplemented!(),
618+
SqlType::Point => unimplemented!(),
617619
}
618620
}
619621

@@ -758,5 +760,6 @@ pub fn unique_value_of_type(typ: &SqlType, idx: u32) -> DfValue {
758760
SqlType::Interval { .. } => unimplemented!(),
759761
SqlType::Array(_) => unimplemented!(),
760762
SqlType::Other(_) => unimplemented!(),
763+
SqlType::Point => unimplemented!(),
761764
}
762765
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
statement ok
2+
create table locations (id int primary key, loc point);
3+
4+
statement ok
5+
insert into locations values
6+
(1, ST_PointFromText('POINT(1 2)')),
7+
(2, ST_PointFromText('POINT(8.123 9.3145732)'));
8+
9+
query B nosort
10+
select loc from locations where id = ?
11+
? = 1
12+
----
13+
0x000000000101000000000000000000F03F0000000000000040
14+
15+
query B nosort
16+
select loc from locations where id = ?
17+
? = 2
18+
----
19+
0x000000000101000000E5D022DBF93E204069650CBD0FA12240
20+
21+
22+
23+
# now test tables that explicitly set the SRID
24+
25+
statement ok
26+
create table locations2 (id int primary key, loc point srid 4326);
27+
28+
statement ok
29+
insert into locations2 values
30+
(1, ST_PointFromText('POINT(1 2)', 4326)),
31+
(2, ST_PointFromText('POINT(8.123 9.3145732)', 4326));
32+
33+
query B nosort
34+
select loc from locations2 where id = ?
35+
? = 1
36+
----
37+
0xE610000001010000000000000000000040000000000000F03F
38+
39+
query B nosort
40+
select loc from locations2 where id = ?
41+
? = 2
42+
----
43+
0xE6100000010100000069650CBD0FA12240E5D022DBF93E2040

nom-sql/src/sql_type.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,18 @@ fn type_identifier_part3(
454454
map(tag_no_case("bigserial"), |_| SqlType::BigSerial),
455455
map(tag_no_case("citext"), |_| SqlType::Citext),
456456
map(tag("\"char\""), |_| SqlType::QuotedChar),
457+
// if a point is followed by an optional srid attribute, we need to ignore it but
458+
// we need to parse it out.
459+
map(
460+
tuple((
461+
tag_no_case("point"),
462+
opt(preceded(
463+
tuple((whitespace1, tag_no_case("srid"), whitespace1)),
464+
digit1,
465+
)),
466+
)),
467+
|_| SqlType::Point,
468+
),
457469
map(other_type(dialect), SqlType::Other),
458470
))(i)
459471
}
@@ -767,6 +779,18 @@ mod tests {
767779
assert_eq!(res, SqlType::Jsonb);
768780
}
769781

782+
#[test]
783+
fn point_type() {
784+
let res = test_parse!(type_identifier(Dialect::PostgreSQL), b"point");
785+
assert_eq!(res, SqlType::Point);
786+
}
787+
788+
#[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);
792+
}
793+
770794
#[test]
771795
fn bit_type() {
772796
let res = test_parse!(type_identifier(Dialect::PostgreSQL), b"bit");

readyset-data/src/float.rs

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

@@ -282,6 +283,7 @@ pub(crate) fn coerce_decimal(
282283
| DfType::Bit(_)
283284
| DfType::VarBit(_)
284285
| DfType::Array(_)
286+
| DfType::Point
285287
| DfType::Row => Err(ReadySetError::DfValueConversionError {
286288
src_type: "Decimal".to_string(),
287289
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
@@ -205,7 +205,8 @@ where
205205
| DfType::Uuid
206206
| DfType::VarBit(_)
207207
| DfType::Array(_)
208-
| DfType::Row => Err(ReadySetError::DfValueConversionError {
208+
| DfType::Row
209+
| DfType::Point => Err(ReadySetError::DfValueConversionError {
209210
src_type: from_ty.to_string(),
210211
target_type: to_ty.to_string(),
211212
details: "Not allowed".to_string(),

readyset-data/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2579,7 +2579,8 @@ mod arbitrary {
25792579
| Some(DfType::MacAddr)
25802580
| Some(DfType::Uuid)
25812581
| Some(DfType::Inet)
2582-
| Some(DfType::Row) => Just(DfValue::None).boxed(),
2582+
| Some(DfType::Row)
2583+
| Some(DfType::Point) => Just(DfValue::None).boxed(),
25832584
}
25842585
}
25852586
}

readyset-data/src/text.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ pub(crate) trait TextCoerce: Sized + Clone + Into<DfValue> {
597597
}
598598
}
599599

600-
DfType::Bit(_) | DfType::VarBit(_) | DfType::Row => {
600+
DfType::Bit(_) | DfType::VarBit(_) | DfType::Row | DfType::Point => {
601601
Err(Self::coerce_err(to_ty, "Not allowed"))
602602
}
603603
}

readyset-data/src/timestamp.rs

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

readyset-data/src/type.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ pub enum DfType {
204204

205205
/// [PostgreSQL `jsonb`](https://www.postgresql.org/docs/current/datatype-json.html).
206206
Jsonb,
207+
208+
/// [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.
211+
Point,
207212
}
208213

209214
/// Defaults.
@@ -317,6 +322,7 @@ impl DfType {
317322
MacAddr => unsupported!("Unsupported type: MacAddr"),
318323
Inet => unsupported!("Unsupported type: Inet"),
319324
Citext => Self::Text(Collation::Citext),
325+
Point => Self::Point,
320326
Other(ref id) => resolve_custom_type(id.clone()).ok_or_else(|| {
321327
let id_upper = format!("{}", id.display_unquoted()).to_uppercase();
322328
unsupported_err!("Unsupported type: {}", id_upper)
@@ -373,9 +379,11 @@ impl DfType {
373379
| DfType::Timestamp { .. }
374380
| DfType::TimestampTz { .. } => PgTypeCategory::DateTime,
375381
DfType::MacAddr | DfType::Inet => PgTypeCategory::NetworkAddress,
376-
DfType::Uuid | DfType::Enum { .. } | DfType::Json | DfType::Jsonb => {
377-
PgTypeCategory::UserDefined
378-
}
382+
DfType::Uuid
383+
| DfType::Enum { .. }
384+
| DfType::Json
385+
| DfType::Jsonb
386+
| DfType::Point => PgTypeCategory::UserDefined,
379387
}
380388
}
381389

@@ -820,6 +828,7 @@ impl fmt::Display for DfType {
820828
write!(f, "({})", variants.iter().join(", "))
821829
}
822830
Self::Numeric { prec, scale } => write!(f, "{kind:?}({prec}, {scale})"),
831+
Self::Point => write!(f, "Point"),
823832
}
824833
}
825834
}

readyset-e2e-tests/tests/types_mysql.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ fn arbitrary_mysql_value_for_type(sql_type: SqlType) -> impl Strategy<Value = Va
319319
SqlType::Signed | SqlType::Unsigned | SqlType::UnsignedInteger | SqlType::SignedInteger => {
320320
unimplemented!("This type is only valid in `CAST` and can't be used as a Column Def")
321321
}
322+
SqlType::Point => unimplemented!("Points aren't implemented yet"),
322323
}
323324
}
324325

0 commit comments

Comments
 (0)