Repository: cloudspannerecosystem/harbourbridge
Pull request #367 (2022-08-25 06:34:13)

Supporting changes for low downtime migrations
This PR finishes the low downtime workflow by adding support to Write the session file to GCS after launching datastream.

This PR also takes care of the following:

- Multiplexing the snapshot migration logic correctly for all use cases, non streaming, DynamoDB streaming and MySQL/Oracle Streaming
- It also sets the numWorkers parameters now when launching the dataflow job.


Patch:
diff --git a/common/constants/constants.go b/common/constants/constants.go
index 639832c..743f5a1 100644
--- a/common/constants/constants.go
+++ b/common/constants/constants.go
@@ -61,4 +61,7 @@ const (
 
 	// Information passed in metadata while using Cloud Spanner client.
 	MigrationMetadataKey string = "cloud-spanner-migration-metadata"
+
+	// Scheme used for GCS paths
+	GCS_SCHEME string = "gs"
 )
diff --git a/common/utils/utils.go b/common/utils/utils.go
index c69d9df..a3dc670 100644
--- a/common/utils/utils.go
+++ b/common/utils/utils.go
@@ -73,7 +73,7 @@ func NewIOStreams(driver string, dumpFile string) IOStreams {
 		fmt.Printf("\nLoading dump file from path: %s\n", dumpFile)
 		var f *os.File
 		var err error
-		if u.Scheme == "gs" {
+		if u.Scheme == constants.GCS_SCHEME {
 			bucketName := u.Host
 			filePath := u.Path[1:] // removes "/" from beginning of path
 			f, err = DownloadFromGCS(bucketName, filePath, "harbourbridge.gcs.data")
@@ -152,7 +152,7 @@ func PreloadGCSFiles(tables []ManifestTable) ([]ManifestTable, error) {
 			if err != nil {
 				return nil, fmt.Errorf("unable parse file path %s for table %s", filePath, table.Table_name)
 			}
-			if u.Scheme == "gs" {
+			if u.Scheme == constants.GCS_SCHEME {
 				bucketName := u.Host
 				filePath := u.Path[1:] // removes "/" from beginning of path
 				tmpFile := strings.ReplaceAll(filePath, "/", ".")
@@ -170,6 +170,52 @@ func PreloadGCSFiles(tables []ManifestTable) ([]ManifestTable, error) {
 	return tables, nil
 }
 
+func ParseGCSFilePath(filePath string) (*url.URL, error) {
+	if len(filePath) == 0 {
+		return nil, fmt.Errorf("found empty GCS path")
+	}
+	if filePath[len(filePath)-1] != '/' {
+		filePath = filePath + "/"
+	}
+	u, err := url.Parse(filePath)
+	if err != nil {
+		return nil, fmt.Errorf("parseFilePath: unable to parse file path %s", filePath)
+	}
+	if u.Scheme != constants.GCS_SCHEME {
+		return nil, fmt.Errorf("not a valid GCS path: %s, should start with 'gs'", filePath)
+	}
+	return u, nil
+}
+
+func WriteToGCS(filePath, fileName, data string) error {
+	ctx := context.Background()
+
+	client, err := storage.NewClient(ctx)
+	if err != nil {
+		fmt.Printf("Failed to create GCS client")
+		return err
+	}
+	defer client.Close()
+	u, err := ParseGCSFilePath(filePath)
+	if err != nil {
+		return fmt.Errorf("parseFilePath: unable to parse file path: %v", err)
+	}
+	bucketName := u.Host
+	bucket := client.Bucket(bucketName)
+	obj := bucket.Object(u.Path[1:] + fileName)
+
+	w := obj.NewWriter(ctx)
+	if _, err := fmt.Fprint(w, data); err != nil {
+		fmt.Printf("Failed to write to Cloud Storage: %s", filePath)
+		return err
+	}
+	if err := w.Close(); err != nil {
+		fmt.Printf("Failed to close GCS file: %s", filePath)
+		return err
+	}
+	return nil
+}
+
 // GetProject returns the cloud project we should use for accessing Spanner.
 // Use environment variable GCLOUD_PROJECT if it is set.
 // Otherwise, use the default project returned from gcloud.
diff --git a/conversion/conversion.go b/conversion/conversion.go
index 2156c98..01b3662 100644
--- a/conversion/conversion.go
+++ b/conversion/conversion.go
@@ -174,7 +174,7 @@ func schemaFromDatabase(sourceProfile profiles.SourceProfile, targetProfile prof
 	return conv, common.ProcessSchema(conv, infoSchema)
 }
 
-func performSnapshotMigration(config writer.BatchWriterConfig, conv *internal.Conv, client *sp.Client, infoSchema common.InfoSchema) (*writer.BatchWriter, error) {
+func performSnapshotMigration(config writer.BatchWriterConfig, conv *internal.Conv, client *sp.Client, infoSchema common.InfoSchema) *writer.BatchWriter {
 	common.SetRowStats(conv, infoSchema)
 	totalRows := conv.Rows()
 	var p *internal.Progress
@@ -184,7 +184,19 @@ func performSnapshotMigration(config writer.BatchWriterConfig, conv *internal.Co
 	batchWriter := populateDataConv(conv, config, client, p)
 	common.ProcessData(conv, infoSchema)
 	batchWriter.Flush()
-	return batchWriter, nil
+	return batchWriter
+}
+
+func snapshotMigrationHandler(sourceProfile profiles.SourceProfile, config writer.BatchWriterConfig, conv *internal.Conv, client *sp.Client, infoSchema common.InfoSchema) (*writer.BatchWriter, error) {
+	switch sourceProfile.Driver {
+	// Skip snapshot migration via harbourbridge for mysql and oracle since dataflow job will job will handle this from backfilled data.
+	case constants.MYSQL, constants.ORACLE:
+		return &writer.BatchWriter{}, nil
+	case constants.DYNAMODB:
+		return performSnapshotMigration(config, conv, client, infoSchema), nil
+	default:
+		return &writer.BatchWriter{}, fmt.Errorf("streaming migration not supported for driver %s", sourceProfile.Driver)
+	}
 }
 
 func dataFromDatabase(ctx context.Context, sourceProfile profiles.SourceProfile, targetProfile profiles.TargetProfile, config writer.BatchWriterConfig, conv *internal.Conv, client *sp.Client) (*writer.BatchWriter, error) {
@@ -198,18 +210,17 @@ func dataFromDatabase(ctx context.Context, sourceProfile profiles.SourceProfile,
 		if err != nil {
 			return nil, err
 		}
-	}
-	bw, err := performSnapshotMigration(config, conv, client, infoSchema)
-	if err != nil {
-		return nil, err
-	}
-	if sourceProfile.Conn.Streaming {
+		bw, err := snapshotMigrationHandler(sourceProfile, config, conv, client, infoSchema)
+		if err != nil {
+			return nil, err
+		}
 		err = infoSchema.StartStreamingMigration(ctx, client, conv, streamInfo)
 		if err != nil {
 			return nil, err
 		}
+		return bw, nil
 	}
-	return bw, nil
+	return performSnapshotMigration(config, conv, client, infoSchema), nil
 }
 
 func getDynamoDBClientConfig() (*aws.Config, error) {
diff --git a/internal/convert.go b/internal/convert.go
index 7ed555c..d864761 100644
--- a/internal/convert.go
+++ b/internal/convert.go
@@ -332,7 +332,7 @@ func (conv *Conv) AddPrimaryKeys() {
 			if !primaryKeyPopulated {
 				k := conv.buildPrimaryKey(t)
 				ct.ColNames = append(ct.ColNames, k)
-				ct.ColDefs[k] = ddl.ColumnDef{Name: k, T: ddl.Type{Name: ddl.Int64}}
+				ct.ColDefs[k] = ddl.ColumnDef{Name: k, T: ddl.Type{Name: ddl.String, Len: 50}}
 				ct.Pks = []ddl.IndexKey{{Col: k}}
 				conv.SyntheticPKeys[t] = SyntheticPKey{k, 0}
 			}
diff --git a/sources/mysql/data.go b/sources/mysql/data.go
index 590e811..33de4ee 100644
--- a/sources/mysql/data.go
+++ b/sources/mysql/data.go
@@ -84,7 +84,7 @@ func ConvertData(conv *internal.Conv, srcTable string, srcCols []string, srcSche
 	}
 	if aux, ok := conv.SyntheticPKeys[spTable]; ok {
 		c = append(c, aux.Col)
-		v = append(v, int64(bits.Reverse64(uint64(aux.Sequence))))
+		v = append(v, fmt.Sprintf("%d", int64(bits.Reverse64(uint64(aux.Sequence)))))
 		aux.Sequence++
 		conv.SyntheticPKeys[spTable] = aux
 	}
diff --git a/sources/mysql/infoschema.go b/sources/mysql/infoschema.go
index 2542877..97c5043 100644
--- a/sources/mysql/infoschema.go
+++ b/sources/mysql/infoschema.go
@@ -17,6 +17,7 @@ package mysql
 import (
 	"context"
 	"database/sql"
+	"encoding/json"
 	"fmt"
 	"sort"
 	"strings"
@@ -25,6 +26,7 @@ import (
 	_ "github.com/go-sql-driver/mysql" // The driver should be used via the database/sql package.
 	_ "github.com/lib/pq"
 
+	"github.com/cloudspannerecosystem/harbourbridge/common/utils"
 	"github.com/cloudspannerecosystem/harbourbridge/internal"
 	"github.com/cloudspannerecosystem/harbourbridge/profiles"
 	"github.com/cloudspannerecosystem/harbourbridge/schema"
@@ -350,8 +352,22 @@ func (isi InfoSchemaImpl) StartChangeDataCapture(ctx context.Context, conv *inte
 // performing a streaming migration.
 func (isi InfoSchemaImpl) StartStreamingMigration(ctx context.Context, client *sp.Client, conv *internal.Conv, streamingInfo map[string]interface{}) error {
 	streamingCfg, _ := streamingInfo["streamingCfg"].(streaming.StreamingCfg)
-	err := streaming.StartDataflow(ctx, isi.SourceProfile, isi.TargetProfile, streamingCfg)
+	convJSON, err := json.MarshalIndent(conv, "", " ")
 	if err != nil {
+		err = fmt.Errorf("can't encode session state to JSON: %v", err)
+		return err
+	}
+	fmt.Printf("Writing session file to GCS...")
+	err = utils.WriteToGCS(streamingCfg.TmpDir, "session.json", string(convJSON))
+	if err != nil {
+		err = fmt.Errorf("error writing session file to GCS: %v", err)
+		return err
+	}
+	fmt.Println("Done")
+
+	err = streaming.StartDataflow(ctx, isi.SourceProfile, isi.TargetProfile, streamingCfg)
+	if err != nil {
+		err = fmt.Errorf("error starting dataflow: %v", err)
 		return err
 	}
 	return nil
diff --git a/sources/oracle/data.go b/sources/oracle/data.go
index ee251ba..5c1dea4 100644
--- a/sources/oracle/data.go
+++ b/sources/oracle/data.go
@@ -80,7 +80,7 @@ func convertData(conv *internal.Conv, srcTable string, srcCols []string, srcSche
 	}
 	if aux, ok := conv.SyntheticPKeys[spTable]; ok {
 		c = append(c, aux.Col)
-		v = append(v, int64(bits.Reverse64(uint64(aux.Sequence))))
+		v = append(v, fmt.Sprintf("%d", int64(bits.Reverse64(uint64(aux.Sequence)))))
 		aux.Sequence++
 		conv.SyntheticPKeys[spTable] = aux
 	}
diff --git a/sources/postgres/data.go b/sources/postgres/data.go
index a839281..a64a3f5 100644
--- a/sources/postgres/data.go
+++ b/sources/postgres/data.go
@@ -102,7 +102,7 @@ func ConvertData(conv *internal.Conv, srcTable string, srcCols []string, vals []
 	}
 	if aux, ok := conv.SyntheticPKeys[spTable]; ok {
 		c = append(c, aux.Col)
-		v = append(v, int64(bits.Reverse64(uint64(aux.Sequence))))
+		v = append(v, fmt.Sprintf("%d", int64(bits.Reverse64(uint64(aux.Sequence)))))
 		aux.Sequence++
 		conv.SyntheticPKeys[spTable] = aux
 	}
diff --git a/sources/postgres/infoschema.go b/sources/postgres/infoschema.go
index bfbd6d6..b1b267c 100644
--- a/sources/postgres/infoschema.go
+++ b/sources/postgres/infoschema.go
@@ -156,7 +156,7 @@ func convertSQLRow(conv *internal.Conv, srcTable string, srcCols []string, srcSc
 	}
 	if aux, ok := conv.SyntheticPKeys[spTable]; ok {
 		cs = append(cs, aux.Col)
-		vs = append(vs, int64(bits.Reverse64(uint64(aux.Sequence))))
+		vs = append(vs, fmt.Sprintf("%d", int64(bits.Reverse64(uint64(aux.Sequence)))))
 		aux.Sequence++
 		conv.SyntheticPKeys[spTable] = aux
 	}
diff --git a/sources/sqlserver/data.go b/sources/sqlserver/data.go
index 2a4fe3b..fd4963d 100644
--- a/sources/sqlserver/data.go
+++ b/sources/sqlserver/data.go
@@ -77,7 +77,7 @@ func ConvertData(conv *internal.Conv, srcTable string, srcCols []string, srcSche
 	}
 	if aux, ok := conv.SyntheticPKeys[spTable]; ok {
 		c = append(c, aux.Col)
-		v = append(v, int64(bits.Reverse64(uint64(aux.Sequence))))
+		v = append(v, fmt.Sprintf("%d", int64(bits.Reverse64(uint64(aux.Sequence)))))
 		aux.Sequence++
 		conv.SyntheticPKeys[spTable] = aux
 	}
diff --git a/streaming/streaming.go b/streaming/streaming.go
index ae8d7dc..eed26f4 100644
--- a/streaming/streaming.go
+++ b/streaming/streaming.go
@@ -18,10 +18,12 @@ import (
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
+	"strings"
 	"time"
 
 	dataflow "cloud.google.com/go/dataflow/apiv1beta3"
 	datastream "cloud.google.com/go/datastream/apiv1alpha1"
+	"cloud.google.com/go/storage"
 	datastreampb "google.golang.org/genproto/googleapis/cloud/datastream/v1alpha1"
 	dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3"
 	fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
@@ -31,6 +33,11 @@ import (
 	"github.com/cloudspannerecosystem/harbourbridge/profiles"
 )
 
+const (
+	numWorkers int32 = 50
+	maxWorkers int32 = 50
+)
+
 type SrcConnCfg struct {
 	Name     string
 	Location string
@@ -58,6 +65,7 @@ type DataflowCfg struct {
 type StreamingCfg struct {
 	DatastreamCfg DatastreamCfg
 	DataflowCfg   DataflowCfg
+	TmpDir        string
 }
 
 // VerifyAndUpdateCfg checks the fields and errors out if certain fields are empty.
@@ -100,11 +108,30 @@ func VerifyAndUpdateCfg(streamingCfg *StreamingCfg, dbName string) error {
 	if dfCfg.JobName == "" {
 		// Update names to have more info like dbname.
 		jobName, err := utils.GenerateName("hb-dataflow-" + dbName)
+		jobName = strings.Replace(jobName, "_", "-", -1)
 		if err != nil {
 			return fmt.Errorf("error generating stream name: %v", err)
 		}
 		streamingCfg.DataflowCfg.JobName = jobName
 	}
+
+	filePath := streamingCfg.TmpDir
+	u, err := utils.ParseGCSFilePath(filePath)
+	if err != nil {
+		return fmt.Errorf("parseFilePath: unable to parse file path: %v", err)
+	}
+	bucketName := u.Host
+	ctx := context.Background()
+	client, err := storage.NewClient(ctx)
+	if err != nil {
+		return fmt.Errorf("failed to create GCS client")
+	}
+	defer client.Close()
+	bucket := client.Bucket(bucketName)
+	_, err = bucket.Attrs(ctx)
+	if err != nil {
+		return fmt.Errorf("bucket %s does not exist", bucketName)
+	}
 	return nil
 }
 
@@ -187,7 +214,7 @@ func LaunchStream(ctx context.Context, sourceProfile profiles.SourceProfile, pro
 		SourceConfig:      srcCfg,
 		DestinationConfig: dstCfg,
 		State:             datastreampb.Stream_RUNNING,
-		BackfillStrategy:  &datastreampb.Stream_BackfillNone{BackfillNone: &datastreampb.Stream_BackfillNoneStrategy{}},
+		BackfillStrategy:  &datastreampb.Stream_BackfillAll{BackfillAll: &datastreampb.Stream_BackfillAllStrategy{}},
 	}
 	createStreamRequest := &datastreampb.CreateStreamRequest{
 		Parent:   fmt.Sprintf("projects/%s/locations/%s", projectID, datastreamCfg.StreamLocation),
@@ -199,13 +226,13 @@ func LaunchStream(ctx context.Context, sourceProfile profiles.SourceProfile, pro
 
 	dsOp, err := dsClient.CreateStream(ctx, createStreamRequest)
 	if err != nil {
-		fmt.Printf("createStreamRequest: %+v\n", createStreamRequest)
+		fmt.Printf("cannot create stream: createStreamRequest: %+v\n", createStreamRequest)
 		return fmt.Errorf("cannot create stream: %v ", err)
 	}
 
 	_, err = dsOp.Wait(ctx)
 	if err != nil {
-		fmt.Printf("createStreamRequest: %+v\n", createStreamRequest)
+		fmt.Printf("datastream create operation failed: createStreamRequest: %+v\n", createStreamRequest)
 		return fmt.Errorf("datastream create operation failed: %v", err)
 	}
 	fmt.Println("Successfully created stream ", datastreamCfg.StreamId)
@@ -229,8 +256,10 @@ func LaunchStream(ctx context.Context, sourceProfile profiles.SourceProfile, pro
 }
 
 // LaunchDataflowJob populates the parameters from the streaming config and triggers a Dataflow job.
-func LaunchDataflowJob(ctx context.Context, targetProfile profiles.TargetProfile, datastreamCfg DatastreamCfg, dataflowCfg DataflowCfg) error {
+func LaunchDataflowJob(ctx context.Context, targetProfile profiles.TargetProfile, streamingCfg StreamingCfg) error {
 	project, instance, dbName, _ := targetProfile.GetResourceIds(ctx, time.Now(), "", nil)
+	dataflowCfg := streamingCfg.DataflowCfg
+	datastreamCfg := streamingCfg.DatastreamCfg
 	fmt.Println("Launching dataflow job ", dataflowCfg.JobName, " in ", project, "-", dataflowCfg.Location)
 
 	c, err := dataflow.NewFlexTemplatesClient(ctx)
@@ -265,6 +294,11 @@ func LaunchDataflowJob(ctx context.Context, targetProfile profiles.TargetProfile
 			"streamName":       fmt.Sprintf("projects/%s/locations/%s/streams/%s", project, datastreamCfg.StreamLocation, datastreamCfg.StreamId),
 			"instanceId":       instance,
 			"databaseId":       dbName,
+			"sessionFilePath":  streamingCfg.TmpDir + "session.json",
+		},
+		Environment: &dataflowpb.FlexTemplateRuntimeEnvironment{
+			NumWorkers: numWorkers,
+			MaxWorkers: maxWorkers,
 		},
 	}
 
@@ -313,7 +347,7 @@ func StartDatastream(ctx context.Context, sourceProfile profiles.SourceProfile,
 }
 
 func StartDataflow(ctx context.Context, sourceProfile profiles.SourceProfile, targetProfile profiles.TargetProfile, streamingCfg StreamingCfg) error {
-	err := LaunchDataflowJob(ctx, targetProfile, streamingCfg.DatastreamCfg, streamingCfg.DataflowCfg)
+	err := LaunchDataflowJob(ctx, targetProfile, streamingCfg)
 	if err != nil {
 		return fmt.Errorf("error launching dataflow: %v", err)
 	}
diff --git a/ui/src/app/components/direct-connection/direct-connection.component.html b/ui/src/app/components/direct-connection/direct-connection.component.html
index bf3a0b0..f09314e 100644
--- a/ui/src/app/components/direct-connection/direct-connection.component.html
+++ b/ui/src/app/components/direct-connection/direct-connection.component.html
@@ -1,7 +1,7 @@
-<div class="container">
-  <mat-card class="form-container">
+<div class="connect-load-database-container">
+  <div class="form-container">
     <form [formGroup]="connectForm" (ngSubmit)="connectToDb()">
-      <h3>Connect to a Database</h3>
+      <h3 class="primary-header">Connect to a Database</h3>
 
       <mat-form-field class="full-width" appearance="outline">
         <mat-label>Database Engine</mat-label>
@@ -12,7 +12,7 @@
         </mat-select>
       </mat-form-field>
 
-      <h3>Connection Detail</h3>
+      <h3 class="primary-header">Connection Detail</h3>
 
       <mat-form-field class="full-width" appearance="outline">
         <mat-label>Hostname</mat-label>
@@ -51,5 +51,5 @@
       </button>
       <button mat-raised-button [routerLink]="'/'">Cancel</button>
     </form>
-  </mat-card>
+  </div>
 </div>
diff --git a/ui/src/app/components/direct-connection/direct-connection.component.scss b/ui/src/app/components/direct-connection/direct-connection.component.scss
index 012cd27..6889d9e 100644
--- a/ui/src/app/components/direct-connection/direct-connection.component.scss
+++ b/ui/src/app/components/direct-connection/direct-connection.component.scss
@@ -1,17 +1,5 @@
-.container {
-  padding: 0 20px;
+.connect-load-database-container {
   h3 {
     margin-bottom: 0px;
   }
-  h5 {
-    margin-bottom: 20px;
-    color: #5c5c5c;
-  }
-  .mat-form-field {
-    width: 400px;
-    margin-right: 20px;
-  }
-  button {
-    margin-right: 20px;
-  }
 }
diff --git a/ui/src/app/components/home/home.component.html b/ui/src/app/components/home/home.component.html
index e5786b7..f852ce6 100644
--- a/ui/src/app/components/home/home.component.html
+++ b/ui/src/app/components/home/home.component.html
@@ -1,6 +1,6 @@
 <div class="container">
-  <h3>Get started with HarbourBridge</h3>
-  <div class="summary">
+  <h3 class="primary-header">Get started with HarbourBridge</h3>
+  <div class="summary global-font-color body-font-size">
     HarbourBridge is a stand-alone open source tool for Cloud Spanner evaluation and migration,
     using data from an existing PostgreSQL, MySQL, SQL Server, Oracle or DynamoDB database.
     <a href="https://github.com/cloudspannerecosystem/harbourbridge#readme">Learn More</a>.
diff --git a/ui/src/app/components/home/home.component.ts b/ui/src/app/components/home/home.component.ts
index 44a687c..d98c0a1 100644
--- a/ui/src/app/components/home/home.component.ts
+++ b/ui/src/app/components/home/home.component.ts
@@ -7,6 +7,5 @@ import { Component, OnInit } from '@angular/core'
 })
 export class HomeComponent implements OnInit {
   constructor() {}
-
   ngOnInit(): void {}
 }
diff --git a/ui/src/app/components/load-dump/load-dump.component.html b/ui/src/app/components/load-dump/load-dump.component.html
index 76dc9cb..afb7bf8 100644
--- a/ui/src/app/components/load-dump/load-dump.component.html
+++ b/ui/src/app/components/load-dump/load-dump.component.html
@@ -1,7 +1,7 @@
-<div class="container">
-  <mat-card class="form-container">
+<div class="connect-load-database-container">
+  <div class="form-container">
     <form [formGroup]="connectForm" (ngSubmit)="convertFromDump()">
-      <h3>Load from database dump</h3>
+      <h3 class="primary-header">Load from database dump</h3>
 
       <mat-form-field class="full-width" appearance="outline">
         <mat-label>Database Engine</mat-label>
@@ -12,7 +12,7 @@
         </mat-select>
       </mat-form-field>
 
-      <h3>Dump File</h3>
+      <h3 class="primary-header">Dump File</h3>
 
       <mat-form-field class="full-width" appearance="outline">
         <mat-label>File path</mat-label>
@@ -30,5 +30,5 @@
       </button>
       <button mat-raised-button [routerLink]="'/'">Cancel</button>
     </form>
-  </mat-card>
+  </div>
 </div>
diff --git a/ui/src/app/components/load-dump/load-dump.component.scss b/ui/src/app/components/load-dump/load-dump.component.scss
index 6ed2783..8b13789 100644
--- a/ui/src/app/components/load-dump/load-dump.component.scss
+++ b/ui/src/app/components/load-dump/load-dump.component.scss
@@ -1,14 +1,1 @@
-.container {
-  padding: 0 20px;
-  h5 {
-    margin-bottom: 20px;
-    color: #5c5c5c;
-  }
-  .mat-form-field {
-    width: 400px;
-    margin-right: 20px;
-  }
-  button {
-    margin-right: 20px;
-  }
-}
+
diff --git a/ui/src/app/components/load-session/load-session.component.html b/ui/src/app/components/load-session/load-session.component.html
index a908035..df10cf9 100644
--- a/ui/src/app/components/load-session/load-session.component.html
+++ b/ui/src/app/components/load-session/load-session.component.html
@@ -1,7 +1,7 @@
-<div class="container">
-  <mat-card class="form-container">
+<div class="connect-load-database-container">
+  <div class="form-container">
     <form [formGroup]="connectForm" (ngSubmit)="convertFromSessionFile()">
-      <h3>Load from session</h3>
+      <h3 class="primary-header">Load from session</h3>
 
       <mat-form-field class="full-width" appearance="outline">
         <mat-label>Database Engine</mat-label>
@@ -12,7 +12,7 @@
         </mat-select>
       </mat-form-field>
 
-      <h3>Session File</h3>
+      <h3 class="primary-header">Session File</h3>
 
       <mat-form-field class="full-width" appearance="outline">
         <mat-label>File path</mat-label>
@@ -30,5 +30,5 @@
       </button>
       <button mat-raised-button [routerLink]="'/'">Cancel</button>
     </form>
-  </mat-card>
+  </div>
 </div>
diff --git a/ui/src/app/components/load-session/load-session.component.scss b/ui/src/app/components/load-session/load-session.component.scss
index 6ed2783..8b13789 100644
--- a/ui/src/app/components/load-session/load-session.component.scss
+++ b/ui/src/app/components/load-session/load-session.component.scss
@@ -1,14 +1,1 @@
-.container {
-  padding: 0 20px;
-  h5 {
-    margin-bottom: 20px;
-    color: #5c5c5c;
-  }
-  .mat-form-field {
-    width: 400px;
-    margin-right: 20px;
-  }
-  button {
-    margin-right: 20px;
-  }
-}
+
diff --git a/ui/src/app/components/object-detail/object-detail.component.html b/ui/src/app/components/object-detail/object-detail.component.html
index f545077..450e8d6 100644
--- a/ui/src/app/components/object-detail/object-detail.component.html
+++ b/ui/src/app/components/object-detail/object-detail.component.html
@@ -82,6 +82,7 @@
   </div>
 
   <mat-tab-group
+    [ngClass]="{ 'height-on-edit': isEditMode || isPkEditMode || isFkEditMode }"
     *ngIf="currentObject!.type === 'tableName'"
     (selectedTabChange)="tabChanged($event)"
   >
@@ -510,7 +511,7 @@
             <th mat-header-cell *matHeaderCellDef class="db_name" colspan="5">
               <div class="spanner_edit-button">
                 <span>Spanner</span>
-                <div *ngIf="!isFkEditMode && fkDataSource.length > 0 && !interleaveParentName">
+                <div *ngIf="!isFkEditMode && fkDataSource.length > 0 && !interleaveParentName && currentObject!.isSpannerNode ">
                   <button mat-stroked-button color="primary" (click)="toggleFkEdit()">
                     <mat-icon class="edit-icon">edit</mat-icon>
                     EDIT
@@ -703,7 +704,7 @@
           <div class="spanner_edit-button">
             <span>Spanner</span>
 
-            <div *ngIf="!isIndexEditMode">
+            <div *ngIf="!isIndexEditMode && currentObject!.isSpannerNode">
               <button mat-stroked-button color="primary" (click)="toggleIndexEdit()">
                 <mat-icon class="edit-icon">edit</mat-icon>
                 EDIT
@@ -817,7 +818,7 @@
   </div>
 
   <div class="save-edits">
-    <mat-divider></mat-divider>
+    <mat-divider *ngIf="isEditMode || isPkEditMode || isFkEditMode"></mat-divider>
     <div class="save-button" *ngIf="isEditMode && currentTabIndex === 0">
       <button mat-raised-button color="primary" (click)="toggleEdit()">SAVE & CONVERT</button>
     </div>
diff --git a/ui/src/app/components/object-detail/object-detail.component.scss b/ui/src/app/components/object-detail/object-detail.component.scss
index 690b928..be82567 100644
--- a/ui/src/app/components/object-detail/object-detail.component.scss
+++ b/ui/src/app/components/object-detail/object-detail.component.scss
@@ -1,5 +1,6 @@
 .no-table-selected {
   height: 90%;
+  background-color: white;
 }
 
 .select-table-message {
@@ -49,7 +50,11 @@
 
 .table {
   height: 100%;
+  background-color: white;
   .mat-tab-group {
+    height: 93%;
+  }
+  .height-on-edit {
     height: 84%;
   }
 }
@@ -163,7 +168,7 @@
 
   .mat-column-srcIsNotNull,
   .mat-column-spIsNotNull {
-    min-width: 70px;
+    min-width: 100px;
   }
 
   .mat-column-srcIsNotNull,
diff --git a/ui/src/app/components/object-explorer/object-explorer.component.html b/ui/src/app/components/object-explorer/object-explorer.component.html
index 9443894..44d95df 100644
--- a/ui/src/app/components/object-explorer/object-explorer.component.html
+++ b/ui/src/app/components/object-explorer/object-explorer.component.html
@@ -4,7 +4,12 @@
     selectedIndex="1"
     (selectedTabChange)="onTabChanged()"
   >
-    <mat-tab [label]="srcDbName.toUpperCase()">
+    <mat-tab>
+      <ng-template mat-tab-label>
+        <span [ngClass]="{ 'blue-font-color': selectedTab === 'source' }">
+          {{ srcDbName.toUpperCase() }}
+        </span>
+      </ng-template>
       <div class="filter-wrapper">
         <div class="left">
           <span class="material-icons filter-icon">filter_list</span>
@@ -167,7 +172,10 @@
         </table>
       </div>
     </mat-tab>
-    <mat-tab label="SPANNER DRAFT">
+    <mat-tab>
+      <ng-template mat-tab-label>
+        <span [ngClass]="{ 'blue-font-color': selectedTab === 'spanner' }"> SPANNER DRAFT </span>
+      </ng-template>
       <div class="filter-wrapper">
         <div class="left">
           <span class="material-icons filter-icon">filter_list</span>
diff --git a/ui/src/app/components/object-explorer/object-explorer.component.scss b/ui/src/app/components/object-explorer/object-explorer.component.scss
index a5a3ca1..28bbfd8 100644
--- a/ui/src/app/components/object-explorer/object-explorer.component.scss
+++ b/ui/src/app/components/object-explorer/object-explorer.component.scss
@@ -1,5 +1,6 @@
 .container {
   position: relative;
+  background-color: white;
   .filter-wrapper {
     padding: 0 10px;
   }
diff --git a/ui/src/app/components/rule/rule.component.scss b/ui/src/app/components/rule/rule.component.scss
index e11adf5..9667867 100644
--- a/ui/src/app/components/rule/rule.component.scss
+++ b/ui/src/app/components/rule/rule.component.scss
@@ -2,6 +2,7 @@
   height: calc(100vh - 271px);
   position: relative;
   overflow-y: auto;
+  background-color: #ffffff;
   .rule-header {
     padding-top: 6px;
     padding-bottom: 6px;
diff --git a/ui/src/app/components/session-listing/session-listing.component.html b/ui/src/app/components/session-listing/session-listing.component.html
index 3b416aa..eca56f9 100644
--- a/ui/src/app/components/session-listing/session-listing.component.html
+++ b/ui/src/app/components/session-listing/session-listing.component.html
@@ -1,5 +1,5 @@
 <div class="sessions-wrapper">
-  <h3>Session history</h3>
+  <h3 class="primary-header">Session history</h3>
   <div class="summary">
     Choose a session to resume an existing migration session, or download the session file.
   </div>
diff --git a/ui/src/app/components/source-selection/source-selection.component.html b/ui/src/app/components/source-selection/source-selection.component.html
index 325bb51..49747ea 100644
--- a/ui/src/app/components/source-selection/source-selection.component.html
+++ b/ui/src/app/components/source-selection/source-selection.component.html
@@ -1,12 +1,12 @@
 <div *ngIf="!isDatabaseLoading">
   <div class="prerequisites">
     <mat-card>
-      <mat-card-title>Prerequisites</mat-card-title>
-      <mat-card-subtitle
+      <mat-card-title class="primary-header">Prerequisites</mat-card-title>
+      <mat-card-subtitle class="body-font-size"
         >Before we begin, please ensure you have done the following:</mat-card-subtitle
       >
       <hr />
-      <div>
+      <div class="body-font-size">
         <p>
           <span class="bullet">1</span>
           <span>Create and set default Google Cloud project</span>
diff --git a/ui/src/app/components/source-selection/source-selection.component.scss b/ui/src/app/components/source-selection/source-selection.component.scss
index 3a679b5..8f692f6 100644
--- a/ui/src/app/components/source-selection/source-selection.component.scss
+++ b/ui/src/app/components/source-selection/source-selection.component.scss
@@ -1,3 +1,3 @@
 .prerequisites {
   padding: 0 20px;
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/components/summary/summary.component.scss b/ui/src/app/components/summary/summary.component.scss
index 9719606..63c7581 100644
--- a/ui/src/app/components/summary/summary.component.scss
+++ b/ui/src/app/components/summary/summary.component.scss
@@ -2,6 +2,7 @@
   height: calc(100vh - 271px);
   position: relative;
   overflow-y: auto;
+  background-color: white;
   .no-object-container {
     height: 100%;
     width: 100%;
diff --git a/ui/src/app/components/update-spanner-config-form/update-spanner-config-form.component.html b/ui/src/app/components/update-spanner-config-form/update-spanner-config-form.component.html
index 2e7e3a1..7a559b9 100644
--- a/ui/src/app/components/update-spanner-config-form/update-spanner-config-form.component.html
+++ b/ui/src/app/components/update-spanner-config-form/update-spanner-config-form.component.html
@@ -14,7 +14,7 @@
   </form>
 </div>
 <div mat-dialog-actions class="buttons-container">
-  <button mat-button color="primary" mat-dialog-close>Cancel</button>
+  <button mat-button color="primary" mat-dialog-close>CANCEL</button>
   <button
     mat-button
     (click)="updateSpannerConfig()"
@@ -22,6 +22,6 @@
     color="primary"
     [disabled]="!updateConfigForm.valid"
   >
-    Connect
+    CONNECT
   </button>
 </div>
diff --git a/ui/src/app/components/workspace/workspace.component.html b/ui/src/app/components/workspace/workspace.component.html
index e784f9c..e951e83 100644
--- a/ui/src/app/components/workspace/workspace.component.html
+++ b/ui/src/app/components/workspace/workspace.component.html
@@ -11,7 +11,7 @@
       <button mat-button (click)="openSaveSessionSidenav()" *ngIf="!isOfflineStatus">
         SAVE SESSION
       </button>
-      <button mat-button (click)="downloadSession()">DOWNLOAD SESSION</button>
+      <button mat-button color="primary" (click)="downloadSession()">DOWNLOAD SESSION</button>
     </div>
   </div>
   <div class="container">
diff --git a/ui/src/styles.scss b/ui/src/styles.scss
index c5b337f..f17fc50 100644
--- a/ui/src/styles.scss
+++ b/ui/src/styles.scss
@@ -17,6 +17,32 @@ body {
 .cursor-pointer {
   cursor: pointer;
 }
+.mat-drawer-container {
+  background-color: white;
+}
+
+.mat-button.mat-primary {
+  color: #3367d6;
+}
+.global-font-color {
+  color: #000000;
+}
+.body-font-size {
+  font-size: 14px;
+}
+.primary-header {
+  font-size: 20px !important;
+}
+.mat-stroked-button.mat-primary {
+  color: #3367d6;
+}
+.mat-raised-button.mat-primary {
+  color: white;
+  background-color: #3367d6;
+}
+.blue-font-color {
+  color: #3367d6;
+}
 
 .header {
   padding: 0 20px;
@@ -59,13 +85,15 @@ body {
   .mat-card-title {
     font-size: 13pt;
     font-weight: normal;
+    color: #000000;
   }
   .mat-card-subtitle {
     font-size: 9pt;
     font-weight: normal;
+    color: #000000;
   }
   p {
-    color: #5c5c5c;
+    color: #000000;
     .bullet {
       position: relative;
       display: inline-block;
@@ -88,4 +116,23 @@ body {
     border-color: #ffffff;
     margin-bottom: 20px;
   }
-}
\ No newline at end of file
+}
+
+.connect-load-database-container {
+  padding: 0 20px;
+  h5 {
+    margin-bottom: 20px;
+    color: #5c5c5c;
+  }
+  .mat-form-field {
+    width: 400px;
+    margin-right: 20px;
+  }
+  button {
+    margin-right: 20px;
+  }
+  .form-container {
+    background-color: inherit;
+    padding: 16px;
+  }
+}


Test patch:
diff --git a/internal/convert_test.go b/internal/convert_test.go
index 24b76c5..29fbde7 100644
--- a/internal/convert_test.go
+++ b/internal/convert_test.go
@@ -222,7 +222,7 @@ func TestAddPrimaryKeys(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"a":        {Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        {Name: "b", T: ddl.Type{Name: ddl.Float64}},
-						"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{{Name: "", Table: "", Unique: false, Keys: []ddl.IndexKey{{Col: "b"}}}},
@@ -250,7 +250,7 @@ func TestAddPrimaryKeys(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"a":        {Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        {Name: "b", T: ddl.Type{Name: ddl.Float64}},
-						"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{{Col: "synth_id"}}},
 			},
diff --git a/sources/mysql/data_test.go b/sources/mysql/data_test.go
index a736bc9..c57a88c 100644
--- a/sources/mysql/data_test.go
+++ b/sources/mysql/data_test.go
@@ -285,14 +285,14 @@ func TestConvertsyntheticPKey(t *testing.T) {
 			cols:  []string{"a", "b", "c"},
 			vals:  []string{"6", "6.6", "true"},
 			ecols: []string{"a", "b", "c", "synth_id"},
-			evals: []interface{}{int64(6), float64(6.6), true, int64(0)},
+			evals: []interface{}{int64(6), float64(6.6), true, "0"},
 		},
 		{
 			name:  "Sequence 1",
 			cols:  []string{"a"},
 			vals:  []string{"7"},
 			ecols: []string{"a", "synth_id"},
-			evals: []interface{}{int64(7), int64(bits.Reverse64(1))},
+			evals: []interface{}{int64(7), fmt.Sprintf("%d", int64(bits.Reverse64(1)))},
 		},
 	}
 	tableName := "testtable"
diff --git a/sources/mysql/infoschema_test.go b/sources/mysql/infoschema_test.go
index dc1e101..9e21ce2 100644
--- a/sources/mysql/infoschema_test.go
+++ b/sources/mysql/infoschema_test.go
@@ -388,7 +388,7 @@ func TestProcessData_MultiCol(t *testing.T) {
 				"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
 				"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.Float64}},
 				"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
-				"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+				"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 			},
 			Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}}},
 	}
@@ -404,8 +404,8 @@ func TestProcessData_MultiCol(t *testing.T) {
 		})
 	common.ProcessData(conv, isi)
 	assert.Equal(t, []spannerData{
-		{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"cat", float64(42.3), int64(0)}},
-		{table: "test", cols: []string{"a", "c", "synth_id"}, vals: []interface{}{"dog", int64(22), int64(-9223372036854775808)}}},
+		{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"cat", float64(42.3), "0"}},
+		{table: "test", cols: []string{"a", "c", "synth_id"}, vals: []interface{}{"dog", int64(22), "-9223372036854775808"}}},
 		rows)
 	assert.Equal(t, int64(0), conv.Unexpecteds())
 }
diff --git a/sources/mysql/mysqldump_test.go b/sources/mysql/mysqldump_test.go
index 1111e81..6937850 100644
--- a/sources/mysql/mysqldump_test.go
+++ b/sources/mysql/mysqldump_test.go
@@ -125,7 +125,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 						"productid": {Name: "productid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"userid":    {Name: "userid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
 						"quantity":  {Name: "quantity", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id":  {Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id":  {Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{{Col: "synth_id"}}}},
 		},
@@ -175,7 +175,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        {Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        {Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{{Name: "fk_test", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}}}},
@@ -209,7 +209,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "A_fk_test_2", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}},
@@ -235,7 +235,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}}}},
@@ -260,7 +260,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}}}},
@@ -294,7 +294,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 						"e":        ddl.ColumnDef{Name: "e", T: ddl.Type{Name: ddl.Int64}},
 						"f":        ddl.ColumnDef{Name: "f", T: ddl.Type{Name: ddl.Int64}},
 						"g":        ddl.ColumnDef{Name: "g", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"e"}, ReferTable: "test", ReferColumns: []string{"a"}},
@@ -322,7 +322,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 						"e":        ddl.ColumnDef{Name: "e", T: ddl.Type{Name: ddl.Int64}},
 						"f":        ddl.ColumnDef{Name: "f", T: ddl.Type{Name: ddl.Int64}},
 						"g":        ddl.ColumnDef{Name: "g", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"e", "f"}, ReferTable: "test", ReferColumns: []string{"a", "b"}}}}},
@@ -343,7 +343,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: false}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -405,7 +405,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: false}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -468,7 +468,7 @@ func TestProcessMySQLDump_MultiCol(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: false}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -625,10 +625,10 @@ CREATE TABLE test (a text PRIMARY KEY, b text);`,
 				"('a33','b',9),\n" +
 				"('a3','b',7);",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a1", "b1", int64(42), bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a22", "b99", int64(6), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a33", "b", int64(9), bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), bitReverse(3)}}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a1", "b1", int64(42), fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a22", "b99", int64(6), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a33", "b", int64(9), fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), fmt.Sprintf("%d", bitReverse(3))}}},
 		},
 		{
 			name: "INSERT INTO with empty cols",
@@ -639,10 +639,10 @@ CREATE TABLE test (a text PRIMARY KEY, b text);`,
 				"('a33','b',NULL),\n" +
 				"('a3','b',7);\n",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"b", "n", "synth_id"}, vals: []interface{}{"b1", int64(42), bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "n", "synth_id"}, vals: []interface{}{"a22", int64(6), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"a33", "b", bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), bitReverse(3)}}},
