Skip to content
This repository was archived by the owner on Aug 30, 2025. It is now read-only.
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
6 changes: 6 additions & 0 deletions backend/gen/go/db/dbschemas/mysql/system.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4,572 changes: 2,390 additions & 2,182 deletions backend/gen/go/protos/mgmt/v1alpha1/job.pb.go

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions backend/gen/go/protos/mgmt/v1alpha1/job.pb.json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions backend/pkg/dbschemas/sql/mysql/queries/system.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SELECT
IFNULL(REPLACE(REPLACE(REPLACE(REPLACE(c.COLUMN_DEFAULT, '_utf8mb4\\\'', '_utf8mb4\''), '_utf8mb3\\\'', '_utf8mb3\''), '\\\'', '\''), '\\\'', '\''), '') AS column_default, -- hack to fix this bug https://bugs.mysql.com/bug.php?
c.is_nullable,
c.data_type,
c.column_type, -- same as data_type but includes things like the length, or set/enum information
c.character_maximum_length,
c.numeric_precision,
c.numeric_scale,
Expand Down Expand Up @@ -214,6 +215,7 @@ SELECT
c.TABLE_NAME AS table_name,
c.COLUMN_NAME AS column_name,
c.COLUMN_TYPE AS data_type,
Copy link
Member Author

Choose a reason for hiding this comment

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

this is kinda weird. the above query we are using c.data_type but this one we are using c.column_type which is different. I didnt want to update it at the expense of potentially causing a bux.

c.COLUMN_TYPE AS column_type, -- same as data_type but includes things like the length, or set/enum information
Copy link
Member Author

Choose a reason for hiding this comment

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

@alishakawaguchi - This column_type properly tracks mysql set and enum values. So I'm guessing that the mysql schema drift changes won't track if this changes. I created a ticket for this: NEOS-1791

