Repository: ariga/atlas
Pull request #2791 (2024-05-20 11:50:17)

sql/mysql: support inet4 + inet6 for MariaDB 10.10+
Fixed: https://github.com/ariga/atlas-provider-gorm/issues/46


Patch:
diff --git a/sql/mysql/convert.go b/sql/mysql/convert.go
index 957d34e7..c75a20a5 100644
--- a/sql/mysql/convert.go
+++ b/sql/mysql/convert.go
@@ -101,6 +101,8 @@ func FormatType(t schema.Type) (string, error) {
 		}
 	case *schema.UUIDType:
 		f = strings.ToLower(t.T)
+	case *NetworkType:
+		f = strings.ToLower(t.T)
 	case *schema.UnsupportedType:
 		// Do not accept unsupported types as we should cover all cases.
 		return "", fmt.Errorf("unsupported type %q", t.T)
@@ -244,6 +246,10 @@ func ParseType(raw string) (schema.Type, error) {
 		return &schema.UUIDType{
 			T: t,
 		}, nil
+	case TypeInet4, TypeInet6:
+		return &NetworkType{
+			T: t,
+		}, nil
 	default:
 		return &schema.UnsupportedType{
 			T: t,
diff --git a/sql/mysql/diff.go b/sql/mysql/diff.go
index 7c64bec8..c8978fd6 100644
--- a/sql/mysql/diff.go
+++ b/sql/mysql/diff.go
@@ -458,7 +458,7 @@ func (d *diff) typeChanged(from, to *schema.Column) (bool, error) {
 	var changed bool
 	switch fromT := fromT.(type) {
 	case *BitType, *schema.BinaryType, *schema.BoolType, *schema.DecimalType, *schema.FloatType,
-		*schema.JSONType, *schema.StringType, *schema.SpatialType, *schema.TimeType, *schema.UUIDType:
+		*schema.JSONType, *schema.StringType, *schema.SpatialType, *schema.TimeType, *schema.UUIDType, *NetworkType:
 		ft, err := FormatType(fromT)
 		if err != nil {
 			return false, err
diff --git a/sql/mysql/driver.go b/sql/mysql/driver.go
index 23d6070e..d4ab12e8 100644
--- a/sql/mysql/driver.go
+++ b/sql/mysql/driver.go
@@ -431,6 +431,9 @@ const (
 	TypeGeometryCollection = "geometrycollection" // Geometry_type::kGeometrycollection
 
 	TypeUUID = "uuid" // MariaDB supported uuid type from 10.7.0+
+
+	TypeInet4 = "inet4" // MariaDB type for storage of IPv4 addresses, from 10.10.0+.
+	TypeInet6 = "inet6" // MariaDB type for storage of IPv6 addresses, from 10.10.0+.
 )
 
 // Additional common constants in MySQL.
diff --git a/sql/mysql/inspect.go b/sql/mysql/inspect.go
index 282c0f15..b77106a8 100644
--- a/sql/mysql/inspect.go
+++ b/sql/mysql/inspect.go
@@ -911,6 +911,12 @@ type (
 		Values []string
 	}
 
+	// NetworkType stores an IPv4 or IPv6 address.
+	NetworkType struct {
+		schema.Type
+		T string
+	}
+
 	// putShow is an intermediate table attribute used
 	// on inspection to indicate if the 'SHOW TABLE' is
 	// required and for what.
diff --git a/sql/mysql/sqlspec.go b/sql/mysql/sqlspec.go
index 5787b734..6cc8c51e 100644
--- a/sql/mysql/sqlspec.go
+++ b/sql/mysql/sqlspec.go
@@ -546,6 +546,8 @@ var TypeRegistry = schemahcl.NewRegistry(
 		schemahcl.NewTypeSpec(TypePolygon),
 		schemahcl.NewTypeSpec(TypeMultiPolygon),
 		schemahcl.NewTypeSpec(TypeGeometryCollection),
+		schemahcl.NewTypeSpec(TypeInet4),
+		schemahcl.NewTypeSpec(TypeInet6),
 	),
 )
 


Test patch:
diff --git a/sql/mysql/inspect_test.go b/sql/mysql/inspect_test.go
index bd776b31..957899f8 100644
--- a/sql/mysql/inspect_test.go
+++ b/sql/mysql/inspect_test.go
@@ -172,6 +172,8 @@ func TestDriver_InspectTable(t *testing.T) {
 | users      |  dt0           | datetime /* mariadb-5.3 */    |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |
 | users      |  dt1           | datetime(6) /* mariadb-5.3 */ |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |
 | users      |  dt2           | time(1) /* mariadb-5.3 */     |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |
+| users      |  inet4         | inet4                         |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |
+| users      |  inet6         | inet6                         |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |
 +------------+----------------+-------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+
 `))
 				m.ExpectQuery(queryIndexes).
@@ -199,6 +201,8 @@ func TestDriver_InspectTable(t *testing.T) {
 					{Name: "dt0", Type: &schema.ColumnType{Raw: "datetime /* mariadb-5.3 */", Type: &schema.TimeType{T: "datetime"}}},
 					{Name: "dt1", Type: &schema.ColumnType{Raw: "datetime(6) /* mariadb-5.3 */", Type: &schema.TimeType{T: "datetime", Precision: sqlx.P(6)}}},
 					{Name: "dt2", Type: &schema.ColumnType{Raw: "time(1) /* mariadb-5.3 */", Type: &schema.TimeType{T: "time", Precision: sqlx.P(1)}}},
+					{Name: "inet4", Type: &schema.ColumnType{Raw: "inet4", Type: &NetworkType{T: "inet4"}}},
+					{Name: "inet6", Type: &schema.ColumnType{Raw: "inet6", Type: &NetworkType{T: "inet6"}}},
 				}, t.Columns)
 				require.EqualValues([]schema.Attr{
 					&schema.Check{Name: "users_chk_1", Expr: `longtext <> '\'\'""'`},
diff --git a/sql/mysql/sqlspec_test.go b/sql/mysql/sqlspec_test.go
index a2c1766d..730595c5 100644
--- a/sql/mysql/sqlspec_test.go
+++ b/sql/mysql/sqlspec_test.go
@@ -1539,6 +1539,14 @@ func TestTypes(t *testing.T) {
 			typeExpr: "boolean",
 			expected: &schema.BoolType{T: TypeBool},
 		},
+		{
+			typeExpr: "inet4",
+			expected: &NetworkType{T: TypeInet4},
+		},
+		{
+			typeExpr: "inet6",
+			expected: &NetworkType{T: TypeInet6},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.typeExpr, func(t *testing.T) {