+				spannerData{table: "test", cols: []string{"b", "n", "synth_id"}, vals: []interface{}{"b1", int64(42), fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "n", "synth_id"}, vals: []interface{}{"a22", int64(6), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"a33", "b", fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), fmt.Sprintf("%d", bitReverse(3))}}},
 		},
 		{
 			name: "INSERT",
@@ -657,7 +657,7 @@ CREATE TABLE test (a text PRIMARY KEY, b text);`,
 			input: "CREATE TABLE test (a text NOT NULL, b text NOT NULL, n bigint);\n" +
 				"INSERT INTO test (a, b, n) VALUES ('a42', 'b6', 2);",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a42", "b6", int64(2), bitReverse(0)}}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a42", "b6", int64(2), fmt.Sprintf("%d", bitReverse(0))}}},
 		},
 		{
 			name: "INSERT with spaces",
@@ -809,14 +809,14 @@ func TestProcessMySQLDump_DataError(t *testing.T) {
 					vals: []interface{}{int64(7), float64(42.1), true,
 						getDate("2019-10-29"), []byte{0x89, 0x50},
 						[]spanner.NullString{{StringVal: "42", Valid: true}, {StringVal: "6", Valid: true}},
-						bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "synth_id"}, vals: []interface{}{int64(7), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"b", "synth_id"}, vals: []interface{}{float64(42.1), bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"c", "synth_id"}, vals: []interface{}{true, bitReverse(3)}},
-				spannerData{table: "test", cols: []string{"d", "synth_id"}, vals: []interface{}{getDate("2019-10-29"), bitReverse(4)}},
-				spannerData{table: "test", cols: []string{"e", "synth_id"}, vals: []interface{}{[]byte{0x89, 0x50}, bitReverse(5)}},
+						fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "synth_id"}, vals: []interface{}{int64(7), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"b", "synth_id"}, vals: []interface{}{float64(42.1), fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"c", "synth_id"}, vals: []interface{}{true, fmt.Sprintf("%d", bitReverse(3))}},
+				spannerData{table: "test", cols: []string{"d", "synth_id"}, vals: []interface{}{getDate("2019-10-29"), fmt.Sprintf("%d", bitReverse(4))}},
+				spannerData{table: "test", cols: []string{"e", "synth_id"}, vals: []interface{}{[]byte{0x89, 0x50}, fmt.Sprintf("%d", bitReverse(5))}},
 				spannerData{table: "test", cols: []string{"f", "synth_id"},
-					vals: []interface{}{[]spanner.NullString{{StringVal: "42", Valid: true}, {StringVal: "6", Valid: true}}, bitReverse(6)}},
+					vals: []interface{}{[]spanner.NullString{{StringVal: "42", Valid: true}, {StringVal: "6", Valid: true}}, fmt.Sprintf("%d", bitReverse(6))}},
 			},
 		},
 	}
@@ -876,7 +876,7 @@ func TestProcessMySQLDump_AddPrimaryKeys(t *testing.T) {
 						"productid": ddl.ColumnDef{Name: "productid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"userid":    ddl.ColumnDef{Name: "userid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"quantity":  ddl.ColumnDef{Name: "quantity", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}}}},
 		},
@@ -891,7 +891,7 @@ func TestProcessMySQLDump_AddPrimaryKeys(t *testing.T) {
 						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"synth_id0": ddl.ColumnDef{Name: "synth_id0", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"synth_id1": ddl.ColumnDef{Name: "synth_id1", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id2": ddl.ColumnDef{Name: "synth_id2", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id2": ddl.ColumnDef{Name: "synth_id2", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id2"}}}},
 		},
diff --git a/sources/oracle/data_test.go b/sources/oracle/data_test.go
index 6739013..ebb8f02 100644
--- a/sources/oracle/data_test.go
+++ b/sources/oracle/data_test.go
@@ -132,14 +132,14 @@ func TestConvertsyntheticPKey(t *testing.T) {
 			cols:  []string{"a", "b", "c"},
 			vals:  []string{"6", "6.6", "t"},
 			ecols: []string{"a", "b", "c", "synth_id"},
-			evals: []interface{}{int64(6), float64(6.6), "t", int64(0)},
+			evals: []interface{}{int64(6), float64(6.6), "t", "0"},
 		},
 		{
 			name:  "Sequence 1",
 			cols:  []string{"a"},
 			vals:  []string{"7"},
 			ecols: []string{"a", "synth_id"},
-			evals: []interface{}{int64(7), int64(bits.Reverse64(1))},
+			evals: []interface{}{int64(7), fmt.Sprintf("%d", int64(bits.Reverse64(1)))},
 		},
 	}
 	tableName := "testtable"
diff --git a/sources/postgres/data_test.go b/sources/postgres/data_test.go
index 89d5673..9b9718d 100644
--- a/sources/postgres/data_test.go
+++ b/sources/postgres/data_test.go
@@ -258,14 +258,14 @@ func TestConvertData(t *testing.T) {
 			cols:  []string{"a", "b", "c"},
 			vals:  []string{"6", "6.6", "true"},
 			ecols: []string{"a", "b", "c", "synth_id"},
-			evals: []interface{}{int64(6), float64(6.6), true, int64(0)},
+			evals: []interface{}{int64(6), float64(6.6), true, "0"},
 		},
 		{
 			name:  "Sequence 1",
 			cols:  []string{"a"},
 			vals:  []string{"7"},
 			ecols: []string{"a", "synth_id"},
-			evals: []interface{}{int64(7), int64(bits.Reverse64(1))},
+			evals: []interface{}{int64(7), fmt.Sprintf("%d", int64(bits.Reverse64(1)))},
 		},
 	}
 	conv := buildConv(spTable, srcTable)
diff --git a/sources/postgres/infoschema_test.go b/sources/postgres/infoschema_test.go
index 66459f6..cf79fdd 100644
--- a/sources/postgres/infoschema_test.go
+++ b/sources/postgres/infoschema_test.go
@@ -467,8 +467,8 @@ func TestConvertSqlRow_MultiCol(t *testing.T) {
 		})
 	common.ProcessData(conv, InfoSchemaImpl{db})
 	assert.Equal(t, []spannerData{
-		{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"cat", float64(42.3), int64(0)}},
-		{table: "test", cols: []string{"a", "c", "synth_id"}, vals: []interface{}{"dog", int64(22), int64(-9223372036854775808)}}},
+		{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"cat", float64(42.3), "0"}},
+		{table: "test", cols: []string{"a", "c", "synth_id"}, vals: []interface{}{"dog", int64(22), "-9223372036854775808"}}},
 		rows)
 	assert.Equal(t, int64(0), conv.Unexpecteds())
 }
diff --git a/sources/postgres/pgdump_test.go b/sources/postgres/pgdump_test.go
index 38ec38b..f0aceb4 100644
--- a/sources/postgres/pgdump_test.go
+++ b/sources/postgres/pgdump_test.go
@@ -131,7 +131,7 @@ func TestProcessPgDump(t *testing.T) {
 						"productid": ddl.ColumnDef{Name: "productid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"userid":    ddl.ColumnDef{Name: "userid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
 						"quantity":  ddl.ColumnDef{Name: "quantity", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}}}},
 		},
@@ -181,7 +181,7 @@ func TestProcessPgDump(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}},
@@ -207,7 +207,7 @@ func TestProcessPgDump(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}},
@@ -234,7 +234,7 @@ func TestProcessPgDump(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"c", "d"}, ReferTable: "test", ReferColumns: []string{"a", "b"}}},
@@ -271,7 +271,7 @@ func TestProcessPgDump(t *testing.T) {
 						"e":        ddl.ColumnDef{Name: "e", T: ddl.Type{Name: ddl.Int64}},
 						"f":        ddl.ColumnDef{Name: "f", T: ddl.Type{Name: ddl.Int64}},
 						"g":        ddl.ColumnDef{Name: "g", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"e"}, ReferTable: "test", ReferColumns: []string{"a"}},
@@ -293,7 +293,7 @@ func TestProcessPgDump(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: false}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -314,7 +314,7 @@ func TestProcessPgDump(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: true}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -487,10 +487,10 @@ func TestProcessPgDump(t *testing.T) {
 				"a3	b	7\n" +
 				"\\.\n",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a1", "b1", int64(42), bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a22", "b99", int64(6), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a33", "b", int64(9), bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), bitReverse(3)}}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a1", "b1", int64(42), fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a22", "b99", int64(6), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a33", "b", int64(9), fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), fmt.Sprintf("%d", bitReverse(3))}}},
 		},
 		{
 			name: "COPY FROM with empty cols",
@@ -502,10 +502,10 @@ func TestProcessPgDump(t *testing.T) {
 				"a3	b	7\n" +
 				"\\.\n",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"b", "n", "synth_id"}, vals: []interface{}{"b1", int64(42), bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "n", "synth_id"}, vals: []interface{}{"a22", int64(6), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"a33", "b", bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), bitReverse(3)}}},
+				spannerData{table: "test", cols: []string{"b", "n", "synth_id"}, vals: []interface{}{"b1", int64(42), fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "n", "synth_id"}, vals: []interface{}{"a22", int64(6), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"a33", "b", fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), fmt.Sprintf("%d", bitReverse(3))}}},
 		},
 		{
 			name: "INSERT",
@@ -538,7 +538,7 @@ func TestProcessPgDump(t *testing.T) {
 			input: "CREATE TABLE test (a text NOT NULL, b text NOT NULL, n bigint);\n" +
 				"INSERT INTO test (a, b, n) VALUES ('a42', 'b6', 2);",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a42", "b6", int64(2), bitReverse(0)}}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a42", "b6", int64(2), fmt.Sprintf("%d", bitReverse(0))}}},
 		},
 		{
 			name: "INSERT with spaces",
@@ -690,15 +690,15 @@ COPY test (id, a, b, c, d, e, f, g) FROM stdin;
 					vals: []interface{}{int64(7), float64(42.1), true, getTime(t, "2019-10-29T05:30:00Z"),
 						getDate("2019-10-29"), []byte{0x0, 0x1, 0xbe, 0xef},
 						[]spanner.NullInt64{{Int64: 42, Valid: true}, {Int64: 6, Valid: true}},
-						bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"int8", "synth_id"}, vals: []interface{}{int64(7), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"float8", "synth_id"}, vals: []interface{}{float64(42.1), bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"bool", "synth_id"}, vals: []interface{}{true, bitReverse(3)}},
-				spannerData{table: "test", cols: []string{"timestamp", "synth_id"}, vals: []interface{}{getTime(t, "2019-10-29T05:30:00Z"), bitReverse(4)}},
-				spannerData{table: "test", cols: []string{"date", "synth_id"}, vals: []interface{}{getDate("2019-10-29"), bitReverse(5)}},
-				spannerData{table: "test", cols: []string{"bytea", "synth_id"}, vals: []interface{}{[]byte{0x0, 0x1, 0xbe, 0xef}, bitReverse(6)}},
+						fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"int8", "synth_id"}, vals: []interface{}{int64(7), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"float8", "synth_id"}, vals: []interface{}{float64(42.1), fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"bool", "synth_id"}, vals: []interface{}{true, fmt.Sprintf("%d", bitReverse(3))}},
+				spannerData{table: "test", cols: []string{"timestamp", "synth_id"}, vals: []interface{}{getTime(t, "2019-10-29T05:30:00Z"), fmt.Sprintf("%d", bitReverse(4))}},
+				spannerData{table: "test", cols: []string{"date", "synth_id"}, vals: []interface{}{getDate("2019-10-29"), fmt.Sprintf("%d", bitReverse(5))}},
+				spannerData{table: "test", cols: []string{"bytea", "synth_id"}, vals: []interface{}{[]byte{0x0, 0x1, 0xbe, 0xef}, fmt.Sprintf("%d", bitReverse(6))}},
 				spannerData{table: "test", cols: []string{"arr", "synth_id"},
-					vals: []interface{}{[]spanner.NullInt64{{Int64: 42, Valid: true}, {Int64: 6, Valid: true}}, bitReverse(7)}},
+					vals: []interface{}{[]spanner.NullInt64{{Int64: 42, Valid: true}, {Int64: 6, Valid: true}}, fmt.Sprintf("%d", bitReverse(7))}},
 			},
 		},
 	}
@@ -799,7 +799,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 						"productid": ddl.ColumnDef{Name: "productid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"userid":    ddl.ColumnDef{Name: "userid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
 						"quantity":  ddl.ColumnDef{Name: "quantity", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}}}},
 		},
@@ -849,7 +849,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}},
@@ -875,7 +875,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"d"}, ReferTable: "test", ReferColumns: []string{"a"}}},
@@ -902,7 +902,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 					ColDefs: map[string]ddl.ColumnDef{
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.Int64}},
 						"d":        ddl.ColumnDef{Name: "d", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"c", "d"}, ReferTable: "test", ReferColumns: []string{"a", "b"}}},
@@ -939,7 +939,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 						"e":        ddl.ColumnDef{Name: "e", T: ddl.Type{Name: ddl.Int64}},
 						"f":        ddl.ColumnDef{Name: "f", T: ddl.Type{Name: ddl.Int64}},
 						"g":        ddl.ColumnDef{Name: "g", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Fks: []ddl.Foreignkey{ddl.Foreignkey{Name: "fk_test", Columns: []string{"e"}, ReferTable: "test", ReferColumns: []string{"a"}},
@@ -961,7 +961,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: false}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -982,7 +982,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 						"a":        ddl.ColumnDef{Name: "a", T: ddl.Type{Name: ddl.Int64}},
 						"b":        ddl.ColumnDef{Name: "b", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"c":        ddl.ColumnDef{Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
-						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id": ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks:     []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}},
 					Indexes: []ddl.CreateIndex{ddl.CreateIndex{Name: "custom_index", Table: "test", Unique: false, Keys: []ddl.IndexKey{ddl.IndexKey{Col: "b", Desc: true}, ddl.IndexKey{Col: "c", Desc: false}}}}}},
@@ -1155,10 +1155,10 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 				"a3	b	7\n" +
 				"\\.\n",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a1", "b1", int64(42), bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a22", "b99", int64(6), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a33", "b", int64(9), bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), bitReverse(3)}}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a1", "b1", int64(42), fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a22", "b99", int64(6), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a33", "b", int64(9), fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), fmt.Sprintf("%d", bitReverse(3))}}},
 		},
 		{
 			name: "COPY FROM with empty cols",
@@ -1170,10 +1170,10 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 				"a3	b	7\n" +
 				"\\.\n",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"b", "n", "synth_id"}, vals: []interface{}{"b1", int64(42), bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"a", "n", "synth_id"}, vals: []interface{}{"a22", int64(6), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"a33", "b", bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), bitReverse(3)}}},
+				spannerData{table: "test", cols: []string{"b", "n", "synth_id"}, vals: []interface{}{"b1", int64(42), fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"a", "n", "synth_id"}, vals: []interface{}{"a22", int64(6), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"a", "b", "synth_id"}, vals: []interface{}{"a33", "b", fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a3", "b", int64(7), fmt.Sprintf("%d", bitReverse(3))}}},
 		},
 		{
 			name: "INSERT",
@@ -1206,7 +1206,7 @@ func TestProcessPgDumpPGTarget(t *testing.T) {
 			input: "CREATE TABLE test (a text NOT NULL, b text NOT NULL, n bigint);\n" +
 				"INSERT INTO test (a, b, n) VALUES ('a42', 'b6', 2);",
 			expectedData: []spannerData{
-				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a42", "b6", int64(2), bitReverse(0)}}},
+				spannerData{table: "test", cols: []string{"a", "b", "n", "synth_id"}, vals: []interface{}{"a42", "b6", int64(2), fmt.Sprintf("%d", bitReverse(0))}}},
 		},
 		{
 			name: "INSERT with spaces",
@@ -1358,15 +1358,15 @@ COPY test (id, a, b, c, d, e) FROM stdin;
 					vals: []interface{}{int64(7), float64(42.1), true, getTime(t, "2019-10-29T05:30:00Z"),
 						getDate("2019-10-29"), []byte{0x0, 0x1, 0xbe, 0xef},
 						"{42,6}",
-						bitReverse(0)}},
-				spannerData{table: "test", cols: []string{"int8", "synth_id"}, vals: []interface{}{int64(7), bitReverse(1)}},
-				spannerData{table: "test", cols: []string{"float8", "synth_id"}, vals: []interface{}{float64(42.1), bitReverse(2)}},
-				spannerData{table: "test", cols: []string{"bool", "synth_id"}, vals: []interface{}{true, bitReverse(3)}},
-				spannerData{table: "test", cols: []string{"timestamp", "synth_id"}, vals: []interface{}{getTime(t, "2019-10-29T05:30:00Z"), bitReverse(4)}},
-				spannerData{table: "test", cols: []string{"date", "synth_id"}, vals: []interface{}{getDate("2019-10-29"), bitReverse(5)}},
-				spannerData{table: "test", cols: []string{"bytea", "synth_id"}, vals: []interface{}{[]byte{0x0, 0x1, 0xbe, 0xef}, bitReverse(6)}},
-				spannerData{table: "test", cols: []string{"arr", "synth_id"}, vals: []interface{}{"{42,6}", bitReverse(7)}},
-				spannerData{table: "test", cols: []string{"arr", "synth_id"}, vals: []interface{}{"{42, 6}", bitReverse(8)}},
+						fmt.Sprintf("%d", bitReverse(0))}},
+				spannerData{table: "test", cols: []string{"int8", "synth_id"}, vals: []interface{}{int64(7), fmt.Sprintf("%d", bitReverse(1))}},
+				spannerData{table: "test", cols: []string{"float8", "synth_id"}, vals: []interface{}{float64(42.1), fmt.Sprintf("%d", bitReverse(2))}},
+				spannerData{table: "test", cols: []string{"bool", "synth_id"}, vals: []interface{}{true, fmt.Sprintf("%d", bitReverse(3))}},
+				spannerData{table: "test", cols: []string{"timestamp", "synth_id"}, vals: []interface{}{getTime(t, "2019-10-29T05:30:00Z"), fmt.Sprintf("%d", bitReverse(4))}},
+				spannerData{table: "test", cols: []string{"date", "synth_id"}, vals: []interface{}{getDate("2019-10-29"), fmt.Sprintf("%d", bitReverse(5))}},
+				spannerData{table: "test", cols: []string{"bytea", "synth_id"}, vals: []interface{}{[]byte{0x0, 0x1, 0xbe, 0xef}, fmt.Sprintf("%d", bitReverse(6))}},
+				spannerData{table: "test", cols: []string{"arr", "synth_id"}, vals: []interface{}{"{42,6}", fmt.Sprintf("%d", bitReverse(7))}},
+				spannerData{table: "test", cols: []string{"arr", "synth_id"}, vals: []interface{}{"{42, 6}", fmt.Sprintf("%d", bitReverse(8))}},
 			},
 		},
 	}
@@ -1441,7 +1441,7 @@ func TestProcessPgDump_AddPrimaryKeys(t *testing.T) {
 						"productid": ddl.ColumnDef{Name: "productid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"userid":    ddl.ColumnDef{Name: "userid", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"quantity":  ddl.ColumnDef{Name: "quantity", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id"}}}},
 		},
@@ -1456,7 +1456,7 @@ func TestProcessPgDump_AddPrimaryKeys(t *testing.T) {
 						"synth_id":  ddl.ColumnDef{Name: "synth_id", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"synth_id0": ddl.ColumnDef{Name: "synth_id0", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}},
 						"synth_id1": ddl.ColumnDef{Name: "synth_id1", T: ddl.Type{Name: ddl.Int64}},
-						"synth_id2": ddl.ColumnDef{Name: "synth_id2", T: ddl.Type{Name: ddl.Int64}},
+						"synth_id2": ddl.ColumnDef{Name: "synth_id2", T: ddl.Type{Name: ddl.String, Len: 50}},
 					},
 					Pks: []ddl.IndexKey{ddl.IndexKey{Col: "synth_id2"}}}},
 		},
diff --git a/sources/sqlserver/data_test.go b/sources/sqlserver/data_test.go
index 4e43c9b..f188a52 100644
--- a/sources/sqlserver/data_test.go
+++ b/sources/sqlserver/data_test.go
@@ -237,14 +237,14 @@ func TestConvertsyntheticPKey(t *testing.T) {
 			cols:  []string{"a", "b", "c"},
 			vals:  []string{"6", "6.6", "true"},
 			ecols: []string{"a", "b", "c", "synth_id"},
-			evals: []interface{}{int64(6), float64(6.6), true, int64(0)},
+			evals: []interface{}{int64(6), float64(6.6), true, "0"},
 		},
 		{
 			name:  "Sequence 1",
 			cols:  []string{"a"},
 			vals:  []string{"7"},
 			ecols: []string{"a", "synth_id"},
-			evals: []interface{}{int64(7), int64(bits.Reverse64(1))},
+			evals: []interface{}{int64(7), fmt.Sprintf("%d", int64(bits.Reverse64(1)))},
 		},
 	}
 	tableName := "testtable"