IFNULL(REPLACE(REPLACE(REPLACE(REPLACE(c.COLUMN_DEFAULT, '_utf8mb4\\\'', '_utf8mb4\''), '_utf8mb3\\\'', '_utf8mb3\''), '\\\'', '\''), '\\\'', '\''), '') AS column_default, -- hack to fix this bug https://bugs.mysql.com/bug.php?
CASE WHEN c.IS_NULLABLE = 'YES' THEN 1 ELSE 0 END AS is_nullable,
CAST(IF(c.DATA_TYPE IN ('varchar', 'char'), c.CHARACTER_MAXIMUM_LENGTH, -1) AS SIGNED) AS character_maximum_length,
Expand Down
2 changes: 2 additions & 0 deletions backend/pkg/sqlmanager/mysql/mysql-manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func (m *MysqlManager) GetDatabaseSchema(ctx context.Context) ([]*sqlmanager_sha
TableName: row.TableName,
ColumnName: row.ColumnName,
DataType: row.DataType,
MysqlColumnType: row.ColumnType,
ColumnDefault: columnDefaultStr,
ColumnDefaultType: columnDefaultType,
IsNullable: row.IsNullable != "NO",
Expand Down Expand Up @@ -197,6 +198,7 @@ func (m *MysqlManager) GetDatabaseTableSchemasBySchemasAndTables(ctx context.Con
TableName: row.TableName,
ColumnName: row.ColumnName,
DataType: row.DataType,
MysqlColumnType: row.ColumnType,
ColumnDefault: columnDefaultStr,
ColumnDefaultType: columnDefaultType,
IsNullable: row.IsNullable == 1,
Expand Down
1 change: 1 addition & 0 deletions backend/pkg/sqlmanager/shared/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type DatabaseSchemaRow struct {
TableName string
ColumnName string
DataType string
MysqlColumnType string // will only be populated for mysql. Same as the DataType but includes length, etc. varchar(255), enum('a', 'b'), etc.
ColumnDefault string
ColumnDefaultType *string
IsNullable bool
Expand Down
21 changes: 20 additions & 1 deletion backend/protos/mgmt/v1alpha1/job.proto
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ message PostgresSourceTableOption {

message MysqlSourceConnectionOptions {
// Whether to halt the job if a new column is added
bool halt_on_new_column_addition = 1;
// Deprecated: Use new_column_addition_strategy instead
bool halt_on_new_column_addition = 1 [deprecated = true];
// The list of schemas (and their tables) along with any configuration options that will be used.
repeated MysqlSourceSchemaOption schemas = 2;
// The unique connection id to a mysql connection configuration
Expand All @@ -218,6 +219,9 @@ message MysqlSourceConnectionOptions {
// Provide a strategy of what to do in the event Neosync encounters a column that is removed from the source table.
ColumnRemovalStrategy column_removal_strategy = 5;

// Provide a strategy of what to do in the event Neosync encounters an unmapped column for the job's mapped tables.
NewColumnAdditionStrategy new_column_addition_strategy = 6;

message ColumnRemovalStrategy {
oneof strategy {
// halt job if a column is removed
Expand All @@ -232,6 +236,21 @@ message MysqlSourceConnectionOptions {
// Configuration for the ContinueJob strategy
message ContinueJob {}
}

message NewColumnAdditionStrategy {
oneof strategy {
// halt job if a new column is detected.
HaltJob halt_job = 1;
// automatically handle unmapped columns. It handles this by using the DBs default/nullable values.
// If this doesn't exist, will fall back to configuring generators for supported datatypes.
// If none of the criteria above can be met, the job run will fail to prevent leaking of PII.
AutoMap auto_map = 2;
}
// Configuration for the HaltJob strategy
message HaltJob {}
// Configuration for the AutoMap strategy
message AutoMap {}
}
}

message MysqlSourceSchemaOption {
Expand Down
71 changes: 65 additions & 6 deletions backend/sql/postgresql/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -1209,13 +1209,23 @@ func (s *MongoDbSourceOptions) FromDto(dto *mgmtv1alpha1.MongoDBSourceConnection
}

type MysqlSourceOptions struct {
HaltOnNewColumnAddition bool `json:"haltOnNewColumnAddition"`
SubsetByForeignKeyConstraints bool `json:"subsetByForeignKeyConstraints"`
Schemas []*MysqlSourceSchemaOption `json:"schemas"`
ConnectionId string `json:"connectionId"`
ColumnRemovalStrategy *MysqlColumnRemovalStrategy `json:"columnRemovalStrategy,omitempty"`
// @deprecated
HaltOnNewColumnAddition bool `json:"haltOnNewColumnAddition"`
SubsetByForeignKeyConstraints bool `json:"subsetByForeignKeyConstraints"`
Schemas []*MysqlSourceSchemaOption `json:"schemas"`
ConnectionId string `json:"connectionId"`
ColumnRemovalStrategy *MysqlColumnRemovalStrategy `json:"columnRemovalStrategy,omitempty"`
NewColumnAdditionStrategy *MysqlNewColumnAdditionStrategy `json:"newColumnAdditionStrategy,omitempty"`
}

type MysqlNewColumnAdditionStrategy struct {
HaltJob *MysqlHaltJobNewColumnAdditionStrategy `json:"haltJob,omitempty"`
AutoMap *MysqlAutoMapNewColumnAdditionStrategy `json:"autoMap,omitempty"`
}

type MysqlHaltJobNewColumnAdditionStrategy struct{}
type MysqlAutoMapNewColumnAdditionStrategy struct{}

type MysqlColumnRemovalStrategy struct {
HaltJob *MysqlHaltJobColumnRemovalStrategy `json:"haltJob,omitempty"`
ContinueJob *MysqlContinueJobColumnRemovalStrategy `json:"continueJob,omitempty"`
Expand Down Expand Up @@ -1466,11 +1476,60 @@ func (s *MysqlSourceOptions) ToDto() *mgmtv1alpha1.MysqlSourceConnectionOptions
if s.ColumnRemovalStrategy != nil {
dto.ColumnRemovalStrategy = s.ColumnRemovalStrategy.ToDto()
}
if s.NewColumnAdditionStrategy != nil {
dto.NewColumnAdditionStrategy = s.NewColumnAdditionStrategy.ToDto()
} else if s.HaltOnNewColumnAddition {
dto.NewColumnAdditionStrategy = &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy{
Strategy: &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_HaltJob_{
HaltJob: &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_HaltJob{},
},
}
dto.HaltOnNewColumnAddition = true //nolint:staticcheck
}

return dto
}

func (s *MysqlNewColumnAdditionStrategy) ToDto() *mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy {
if s.HaltJob != nil {
return &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy{
Strategy: &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_HaltJob_{
HaltJob: &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_HaltJob{},
},
}
}
if s.AutoMap != nil {
return &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy{
Strategy: &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_AutoMap_{
AutoMap: &mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_AutoMap{},
},
}
}
return nil
}

func (s *MysqlNewColumnAdditionStrategy) FromDto(dto *mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy) {
if dto.GetStrategy() != nil {
switch dto.GetStrategy().(type) {
case *mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_HaltJob_:
s.HaltJob = &MysqlHaltJobNewColumnAdditionStrategy{}
case *mgmtv1alpha1.MysqlSourceConnectionOptions_NewColumnAdditionStrategy_AutoMap_:
s.AutoMap = &MysqlAutoMapNewColumnAdditionStrategy{}
}
}
}

func (s *MysqlSourceOptions) FromDto(dto *mgmtv1alpha1.MysqlSourceConnectionOptions) {
s.HaltOnNewColumnAddition = dto.HaltOnNewColumnAddition
s.HaltOnNewColumnAddition = dto.HaltOnNewColumnAddition //nolint:staticcheck
if dto.GetNewColumnAdditionStrategy().GetStrategy() != nil {
s.NewColumnAdditionStrategy = &MysqlNewColumnAdditionStrategy{}
s.NewColumnAdditionStrategy.FromDto(dto.GetNewColumnAdditionStrategy())
} else if dto.HaltOnNewColumnAddition { //nolint:staticcheck
s.NewColumnAdditionStrategy = &MysqlNewColumnAdditionStrategy{
HaltJob: &MysqlHaltJobNewColumnAdditionStrategy{},
}
s.HaltOnNewColumnAddition = true
}
s.SubsetByForeignKeyConstraints = dto.SubsetByForeignKeyConstraints
s.Schemas = FromDtoMysqlSourceSchemaOptions(dto.Schemas)
s.ConnectionId = dto.ConnectionId
Expand Down
46 changes: 45 additions & 1 deletion docs/docs/guides/new-column-addition-strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This is a common occurrence for any company that is adding new columns to a data
| Strategy | Description | PostgreSQL | MySQL | MS SQL Server |
| -------- | ----------------------------------------------------------------------------------------------- | ---------- | ----- | ------------- |
| Halt | Stops the job run if a new column is detected that is not found in the configured job mappings. | ✅ | ✅ | ✅ |
| AutoMap | Automatically generates a fake value. See more below. | ✅ | | ❌ |
| AutoMap | Automatically generates a fake value. See more below. | ✅ | | ❌ |
| Continue | Ignores new columns; may fail if column doesn't have default. See more below. | ✅ | ✅ | ✅ |

## Halt Strategy
Expand Down Expand Up @@ -111,3 +111,47 @@ Postgres has many data types and not all of them are currently supported in the
| text[] | ❌ | |

<!-- cspell:enable -->

### MySQL

MySQL has many data types and not all of them are currently supported in the auto map mode. Support will continue to increase over time.

<!-- cspell:disable -->

| Data Type | Support | Generator |
| ---------------- | ------- | ------------------- |
| tinyint | ✅ | GenerateInt64 |
| smallint | ✅ | GenerateInt64 |
| mediumint | ✅ | GenerateInt64 |
| integer | ✅ | GenerateInt64 |
| int | ✅ | GenerateInt64 |
| bigint | ✅ | GenerateInt64 |
| float | ✅ | GenerateFloat64 |
| decimal | ✅ | GenerateFloat64 |
| dec | ✅ | GenerateFloat64 |
| double | ✅ | GenerateFloat64 |
| double precision | ✅ | GenerateFloat64 |
| char | ✅ | GenerateString |
| varchar | ✅ | GenerateString |
| tinytext | ✅ | GenerateString |
| text | ✅ | GenerateString |
| mediumtext | ✅ | GenerateString |
| longtext | ✅ | GenerateString |
| boolean | ✅ | GenerateBool |
| bool | ✅ | GenerateBool |
| enum | ✅ | GenerateCategorical |
| set | ✅ | GenerateCategorical |
| date | ✅ | GenerateJavaScript |
| datetime | ✅ | GenerateJavaScript |
| timestamp | ✅ | GenerateJavaScript |
| time | ✅ | GenerateJavaScript |
| year | ✅ | GenerateJavaScript |
| bit | ❌ | |
| binary | ❌ | |
| varbinary | ❌ | |
| tinyblob | ❌ | |
| blob | ❌ | |
| mediumblob | ❌ | |
| longblob | ❌ | |

<!-- cspell:enable -->
60 changes: 59 additions & 1 deletion docs/openapi/mgmt/v1alpha1/job.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3504,7 +3504,9 @@ components:
haltOnNewColumnAddition:
type: boolean
title: halt_on_new_column_addition
description: Whether to halt the job if a new column is added
description: |-
Whether to halt the job if a new column is added
Deprecated: Use new_column_addition_strategy instead
schemas:
type: array
items:
Expand All @@ -3525,6 +3527,11 @@ components:
- $ref: '#/components/schemas/mgmt.v1alpha1.MysqlSourceConnectionOptions.ColumnRemovalStrategy'
title: column_removal_strategy
description: Provide a strategy of what to do in the event Neosync encounters a column that is removed from the source table.
newColumnAdditionStrategy:
allOf:
- $ref: '#/components/schemas/mgmt.v1alpha1.MysqlSourceConnectionOptions.NewColumnAdditionStrategy'
title: new_column_addition_strategy
description: Provide a strategy of what to do in the event Neosync encounters an unmapped column for the job's mapped tables.
title: MysqlSourceConnectionOptions
additionalProperties: false
mgmt.v1alpha1.MysqlSourceConnectionOptions.ColumnRemovalStrategy:
Expand Down Expand Up @@ -3575,6 +3582,57 @@ components:
title: HaltJob
additionalProperties: false
description: Configuration for the HaltJob strategy
mgmt.v1alpha1.MysqlSourceConnectionOptions.NewColumnAdditionStrategy:
type: object
allOf:
- anyOf:
- required:
- autoMap
- required:
- haltJob
- not:
anyOf:
- required:
- autoMap
- required:
- haltJob
anyOf:
- required:
- autoMap
- required:
- haltJob
- not:
anyOf:
- required:
- autoMap
- required:
- haltJob
properties:
haltJob:
allOf:
- $ref: '#/components/schemas/mgmt.v1alpha1.MysqlSourceConnectionOptions.NewColumnAdditionStrategy.HaltJob'
title: halt_job
description: halt job if a new column is detected.
autoMap:
allOf:
- $ref: '#/components/schemas/mgmt.v1alpha1.MysqlSourceConnectionOptions.NewColumnAdditionStrategy.AutoMap'
title: auto_map
description: |-
automatically handle unmapped columns. It handles this by using the DBs default/nullable values.
If this doesn't exist, will fall back to configuring generators for supported datatypes.
If none of the criteria above can be met, the job run will fail to prevent leaking of PII.
title: NewColumnAdditionStrategy
additionalProperties: false
mgmt.v1alpha1.MysqlSourceConnectionOptions.NewColumnAdditionStrategy.AutoMap:
type: object
title: AutoMap
additionalProperties: false
description: Configuration for the AutoMap strategy
mgmt.v1alpha1.MysqlSourceConnectionOptions.NewColumnAdditionStrategy.HaltJob:
type: object
title: HaltJob
additionalProperties: false
description: Configuration for the HaltJob strategy
mgmt.v1alpha1.MysqlSourceSchemaOption:
type: object
properties:
Expand Down
Loading