Repository: cloudspannerecosystem/harbourbridge
Pull request #365 (2022-08-17 07:25:02)

Add releaser script and update Makefile
- Adds a releaser script to create new releases for Harbourbridge.
- Updates the Makefile to remove redundant build targets and add relevant ones.


Patch:
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index d018a4c..87b69eb 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -28,6 +28,6 @@ jobs:
           go-version: '^1.13'
       - run: go version
       - run: go vet .
-      - run: go install golang.org/x/tools/cmd/goimports && test -z $(goimports -l .)
-      - run: go install golang.org/x/lint/golint && golint .
+      - run: go get golang.org/x/tools/cmd/goimports && test -z $(goimports -l .)
+      - run: go install golang.org/x/lint/golint@latest && golint .
       - run: go install honnef.co/go/tools/cmd/staticcheck@latest && staticcheck .
diff --git a/.gitignore b/.gitignore
index 44bdf4f..e329760 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ web/harbour_bridge_output/
 harbour_bridge_output/
 *__debug_bin*
 *.code-workspace
+*.log
 
 # angular ui development
 ui/.angular
@@ -11,4 +12,4 @@ ui/dist
 ui/node_modules
 
 # webv2 config
-webv2/config.json
+webv2/config.json
\ No newline at end of file
diff --git a/Makefile b/Makefile
index adb8295..b6a46e7 100644
--- a/Makefile
+++ b/Makefile
@@ -9,26 +9,18 @@ build:
 # Build a static binary
 build-static:
 	go build -a -tags osusergo,netgo -ldflags '-w -extldflags "-static"' -o harbourbridge main.go
-# Build the default binary with vendored dependencies
-build-vendor:
+# Create a new release for Harbourbridge.
+release:
+	./release.sh ${VERSION}
+# Update vendor dependencies
+update-vendor:
 	go mod tidy
-# 	vendor the dependencies
 	go mod vendor
 # 	vendor non-go files
 	go install github.com/goware/modvendor@latest
 	$(GOPATH)/bin/modvendor -copy="**/*.c **/*.h **/*.proto" -v
-# 	build the binary
-	go build
-# Build the static binary with vendored dependencies
-build-static-vendor:
-	go mod tidy
-# 	vendor the dependencies
-	go mod vendor
-# 	vendor non-go files
-	go install github.com/goware/modvendor@latest
-	$(GOPATH)/bin/modvendor -copy="**/*.c **/*.h **/*.proto" -v
-# build the binary
-	go build -a -tags osusergo,netgo -ldflags '-w -extldflags "-static"' -o harbourbridge main.go
+	git add -u
+	git commit -m "Update Vendor files" --no-edit
 # Run unit tests
 test:
 	go test -v ./...
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 7896e7b..dd0c4f5 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -38,7 +38,7 @@ var (
 	sessionFile = "session.json"
 )
 
-const defaultWritersLimit = 40
+const DefaultWritersLimit = 40
 
 // CommandLine provides the core processing for HarbourBridge when run as a command-line tool.
 // It performs the following steps:
@@ -116,7 +116,7 @@ func CommandLine(ctx context.Context, driver, targetDb, dbURI string, dataOnly,
 
 	// We pass an empty string to the sqlConnectionStr parameter as this is the legacy codepath,
 	// which reads the environment variables and constructs the string later on.
-	bw, err := conversion.DataConv(ctx, sourceProfile, targetProfile, ioHelper, client, conv, dataOnly, defaultWritersLimit)
+	bw, err := conversion.DataConv(ctx, sourceProfile, targetProfile, ioHelper, client, conv, dataOnly, DefaultWritersLimit)
 	if err != nil {
 		return fmt.Errorf("can't finish data conversion for db %s: %v", dbURI, err)
 	}
diff --git a/cmd/data.go b/cmd/data.go
index 1fb1917..592016f 100644
--- a/cmd/data.go
+++ b/cmd/data.go
@@ -44,10 +44,10 @@ type DataCmd struct {
 	targetProfile   string
 	sessionJSON     string
 	filePrefix      string // TODO: move filePrefix to global flags
-	writeLimit      int64
+	WriteLimit      int64
 	dryRun          bool
 	logLevel        string
-	skipForeignKeys bool
+	SkipForeignKeys bool
 }
 
 // Name returns the name of operation.
@@ -79,10 +79,10 @@ func (cmd *DataCmd) SetFlags(f *flag.FlagSet) {
 	f.StringVar(&cmd.target, "target", "Spanner", "Specifies the target DB, defaults to Spanner (accepted values: `Spanner`)")
 	f.StringVar(&cmd.targetProfile, "target-profile", "", "Flag for specifying connection profile for target database e.g., \"dialect=postgresql\"")
 	f.StringVar(&cmd.filePrefix, "prefix", "", "File prefix for generated files")
-	f.Int64Var(&cmd.writeLimit, "write-limit", defaultWritersLimit, "Write limit for writes to spanner")
+	f.Int64Var(&cmd.WriteLimit, "write-limit", DefaultWritersLimit, "Write limit for writes to spanner")
 	f.BoolVar(&cmd.dryRun, "dry-run", false, "Flag for generating DDL and schema conversion report without creating a spanner database")
 	f.StringVar(&cmd.logLevel, "log-level", "INFO", "Configure the logging level for the command (INFO, DEBUG), defaults to INFO")
-	f.BoolVar(&cmd.skipForeignKeys, "skip-foreign-keys", false, "Skip creating foreign keys after data migration is complete (ddl statements for foreign keys can still be found in the downloaded schema.ddl.txt file and the same can be applied separately)")
+	f.BoolVar(&cmd.SkipForeignKeys, "skip-foreign-keys", false, "Skip creating foreign keys after data migration is complete (ddl statements for foreign keys can still be found in the downloaded schema.ddl.txt file and the same can be applied separately)")
 }
 
 func (cmd *DataCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
@@ -128,42 +128,19 @@ func (cmd *DataCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface
 	}
 
 	var (
-		dbURI       string
-		adminClient *database.DatabaseAdminClient
-		client      *sp.Client
+		dbURI string
 	)
 	if !cmd.dryRun {
 		now := time.Now()
-		adminClient, client, dbURI, err = CreateDatabaseClient(ctx, targetProfile, sourceProfile.Driver, dbName, ioHelper)
+		bw, err = MigrateDatabase(ctx, targetProfile, sourceProfile, dbName, &ioHelper, cmd, conv)
 		if err != nil {
-			err = fmt.Errorf("can't create database client: %v", err)
+			err = fmt.Errorf("can't finish database migration for db %s: %v", dbName, err)
 			return subcommands.ExitFailure
 		}
-		defer adminClient.Close()
-		defer client.Close()
-		if !sourceProfile.UseTargetSchema() {
-			err = validateExistingDb(ctx, conv.TargetDb, dbURI, adminClient, client, conv)
-			if err != nil {
-				err = fmt.Errorf("error while validating existing database: %v", err)
-				return subcommands.ExitFailure
-			}
-		}
-		bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, &ioHelper, client, conv, true, cmd.writeLimit)
-		if err != nil {
-			err = fmt.Errorf("can't finish data conversion for db %s: %v", dbURI, err)
-			return subcommands.ExitFailure
-		}
-
-		if !cmd.skipForeignKeys {
-			if err = conversion.UpdateDDLForeignKeys(ctx, adminClient, dbURI, conv, ioHelper.Out); err != nil {
-				err = fmt.Errorf("can't perform update schema on db %s with foreign keys: %v", dbURI, err)
-				return subcommands.ExitFailure
-			}
-		}
 		banner = utils.GetBanner(now, dbURI)
 	} else {
 		conv.Audit.DryRun = true
-		bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, &ioHelper, nil, conv, true, cmd.writeLimit)
+		bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, &ioHelper, nil, conv, true, cmd.WriteLimit)
 		if err != nil {
 			err = fmt.Errorf("can't finish data conversion for db %s: %v", dbName, err)
 			return subcommands.ExitFailure
diff --git a/cmd/schema.go b/cmd/schema.go
index 0a85965..d6eb2bc 100644
--- a/cmd/schema.go
+++ b/cmd/schema.go
@@ -22,7 +22,6 @@ import (
 	"path"
 	"time"
 
-	database "cloud.google.com/go/spanner/admin/database/apiv1"
 	"github.com/cloudspannerecosystem/harbourbridge/common/constants"
 	"github.com/cloudspannerecosystem/harbourbridge/common/utils"
 	"github.com/cloudspannerecosystem/harbourbridge/conversion"
@@ -118,22 +117,10 @@ func (cmd *SchemaCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interfa
 	conv.Audit.MigrationRequestId = "HB-" + uuid.New().String()
 	conv.Audit.MigrationType = migration.MigrationData_SCHEMA_ONLY.Enum()
 
-	var (
-		adminClient *database.DatabaseAdminClient
-		dbURI       string
-	)
-
 	if !cmd.dryRun {
-		adminClient, _, dbURI, err = CreateDatabaseClient(ctx, targetProfile, sourceProfile.Driver, dbName, ioHelper)
-		if err != nil {
-			err = fmt.Errorf("can't create database client: %v", err)
-			return subcommands.ExitFailure
-		}
-		defer adminClient.Close()
-
-		err = conversion.CreateOrUpdateDatabase(ctx, adminClient, dbURI, sourceProfile.Driver, targetProfile.TargetDb, conv, ioHelper.Out)
+		_, err = MigrateDatabase(ctx, targetProfile, sourceProfile, dbName, &ioHelper, cmd, conv)
 		if err != nil {
-			err = fmt.Errorf("can't create/update database: %v", err)
+			err = fmt.Errorf("can't finish database migration for db %s: %v", dbName, err)
 			return subcommands.ExitFailure
 		}
 	}
diff --git a/cmd/schema_and_data.go b/cmd/schema_and_data.go
index e5517e6..ffc023a 100644
--- a/cmd/schema_and_data.go
+++ b/cmd/schema_and_data.go
@@ -22,8 +22,6 @@ import (
 	"path"
 	"time"
 
-	sp "cloud.google.com/go/spanner"
-	database "cloud.google.com/go/spanner/admin/database/apiv1"
 	"github.com/cloudspannerecosystem/harbourbridge/common/constants"
 	"github.com/cloudspannerecosystem/harbourbridge/common/utils"
 	"github.com/cloudspannerecosystem/harbourbridge/conversion"
@@ -42,9 +40,9 @@ type SchemaAndDataCmd struct {
 	sourceProfile   string
 	target          string
 	targetProfile   string
-	skipForeignKeys bool
+	SkipForeignKeys bool
 	filePrefix      string // TODO: move filePrefix to global flags
-	writeLimit      int64
+	WriteLimit      int64
 	dryRun          bool
 	logLevel        string
 }
@@ -76,9 +74,9 @@ func (cmd *SchemaAndDataCmd) SetFlags(f *flag.FlagSet) {
 	f.StringVar(&cmd.sourceProfile, "source-profile", "", "Flag for specifying connection profile for source database e.g., \"file=<path>,format=dump\"")
 	f.StringVar(&cmd.target, "target", "Spanner", "Specifies the target DB, defaults to Spanner (accepted values: `Spanner`)")
 	f.StringVar(&cmd.targetProfile, "target-profile", "", "Flag for specifying connection profile for target database e.g., \"dialect=postgresql\"")
-	f.BoolVar(&cmd.skipForeignKeys, "skip-foreign-keys", false, "Skip creating foreign keys after data migration is complete (ddl statements for foreign keys can still be found in the downloaded schema.ddl.txt file and the same can be applied separately)")
+	f.BoolVar(&cmd.SkipForeignKeys, "skip-foreign-keys", false, "Skip creating foreign keys after data migration is complete (ddl statements for foreign keys can still be found in the downloaded schema.ddl.txt file and the same can be applied separately)")
 	f.StringVar(&cmd.filePrefix, "prefix", "", "File prefix for generated files")
-	f.Int64Var(&cmd.writeLimit, "write-limit", defaultWritersLimit, "Write limit for writes to spanner")
+	f.Int64Var(&cmd.WriteLimit, "write-limit", DefaultWritersLimit, "Write limit for writes to spanner")
 	f.BoolVar(&cmd.dryRun, "dry-run", false, "Flag for generating DDL and schema conversion report without creating a spanner database")
 	f.StringVar(&cmd.logLevel, "log-level", "INFO", "Configure the logging level for the command (INFO, DEBUG), defaults to INFO")
 }
@@ -112,12 +110,10 @@ func (cmd *SchemaAndDataCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...
 	}
 
 	var (
-		conv        *internal.Conv
-		bw          *writer.BatchWriter
-		banner      string
-		dbURI       string
-		adminClient *database.DatabaseAdminClient
-		client      *sp.Client
+		conv   *internal.Conv
+		bw     *writer.BatchWriter
+		banner string
+		dbURI  string
 	)
 	conv, err = conversion.SchemaConv(sourceProfile, targetProfile, &ioHelper)
 	if err != nil {
@@ -135,33 +131,11 @@ func (cmd *SchemaAndDataCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...
 
 	if !cmd.dryRun {
 		conversion.Report(sourceProfile.Driver, nil, ioHelper.BytesRead, "", conv, cmd.filePrefix+reportFile, ioHelper.Out)
-		adminClient, client, dbURI, err = CreateDatabaseClient(ctx, targetProfile, sourceProfile.Driver, dbName, ioHelper)
+		bw, err = MigrateDatabase(ctx, targetProfile, sourceProfile, dbName, &ioHelper, cmd, conv)
 		if err != nil {
-			err = fmt.Errorf("can't create database client: %v", err)
+			err = fmt.Errorf("can't finish database migration for db %s: %v", dbName, err)
 			return subcommands.ExitFailure
 		}
-		defer adminClient.Close()
-		defer client.Close()
-
-		err = conversion.CreateOrUpdateDatabase(ctx, adminClient, dbURI, sourceProfile.Driver, targetProfile.TargetDb, conv, ioHelper.Out)
-		if err != nil {
-			err = fmt.Errorf("can't create/update database: %v", err)
-			return subcommands.ExitFailure
-		}
-		schemaCoversionEndTime := time.Now()
-		conv.Audit.SchemaConversionDuration = schemaCoversionEndTime.Sub(schemaConversionStartTime)
-
-		bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, &ioHelper, client, conv, true, cmd.writeLimit)
-		if err != nil {
-			err = fmt.Errorf("can't finish data conversion for db %s: %v", dbURI, err)
-			return subcommands.ExitFailure
-		}
-		if !cmd.skipForeignKeys {
-			if err = conversion.UpdateDDLForeignKeys(ctx, adminClient, dbURI, conv, ioHelper.Out); err != nil {
-				err = fmt.Errorf("can't perform update schema on db %s with foreign keys: %v", dbURI, err)
-				return subcommands.ExitFailure
-			}
-		}
 		dataCoversionEndTime := time.Now()
 		conv.Audit.DataConversionDuration = dataCoversionEndTime.Sub(schemaCoversionEndTime)
 		banner = utils.GetBanner(schemaConversionStartTime, dbURI)
@@ -170,7 +144,7 @@ func (cmd *SchemaAndDataCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...
 		conv.Audit.DryRun = true
 		schemaCoversionEndTime := time.Now()
 		conv.Audit.SchemaConversionDuration = schemaCoversionEndTime.Sub(schemaConversionStartTime)
-		bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, &ioHelper, nil, conv, true, cmd.writeLimit)
+		bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, &ioHelper, nil, conv, true, cmd.WriteLimit)
 		if err != nil {
 			err = fmt.Errorf("can't finish data conversion for db %s: %v", dbName, err)
 			return subcommands.ExitFailure
diff --git a/cmd/utils.go b/cmd/utils.go
index 143de93..ef17178 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -22,7 +22,10 @@ import (
 	sp "cloud.google.com/go/spanner"
 	database "cloud.google.com/go/spanner/admin/database/apiv1"
 	"github.com/cloudspannerecosystem/harbourbridge/common/utils"
+	"github.com/cloudspannerecosystem/harbourbridge/conversion"
+	"github.com/cloudspannerecosystem/harbourbridge/internal"
 	"github.com/cloudspannerecosystem/harbourbridge/profiles"
+	"github.com/cloudspannerecosystem/harbourbridge/spanner/writer"
 )
 
 // CreateDatabaseClient creates new database client and admin client.
@@ -54,20 +57,20 @@ func CreateDatabaseClient(ctx context.Context, targetProfile profiles.TargetProf
 
 // PrepareMigrationPrerequisites creates source and target profiles, opens a new IOStream and generates the database name.
 func PrepareMigrationPrerequisites(sourceProfileString, targetProfileString, source string) (profiles.SourceProfile, profiles.TargetProfile, utils.IOStreams, string, error) {
-	sourceProfile, err := profiles.NewSourceProfile(sourceProfileString, source)
+	targetProfile, err := profiles.NewTargetProfile(targetProfileString)
 	if err != nil {
 		return profiles.SourceProfile{}, profiles.TargetProfile{}, utils.IOStreams{}, "", err
 	}
-	sourceProfile.Driver, err = sourceProfile.ToLegacyDriver(source)
+	targetProfile.TargetDb = targetProfile.ToLegacyTargetDb()
+
+	sourceProfile, err := profiles.NewSourceProfile(sourceProfileString, source)
 	if err != nil {
-		return profiles.SourceProfile{}, profiles.TargetProfile{}, utils.IOStreams{}, "", err
+		return profiles.SourceProfile{}, targetProfile, utils.IOStreams{}, "", err
 	}
-
-	targetProfile, err := profiles.NewTargetProfile(targetProfileString)
+	sourceProfile.Driver, err = sourceProfile.ToLegacyDriver(source)
 	if err != nil {
-		return sourceProfile, profiles.TargetProfile{}, utils.IOStreams{}, "", err
+		return profiles.SourceProfile{}, targetProfile, utils.IOStreams{}, "", err
 	}
-	targetProfile.TargetDb = targetProfile.ToLegacyTargetDb()
 
 	dumpFilePath := ""
 	if sourceProfile.Ty == profiles.SourceProfileTypeFile && (sourceProfile.File.Format == "" || sourceProfile.File.Format == "dump") {
@@ -85,3 +88,86 @@ func PrepareMigrationPrerequisites(sourceProfileString, targetProfileString, sou
 	}
 	return sourceProfile, targetProfile, ioHelper, dbName, nil
 }
+
+// MigrateData creates database and populates data in it.
+func MigrateDatabase(ctx context.Context, targetProfile profiles.TargetProfile, sourceProfile profiles.SourceProfile, dbName string, ioHelper *utils.IOStreams, cmd interface{}, conv *internal.Conv) (*writer.BatchWriter, error) {
+	var bw *writer.BatchWriter
+	adminClient, client, dbURI, err := CreateDatabaseClient(ctx, targetProfile, sourceProfile.Driver, dbName, *ioHelper)
+	if err != nil {
+		err = fmt.Errorf("can't create database client: %v", err)
+		return nil, err
+	}
+	defer adminClient.Close()
+	defer client.Close()
+	switch v := cmd.(type) {
+	case *SchemaCmd:
+		err = migrateSchema(ctx, targetProfile, sourceProfile, ioHelper, conv, dbURI, adminClient)
+	case *DataCmd:
+		bw, err = migrateData(ctx, targetProfile, sourceProfile, ioHelper, conv, dbURI, adminClient, client, v)
+	case *SchemaAndDataCmd:
+		bw, err = migrateSchemaAndData(ctx, targetProfile, sourceProfile, ioHelper, conv, dbURI, adminClient, client, v)
+	}
+	if err != nil {
+		err = fmt.Errorf("can't migrate database: %v", err)
+		return nil, err
+	}
+	return bw, nil
+}
+
+func migrateSchema(ctx context.Context, targetProfile profiles.TargetProfile, sourceProfile profiles.SourceProfile,
+	ioHelper *utils.IOStreams, conv *internal.Conv, dbURI string, adminClient *database.DatabaseAdminClient) error {
+	err := conversion.CreateOrUpdateDatabase(ctx, adminClient, dbURI, sourceProfile.Driver, targetProfile.TargetDb, conv, ioHelper.Out)
+	if err != nil {
+		err = fmt.Errorf("can't create/update database: %v", err)
+		return err
+	}
+	return nil
+}
+
+func migrateData(ctx context.Context, targetProfile profiles.TargetProfile, sourceProfile profiles.SourceProfile,
+	ioHelper *utils.IOStreams, conv *internal.Conv, dbURI string, adminClient *database.DatabaseAdminClient, client *sp.Client, cmd *DataCmd) (*writer.BatchWriter, error) {
+	var (
+		bw  *writer.BatchWriter
+		err error
+	)
+	if !sourceProfile.UseTargetSchema() {
+		err = validateExistingDb(ctx, conv.TargetDb, dbURI, adminClient, client, conv)
+		if err != nil {
+			err = fmt.Errorf("error while validating existing database: %v", err)
+			return nil, err
+		}
+	}
+	bw, err = conversion.DataConv(ctx, sourceProfile, targetProfile, ioHelper, client, conv, true, cmd.WriteLimit)
+	if err != nil {
+		err = fmt.Errorf("can't finish data conversion for db %s: %v", dbURI, err)
+		return nil, err
+	}
+	if !cmd.SkipForeignKeys {
+		if err = conversion.UpdateDDLForeignKeys(ctx, adminClient, dbURI, conv, ioHelper.Out); err != nil {
+			err = fmt.Errorf("can't perform update schema on db %s with foreign keys: %v", dbURI, err)
+			return bw, err
+		}
+	}
+	return bw, nil
+}
+
+func migrateSchemaAndData(ctx context.Context, targetProfile profiles.TargetProfile, sourceProfile profiles.SourceProfile,
+	ioHelper *utils.IOStreams, conv *internal.Conv, dbURI string, adminClient *database.DatabaseAdminClient, client *sp.Client, cmd *SchemaAndDataCmd) (*writer.BatchWriter, error) {
+	err := conversion.CreateOrUpdateDatabase(ctx, adminClient, dbURI, sourceProfile.Driver, targetProfile.TargetDb, conv, ioHelper.Out)
+	if err != nil {
+		err = fmt.Errorf("can't create/update database: %v", err)
+		return nil, err
+	}
+	bw, err := conversion.DataConv(ctx, sourceProfile, targetProfile, ioHelper, client, conv, true, cmd.WriteLimit)
+	if err != nil {
+		err = fmt.Errorf("can't finish data conversion for db %s: %v", dbURI, err)
+		return nil, err
+	}
+	if !cmd.SkipForeignKeys {
+		if err = conversion.UpdateDDLForeignKeys(ctx, adminClient, dbURI, conv, ioHelper.Out); err != nil {
+			err = fmt.Errorf("can't perform update schema on db %s with foreign keys: %v", dbURI, err)
+			return bw, err
+		}
+	}
+	return bw, nil
+}
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/go.mod b/go.mod
index 8f5eb59..6b7123f 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,6 @@ require (
 	github.com/aws/aws-sdk-go v1.35.3
 	github.com/basgys/goxml2json v1.1.0
 	github.com/bitly/go-simplejson v0.5.0 // indirect
-	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
 	github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
 	github.com/cncf/xds/go v0.0.0-20220121163655-4a2b9fdd466b // indirect
 	github.com/denisenkom/go-mssqldb v0.11.0
diff --git a/go.sum b/go.sum
index ddd8a83..4a52ff4 100644
--- a/go.sum
+++ b/go.sum
@@ -84,7 +84,6 @@ github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
 github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
-github.com/Jeffail/gabs/v2 v2.5.1 h1:ANfZYjpMlfTTKebycu4X1AgkVWumFVDYQl7JwOr4mDk=
 github.com/Jeffail/gabs/v2 v2.5.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI=
 github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
 github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
@@ -104,7 +103,6 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
 github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/apache/thrift v0.0.0-20181112125854-24918abba929/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apache/thrift v0.13.1-0.20201008052519-daf620915714 h1:Jz3KVLYY5+JO7rDiX0sAuRGtuv2vG01r17Y9nLMWNUw=
 github.com/apache/thrift v0.13.1-0.20201008052519-daf620915714/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -128,11 +126,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
 github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
 github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ=
 github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/carlmjohnson/flagext v0.21.0 h1:/c4uK3ie786Z7caXLcIMvePNSSiH3bQVGDvmGLMme60=
 github.com/carlmjohnson/flagext v0.21.0/go.mod h1:Eenv0epIUAr4NuedNmkzI8WmBmjIxZC239XcKxYS2ac=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk=
@@ -165,18 +159,13 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20220121163655-4a2b9fdd466b h1:+CVhWLkTEEGdjn4cRvVCk6epN2T8eVyrpE/s1U1Y/Cg=
 github.com/cncf/xds/go v0.0.0-20220121163655-4a2b9fdd466b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
-github.com/cockroachdb/datadriven v1.0.0 h1:uhZrAfEayBecH2w2tZmhe20HJ7hDvrrA4x2Bg9YdZKM=
 github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4=
 github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
 github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM=
-github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y=
 github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
-github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
 github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
 github.com/cockroachdb/pebble v0.0.0-20210719141320-8c3bd06debb5/go.mod h1:JXfQr3d+XO4bL1pxGwKKo09xylQSdZ/mpZ9b2wfVcPs=
-github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
 github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
-github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
 github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
 github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
@@ -229,7 +218,6 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA
 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
-github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
 github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
 github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
@@ -265,15 +253,12 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
 github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
 github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
-github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
 github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
 github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
-github.com/fsouza/fake-gcs-server v1.19.0 h1:XyaGOlqo+R5sjT03x2ymk0xepaQlgwhRLTT2IopW0zA=
 github.com/fsouza/fake-gcs-server v1.19.0/go.mod h1:JtXHY/QzHhtyIxsNfIuQ+XgHtRb5B/w8nqbL5O8zqo0=
 github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
@@ -283,7 +268,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
 github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
 github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
 github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -337,7 +321,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
 github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
 github.com/golang/protobuf v0.0.0-20180814211427-aa810b61a9c7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -431,17 +414,14 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
 github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
 github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -493,12 +473,9 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/joho/sqltocsv v0.0.0-20210428211105-a6d6801d59df h1:Zrb0IbuLOGHL7nrO2WrcuNWgDTlzFv3zY69QMx4ggQE=
 github.com/joho/sqltocsv v0.0.0-20210428211105-a6d6801d59df/go.mod h1:mAVCUAYtW9NG31eB30umMSLKcDt6mCUWSjoSn5qBh0k=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
 github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
-github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -514,7 +491,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
-github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
 github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
 github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
 github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
@@ -572,8 +548,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
 github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
-github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
-github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -582,8 +556,6 @@ github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQ
 github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
-github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
@@ -600,7 +572,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
 github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
 github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
@@ -614,7 +585,6 @@ github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef h1:K0Fn+DoFqNqktdZtdV3
 github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef/go.mod h1:7WjlapSfwQyo6LNmIvEWzsW1hbBQfpUO4JWnuQRmva8=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
@@ -622,14 +592,11 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
 github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
 github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
-github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
 github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
 github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
 github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@@ -659,7 +626,6 @@ github.com/pingcap/errors v0.11.5-0.20211224045212-9687c2b0f87c/go.mod h1:X2r9ue
 github.com/pingcap/failpoint v0.0.0-20210918120811-547c13e3eb00/go.mod h1:4qGtCB0QK0wBzKtFEGDhxXnSnbQApw1gc9siScUl8ew=
 github.com/pingcap/failpoint v0.0.0-20220303073211-00fea37feb66 h1:v+/0tBl7umw+ZxfTeAId/R9pmb8fn2MqsrTHAs8qFAk=
 github.com/pingcap/failpoint v0.0.0-20220303073211-00fea37feb66/go.mod h1:4qGtCB0QK0wBzKtFEGDhxXnSnbQApw1gc9siScUl8ew=
-github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059 h1:Pe2LbxRmbTfAoKJ65bZLmhahmvHm7n9DUxGRQT00208=
 github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059/go.mod h1:fMRU1BA1y+r89AxUoaAar4JjrhUkVDt0o0Np6V8XbDQ=
 github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989 h1:surzm05a8C9dN8dIUmo4Be2+pMRb6f55i+UIYrluu2E=
 github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw=
@@ -743,11 +709,9 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA=
 github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA=
-github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
 github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
 github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU=
 github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
 github.com/sijms/go-ora/v2 v2.2.17 h1:7w1lkgxorhhx/xG5fS/hWhLqBw9BrSFxTvx9oBj0Z0E=
 github.com/sijms/go-ora/v2 v2.2.17/go.mod h1:jzfAFD+4CXHE+LjGWFl6cPrtiIpQVxakI2gvrMF2w6Y=
@@ -755,12 +719,10 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
 github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -788,7 +750,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2 h1:mbAskLJ0oJfDRtkanvQPiooDH8HvJ2FBh+iKT/OmiQQ=
 github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2/go.mod h1:2PfKggNGDuadAa0LElHrByyrz4JPZ9fFx6Gs7nx7ZZU=
 github.com/tikv/client-go/v2 v2.0.1-0.20220406091203-f73ec0e675f4 h1:bi/tuV42dQCu7TTTOwHQW6cHVrV1fhet+Hzo5CUODBQ=
 github.com/tikv/client-go/v2 v2.0.1-0.20220406091203-f73ec0e675f4/go.mod h1:0scaG+seu7L56apm+Gjz9vckyO7ABIzM6T7n00mrIXs=
@@ -799,7 +760,6 @@ github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ
 github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
 github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/twmb/murmur3 v1.1.3 h1:D83U0XYKcHRYwYIpBKf3Pks91Z0Byda/9SJ8B6EMRcA=
 github.com/twmb/murmur3 v1.1.3/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
@@ -821,13 +781,10 @@ github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xitongsys/parquet-go v1.5.1/go.mod h1:xUxwM8ELydxh4edHGegYq1pA8NnMKDx0K/GyB0o2bww=
-github.com/xitongsys/parquet-go v1.5.5-0.20201110004701-b09c49d6d457 h1:tBbuFCtyJNKT+BFAv6qjvTFpVdy97IYNaBwGUXifIUs=
 github.com/xitongsys/parquet-go v1.5.5-0.20201110004701-b09c49d6d457/go.mod h1:pheqtXeHQFzxJk45lRQ0UIGIivKnLXvialZSFWs81A8=
 github.com/xitongsys/parquet-go-source v0.0.0-20190524061010-2b72cbee77d5/go.mod h1:xxCx7Wpym/3QCo6JhujJX51dzSXrwmb0oH6FQb39SEA=
-github.com/xitongsys/parquet-go-source v0.0.0-20200817004010-026bad9b25d0 h1:a742S4V5A15F93smuVxA60LQWsrCnN8bKeWDBARU1/k=
 github.com/xitongsys/parquet-go-source v0.0.0-20200817004010-026bad9b25d0/go.mod h1:HYhIKsdns7xz80OgkbgJYrtQY7FjHWHKH6cvN7+czGE=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
@@ -843,24 +800,18 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
 github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
 github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
 go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
 go.etcd.io/etcd/api/v3 v3.5.2 h1:tXok5yLlKyuQ/SXSjtqHc4uzNaMqZi2XsoSPr/LlJXI=
 go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
 go.etcd.io/etcd/client/pkg/v3 v3.5.2 h1:4hzqQ6hIb3blLyQ8usCU4h3NghkqcsohEQ3o3VetYxE=
 go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/v2 v2.305.2 h1:ymrVwTkefuqA/rPkSW7/B4ApijbPVefRumkY+stNfS0=
 go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI=
 go.etcd.io/etcd/client/v3 v3.5.2 h1:WdnejrUtQC4nCxK0/dLTMqKOB+U5TP/2Ya0BJL+1otA=
 go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
 go.etcd.io/etcd/etcdutl/v3 v3.5.2/go.mod h1:f+KEUNxRzqQGq1Y/SsaDN5cmlOGRWgfE3lXEDi5F1Ys=
-go.etcd.io/etcd/pkg/v3 v3.5.2 h1:YZUojdoPhOyl5QILYnR8LTUbbNefu/sV4ma+ZMr2tto=
 go.etcd.io/etcd/pkg/v3 v3.5.2/go.mod h1:zsXz+9D/kijzRiG/UnFGDTyHKcVp0orwiO8iMLAi+k0=
-go.etcd.io/etcd/raft/v3 v3.5.2 h1:uCC37qOXqBvKqTGHGyhASsaCsnTuJugl1GvneJNwHWo=
 go.etcd.io/etcd/raft/v3 v3.5.2/go.mod h1:G6pCP1sFgbjod7/KnEHY0vHUViqxjkdt6AiKsD0GRr8=
-go.etcd.io/etcd/server/v3 v3.5.2 h1:B6ytJvS4Fmt8nkjzS2/8POf4tuPhFMluE0lWd4dx/7U=
 go.etcd.io/etcd/server/v3 v3.5.2/go.mod h1:mlG8znIEz4N/28GABrohZCBM11FqgGVQcpbcyJgh0j0=
-go.etcd.io/etcd/tests/v3 v3.5.2 h1:uk7/uMGVebpBDl+roivowHt6gJ5Fnqwik3syDkoSKdo=
 go.etcd.io/etcd/tests/v3 v3.5.2/go.mod h1:Jdzbei4uFi9C3xDBfCwckRXjlX0UPooiP4g/zXgBMgQ=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -870,27 +821,16 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
 go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
-go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g=
 go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
-go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
 go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
-go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8=
 go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
-go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw=
 go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
-go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8=
 go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
-go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g=
 go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
-go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8=
 go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
-go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
 go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
-go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -938,7 +878,6 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -955,7 +894,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20200513190911-00229845015e h1:rMqLP+9XLy+LdbCXHjJHAmTfXCr93W7oruWA6Hq1Alc=
 golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@@ -971,7 +909,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -986,7 +923,6 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
 golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1265,9 +1201,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
-gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
 gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
-gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
 gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -1468,7 +1402,6 @@ gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3M
 gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -1495,7 +1428,6 @@ modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=
 modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
 modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
-modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
 modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
 modernc.org/parser v1.0.0/go.mod h1:H20AntYJ2cHHL6MHthJ8LZzXCdDCHMWt1KZXtIMjejA=
 modernc.org/parser v1.0.2/go.mod h1:TXNq3HABP3HMaqLK7brD1fLA/LfN0KS6JxZn71QdDqs=
@@ -1508,9 +1440,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
-sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 h1:e1sMhtVq9AfcEy8AXNb8eSg6gbzfdpYhoNqnPJa+GzI=
 sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
diff --git a/internal/convert.go b/internal/convert.go
index 7ed555c..a00092b 100644
--- a/internal/convert.go
+++ b/internal/convert.go
@@ -146,8 +146,8 @@ type statementStat struct {
 // Stores the audit information of conversion.
 // Elements that do not affect the migration functionality but are relevant for the migration metadata.
 type Audit struct {
-	ToSpannerFkIdx           map[string]FkeyAndIdxs                 `json:"-"` // Maps from source-DB table name to Spanner names for table name, foreign key and indexes.
-	ToSourceFkIdx            map[string]FkeyAndIdxs                 `json:"-"` // Maps from Spanner table name to source-DB names for table name, foreign key and indexes.
+	ToSpannerFkIdx           map[string]FkeyAndIdxs                 // Maps from source-DB table name to Spanner names for table name, foreign key and indexes.
+	ToSourceFkIdx            map[string]FkeyAndIdxs                 // Maps from Spanner table name to source-DB names for table name, foreign key and indexes.
 	SchemaConversionDuration time.Duration                          `json:"-"` // Duration of schema conversion.
 	DataConversionDuration   time.Duration                          `json:"-"` // Duration of data conversion.
 	MigrationRequestId       string                                 `json:"-"` // Unique request id generated per migration
@@ -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/internal/mapping.go b/internal/mapping.go
index 48ff178..7035b33 100644
--- a/internal/mapping.go
+++ b/internal/mapping.go
@@ -219,14 +219,17 @@ func resolveFks(conv *Conv, table string, fks []ddl.Foreignkey) []ddl.Foreignkey
 		var err error
 		if fk.Columns, err = resolveColRefs(conv, table, fk.Columns); err != nil {
 			conv.Unexpected(fmt.Sprintf("Can't resolve Columns in foreign key constraint: %s", err))
+			delete(conv.UsedNames, fk.Name)
 			continue
 		}
 		if fk.ReferTable, err = resolveTableRef(conv, fk.ReferTable); err != nil {
 			conv.Unexpected(fmt.Sprintf("Can't resolve ReferTable in foreign key constraint: %s", err))
+			delete(conv.UsedNames, fk.Name)
 			continue
 		}
 		if fk.ReferColumns, err = resolveColRefs(conv, fk.ReferTable, fk.ReferColumns); err != nil {
 			conv.Unexpected(fmt.Sprintf("Can't resolve ReferColumns in foreign key constraint: %s", err))
+			delete(conv.UsedNames, fk.Name)
 			continue
 		}
 		resolved = append(resolved, fk)
diff --git a/internal/report.go b/internal/report.go
index a33a045..23311cf 100644
--- a/internal/report.go
+++ b/internal/report.go
@@ -246,7 +246,9 @@ func AnalyzeTables(conv *Conv, badWrites map[string]int64) (r []tableReport) {
 	}
 	sort.Strings(tables)
 	for _, srcTable := range tables {
-		r = append(r, buildTableReport(conv, srcTable, badWrites))
+		if _, isPresent := conv.ToSpanner[srcTable]; isPresent {
+			r = append(r, buildTableReport(conv, srcTable, badWrites))
+		}
 	}
 	return r
 }
diff --git a/release.sh b/release.sh
new file mode 100755
index 0000000..1eeb03a
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+set -e
+
+if [ $# -eq 0 ]
+then
+	echo "No version supplied. Run \`make release VERSION=X.X\`"
+	exit 1
+fi
+
+version=$1
+
+if ! echo $version | grep -Eq "^[0-9]+\.[0-9]+\.[0-9]+$"
+then
+	echo "Invalid version: ${version}"
+	echo "Please specify a semantic version with no prefix (e.g. X.X.X)."
+	exit 1
+fi
+echo "Version is semantically valid, please ensure that it is the next version as per SemVer..."
+
+echo "Verifying that all tests pass..."
+make test
+
+echo "Verifying that harbourbrige binary can be built..."
+make build-static
+
+echo "Creating Github tag v${version}"
+git tag "v${version}"
+git push origin "v${version}"
+echo "Github tag v${version} created"
+
+echo "Create a new release by visiting https://github.com/cloudspannerecosystem/harbourbridge/releases/new?tag=v${version}&title=v${version}"
\ No newline at end of file
diff --git a/sources/common/toddl.go b/sources/common/toddl.go
index f6850f1..2dffae0 100644
--- a/sources/common/toddl.go
+++ b/sources/common/toddl.go
@@ -52,58 +52,63 @@ type ToDdl interface {
 // the Spanner schema to conv.SpSchema.
 func SchemaToSpannerDDL(conv *internal.Conv, toddl ToDdl) error {
 	for _, srcTable := range conv.SrcSchema {
-		spTableName, err := internal.GetSpannerTable(conv, srcTable.Name)
+		SchemaToSpannerDDLHelper(conv, toddl, srcTable, false)
+	}
+	internal.ResolveRefs(conv)
+	return nil
+}
+
+func SchemaToSpannerDDLHelper(conv *internal.Conv, toddl ToDdl, srcTable schema.Table, isRestore bool) error {
+	spTableName, err := internal.GetSpannerTable(conv, srcTable.Name)
+	if err != nil {
+		conv.Unexpected(fmt.Sprintf("Couldn't map source table %s to Spanner: %s", srcTable.Name, err))
+		return err
+	}
+	var spColNames []string
+	spColDef := make(map[string]ddl.ColumnDef)
+	conv.Issues[srcTable.Name] = make(map[string][]internal.SchemaIssue)
+	// Iterate over columns using ColNames order.
+	for _, srcColName := range srcTable.ColNames {
+		srcCol := srcTable.ColDefs[srcColName]
+		colName, err := internal.GetSpannerCol(conv, srcTable.Name, srcCol.Name, false)
 		if err != nil {
-			conv.Unexpected(fmt.Sprintf("Couldn't map source table %s to Spanner: %s", srcTable.Name, err))
+			conv.Unexpected(fmt.Sprintf("Couldn't map source column %s of table %s to Spanner: %s", srcTable.Name, srcCol.Name, err))
 			continue
 		}
-		var spColNames []string
-		spColDef := make(map[string]ddl.ColumnDef)
-		conv.Issues[srcTable.Name] = make(map[string][]internal.SchemaIssue)
-		// Iterate over columns using ColNames order.
-		for _, srcColName := range srcTable.ColNames {
-			srcCol := srcTable.ColDefs[srcColName]
-			colName, err := internal.GetSpannerCol(conv, srcTable.Name, srcCol.Name, false)
-			if err != nil {
-				conv.Unexpected(fmt.Sprintf("Couldn't map source column %s of table %s to Spanner: %s", srcTable.Name, srcCol.Name, err))
-				continue
-			}
-			spColNames = append(spColNames, colName)
-			ty, issues := toddl.ToSpannerType(conv, srcCol.Type)
-			// TODO(hengfeng): add issues for all elements of srcCol.Ignored.
-			if srcCol.Ignored.ForeignKey {
-				issues = append(issues, internal.ForeignKey)
-			}
-			if srcCol.Name != colName {
-				issues = append(issues, internal.IllegalName)
-			}
-			if srcCol.Ignored.Default {
-				issues = append(issues, internal.DefaultValue)
-			}
-			if srcCol.Ignored.AutoIncrement { //TODO(adibh) - check why this is not there in postgres
-				issues = append(issues, internal.AutoIncrement)
-			}
-			if len(issues) > 0 {
-				conv.Issues[srcTable.Name][srcCol.Name] = issues
-			}
-			spColDef[colName] = ddl.ColumnDef{
-				Name:    colName,
-				T:       ty,
-				NotNull: srcCol.NotNull,
-				Comment: "From: " + quoteIfNeeded(srcCol.Name) + " " + srcCol.Type.Print(),
-			}
+		spColNames = append(spColNames, colName)
+		ty, issues := toddl.ToSpannerType(conv, srcCol.Type)
+		// TODO(hengfeng): add issues for all elements of srcCol.Ignored.
+		if srcCol.Ignored.ForeignKey {
+			issues = append(issues, internal.ForeignKey)
+		}
+		if srcCol.Name != colName {
+			issues = append(issues, internal.IllegalName)
+		}
+		if srcCol.Ignored.Default {
+			issues = append(issues, internal.DefaultValue)
+		}
+		if srcCol.Ignored.AutoIncrement { //TODO(adibh) - check why this is not there in postgres
+			issues = append(issues, internal.AutoIncrement)
+		}
+		if len(issues) > 0 {
+			conv.Issues[srcTable.Name][srcCol.Name] = issues
+		}
+		spColDef[colName] = ddl.ColumnDef{
+			Name:    colName,
+			T:       ty,
+			NotNull: srcCol.NotNull,
+			Comment: "From: " + quoteIfNeeded(srcCol.Name) + " " + srcCol.Type.Print(),
 		}
-		comment := "Spanner schema for source table " + quoteIfNeeded(srcTable.Name)
-		conv.SpSchema[spTableName] = ddl.CreateTable{
-			Name:     spTableName,
-			ColNames: spColNames,
-			ColDefs:  spColDef,
-			Pks:      cvtPrimaryKeys(conv, srcTable.Name, srcTable.PrimaryKeys),
-			Fks:      cvtForeignKeys(conv, spTableName, srcTable.Name, srcTable.ForeignKeys),
-			Indexes:  cvtIndexes(conv, spTableName, srcTable.Name, srcTable.Indexes),
-			Comment:  comment}
 	}
-	internal.ResolveRefs(conv)
+	comment := "Spanner schema for source table " + quoteIfNeeded(srcTable.Name)
+	conv.SpSchema[spTableName] = ddl.CreateTable{
+		Name:     spTableName,
+		ColNames: spColNames,
+		ColDefs:  spColDef,
+		Pks:      cvtPrimaryKeys(conv, srcTable.Name, srcTable.PrimaryKeys),
+		Fks:      cvtForeignKeys(conv, spTableName, srcTable.Name, srcTable.ForeignKeys, isRestore),
+		Indexes:  cvtIndexes(conv, spTableName, srcTable.Name, srcTable.Indexes),
+		Comment:  comment}
 	return nil
 }
 
@@ -130,44 +135,57 @@ func cvtPrimaryKeys(conv *internal.Conv, srcTable string, srcKeys []schema.Key)
 	return spKeys
 }
 
-func cvtForeignKeys(conv *internal.Conv, spTableName string, srcTable string, srcKeys []schema.ForeignKey) []ddl.Foreignkey {
+func cvtForeignKeys(conv *internal.Conv, spTableName string, srcTable string, srcKeys []schema.ForeignKey, isRestore bool) []ddl.Foreignkey {
 	var spKeys []ddl.Foreignkey
 	for _, key := range srcKeys {
-		if len(key.Columns) != len(key.ReferColumns) {
-			conv.Unexpected(fmt.Sprintf("ConvertForeignKeys: columns and referColumns don't have the same lengths: len(columns)=%d, len(referColumns)=%d for source table: %s, referenced table: %s", len(key.Columns), len(key.ReferColumns), srcTable, key.ReferTable))
-			continue
-		}
-		spReferTable, err := internal.GetSpannerTable(conv, key.ReferTable)
+		spKey, err := cvtForeignKeysHelper(conv, spTableName, srcTable, key, isRestore)
 		if err != nil {
-			conv.Unexpected(fmt.Sprintf("Can't map foreign key for source table: %s, referenced table: %s", srcTable, key.ReferTable))
 			continue
 		}
-		var spCols, spReferCols []string
-		for i, col := range key.Columns {
-			spCol, err1 := internal.GetSpannerCol(conv, srcTable, col, false)
-			spReferCol, err2 := internal.GetSpannerCol(conv, key.ReferTable, key.ReferColumns[i], false)
-			if err1 != nil || err2 != nil {
-				conv.Unexpected(fmt.Sprintf("Can't map foreign key for table: %s, referenced table: %s, column: %s", srcTable, key.ReferTable, col))
-				continue
-			}
-			spCols = append(spCols, spCol)
-			spReferCols = append(spReferCols, spReferCol)
-		}
-		spKeyName := internal.ToSpannerForeignKey(conv, key.Name)
-
-		spKey := ddl.Foreignkey{
-			Name:         spKeyName,
-			Columns:      spCols,
-			ReferTable:   spReferTable,
-			ReferColumns: spReferCols}
 		spKeys = append(spKeys, spKey)
-		conv.Audit.ToSpannerFkIdx[srcTable].ForeignKey[key.Name] = spKeyName
-		conv.Audit.ToSourceFkIdx[spTableName].ForeignKey[spKeyName] = key.Name
 	}
-
 	return spKeys
 }
 
+func cvtForeignKeysHelper(conv *internal.Conv, spTableName string, srcTable string, srcKey schema.ForeignKey, isRestore bool) (ddl.Foreignkey, error) {
+	if len(srcKey.Columns) != len(srcKey.ReferColumns) {
+		conv.Unexpected(fmt.Sprintf("ConvertForeignKeys: columns and referColumns don't have the same lengths: len(columns)=%d, len(referColumns)=%d for source table: %s, referenced table: %s", len(srcKey.Columns), len(srcKey.ReferColumns), srcTable, srcKey.ReferTable))
+		return ddl.Foreignkey{}, fmt.Errorf("ConvertForeignKeys: columns and referColumns don't have the same lengths")
+	}
+	_, isPresent := conv.UsedNames[srcKey.ReferTable]
+	if !isPresent && isRestore {
+		return ddl.Foreignkey{}, nil
+	}
+	spReferTable, err := internal.GetSpannerTable(conv, srcKey.ReferTable)
+
+	if err != nil {
+		conv.Unexpected(fmt.Sprintf("Can't map foreign key for source table: %s, referenced table: %s", srcTable, srcKey.ReferTable))
+		return ddl.Foreignkey{}, err
+	}
+	var spCols, spReferCols []string
+	for i, col := range srcKey.Columns {
+		spCol, err1 := internal.GetSpannerCol(conv, srcTable, col, false)
+		spReferCol, err2 := internal.GetSpannerCol(conv, srcKey.ReferTable, srcKey.ReferColumns[i], false)
+		if err1 != nil || err2 != nil {
+			conv.Unexpected(fmt.Sprintf("Can't map foreign key for table: %s, referenced table: %s, column: %s", srcTable, srcKey.ReferTable, col))
+			continue
+		}
+		spCols = append(spCols, spCol)
+		spReferCols = append(spReferCols, spReferCol)
+	}
+	spKeyName := internal.ToSpannerForeignKey(conv, srcKey.Name)
+
+	spKey := ddl.Foreignkey{
+		Name:         spKeyName,
+		Columns:      spCols,
+		ReferTable:   spReferTable,
+		ReferColumns: spReferCols}
+	conv.Audit.ToSpannerFkIdx[srcTable].ForeignKey[srcKey.Name] = spKeyName
+	conv.Audit.ToSourceFkIdx[spTableName].ForeignKey[spKeyName] = srcKey.Name
+
+	return spKey, nil
+}
+
 func cvtIndexes(conv *internal.Conv, spTableName string, srcTable string, srcIndexes []schema.Index) []ddl.CreateIndex {
 	var spIndexes []ddl.CreateIndex
 	for _, srcIndex := range srcIndexes {
@@ -209,3 +227,39 @@ func cvtIndexes(conv *internal.Conv, spTableName string, srcTable string, srcInd
 	}
 	return spIndexes
 }
+
+func SrcTableToSpannerDDL(conv *internal.Conv, toddl ToDdl, srcTable schema.Table) error {
+	err := SchemaToSpannerDDLHelper(conv, toddl, srcTable, true)
+	if err != nil {
+		return err
+	}
+	for srcTableName, sourceTable := range conv.SrcSchema {
+		if _, isPresent := conv.ToSpanner[srcTableName]; !isPresent {
+			continue
+		}
+		spTableName := conv.ToSpanner[srcTableName].Name
+		if _, isPresent := conv.SpSchema[spTableName]; !isPresent {
+			continue
+		}
+		spTable := conv.SpSchema[spTableName]
+		if sourceTable.Name != srcTable.Name {
+			spTable.Fks = cvtForeignKeysForAReferenceTable(conv, spTableName, srcTableName, srcTable.Name, sourceTable.ForeignKeys, spTable.Fks)
+			conv.SpSchema[spTableName] = spTable
+		}
+	}
+	internal.ResolveRefs(conv)
+	return nil
+}
+
+func cvtForeignKeysForAReferenceTable(conv *internal.Conv, spTableName string, srcTable string, referTable string, srcKeys []schema.ForeignKey, spKeys []ddl.Foreignkey) []ddl.Foreignkey {
+	for _, key := range srcKeys {
+		if key.ReferTable == referTable {
+			spKey, err := cvtForeignKeysHelper(conv, spTableName, srcTable, key, true)
+			if err != nil {
+				continue
+			}
+			spKeys = append(spKeys, spKey)
+		}
+	}
+	return spKeys
+}
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/app-routing.module.ts b/ui/src/app/app-routing.module.ts
index 06f7481..aab8250 100644
--- a/ui/src/app/app-routing.module.ts
+++ b/ui/src/app/app-routing.module.ts
@@ -8,7 +8,7 @@ import { LoadSessionComponent } from './components/load-session/load-session.com
 import { SourceSelectionComponent } from './components/source-selection/source-selection.component'
 import { SummaryComponent } from './components/summary/summary.component'
 import { WorkspaceComponent } from './components/workspace/workspace.component'
-
+import { PrepareMigrationComponent } from './components/prepare-migration/prepare-migration.component'
 
 const routes: Routes = [
   {
@@ -46,6 +46,10 @@ const routes: Routes = [
     path: 'instruction',
     component: InstructionComponent,
   },
+  {
+    path: 'prepare-migration',
+    component: PrepareMigrationComponent,
+  },
   {
     path: '**',
     redirectTo : "/",
diff --git a/ui/src/app/app.constants.ts b/ui/src/app/app.constants.ts
index ea40f23..215b82a 100644
--- a/ui/src/app/app.constants.ts
+++ b/ui/src/app/app.constants.ts
@@ -30,3 +30,14 @@ export enum RulesTypes {
   ChangeGlobalDataType = 'globalDatatype',
   AddIndex = 'addIndex',
 }
+
+export enum MigrationModes {
+  schemaOnly = 'Schema',
+  dataOnly = 'Data',
+  schemaAndData = 'Schema And Data',
+}
+
+export enum ObjectDetailNodeType {
+  Table = 'table',
+  Index = 'index',
+}
diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts
index 3f0dcaa..60d6846 100644
--- a/ui/src/app/app.module.ts
+++ b/ui/src/app/app.module.ts
@@ -30,8 +30,10 @@ import { AddIndexFormComponent } from './components/add-index-form/add-index-for
 import { EditGlobalDatatypeFormComponent } from './components/edit-global-datatype-form/edit-global-datatype-form.component'
 import { SidenavViewAssessmentComponent } from './components/sidenav-view-assessment/sidenav-view-assessment.component'
 import { SidenavSaveSessionComponent } from './components/sidenav-save-session/sidenav-save-session.component'
-import { DropIndexDialogComponent } from './components/drop-index-dialog/drop-index-dialog.component'
+import { DropIndexOrTableDialogComponent } from './components/drop-index-or-table-dialog/drop-index-or-table-dialog.component'
 import { DatabaseLoaderComponent } from './components/database-loader/database-loader.component'
+import { PrepareMigrationComponent } from './components/prepare-migration/prepare-migration.component'
+import { TargetDetailsFormComponent } from './components/target-details-form/target-details-form.component'
 
 @NgModule({
   declarations: [
@@ -58,8 +60,10 @@ import { DatabaseLoaderComponent } from './components/database-loader/database-l
     EditGlobalDatatypeFormComponent,
     SidenavViewAssessmentComponent,
     SidenavSaveSessionComponent,
-    DropIndexDialogComponent,
     DatabaseLoaderComponent,
+    DropIndexOrTableDialogComponent,
+    PrepareMigrationComponent,
+    TargetDetailsFormComponent,
   ],
   imports: [
     BrowserModule,
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/drop-index-dialog/drop-index-dialog.component.ts b/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.ts
deleted file mode 100644
index 77ffaba..0000000
--- a/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { Component, Inject, OnInit } from '@angular/core'
-import { FormControl, Validators } from '@angular/forms'
-import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'
-
-@Component({
-  selector: 'app-drop-index-dialog',
-  templateUrl: './drop-index-dialog.component.html',
-  styleUrls: ['./drop-index-dialog.component.scss'],
-})
-export class DropIndexDialogComponent implements OnInit {
-  confirmationInput: FormControl
-  constructor(
-    @Inject(MAT_DIALOG_DATA) public data: string,
-    private dialogRef: MatDialogRef<DropIndexDialogComponent>
-  ) {
-    ;(this.confirmationInput = new FormControl('', [
-      Validators.required,
-      Validators.pattern(`^${data}$`),
-    ])),
-      (dialogRef.disableClose = true)
-  }
-
-  deleteIndex() {
-    this.dialogRef.close('delete')
-  }
-
-  ngOnInit(): void {}
-}
diff --git a/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.html b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.html
similarity index 71%
rename from ui/src/app/components/drop-index-dialog/drop-index-dialog.component.html
rename to ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.html
index 46bb06d..e83ffce 100644
--- a/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.html
+++ b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.html
@@ -1,16 +1,18 @@
 <div mat-dialog-content>
-  <h2>Delete Index ({{ data }})?</h2>
-  <div class="alert-container">
+  <h2>Delete {{ data.type }} ({{ data.name }})?</h2>
+  <div class="alert-container" *ngIf="data.type === 'Index'">
     <mat-icon>warning</mat-icon>
     <span>This operation cannot be undone</span>
   </div>
   <div class="form-container">
     <form>
       <span class="form-custom-label">
-        Confirm deletion by typing the following below: <b>{{ data }}</b>
+        Confirm deletion by typing the following below: <b>{{ data.name }}</b>
       </span>
       <mat-form-field appearance="outline">
-        <mat-label>Index Name</mat-label>
+        <mat-label
+          >{{ data.type == ObjectDetailNodeType.Table ? 'Table' : 'Index' }} Name</mat-label
+        >
         <input matInput type="text" [formControl]="confirmationInput" />
       </mat-form-field>
     </form>
@@ -20,7 +22,7 @@
   <button mat-button color="primary" mat-dialog-close>Cancel</button>
   <button
     mat-button
-    (click)="deleteIndex()"
+    (click)="delete()"
     type="submit"
     color="primary"
     [disabled]="!confirmationInput.valid"
diff --git a/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.scss b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.scss
similarity index 100%
rename from ui/src/app/components/drop-index-dialog/drop-index-dialog.component.scss
rename to ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.scss
diff --git a/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.spec.ts b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.spec.ts
new file mode 100644
index 0000000..cb06df7
--- /dev/null
+++ b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.spec.ts
@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing'
+
+import { DropIndexOrTableDialogComponent } from './drop-index-or-table-dialog.component'
+
+describe('DropIndexOrTableDialogComponent', () => {
+  let component: DropIndexOrTableDialogComponent
+  let fixture: ComponentFixture<DropIndexOrTableDialogComponent>
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [DropIndexOrTableDialogComponent],
+    }).compileComponents()
+  })
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(DropIndexOrTableDialogComponent)
+    component = fixture.componentInstance
+    fixture.detectChanges()
+  })
+
+  it('should create', () => {
+    expect(component).toBeTruthy()
+  })
+})
diff --git a/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.ts b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.ts
new file mode 100644
index 0000000..1f4186b
--- /dev/null
+++ b/ui/src/app/components/drop-index-or-table-dialog/drop-index-or-table-dialog.component.ts
@@ -0,0 +1,30 @@
+import { Component, Inject, OnInit } from '@angular/core'
+import { FormControl, Validators } from '@angular/forms'
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'
+import { ObjectDetailNodeType } from 'src/app/app.constants'
+
+@Component({
+  selector: 'app-drop-index-dialog',
+  templateUrl: './drop-index-or-table-dialog.component.html',
+  styleUrls: ['./drop-index-or-table-dialog.component.scss'],
+})
+export class DropIndexOrTableDialogComponent implements OnInit {
+  ObjectDetailNodeType = ObjectDetailNodeType
+  confirmationInput: FormControl
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: { name: string; type: string },
+    private dialogRef: MatDialogRef<DropIndexOrTableDialogComponent>
+  ) {
+    ;(this.confirmationInput = new FormControl('', [
+      Validators.required,
+      Validators.pattern(`^${data.name}$`),
+    ])),
+      (dialogRef.disableClose = true)
+  }
+
+  delete() {
+    this.dialogRef.close(this.data.type)
+  }
+
+  ngOnInit(): void {}
+}
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..88395c8 100644
--- a/ui/src/app/components/object-detail/object-detail.component.html
+++ b/ui/src/app/components/object-detail/object-detail.component.html
@@ -72,8 +72,32 @@
         <mat-icon>delete</mat-icon>
         <span>DROP INDEX</span>
       </button>
+      <button
+        mat-button
+        color="primary"
+        class="icon drop"
+        (click)="dropTable()"
+        *ngIf="
+          currentObject!.isSpannerNode &&
+          currentObject!.type !== 'indexName' &&
+          !currentObject!.isDeleted
+        "
+      >
+        <mat-icon>delete</mat-icon>
+        <span>DROP TABLE</span>
+      </button>
+      <button
+        mat-button
+        color="primary"
+        class="icon drop"
+        (click)="restoreSpannerTable()"
+        *ngIf="currentObject!.isSpannerNode && currentObject!.isDeleted"
+      >
+        <mat-icon>undo</mat-icon>
+        <span> RESTORE TABLE</span>
+      </button>
     </h3>
-    <div class="interleaved-title" *ngIf="interleaveParentName">
+    <div class="interleaved-title" *ngIf="interleaveParentName && currentObject.isSpannerNode">
       Interleaved:
       <div class="interleave-parent-name">
         {{ interleaveParentName }}
@@ -82,6 +106,7 @@
   </div>
 
   <mat-tab-group
+    [ngClass]="{ 'height-on-edit': isEditMode || isPkEditMode || isFkEditMode }"
     *ngIf="currentObject!.type === 'tableName'"
     (selectedTabChange)="tabChanged($event)"
   >
@@ -96,7 +121,7 @@
             <th mat-header-cell *matHeaderCellDef class="db_name" colspan="6">
               <div class="spanner_edit-button">
                 <span>Spanner</span>
-                <div *ngIf="!isEditMode">
+                <div *ngIf="!isEditMode && !currentObject.isDeleted">
                   <button
                     mat-stroked-button
                     color="primary"
@@ -303,7 +328,7 @@
             <th mat-header-cell *matHeaderCellDef class="db_name" colspan="5">
               <div class="spanner_edit-button">
                 <span>Spanner</span>
-                <div *ngIf="!isPkEditMode">
+                <div *ngIf="!isPkEditMode && !currentObject.isDeleted">
                   <button
                     mat-stroked-button
                     color="primary"
@@ -510,7 +535,15 @@
             <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 &&
+                    !currentObject.isDeleted
+                  "
+                >
                   <button mat-stroked-button color="primary" (click)="toggleFkEdit()">
                     <mat-icon class="edit-icon">edit</mat-icon>
                     EDIT
@@ -652,9 +685,10 @@
     <mat-tab
       label="INTERLEAVE"
       *ngIf="
-        (interleaveStatus.tableInterleaveStatus &&
+        ((interleaveStatus.tableInterleaveStatus &&
           interleaveStatus.tableInterleaveStatus.Possible) ||
-        this.interleaveParentName !== null
+          this.interleaveParentName !== null) &&
+        currentObject.isSpannerNode
       "
     >
       <div class="interleave-tab-container">
@@ -685,7 +719,7 @@
       </div>
     </mat-tab>
 
-    <mat-tab label="SQL">
+    <mat-tab label="SQL" *ngIf="currentObject!.isSpannerNode && !currentObject!.isDeleted">
       <div class="ddl_container">
         <pre><code>{{ddlStmts[currentObject!.name]}}</code></pre>
       </div>
@@ -703,7 +737,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 +851,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-detail/object-detail.component.ts b/ui/src/app/components/object-detail/object-detail.component.ts
index d166483..0ab6e4c 100644
--- a/ui/src/app/components/object-detail/object-detail.component.ts
+++ b/ui/src/app/components/object-detail/object-detail.component.ts
@@ -7,13 +7,13 @@ import { InfodialogComponent } from '../infodialog/infodialog.component'
 import IColumnTabData, { IIndexData } from '../../model/edit-table'
 import { SnackbarService } from 'src/app/services/snackbar/snackbar.service'
 import IFkTabData from 'src/app/model/fk-tab-data'
-import { ObjectExplorerNodeType, StorageKeys } from 'src/app/app.constants'
+import { ObjectDetailNodeType, ObjectExplorerNodeType, StorageKeys } from 'src/app/app.constants'
 import FlatNode from 'src/app/model/schema-object-node'
 import { Subscription, take } from 'rxjs'
 import { MatTabChangeEvent } from '@angular/material/tabs/tab-group'
 import IConv, { ICreateIndex, IPrimaryKey } from 'src/app/model/conv'
-import { DropIndexDialogComponent } from '../drop-index-dialog/drop-index-dialog.component'
 import { ConversionService } from 'src/app/services/conversion/conversion.service'
+import { DropIndexOrTableDialogComponent } from '../drop-index-or-table-dialog/drop-index-or-table-dialog.component'
 
 @Component({
   selector: 'app-object-detail',
@@ -403,7 +403,7 @@ export class ObjectDetailComponent implements OnInit {
   setPkOrder() {
     if (
       this.currentObject &&
-      this.conv.SpSchema[this.currentObject!.name].Pks.length == this.pkData.length
+      this.conv.SpSchema[this.currentObject!.name]?.Pks.length == this.pkData.length
     ) {
       this.pkData.forEach((pk: IColumnTabData, i: number) => {
         if (this.pkData[i].spColName === this.conv.SpSchema[this.currentObject!.name].Pks[i].Col) {
@@ -417,11 +417,11 @@ export class ObjectDetailComponent implements OnInit {
       })
     } else {
       this.pkData.forEach((pk: IColumnTabData, i: number) => {
-        let index = this.conv.SpSchema[this.currentObject!.name].Pks.map(
+        let index = this.conv.SpSchema[this.currentObject!.name]?.Pks.map(
           (item) => item.Col
         ).indexOf(pk.spColName)
         if (index !== -1) {
-          pk.spOrder = this.conv.SpSchema[this.currentObject!.name].Pks[index].Order
+          pk.spOrder = this.conv.SpSchema[this.currentObject!.name]?.Pks[index].Order
         }
       })
     }
@@ -609,7 +609,7 @@ export class ObjectDetailComponent implements OnInit {
   }
 
   checkIsInterleave() {
-    if (this.currentObject) {
+    if (!this.currentObject?.isDeleted && this.currentObject?.isSpannerNode) {
       this.data.getInterleaveConversionForATable(this.currentObject!.name)
     }
   }
@@ -623,7 +623,7 @@ export class ObjectDetailComponent implements OnInit {
     let ddl: string = ''
     if (
       this.currentObject?.type === ObjectExplorerNodeType.Table &&
-      this.ddlStmts[this.currentObject.name].includes(substr)
+      this.ddlStmts[this.currentObject.name]?.includes(substr)
     ) {
       ddl = this.ddlStmts[this.currentObject.name].substring(
         this.ddlStmts[this.currentObject.name].indexOf(substr) + 20
@@ -698,14 +698,14 @@ export class ObjectDetailComponent implements OnInit {
   }
 
   dropIndex() {
-    let openDialog = this.dialog.open(DropIndexDialogComponent, {
+    let openDialog = this.dialog.open(DropIndexOrTableDialogComponent, {
       width: '35vw',
       minWidth: '450px',
       maxWidth: '600px',
-      data: this.currentObject?.name,
+      data: { name: this.currentObject?.name, type: ObjectDetailNodeType.Index },
     })
     openDialog.afterClosed().subscribe((res: string) => {
-      if (res) {
+      if (res === ObjectDetailNodeType.Index) {
         this.data
           .dropIndex(this.currentObject!.parent, this.currentObject!.name)
           .pipe(take(1))
@@ -741,10 +741,48 @@ export class ObjectDetailComponent implements OnInit {
       srcDesc: undefined,
       srcOrder: '',
     })
-
     this.setIndexRows()
   }
 
+  restoreSpannerTable() {
+    let tableId = this.currentObject!.id
+    this.data
+      .restoreTable(tableId)
+      .pipe(take(1))
+      .subscribe((res: string) => {
+        if (res === '') {
+          this.isObjectSelected = false
+        }
+      })
+    this.currentObject = null
+  }
+
+  dropTable() {
+    let openDialog = this.dialog.open(DropIndexOrTableDialogComponent, {
+      width: '35vw',
+      minWidth: '450px',
+      maxWidth: '600px',
+      data: { name: this.currentObject?.name, type: ObjectDetailNodeType.Table },
+    })
+    openDialog.afterClosed().subscribe((res: string) => {
+      if (res === ObjectDetailNodeType.Table) {
+        let tableId = this.currentObject!.id
+        this.data
+          .dropTable(tableId)
+          .pipe(take(1))
+          .subscribe((res: string) => {
+            if (res === '') {
+              this.isObjectSelected = false
+              this.updateSidebar.emit(true)
+            }
+          })
+        this.currentObject = null
+      }
+    })
+  }
+
+  selectedColumnChange(tableName: string) {}
+
   tabChanged(tabChangeEvent: MatTabChangeEvent): void {
     this.currentTabIndex = tabChangeEvent.index
   }
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..fdb6e75 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>
@@ -211,6 +219,14 @@
               >
                 error
               </mat-icon>
+              <mat-icon
+                *ngIf="data.status === 'DARK'"
+                class="icon dark"
+                matTooltip="Deleted"
+                matTooltipPosition="above"
+              >
+                delete
+              </mat-icon>
             </td>
           </ng-container>
           <ng-container matColumnDef="name">
@@ -235,7 +251,11 @@
                 >
               </div>
             </th>
-            <td mat-cell *matCellDef="let data" class="sidebar_link">
+            <td
+              mat-cell
+              *matCellDef="let data"
+              [ngClass]="{ sidebar_link: true, 'gray-out': data.isDeleted }"
+            >
               <button
                 mat-icon-button
                 [style.visibility]="!data.expandable ? 'hidden' : ''"
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..dcf8aa0 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;
   }
@@ -86,22 +87,6 @@
   .icon {
     margin-right: 20px;
   }
-
-  .danger {
-    color: #da4236;
-  }
-
-  .warning {
-    color: #f3b300;
-  }
-
-  .success {
-    color: green;
-  }
-
-  .orange {
-    color: rgb(248, 116, 68);
-  }
 }
 
 .filter-wrapper {
diff --git a/ui/src/app/components/object-explorer/object-explorer.component.ts b/ui/src/app/components/object-explorer/object-explorer.component.ts
index a7f7111..15b2f46 100644
--- a/ui/src/app/components/object-explorer/object-explorer.component.ts
+++ b/ui/src/app/components/object-explorer/object-explorer.component.ts
@@ -39,6 +39,9 @@ export class ObjectExplorerComponent implements OnInit {
       pos: node.pos,
       isSpannerNode: node.isSpannerNode,
       level: level,
+      isDeleted: node.isDeleted ? true : false,
+      id: node.id,
+      parentId: node.parentId,
     }
   }
   treeControl = new FlatTreeControl<FlatNode>(
diff --git a/ui/src/app/components/prepare-migration/prepare-migration.component.html b/ui/src/app/components/prepare-migration/prepare-migration.component.html
new file mode 100644
index 0000000..640b751
--- /dev/null
+++ b/ui/src/app/components/prepare-migration/prepare-migration.component.html
@@ -0,0 +1,81 @@
+<div class="header">
+    <div class="breadcrumb">
+        <a class="breadcrumb_source" mat-button [routerLink]="'/'">Select Source</a>
+        <span>></span>
+        <a class="breadcrumb_workspace" mat-button [routerLink]="'/workspace'">Configure Schema</a>
+        <span>></span>
+        <a class="breadcrumb_prepare_migration" mat-button [routerLink]="'/prepare-migration'">Prepare Migration</a>
+    </div>
+</div>
+<br />
+<div class="body">
+    <div class="definition-container">
+        <h2>Source and destination Database definitions</h2>
+        <div class="summary">
+            <table mat-table [dataSource]="dataSource">
+                <ng-container matColumnDef="Title">
+                    <th mat-header-cell *matHeaderCellDef>Title</th>
+                    <td mat-cell *matCellDef="let element">
+                        <b>{{ element.title }}</b>
+                    </td>
+                </ng-container>
+                <ng-container matColumnDef="Source">
+                    <th mat-header-cell *matHeaderCellDef>Source</th>
+                    <td mat-cell *matCellDef="let element">{{ element.source }}</td>
+                </ng-container>
+                <ng-container matColumnDef="Destination">
+                    <th mat-header-cell *matHeaderCellDef>Destination</th>
+                    <td mat-cell *matCellDef="let element">{{ element.target }}</td>
+                </ng-container>
+                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+            </table>
+        </div>
+    </div>
+    <br />
+    <mat-form-field appearance="outline">
+        <mat-label>Migration Mode:</mat-label>
+        <mat-select [(ngModel)]="selectedMigrationMode">
+            <mat-option *ngFor="let mode of migrationModes" [value]="mode">
+                {{mode}}
+            </mat-option>
+        </mat-select>
+    </mat-form-field>
+
+    <div *ngIf="!(selectedMigrationMode ==='Schema') && isStreamingSupported">
+        <mat-form-field appearance="outline">
+            <mat-label>Migration Type:</mat-label>
+            <mat-select [(ngModel)]="selectedMigrationType">
+                    <mat-option value="bulk">Bulk Migration</mat-option>
+                    <mat-option value="lowdt">Low downtime migration</mat-option>
+            </mat-select>
+        </mat-form-field>
+    </div>
+    <br />
+    <div class="prerequisites">
+        <mat-card>
+            <mat-card-title>Prerequisites</mat-card-title>
+            <mat-card-subtitle>Before we begin, please ensure you have done the following:</mat-card-subtitle>
+            <hr />
+            <div>
+                <p class="point">
+                    <span class="bullet">1</span>
+                    <span>Setup Target details</span><span><button mat-button class="configure"
+                            (click)="openTargetDetailsForm()">
+                            Configure
+                            <mat-icon>edit</mat-icon>
+                        </button></span>
+                </p>
+            </div>
+        </mat-card>
+        <br />
+    </div>
+    <div *ngIf="isTargetDetailSet">
+        <h3>Target Details</h3>
+        <span><b>Target Database:</b>{{ targetDetails.TargetDB }}</span><br />
+        <span><b>Spanner Dialect:</b>{{ targetDetails.Dialect }}</span><br />
+        <span *ngIf="isStreamingCfgSet"><b>Streaming Config:</b>{{ targetDetails.StreamingConfig }}</span><br />
+    </div>
+    <button mat-raised-button type="submit" color="primary" (click)="migrate()" class="migrate"
+        [disabled]="!isTargetDetailSet">Migrate</button>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/components/prepare-migration/prepare-migration.component.scss b/ui/src/app/components/prepare-migration/prepare-migration.component.scss
new file mode 100644
index 0000000..6add83f
--- /dev/null
+++ b/ui/src/app/components/prepare-migration/prepare-migration.component.scss
@@ -0,0 +1,42 @@
+.header {
+  .breadcrumb {
+    .breadcrumb_workspace {
+      color: rgba(0, 0, 0, 0.56);
+    }
+
+    .breadcrumb_prepare_migration {
+      font-weight: 400;
+      font-size: 14px;
+    }
+  }
+}
+
+.definition-container {
+  max-height: 500px;
+  overflow: auto;
+
+  th {
+    font-size: 13px;
+  }
+}
+
+.body {
+  margin-left: 20px;
+}
+
+table {
+  min-width: 30%;
+  max-width: 50%;
+
+  th {
+    width: 10%;
+  }
+}
+
+.configure {
+  color: #1967d2;
+}
+
+.migrate {
+  margin-top: 10px;
+}
\ No newline at end of file
diff --git a/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.spec.ts b/ui/src/app/components/prepare-migration/prepare-migration.component.spec.ts
similarity index 51%
rename from ui/src/app/components/drop-index-dialog/drop-index-dialog.component.spec.ts
rename to ui/src/app/components/prepare-migration/prepare-migration.component.spec.ts
index 050e215..2e4ec07 100644
--- a/ui/src/app/components/drop-index-dialog/drop-index-dialog.component.spec.ts
+++ b/ui/src/app/components/prepare-migration/prepare-migration.component.spec.ts
@@ -1,20 +1,20 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { DropIndexDialogComponent } from './drop-index-dialog.component';
+import { PrepareMigrationComponent } from './prepare-migration.component';
 
-describe('DropIndexDialogComponent', () => {
-  let component: DropIndexDialogComponent;
-  let fixture: ComponentFixture<DropIndexDialogComponent>;
+describe('PrepareMigrationComponent', () => {
+  let component: PrepareMigrationComponent;
+  let fixture: ComponentFixture<PrepareMigrationComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ DropIndexDialogComponent ]
+      declarations: [ PrepareMigrationComponent ]
     })
     .compileComponents();
   });
 
   beforeEach(() => {
-    fixture = TestBed.createComponent(DropIndexDialogComponent);
+    fixture = TestBed.createComponent(PrepareMigrationComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });
diff --git a/ui/src/app/components/prepare-migration/prepare-migration.component.ts b/ui/src/app/components/prepare-migration/prepare-migration.component.ts
new file mode 100644
index 0000000..5bb7908
--- /dev/null
+++ b/ui/src/app/components/prepare-migration/prepare-migration.component.ts
@@ -0,0 +1,105 @@
+import { Component, OnInit } from '@angular/core'
+import { MatDialog } from '@angular/material/dialog'
+import { TargetDetailsFormComponent } from '../target-details-form/target-details-form.component'
+import { TargetDetailsService } from 'src/app/services/target-details/target-details.service'
+import { FetchService } from 'src/app/services/fetch/fetch.service'
+import { SnackbarService } from 'src/app/services/snackbar/snackbar.service'
+import ITargetDetails from 'src/app/model/target-details'
+import { ISessionSummary } from 'src/app/model/conv'
+import IMigrationDetails from 'src/app/model/migrate'
+import { InputType, MigrationModes, SourceDbNames } from 'src/app/app.constants'
+@Component({
+  selector: 'app-prepare-migration',
+  templateUrl: './prepare-migration.component.html',
+  styleUrls: ['./prepare-migration.component.scss'],
+})
+export class PrepareMigrationComponent implements OnInit {
+  displayedColumns = ['Title', 'Source', 'Destination']
+  dataSource: any = []
+  migrationModes: any = []
+  constructor(
+    private dialog: MatDialog,
+    private fetch: FetchService,
+    private snack: SnackbarService,
+    private targetDetailService: TargetDetailsService
+  ) {}
+
+  isTargetDetailSet: boolean = false
+  isStreamingCfgSet: boolean = false
+  isSchemaMigration: boolean = true
+  isStreamingSupported: boolean = false
+  selectedMigrationMode: string = MigrationModes.schemaOnly
+  selectedMigrationType: string = 'bulk'
+  targetDetails: ITargetDetails = this.targetDetailService.getTargetDetails()
+
+  ngOnInit(): void {
+    this.fetch.getSourceDestinationSummary().subscribe({
+      next: (res: ISessionSummary) => {
+        this.dataSource = [
+          { title: 'Database Type', source: res.DatabaseType, target: 'Spanner' },
+          {
+            title: 'Number of tables',
+            source: res.SourceTableCount,
+            target: res.SpannerTableCount,
+          },
+          {
+            title: 'Number of indexes',
+            source: res.SourceIndexCount,
+            target: res.SpannerIndexCount,
+          },
+        ]
+        if (res.ConnectionType == InputType.DumpFile) {
+          this.migrationModes = [MigrationModes.schemaAndData]
+          this.selectedMigrationMode = MigrationModes.schemaAndData
+        } else if (res.ConnectionType == InputType.SessionFile) {
+          this.migrationModes = [MigrationModes.schemaOnly]
+        } else {
+          this.migrationModes = [MigrationModes.schemaOnly, MigrationModes.dataOnly, MigrationModes.schemaAndData]
+        }
+        if (res.DatabaseType == SourceDbNames.MySQL.toLowerCase() || res.DatabaseType == SourceDbNames.Oracle.toLowerCase()) {
+          this.isStreamingSupported = true
+        }
+      },
+      error: (err: any) => {
+         this.snack.openSnackBar(err.error, 'Close')
+      },
+    })
+  }
+
+  openTargetDetailsForm() {
+    let dialogRef = this.dialog.open(TargetDetailsFormComponent, {
+      width: '30vw',
+      minWidth: '400px',
+      maxWidth: '500px',
+      data:this.selectedMigrationType=='lowdt',
+    })
+    dialogRef.afterClosed().subscribe(() => {
+      if (this.targetDetails.TargetDB != '') {
+        this.isTargetDetailSet = true
+      }
+      if (this.targetDetails.StreamingConfig != '') {
+        this.isStreamingCfgSet = true
+      }
+    })
+  }
+
+  migrate() {
+    let payload: IMigrationDetails = {
+      TargetDetails: this.targetDetailService.getTargetDetails(),
+      MigrationType: this.selectedMigrationType,
+      MigrationMode: this.selectedMigrationMode
+    }
+    this.fetch.migrate(payload).subscribe({
+      next: () => {
+        if (this.isStreamingCfgSet) {
+          this.snack.openSnackBar('Migration started successfully', 'Close', 5)
+        } else {
+          this.snack.openSnackBar('Migration completed successfully', 'Close', 5)
+        }
+      },
+      error: (err: any) => {
+        this.snack.openSnackBar(err.error, 'Close')
+      },
+    })
+  }
+}
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 a21984e..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,36 +1,3 @@
 .prerequisites {
   padding: 0 20px;
-  width: 600px;
-  .mat-card-title {
-    font-size: 13pt;
-    font-weight: normal;
-  }
-  .mat-card-subtitle {
-    font-size: 9pt;
-    font-weight: normal;
-  }
-  p {
-    color: #5c5c5c;
-    .bullet {
-      position: absolute;
-      display: inline-block;
-      background-color: #e5e5e5;
-      padding: 0px 5px 10px 5px;
-      margin: 0;
-      border-radius: 10px;
-      font-size: 9px;
-      height: 9px;
-      width: 9px;
-      text-align: center;
-    }
-    span {
-      margin-left: 40px;
-      font-weight: lighter;
-      font-size: 13px;
-    }
-  }
-  hr {
-    border-color: #ffffff;
-    margin-bottom: 20px;
-  }
 }
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/summary/summary.component.ts b/ui/src/app/components/summary/summary.component.ts
index a76a2b2..928febd 100644
--- a/ui/src/app/components/summary/summary.component.ts
+++ b/ui/src/app/components/summary/summary.component.ts
@@ -69,6 +69,9 @@ export class SummaryComponent implements OnInit {
         this.changeIssuesLabel.emit(
           s.NotesCount + s.WarningsCount + s.ErrorsCount + s.SuggestionsCount
         )
+      } else {
+        this.summaryCount = 0
+        this.changeIssuesLabel.emit(0)
       }
     } else {
       this.summaryCount = 0
diff --git a/ui/src/app/components/target-details-form/target-details-form.component.html b/ui/src/app/components/target-details-form/target-details-form.component.html
new file mode 100644
index 0000000..369d8e9
--- /dev/null
+++ b/ui/src/app/components/target-details-form/target-details-form.component.html
@@ -0,0 +1,33 @@
+<div mat-dialog-content>
+    <form [formGroup]="targetDetailsForm" class="target-detail-form">
+        <h2>Target Details</h2>
+    <mat-form-field class="full-width" appearance="outline">
+        <mat-label>Target Database</mat-label>
+        <input matInput placeholder="Target Database" type="text" formControlName="targetDb" />
+      </mat-form-field>
+      <br>
+      <mat-form-field appearance="outline">
+        <mat-label>Target Dialect</mat-label>
+        <mat-select class="input-field" formControlName="dialect" required="true">
+          <mat-option value="google_standard_sql">Google Standard SQL</mat-option>
+        </mat-select>
+      </mat-form-field>
+      <br>
+      <mat-form-field class="full-width" appearance="outline">
+        <mat-label>Streaming config</mat-label>
+        <input matInput placeholder="File path" type="text" formControlName="streamingConfig" />
+      </mat-form-field>
+    </form>
+      <div mat-dialog-actions class="buttons-container">
+        <button mat-button color="primary" mat-dialog-close>Cancel</button>
+        <button
+          mat-button
+          type="submit"
+          color="primary"
+          [disabled]="!(targetDetailsForm.valid)"
+          (click)="updateTargetDetails()"
+        >
+          Save
+        </button>
+      </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/components/target-details-form/target-details-form.component.scss b/ui/src/app/components/target-details-form/target-details-form.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/ui/src/app/components/target-details-form/target-details-form.component.spec.ts b/ui/src/app/components/target-details-form/target-details-form.component.spec.ts
new file mode 100644
index 0000000..47b7beb
--- /dev/null
+++ b/ui/src/app/components/target-details-form/target-details-form.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TargetDetailsFormComponent } from './target-details-form.component';
+
+describe('TargetDetailsFormComponent', () => {
+  let component: TargetDetailsFormComponent;
+  let fixture: ComponentFixture<TargetDetailsFormComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ TargetDetailsFormComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TargetDetailsFormComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/ui/src/app/components/target-details-form/target-details-form.component.ts b/ui/src/app/components/target-details-form/target-details-form.component.ts
new file mode 100644
index 0000000..4276655
--- /dev/null
+++ b/ui/src/app/components/target-details-form/target-details-form.component.ts
@@ -0,0 +1,42 @@
+import { Component, Inject, OnInit } from '@angular/core'
+import { FormBuilder, FormGroup, Validators } from '@angular/forms'
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'
+import ITargetDetails from 'src/app/model/target-details'
+import { TargetDetailsService } from 'src/app/services/target-details/target-details.service'
+
+@Component({
+  selector: 'app-target-details-form',
+  templateUrl: './target-details-form.component.html',
+  styleUrls: ['./target-details-form.component.scss'],
+})
+export class TargetDetailsFormComponent implements OnInit {
+  targetDetailsForm: FormGroup
+  constructor(
+    private formBuilder: FormBuilder,
+    private targetDetailService: TargetDetailsService,
+    private dialogRef: MatDialogRef<TargetDetailsFormComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: boolean
+  ) {
+    this.targetDetailsForm = this.formBuilder.group({
+      targetDb: ['', Validators.required],
+      dialect: ['',Validators.required],
+      streamingConfig: [''],
+    })
+    if (data) {
+      this.targetDetailsForm.get('streamingConfig')?.setValidators(Validators.required)
+    }
+  }
+
+  ngOnInit(): void {}
+
+  updateTargetDetails() {
+    let formValue = this.targetDetailsForm.value
+    let payload: ITargetDetails = {
+      TargetDB: formValue.targetDb,
+      Dialect: formValue.dialect,
+      StreamingConfig: formValue.streamingConfig
+    }
+    this.targetDetailService.updateTargetDetails(payload)
+    this.dialogRef.close()
+  }
+}
\ No newline at end of file
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 c27b243..e951e83 100644
--- a/ui/src/app/components/workspace/workspace.component.html
+++ b/ui/src/app/components/workspace/workspace.component.html
@@ -6,11 +6,12 @@
       <a class="breadcrumb_workspace" mat-button [routerLink]="'/workspace'">Configure Schema</a>
     </div>
     <div class="header_action">
+      <button mat-button (click)="prepareMigration()">PREPARE MIGRATION</button>
       <button mat-button (click)="openAssessment()">VIEW ASSESSMENT</button>
       <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/app/components/workspace/workspace.component.scss b/ui/src/app/components/workspace/workspace.component.scss
index 0cc5d10..b09cfa2 100644
--- a/ui/src/app/components/workspace/workspace.component.scss
+++ b/ui/src/app/components/workspace/workspace.component.scss
@@ -1,38 +1,3 @@
-.header {
-  padding: 0 20px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  border-bottom: 1px solid #cccccc;
-  padding-bottom: 10px;
-  .header_action {
-    button {
-      border: none;
-      background-color: inherit;
-      color: #1967d2;
-      font-size: 0.8rem;
-    }
-  }
-  .breadcrumb {
-    display: flex;
-    align-items: center;
-    .breadcrumb_source {
-      padding-left: 0;
-      color: rgba(0, 0, 0, 0.56);
-      font-weight: 400;
-      font-size: 14px;
-    }
-    .breadcrumb_workspace {
-      font-weight: 400;
-      font-size: 14px;
-    }
-    span {
-      font-size: 1.2rem;
-      color: rgb(143, 143, 143);
-    }
-  }
-}
-
 app-object-detail {
   height: 100%;
 }
diff --git a/ui/src/app/components/workspace/workspace.component.ts b/ui/src/app/components/workspace/workspace.component.ts
index bbc130f..e906b6f 100644
--- a/ui/src/app/components/workspace/workspace.component.ts
+++ b/ui/src/app/components/workspace/workspace.component.ts
@@ -11,6 +11,7 @@ import ISchemaObjectNode, { FlatNode } from 'src/app/model/schema-object-node'
 import { ObjectExplorerNodeType, StorageKeys } from 'src/app/app.constants'
 import { IUpdateTableArgument } from 'src/app/model/update-table'
 import ConversionRate from 'src/app/model/conversion-rate'
+import { Router } from '@angular/router'
 
 @Component({
   selector: 'app-workspace',
@@ -45,7 +46,8 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
     private data: DataService,
     private conversion: ConversionService,
     private dialog: MatDialog,
-    private sidenav: SidenavService
+    private sidenav: SidenavService,
+    private router: Router
   ) {
     this.currentObject = null
   }
@@ -63,6 +65,15 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
 
     this.convObj = this.data.conv.subscribe((data: IConv) => {
       const indexAddedOrRemoved = this.isIndexAddedOrRemoved(data)
+      if (
+        data &&
+        this.conv &&
+        Object.keys(data?.SpSchema).length != Object.keys(this.conv?.SpSchema).length
+      ) {
+        this.conv = data
+        this.reRenderObjectExplorerSpanner()
+        this.reRenderObjectExplorerSrc()
+      }
       this.conv = data
       if (indexAddedOrRemoved && this.conversionRates) this.reRenderObjectExplorerSpanner()
       if (!this.objectExplorerInitiallyRender && this.conversionRates) {
@@ -72,11 +83,11 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
       }
       if (this.currentObject && this.currentObject.type === ObjectExplorerNodeType.Table) {
         this.fkData = this.currentObject
-          ? this.conversion.getFkMapping(this.currentObject.name, data)
+          ? this.conversion.getFkMapping(this.currentObject.id, data)
           : []
 
         this.tableData = this.currentObject
-          ? this.conversion.getColumnMapping(this.currentObject.name, data)
+          ? this.conversion.getColumnMapping(this.currentObject.id, data)
           : []
       }
       if (
@@ -85,9 +96,9 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
         !indexAddedOrRemoved
       ) {
         this.indexData = this.conversion.getIndexMapping(
-          this.currentObject.parent,
+          this.currentObject.parentId,
           this.conv,
-          this.currentObject.name
+          this.currentObject.id
         )
       }
     })
@@ -155,16 +166,16 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
     if (object?.type === ObjectExplorerNodeType.Table) {
       this.currentObject = object
       this.tableData = this.currentObject
-        ? this.conversion.getColumnMapping(this.currentObject.name, this.conv)
+        ? this.conversion.getColumnMapping(this.currentObject.id, this.conv)
         : []
 
       this.fkData = []
       this.fkData = this.currentObject
-        ? this.conversion.getFkMapping(this.currentObject.name, this.conv)
+        ? this.conversion.getFkMapping(this.currentObject.id, this.conv)
         : []
     } else if (object?.type === ObjectExplorerNodeType.Index) {
       this.currentObject = object
-      this.indexData = this.conversion.getIndexMapping(object.parent, this.conv, object.name)
+      this.indexData = this.conversion.getIndexMapping(object.parentId, this.conv, object.id)
     } else {
       this.currentObject = null
     }
@@ -240,4 +251,7 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
     }
     return false
   }
+  prepareMigration() {
+    this.router.navigate(['/prepare-migration'])
+  }
 }
diff --git a/ui/src/app/model/conv.ts b/ui/src/app/model/conv.ts
index 4c735cf..981b4db 100644
--- a/ui/src/app/model/conv.ts
+++ b/ui/src/app/model/conv.ts
@@ -13,6 +13,18 @@ export default interface IConv {
   DatabaseType: string
   DatabaseName: string
   EditorName: string
+  Audit: IAudit
+}
+
+export interface IAudit {
+  ToSpannerFkIdx: Record<string, IFkeyAndIdxs>
+  ToSourceFkIdx: Record<string, IFkeyAndIdxs>
+}
+
+export interface IFkeyAndIdxs {
+  Name: string
+  ForeignKey: Record<string, string>
+  Index: Record<string, string>
 }
 
 export interface IStats {
@@ -31,6 +43,7 @@ export interface NameAndCols {
 // Spanner schema
 export interface ITable {
   Name: string
+  Id: string
   Schema: string
   ColNames: string[]
   ColDefs: Record<string, IColumn>
@@ -44,6 +57,7 @@ export interface IColumn {
   Type: ISpannerType
   NotNull: boolean
   Ignored: IIgnored
+  Id: string
 }
 
 export interface IIgnored {
@@ -65,6 +79,7 @@ export interface IIndex {
   Name: string
   Unique: boolean
   Keys: ISrcIndexKey[]
+  Id: string
 }
 
 export interface ISpannerForeignKey {
@@ -156,3 +171,13 @@ export interface IPkColumnDefs {
   Desc: boolean
   Order: number
 }
+
+export interface ISessionSummary {
+  DatabaseType: string
+  ConnectionDetail: string
+  SourceTableCount: number
+  SpannerTableCount: number
+  SourceIndexCount: number
+  SpannerIndexCount: number
+  ConnectionType: string
+}
diff --git a/ui/src/app/model/migrate.ts b/ui/src/app/model/migrate.ts
new file mode 100644
index 0000000..9f9e9c1
--- /dev/null
+++ b/ui/src/app/model/migrate.ts
@@ -0,0 +1,7 @@
+import ITargetDetails from "./target-details";
+
+export default interface IMigrationDetails {
+    TargetDetails: ITargetDetails
+    MigrationType: string
+    MigrationMode: string
+}
\ No newline at end of file
diff --git a/ui/src/app/model/schema-object-node.ts b/ui/src/app/model/schema-object-node.ts
index f527f1a..373eabd 100644
--- a/ui/src/app/model/schema-object-node.ts
+++ b/ui/src/app/model/schema-object-node.ts
@@ -8,6 +8,9 @@ export default interface ISchemaObjectNode {
   parent: string
   pos: number
   isSpannerNode: boolean
+  isDeleted?: boolean
+  id: string
+  parentId: string
 }
 
 export interface FlatNode {
@@ -19,4 +22,7 @@ export interface FlatNode {
   pos: number
   level: number
   isSpannerNode: boolean
+  isDeleted: boolean
+  id: string
+  parentId: string
 }
diff --git a/ui/src/app/model/target-details.ts b/ui/src/app/model/target-details.ts
new file mode 100644
index 0000000..273f768
--- /dev/null
+++ b/ui/src/app/model/target-details.ts
@@ -0,0 +1,5 @@
+export default interface ITargetDetails {
+    TargetDB: string
+    Dialect: string
+    StreamingConfig:string
+}
\ No newline at end of file
diff --git a/ui/src/app/services/conversion/conversion.service.ts b/ui/src/app/services/conversion/conversion.service.ts
index e9f59dd..1dd2221 100644
--- a/ui/src/app/services/conversion/conversion.service.ts
+++ b/ui/src/app/services/conversion/conversion.service.ts
@@ -20,12 +20,23 @@ export class ConversionService {
     let spannerTableNames = Object.keys(conv.SpSchema).filter((name: string) =>
       name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase())
     )
+    let spannerTableIds = spannerTableNames.map((name: string) => conv.SpSchema[name].Id)
+    let srcTableNames = Object.keys(conv.SrcSchema)
+
+    let deletedTableNames = srcTableNames.filter((srcTableName: string) => {
+      if (spannerTableIds.indexOf(conv.SrcSchema[srcTableName].Id) > -1) {
+        return false
+      }
+      return true
+    })
     let parentNode: ISchemaObjectNode = {
-      name: `Tables (${spannerTableNames.length})`,
+      name: `Tables (${srcTableNames.length})`,
       type: ObjectExplorerNodeType.Tables,
       parent: '',
       pos: -1,
       isSpannerNode: true,
+      id: '',
+      parentId: '',
       children: spannerTableNames.map((name: string) => {
         let spannerTable = conv.SpSchema[name]
         return {
@@ -35,6 +46,8 @@ export class ConversionService {
           parent: '',
           pos: -1,
           isSpannerNode: true,
+          id: spannerTable.Id,
+          parentId: '',
           children: [
             {
               name: `Indexes (${spannerTable.Indexes ? spannerTable.Indexes.length : 0})`,
@@ -43,6 +56,8 @@ export class ConversionService {
               parent: name,
               pos: -1,
               isSpannerNode: true,
+              id: '',
+              parentId: spannerTable.Id,
               children: spannerTable.Indexes
                 ? spannerTable.Indexes.map((index: ICreateIndex, i: number) => {
                     return {
@@ -51,6 +66,8 @@ export class ConversionService {
                       parent: name,
                       pos: i,
                       isSpannerNode: true,
+                      id: index.Id,
+                      parentId: spannerTable.Id,
                     }
                   })
                 : [],
@@ -65,6 +82,20 @@ export class ConversionService {
       parentNode.children?.sort((a, b) => (b.name > a.name ? 1 : a.name > b.name ? -1 : 0))
     }
 
+    deletedTableNames.forEach((tableName: string) => {
+      parentNode.children?.push({
+        name: tableName.replace(/[^A-Za-z0-9_]/g, '_'),
+        status: 'DARK',
+        type: ObjectExplorerNodeType.Table,
+        parent: '',
+        pos: -1,
+        isSpannerNode: true,
+        children: [],
+        isDeleted: true,
+        id: conv.SrcSchema[tableName].Id,
+        parentId: '',
+      })
+    })
     return [
       {
         name: conv.DatabaseName,
@@ -73,6 +104,8 @@ export class ConversionService {
         parent: '',
         pos: -1,
         isSpannerNode: true,
+        id: '',
+        parentId: '',
       },
     ]
   }
@@ -93,16 +126,20 @@ export class ConversionService {
       parent: '',
       pos: -1,
       isSpannerNode: false,
+      id: '',
+      parentId: '',
       children: srcTableNames.map((name: string) => {
         let srcTable = conv.SrcSchema[name]
-        let spname = conv.ToSpanner[name].Name
+        let spname = conv.ToSpanner[name] ? conv.ToSpanner[name].Name : ''
         return {
           name: name,
-          status: conversionRates[spname],
+          status: conversionRates[spname] ? conversionRates[spname] : 'NONE',
           type: ObjectExplorerNodeType.Table,
           parent: '',
           pos: -1,
           isSpannerNode: false,
+          id: srcTable.Id,
+          parentId: '',
           children: [
             {
               name: `Indexes (${srcTable.Indexes?.length || '0'})`,
@@ -111,6 +148,8 @@ export class ConversionService {
               parent: name,
               pos: -1,
               isSpannerNode: false,
+              id: '',
+              parentId: srcTable.Id,
               children: srcTable.Indexes
                 ? srcTable.Indexes.map((index: IIndex, i: number) => {
                     return {
@@ -119,6 +158,8 @@ export class ConversionService {
                       parent: name,
                       isSpannerNode: false,
                       pos: i,
+                      id: index.Id,
+                      parentId: srcTable.Id,
                     }
                   })
                 : [],
@@ -141,17 +182,25 @@ export class ConversionService {
         parent: '',
         isSpannerNode: false,
         pos: -1,
+        id: '',
+        parentId: '',
       },
     ]
   }
 
-  getColumnMapping(tableName: string, data: IConv): IColumnTabData[] {
-    let srcTableName = data.ToSource[tableName].Name
+  getColumnMapping(id: string, data: IConv): IColumnTabData[] {
+    let srcTableName = this.getSourceTableNameFromId(id, data)
+    let spTableName = this.getSpannerTableNameFromId(id, data)
+
+    let srcTableIds = Object.keys(data.SrcSchema[srcTableName].ColDefs).map(
+      (name: string) => data.SrcSchema[srcTableName].ColDefs[name].Id
+    )
+
     const res: IColumnTabData[] = data.SrcSchema[srcTableName].ColNames.map(
       (name: string, i: number) => {
-        let spColName = data.ToSpanner[srcTableName].Cols[name]
+        let spColName = data.ToSpanner[srcTableName]?.Cols[name]
         let srcPks = data.SrcSchema[srcTableName].PrimaryKeys
-        let spannerColDef = data.SpSchema[tableName].ColDefs[spColName]
+        let spannerColDef = spTableName ? data.SpSchema[spTableName]?.ColDefs[spColName] : null
         return {
           spOrder: spannerColDef ? i + 1 : '',
           srcOrder: i + 1,
@@ -159,34 +208,45 @@ export class ConversionService {
           spDataType: spannerColDef ? spannerColDef.T.Name : '',
           srcColName: name,
           srcDataType: data.SrcSchema[srcTableName].ColDefs[name].Type.Name,
-          spIsPk: spannerColDef
-            ? data.SpSchema[tableName].Pks.map((p) => p.Col).indexOf(spColName) !== -1
-            : false,
+          spIsPk:
+            spannerColDef && spTableName
+              ? data.SpSchema[spTableName].Pks?.map((p) => p.Col).indexOf(spColName) !== -1
+              : false,
           srcIsPk: srcPks ? srcPks.map((p) => p.Column).indexOf(name) !== -1 : false,
-          spIsNotNull: spannerColDef ? data.SpSchema[tableName].ColDefs[spColName].NotNull : false,
+          spIsNotNull:
+            spannerColDef && spTableName
+              ? data.SpSchema[spTableName].ColDefs[spColName].NotNull
+              : false,
           srcIsNotNull: data.SrcSchema[srcTableName].ColDefs[name].NotNull,
         }
       }
     )
-    data.SpSchema[srcTableName].ColNames.forEach((name: string, i: number) => {
-      if (data.SrcSchema[srcTableName].ColNames.indexOf(name) < 0) {
-        let spannerColDef = data.SpSchema[tableName].ColDefs[name]
-        res.push({
-          spOrder: i + 1,
-          srcOrder: '',
-          spColName: name,
-          spDataType: spannerColDef ? spannerColDef.T.Name : '',
-          srcColName: '',
-          srcDataType: '',
-          spIsPk: spannerColDef
-            ? data.SpSchema[tableName].Pks.map((p) => p.Col).indexOf(name) !== -1
-            : false,
-          srcIsPk: false,
-          spIsNotNull: spannerColDef ? data.SpSchema[tableName].ColDefs[name].NotNull : false,
-          srcIsNotNull: false,
-        })
-      }
-    })
+    if (spTableName) {
+      data.SpSchema[spTableName]?.ColNames.forEach((name: string, i: number) => {
+        if (spTableName && srcTableIds.indexOf(data.SpSchema[spTableName].ColDefs[name].Id) < 0) {
+          let spannerColDef = spTableName ? data.SpSchema[spTableName].ColDefs[name] : null
+          res.push({
+            spOrder: i + 1,
+            srcOrder: '',
+            spColName: name,
+            spDataType: spannerColDef ? spannerColDef.T.Name : '',
+            srcColName: '',
+            srcDataType: '',
+            spIsPk:
+              spannerColDef && spTableName
+                ? data.SpSchema[spTableName].Pks.map((p) => p.Col).indexOf(name) !== -1
+                : false,
+            srcIsPk: false,
+            spIsNotNull:
+              spannerColDef && spTableName
+                ? data.SpSchema[spTableName].ColDefs[name].NotNull
+                : false,
+            srcIsNotNull: false,
+          })
+        }
+      })
+    }
+
     return res
   }
 
@@ -197,17 +257,26 @@ export class ConversionService {
     return JSON.parse(JSON.stringify(pkColumns))
   }
 
-  getFkMapping(tableName: string, data: IConv): IFkTabData[] {
-    let srcTableName: string = data.ToSource[tableName].Name
-    let spFks = data.SpSchema[tableName].Fks
-    if (!spFks) {
+  getFkMapping(id: string, data: IConv): IFkTabData[] {
+    let srcTableName = this.getSourceTableNameFromId(id, data)
+    let spTableName = this.getSpannerTableNameFromId(id, data)
+
+    let spFks =
+      spTableName && data.SpSchema[spTableName] && data.SpSchema[spTableName].Fks
+        ? data.SpSchema[spTableName].Fks
+        : []
+    let srcFks = data.SrcSchema[srcTableName]?.ForeignKeys
+
+    if (!srcFks) {
       return []
     }
     let spFklength: number = spFks.length
     return data.SrcSchema[srcTableName].ForeignKeys.map((item: ISpannerForeignKey, i: number) => {
       spFklength = spFklength - 1
       if (
-        data.SpSchema[tableName].Fks.length != data.SrcSchema[srcTableName].ForeignKeys.length &&
+        spTableName &&
+        data.SpSchema[spTableName] &&
+        data.SpSchema[spTableName].Fks?.length != data.SrcSchema[srcTableName].ForeignKeys.length &&
         spFklength < 0
       ) {
         return {
@@ -222,43 +291,60 @@ export class ConversionService {
         }
       } else {
         return {
-          spName: data.SpSchema[tableName].Fks[i].Name,
+          spName:
+            spTableName && data.SpSchema[spTableName] ? data.SpSchema[spTableName].Fks[i].Name : '',
           srcName: data.SrcSchema[srcTableName].ForeignKeys[i].Name,
-          spColumns: data.SpSchema[tableName].Fks[i].Columns,
+          spColumns:
+            spTableName && data.SpSchema[spTableName]
+              ? data.SpSchema[spTableName].Fks[i].Columns
+              : [],
           srcColumns: data.SrcSchema[srcTableName].ForeignKeys[i].Columns,
-          spReferTable: data.SpSchema[tableName].Fks[i].ReferTable,
+          spReferTable:
+            spTableName && data.SpSchema[spTableName]
+              ? data.SpSchema[spTableName].Fks[i].ReferTable
+              : '',
           srcReferTable: data.SrcSchema[srcTableName].ForeignKeys[i].ReferTable,
-          spReferColumns: data.SpSchema[tableName].Fks[i].ReferColumns,
+          spReferColumns:
+            spTableName && data.SpSchema[spTableName]
+              ? data.SpSchema[spTableName].Fks[i].ReferColumns
+              : [],
           srcReferColumns: data.SrcSchema[srcTableName].ForeignKeys[i].ReferColumns,
         }
       }
     })
   }
 
-  getIndexMapping(tableName: string, data: IConv, indexName: string): IIndexData[] {
-    let srcTableName = data.ToSource[tableName].Name
-    let spIndex = data.SpSchema[tableName].Indexes.filter((idx) => idx.Name === indexName)[0]
-    let srcIndexs = data.SrcSchema[srcTableName].Indexes?.filter((idx) => idx.Name === indexName)
+  getIndexMapping(tableId: string, data: IConv, indexId: string): IIndexData[] {
+    let srcTableName = this.getSourceTableNameFromId(tableId, data)
+    let spTableName = this.getSpannerTableNameFromId(tableId, data)
+    let spIndex = spTableName
+      ? data.SpSchema[spTableName]?.Indexes.filter((idx) => idx.Id === indexId)[0]
+      : null
+    let srcIndexs = data.SrcSchema[srcTableName].Indexes?.filter((idx) => idx.Id === indexId)
 
-    let res: IIndexData[] = spIndex.Keys.map((idx: IIndexKey, i: number) => {
-      return {
-        srcColName:
-          srcIndexs && srcIndexs.length > 0 && srcIndexs[0].Keys.length > i
-            ? srcIndexs[0].Keys[i].Column
-            : '',
-        srcOrder: srcIndexs && srcIndexs.length > 0 && srcIndexs[0].Keys.length > i ? i + 1 : '',
-        srcDesc:
-          srcIndexs && srcIndexs.length > 0 && srcIndexs[0].Keys.length > i
-            ? srcIndexs[0].Keys[i].Desc
-            : undefined,
-        spColName: idx.Col,
-        spOrder: i + 1,
-        spDesc: idx.Desc,
-      }
-    })
-    if (srcIndexs && srcIndexs[0] && spIndex.Keys.length < srcIndexs[0].Keys.length) {
+    let res: IIndexData[] = spIndex
+      ? spIndex.Keys.map((idx: IIndexKey, i: number) => {
+          return {
+            srcColName:
+              srcIndexs && srcIndexs.length > 0 && srcIndexs[0].Keys.length > i
+                ? srcIndexs[0].Keys[i].Column
+                : '',
+            srcOrder:
+              srcIndexs && srcIndexs.length > 0 && srcIndexs[0].Keys.length > i ? i + 1 : '',
+            srcDesc:
+              srcIndexs && srcIndexs.length > 0 && srcIndexs[0].Keys.length > i
+                ? srcIndexs[0].Keys[i].Desc
+                : undefined,
+            spColName: idx.Col,
+            spOrder: i + 1,
+            spDesc: idx.Desc,
+          }
+        })
+      : []
+    let spKeyLength = spIndex ? spIndex.Keys.length : 0
+    if (srcIndexs && srcIndexs[0] && spKeyLength < srcIndexs[0].Keys.length) {
       srcIndexs[0].Keys.forEach((idx, index) => {
-        if (index >= spIndex.Keys.length) {
+        if (index >= spKeyLength) {
           res.push({
             srcColName: idx.Column,
             srcOrder: index + 1,
@@ -272,4 +358,23 @@ export class ConversionService {
     }
     return res
   }
+
+  getSourceTableNameFromId(id: string, conv: IConv): string {
+    let srcName: string = ''
+    Object.keys(conv.SrcSchema).forEach((key: string) => {
+      if (conv.SrcSchema[key].Id === id) {
+        srcName = conv.SrcSchema[key].Name
+      }
+    })
+    return srcName
+  }
+  getSpannerTableNameFromId(id: string, conv: IConv): string | null {
+    let spName: string | null = null
+    Object.keys(conv.SpSchema).forEach((key: string) => {
+      if (conv.SpSchema[key].Id === id) {
+        spName = conv.SpSchema[key].Name
+      }
+    })
+    return spName
+  }
 }
diff --git a/ui/src/app/services/data/data.service.ts b/ui/src/app/services/data/data.service.ts
index 9fee7f6..1691d6e 100644
--- a/ui/src/app/services/data/data.service.ts
+++ b/ui/src/app/services/data/data.service.ts
@@ -197,6 +197,44 @@ export class DataService {
     )
   }
 
+  restoreTable(tableId: string): Observable<string> {
+    return this.fetch.restoreTable(tableId).pipe(
+      catchError((e: any) => {
+        return of({ error: e.error })
+      }),
+      tap(console.log),
+      map((data) => {
+        if (data.error) {
+          this.snackbar.openSnackBar(data.error, 'Close')
+          return data.error
+        } else {
+          this.convSubject.next(data)
+          this.snackbar.openSnackBar('Table restored successfully', 'Close', 5)
+          return ''
+        }
+      })
+    )
+  }
+
+  dropTable(tableId: string): Observable<string> {
+    return this.fetch.dropTable(tableId).pipe(
+      catchError((e: any) => {
+        return of({ error: e.error })
+      }),
+      tap(console.log),
+      map((data) => {
+        if (data.error) {
+          this.snackbar.openSnackBar(data.error, 'Close')
+          return data.error
+        } else {
+          this.convSubject.next(data)
+          this.snackbar.openSnackBar('Table dropped successfully', 'Close', 5)
+          return ''
+        }
+      })
+    )
+  }
+
   updatePk(pkObj: IPrimaryKey) {
     return this.fetch.updatePk(pkObj).pipe(
       catchError((e: any) => {
diff --git a/ui/src/app/services/fetch/fetch.service.ts b/ui/src/app/services/fetch/fetch.service.ts
index 6ec0f48..9ee972c 100644
--- a/ui/src/app/services/fetch/fetch.service.ts
+++ b/ui/src/app/services/fetch/fetch.service.ts
@@ -3,10 +3,12 @@ import { Injectable } from '@angular/core'
 import IDbConfig from 'src/app/model/db-config'
 import ISession, { ISaveSessionPayload } from '../../model/session'
 import IUpdateTable from '../../model/update-table'
-import IConv, { ICreateIndex, IInterleaveStatus, IPrimaryKey } from '../../model/conv'
+import IConv, { ICreateIndex, IInterleaveStatus, IPrimaryKey, ISessionSummary } from '../../model/conv'
 import IDumpConfig from '../../model/dump-config'
 import ISessionConfig from '../../model/session-config'
 import ISpannerConfig from '../../model/spanner-config'
+import ITargetDetails from '../../model/target-details'
+import IMigrationDetails from 'src/app/model/migrate'
 
 @Injectable({
   providedIn: 'root',
@@ -63,6 +65,13 @@ export class FetchService {
     return this.http.post<HttpResponse<IConv>>(`${this.url}/typemap/table?table=${tableName}`, data)
   }
 
+  restoreTable(tableId: string) {
+    return this.http.post<HttpResponse<IConv>>(`${this.url}/restore/table?tableId=${tableId}`, {})
+  }
+  dropTable(tableId: string) {
+    return this.http.post<HttpResponse<IConv>>(`${this.url}/drop/table?tableId=${tableId}`, {})
+  }
+
   updatePk(pkObj: IPrimaryKey) {
     return this.http.post<HttpResponse<IConv>>(`${this.url}/primaryKey`, pkObj)
   }
@@ -136,4 +145,12 @@ export class FetchService {
   setInterleave(tableName: string) {
     return this.http.get(`${this.url}/setparent?table=${tableName}&update=true`)
   }
+
+  getSourceDestinationSummary() {
+    return this.http.get<ISessionSummary>(`${this.url}/GetSourceDestinationSummary`)
+  }
+
+  migrate(payload: IMigrationDetails) {
+    return this.http.post(`${this.url}/Migrate`,payload)
+  }
 }
diff --git a/ui/src/app/services/target-details/target-details.service.spec.ts b/ui/src/app/services/target-details/target-details.service.spec.ts
new file mode 100644
index 0000000..2610d9a
--- /dev/null
+++ b/ui/src/app/services/target-details/target-details.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { TargetDetailsService } from './target-details.service';
+
+describe('TargetDetailsService', () => {
+  let service: TargetDetailsService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(TargetDetailsService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/ui/src/app/services/target-details/target-details.service.ts b/ui/src/app/services/target-details/target-details.service.ts
new file mode 100644
index 0000000..f5b8753
--- /dev/null
+++ b/ui/src/app/services/target-details/target-details.service.ts
@@ -0,0 +1,18 @@
+import { Injectable } from '@angular/core';
+import ITargetDetails from 'src/app/model/target-details';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class TargetDetailsService {
+  targetDetail : ITargetDetails = {TargetDB:"", Dialect:"google_standard_sql",StreamingConfig:""};
+  constructor() { }
+  updateTargetDetails(details: ITargetDetails) {
+    this.targetDetail.TargetDB = details.TargetDB;
+    this.targetDetail.Dialect = details.Dialect;
+    this.targetDetail.StreamingConfig = details.StreamingConfig;
+  }
+  getTargetDetails() {
+    return this.targetDetail;
+  }
+}
\ No newline at end of file
diff --git a/ui/src/styles.scss b/ui/src/styles.scss
index a15f6df..9b7ce9b 100644
--- a/ui/src/styles.scss
+++ b/ui/src/styles.scss
@@ -17,3 +17,144 @@ 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;
+}
+
+.gray-out {
+  opacity: 0.6;
+}
+
+.danger {
+  color: #da4236;
+}
+
+.warning {
+  color: #f3b300;
+}
+
+.success {
+  color: green;
+}
+
+.orange {
+  color: rgb(248, 116, 68);
+}
+.dark {
+  color: rgb(77, 75, 75);
+}
+.header {
+  padding: 0 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1px solid #cccccc;
+  padding-bottom: 10px;
+  .header_action {
+    button {
+      border: none;
+      background-color: inherit;
+      color: #1967d2;
+      font-size: 0.8rem;
+    }
+  }
+  .breadcrumb {
+    display: flex;
+    align-items: center;
+    .breadcrumb_source {
+      padding-left: 0;
+      color: rgba(0, 0, 0, 0.56);
+      font-weight: 400;
+      font-size: 14px;
+    }
+    .breadcrumb_workspace {
+      font-weight: 400;
+      font-size: 14px;
+    }
+    span {
+      font-size: 1.2rem;
+      color: rgb(143, 143, 143);
+    }
+  }
+}
+
+.prerequisites {
+  padding: 0;
+  width: 600px;
+  .mat-card-title {
+    font-size: 13pt;
+    font-weight: normal;
+    color: #000000;
+  }
+  .mat-card-subtitle {
+    font-size: 9pt;
+    font-weight: normal;
+    color: #000000;
+  }
+  p {
+    color: #000000;
+    .bullet {
+      position: relative;
+      display: inline-block;
+      background-color: #e5e5e5;
+      padding: 0px 5px 10px 5px;
+      margin: 0;
+      border-radius: 12px;
+      font-size: 9px;
+      height: 9px;
+      width: 9px;
+      text-align: center;
+    }
+    span {
+      margin-left: 40px;
+      font-weight: lighter;
+      font-size: 13px;
+    }
+  }
+  hr {
+    border-color: #ffffff;
+    margin-bottom: 20px;
+  }
+}
+
+.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;
+  }
+}
diff --git a/webv2/config.json b/webv2/config.json
index c41b6f4..ca5c424 100755
--- a/webv2/config.json
+++ b/webv2/config.json
@@ -1,4 +1,4 @@
 {
-  "GCPProjectID": "",
-  "SpannerInstanceID": ""
-}
+    "GCPProjectID": "",
+    "SpannerInstanceID": ""
+}
\ No newline at end of file
diff --git a/webv2/helpers/helpers.go b/webv2/helpers/helpers.go
index 00da3a5..ff28d96 100644
--- a/webv2/helpers/helpers.go
+++ b/webv2/helpers/helpers.go
@@ -18,6 +18,7 @@ import (
 	"fmt"
 	"os"
 
+	"github.com/cloudspannerecosystem/harbourbridge/common/constants"
 	"github.com/cloudspannerecosystem/harbourbridge/common/utils"
 	"github.com/cloudspannerecosystem/harbourbridge/conversion"
 	"github.com/cloudspannerecosystem/harbourbridge/webv2/session"
@@ -35,3 +36,16 @@ func UpdateSessionFile() error {
 	}
 	return nil
 }
+
+func GetSourceDatabaseFromDriver(driver string) (string, error) {
+	switch driver {
+	case constants.MYSQLDUMP, constants.MYSQL:
+		return constants.MYSQL, nil
+	case constants.PGDUMP, constants.POSTGRES:
+		return constants.POSTGRES, nil
+	case constants.ORACLE, constants.SQLSERVER:
+		return driver, nil
+	default:
+		return "", fmt.Errorf("unsupported driver type: %v", driver)
+	}
+}
diff --git a/webv2/index/index.go b/webv2/index/index.go
index 3698e09..af7f849 100644
--- a/webv2/index/index.go
+++ b/webv2/index/index.go
@@ -59,7 +59,7 @@ func checkRedundantIndex(index []ddl.CreateIndex, spannerTable ddl.CreateTable)
 		indexFirstColumn := index[i].Keys[0].Col
 
 		if primaryKeyFirstColumn == indexFirstColumn {
-			columnname := keys[i].Col
+			columnname := keys[0].Col
 			sessionState := session.GetSessionState()
 			schemaissue := sessionState.Conv.Issues[spannerTable.Name][columnname]
 			schemaissue = append(schemaissue, internal.RedundantIndex)
diff --git a/webv2/routes.go b/webv2/routes.go
index a1915ab..d7b25c0 100644
--- a/webv2/routes.go
+++ b/webv2/routes.go
@@ -45,6 +45,9 @@ func getRoutes() *mux.Router {
 	// TODO:(searce) take constraint names themselves which are guaranteed to be unique for Spanner.
 	router.HandleFunc("/drop/secondaryindex", dropSecondaryIndex).Methods("POST")
 
+	router.HandleFunc("/restore/table", restoreTable).Methods("POST")
+	router.HandleFunc("/drop/table", dropTable).Methods("POST")
+
 	router.HandleFunc("/rename/fks", renameForeignKeys).Methods("POST")
 	router.HandleFunc("/rename/indexes", renameIndexes).Methods("POST")
 	router.HandleFunc("/add/indexes", addIndexes).Methods("POST")
@@ -68,5 +71,10 @@ func getRoutes() *mux.Router {
 	router.HandleFunc("/GetConfig", config.GetConfig).Methods("GET")
 	router.HandleFunc("/SetSpannerConfig", config.SetSpannerConfig).Methods("POST")
 
+	// Run migration
+	router.HandleFunc("/Migrate", migrate).Methods("POST")
+
+	router.HandleFunc("/GetSourceDestinationSummary", getSourceDestinationSummary).Methods("GET")
+
 	return router
 }
diff --git a/webv2/session/remote_session_store.go b/webv2/session/remote_session_store.go
index 51a3cbd..9884be6 100644
--- a/webv2/session/remote_session_store.go
+++ b/webv2/session/remote_session_store.go
@@ -112,9 +112,8 @@ func (st *spannerStore) GetConvWithMetadata(ctx context.Context, versionId strin
 	}
 
 	convm.Conv = conv
-	convm.Conv.Audit = internal.Audit{
-		MigrationType: migration.MigrationData_SCHEMA_ONLY.Enum(),
-	}
+	convm.Conv.Audit.MigrationType = migration.MigrationData_SCHEMA_ONLY.Enum()
+
 	convm.SessionMetadata = SessionMetadata{
 		SessionName:  scs.SessionName,
 		EditorName:   scs.EditorName,
diff --git a/webv2/session/session_handler.go b/webv2/session/session_handler.go
index c6e4aea..731761c 100644
--- a/webv2/session/session_handler.go
+++ b/webv2/session/session_handler.go
@@ -164,6 +164,9 @@ func ResumeSession(w http.ResponseWriter, r *http.Request) {
 	sessionState.Conv = &convm.Conv
 	sessionState.Driver = convm.DatabaseType
 	sessionState.DbName = convm.DatabaseName
+	sessionState.SourceDBConnDetails = SourceDBConnDetails{
+		ConnectionType: common.SESSION_FILE_MODE,
+	}
 
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(convm)
diff --git a/webv2/session/types.go b/webv2/session/types.go
index c9106e5..c510888 100644
--- a/webv2/session/types.go
+++ b/webv2/session/types.go
@@ -30,17 +30,27 @@ type ConvWithMetadata struct {
 	internal.Conv
 }
 
+type SourceDBConnDetails struct {
+	Host           string
+	Port           string
+	User           string
+	Password       string
+	Path           string
+	ConnectionType string
+}
+
 // SessionState stores information for the current migration session.
 type SessionState struct {
-	SourceDB          *sql.DB        // Connection to source database in case of direct connection
-	DbName            string         // Name of source database
-	Driver            string         // Name of HarbourBridge driver in use
-	Conv              *internal.Conv // Current conversion state
-	SessionFile       string         // Path to session file
-	IsOffline         bool           // True if the connection to remote metadata database is invalid
-	GCPProjectID      string
-	SpannerInstanceID string
-	SessionMetadata   SessionMetadata
+	SourceDB            *sql.DB             // Connection to source database in case of direct connection
+	SourceDBConnDetails SourceDBConnDetails // Connection details for source database
+	DbName              string              // Name of source database
+	Driver              string              // Name of HarbourBridge driver in use
+	Conv                *internal.Conv      // Current conversion state
+	SessionFile         string              // Path to session file
+	IsOffline           bool                // True if the connection to remote metadata database is invalid
+	GCPProjectID        string
+	SpannerInstanceID   string
+	SessionMetadata     SessionMetadata
 	Counter
 }
 
diff --git a/webv2/uniqueid/uniqueid_assignment.go b/webv2/uniqueid/uniqueid_assignment.go
index 5f24b86..bd6db08 100644
--- a/webv2/uniqueid/uniqueid_assignment.go
+++ b/webv2/uniqueid/uniqueid_assignment.go
@@ -32,7 +32,7 @@ func AssignUniqueId(conv *internal.Conv) {
 
 		for spannertablename, spannertable := range conv.SpSchema {
 
-			if sourcetablename == spannertablename {
+			if validSpannerTableName, _ := internal.FixName(sourcetablename); validSpannerTableName == spannertablename {
 
 				tableuniqueid := GenerateTableId()
 				sourcetable.Id = tableuniqueid
@@ -53,7 +53,7 @@ func AssignUniqueId(conv *internal.Conv) {
 
 					for spannercolumnname, spannercolumn := range spannertable.ColDefs {
 
-						if sourcecolumn.Name == spannercolumn.Name {
+						if validSpannerColumnName, _ := internal.FixName(sourcecolumn.Name); validSpannerColumnName == spannercolumn.Name {
 
 							columnuniqueid := GenerateColumnId()
 							sourcecolumn.Id = columnuniqueid
@@ -72,7 +72,7 @@ func AssignUniqueId(conv *internal.Conv) {
 
 					for spannerforeignkeyindex, spannerforeignkey := range spannertable.Fks {
 
-						if sourceforeignkey.Name == spannerforeignkey.Name {
+						if validSpannerFkName, _ := internal.FixName(sourceforeignkey.Name); validSpannerFkName == spannerforeignkey.Name {
 
 							foreignkeyid := GenerateForeignkeyId()
 
@@ -88,9 +88,9 @@ func AssignUniqueId(conv *internal.Conv) {
 
 				for sourcei, sourceindexes := range sourcetable.Indexes {
 
-					for spanneri, spannerindexes := range spannertable.Indexes {
+					for ind, spannerindexes := range spannertable.Indexes {
 
-						if sourceindexes.Name == spannerindexes.Name {
+						if validSpannerIndexName, _ := internal.FixName(sourceindexes.Name); validSpannerIndexName == spannerindexes.Name {
 
 							indexesid := GenerateIndexesId()
 
@@ -98,7 +98,7 @@ func AssignUniqueId(conv *internal.Conv) {
 							spannerindexes.Id = indexesid
 
 							conv.SrcSchema[sourcetable.Name].Indexes[sourcei] = sourceindexes
-							conv.SpSchema[spannertable.Name].Indexes[spanneri] = spannerindexes
+							conv.SpSchema[spannertable.Name].Indexes[ind] = spannerindexes
 
 						}
 
@@ -156,7 +156,7 @@ func updateSpannerTableSecondaryIndexKeyOrder(spannertable ddl.CreateTable) {
 
 		for j := 0; j < len(spannertable.Indexes[i].Keys); j++ {
 
-			for spannercolumnname, _ := range spannertable.ColDefs {
+			for spannercolumnname := range spannertable.ColDefs {
 				if spannertable.Indexes[i].Keys[j].Col == spannercolumnname {
 
 					o := getSpannerColumnIndex(spannertable, spannercolumnname)
@@ -175,7 +175,7 @@ func updateSourceTableSecondaryIndexKeyOrder(sourcetable schema.Table) {
 
 		for j := 0; j < len(sourcetable.Indexes[i].Keys); j++ {
 
-			for spannercolumnname, _ := range sourcetable.ColDefs {
+			for spannercolumnname := range sourcetable.ColDefs {
 				if sourcetable.Indexes[i].Keys[j].Column == spannercolumnname {
 
 					o := getSourceColumnIndex(sourcetable, spannercolumnname)
@@ -258,3 +258,50 @@ func InitObjectId() {
 	sessionState := session.GetSessionState()
 	sessionState.Counter.ObjectId = "0"
 }
+
+//CopyUniqueIdToSpannerTable copy ids from source table to spanner table content
+func CopyUniqueIdToSpannerTable(conv *internal.Conv, spannertablename string) {
+	sourcetablename := conv.ToSource[spannertablename].Name
+	spannertable := conv.SpSchema[spannertablename]
+	sourcetable := conv.SrcSchema[sourcetablename]
+	spannertable.Id = sourcetable.Id
+
+	for spannercolumnname, spannercolumn := range spannertable.ColDefs {
+		if spannercolumn.Name == "synth_id" {
+			columnuniqueid := GenerateColumnId()
+			spannercolumn.Id = columnuniqueid
+			spannertable.ColDefs[spannercolumnname] = spannercolumn
+		}
+	}
+
+	for _, sourcecolumn := range sourcetable.ColDefs {
+		for spannercolumnname, spannercolumn := range spannertable.ColDefs {
+			if validSpannerColumnName, _ := internal.FixName(sourcecolumn.Name); validSpannerColumnName == spannercolumn.Name {
+				spannercolumn.Id = sourcecolumn.Id
+				spannertable.ColDefs[spannercolumnname] = spannercolumn
+				break
+			}
+		}
+	}
+
+	for _, sourceforeignkey := range sourcetable.ForeignKeys {
+		for spannerforeignkeyindex, spannerforeignkey := range spannertable.Fks {
+			if validSpannerFkName, _ := internal.FixName(sourceforeignkey.Name); validSpannerFkName == spannerforeignkey.Name {
+				spannerforeignkey.Id = sourceforeignkey.Id
+				spannertable.Fks[spannerforeignkeyindex] = spannerforeignkey
+			}
+		}
+	}
+
+	for _, sourceindexes := range sourcetable.Indexes {
+		for ind, spannerindexes := range spannertable.Indexes {
+			if validSpannerIndexName, _ := internal.FixName(sourceindexes.Name); validSpannerIndexName == spannerindexes.Name {
+				spannerindexes.Id = sourceindexes.Id
+				spannertable.Indexes[ind] = spannerindexes
+			}
+		}
+	}
+
+	updateSpannerTableIndexKeyOrder(spannertable)
+	conv.SpSchema[spannertablename] = spannertable
+}
diff --git a/webv2/utilities/constants.go b/webv2/utilities/constants.go
new file mode 100644
index 0000000..6c65efa
--- /dev/null
+++ b/webv2/utilities/constants.go
@@ -0,0 +1,23 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package common
+
+const (
+	DUMP_MODE           = "dumpFile"
+	DIRECT_CONNECT_MODE = "directConnect"
+	SESSION_FILE_MODE   = "sessionFile"
+	SCHEMA_ONLY         = "Schema"
+	DATA_ONLY           = "Data"
+)
diff --git a/webv2/web.go b/webv2/web.go
index f4d95c9..8ddebc5 100644
--- a/webv2/web.go
+++ b/webv2/web.go
@@ -20,6 +20,7 @@ package webv2
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"database/sql"
 	"encoding/json"
 	"fmt"
@@ -35,6 +36,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/cloudspannerecosystem/harbourbridge/cmd"
 	"github.com/cloudspannerecosystem/harbourbridge/common/constants"
 	"github.com/cloudspannerecosystem/harbourbridge/common/utils"
 	"github.com/cloudspannerecosystem/harbourbridge/conversion"
@@ -91,6 +93,27 @@ type driverConfig struct {
 	Password string `json:"Password"`
 }
 
+type sessionSummary struct {
+	DatabaseType      string
+	ConnectionDetail  string
+	SourceTableCount  int
+	SpannerTableCount int
+	SourceIndexCount  int
+	SpannerIndexCount int
+	ConnectionType    string
+}
+
+type migrationDetails struct {
+	TargetDetails targetDetails `json:"TargetDetails"`
+	MigrationMode string        `json:MigrationMode`
+	MigrationType string        `json:MigrationType`
+}
+
+type targetDetails struct {
+	TargetDB     string `json:"TargetDB"`
+	StreamingCfg string `json:"StreamingConfig"`
+}
+
 // databaseConnection creates connection with database when using
 // with postgres and mysql driver.
 func databaseConnection(w http.ResponseWriter, r *http.Request) {
@@ -141,6 +164,13 @@ func databaseConnection(w http.ResponseWriter, r *http.Request) {
 	}
 	sessionState.Driver = config.Driver
 	sessionState.SessionFile = ""
+	sessionState.SourceDBConnDetails = session.SourceDBConnDetails{
+		Host:           config.Host,
+		Port:           config.Port,
+		User:           config.User,
+		Password:       config.Password,
+		ConnectionType: utilities.DIRECT_CONNECT_MODE,
+	}
 	w.WriteHeader(http.StatusOK)
 }
 
@@ -254,6 +284,10 @@ func convertSchemaDump(w http.ResponseWriter, r *http.Request) {
 	sessionState.DbName = ""
 	sessionState.SessionFile = ""
 	sessionState.SourceDB = nil
+	sessionState.SourceDBConnDetails = session.SourceDBConnDetails{
+		Path:           dc.FilePath,
+		ConnectionType: utilities.DUMP_MODE,
+	}
 
 	convm := session.ConvWithMetadata{
 		SessionMetadata: sessionMetadata,
@@ -310,6 +344,10 @@ func loadSession(w http.ResponseWriter, r *http.Request) {
 	sessionState.SessionMetadata = sessionMetadata
 	sessionState.Driver = s.Driver
 	sessionState.SessionFile = s.FilePath
+	sessionState.SourceDBConnDetails = session.SourceDBConnDetails{
+		Path:           s.FilePath,
+		ConnectionType: utilities.SESSION_FILE_MODE,
+	}
 
 	convm := session.ConvWithMetadata{
 		SessionMetadata: sessionMetadata,
@@ -734,6 +772,174 @@ type DropDetail struct {
 	Name string `json:"Name"`
 }
 
+func restoreTable(w http.ResponseWriter, r *http.Request) {
+	tableId := r.FormValue("tableId")
+	sessionState := session.GetSessionState()
+	if sessionState.Conv == nil || sessionState.Driver == "" {
+		http.Error(w, fmt.Sprintf("Schema is not converted or Driver is not configured properly. Please retry converting the database to Spanner."), http.StatusNotFound)
+		return
+	}
+	if tableId == "" {
+		http.Error(w, fmt.Sprintf("Table Id is empty"), http.StatusBadRequest)
+	}
+
+	table := ""
+	for _, value := range sessionState.Conv.SrcSchema {
+		if value.Id == tableId {
+			table = value.Name
+			break
+		}
+	}
+	if table == "" {
+		http.Error(w, fmt.Sprintf("Table not found"), http.StatusBadRequest)
+	}
+
+	conv := sessionState.Conv
+	var toddl common.ToDdl
+	switch sessionState.Driver {
+	case constants.MYSQL:
+		toddl = mysql.InfoSchemaImpl{}.GetToDdl()
+	case constants.POSTGRES:
+		toddl = postgres.InfoSchemaImpl{}.GetToDdl()
+	case constants.SQLSERVER:
+		toddl = sqlserver.InfoSchemaImpl{}.GetToDdl()
+	case constants.ORACLE:
+		toddl = oracle.InfoSchemaImpl{}.GetToDdl()
+	case constants.MYSQLDUMP:
+		toddl = mysql.DbDumpImpl{}.GetToDdl()
+	case constants.PGDUMP:
+		toddl = postgres.DbDumpImpl{}.GetToDdl()
+	default:
+		http.Error(w, fmt.Sprintf("Driver : '%s' is not supported", sessionState.Driver), http.StatusBadRequest)
+		return
+	}
+
+	err := common.SrcTableToSpannerDDL(conv, toddl, sessionState.Conv.SrcSchema[table])
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Restoring spanner table fail"), http.StatusBadRequest)
+		return
+	}
+	conv.AddPrimaryKeys()
+	for _, spTable := range conv.SpSchema {
+		uniqueid.CopyUniqueIdToSpannerTable(conv, spTable.Name)
+	}
+	sessionState.Conv = conv
+	primarykey.DetectHotspot()
+
+	convm := session.ConvWithMetadata{
+		SessionMetadata: sessionState.SessionMetadata,
+		Conv:            *sessionState.Conv,
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(convm)
+}
+
+func dropTable(w http.ResponseWriter, r *http.Request) {
+	tableId := r.FormValue("tableId")
+	sessionState := session.GetSessionState()
+	if sessionState.Conv == nil || sessionState.Driver == "" {
+		http.Error(w, fmt.Sprintf("Schema is not converted or Driver is not configured properly. Please retry converting the database to Spanner."), http.StatusNotFound)
+		return
+	}
+	if tableId == "" {
+		http.Error(w, fmt.Sprintf("Table Id is empty"), http.StatusBadRequest)
+	}
+	table := ""
+	for _, value := range sessionState.Conv.SpSchema {
+		if value.Id == tableId {
+			table = value.Name
+			break
+		}
+	}
+	if table == "" {
+		http.Error(w, fmt.Sprintf("Spanner table not found"), http.StatusBadRequest)
+	}
+
+	srcTable := ""
+	for _, value := range sessionState.Conv.SrcSchema {
+		if value.Id == tableId {
+			srcTable = value.Name
+			break
+		}
+	}
+	if srcTable == "" {
+		http.Error(w, fmt.Sprintf("Source table not found"), http.StatusBadRequest)
+	}
+
+	spSchema := sessionState.Conv.SpSchema
+	toSource := sessionState.Conv.ToSource
+	toSpanner := sessionState.Conv.ToSpanner
+	issues := sessionState.Conv.Issues
+	syntheticPkey := sessionState.Conv.SyntheticPKeys
+	toSourceFkIdx := sessionState.Conv.Audit.ToSourceFkIdx
+	toSpannerFkIdx := sessionState.Conv.Audit.ToSpannerFkIdx
+
+	//remove deleted name from usedName
+	usedNames := sessionState.Conv.UsedNames
+	delete(usedNames, table)
+	for _, index := range sessionState.Conv.SpSchema[table].Indexes {
+		delete(usedNames, index.Name)
+	}
+	for _, fk := range sessionState.Conv.SpSchema[table].Fks {
+		delete(usedNames, fk.Name)
+	}
+
+	delete(spSchema, table)
+	delete(toSource, table)
+	delete(toSpanner, srcTable)
+	issues[srcTable] = map[string][]internal.SchemaIssue{}
+	delete(syntheticPkey, table)
+	delete(toSourceFkIdx, table)
+	delete(toSpannerFkIdx, srcTable)
+
+	//drop reference foreign key
+	for tableName, spTable := range spSchema {
+		fks := []ddl.Foreignkey{}
+		for _, fk := range spTable.Fks {
+			if fk.ReferTable != table {
+				fks = append(fks, fk)
+			} else {
+				delete(usedNames, fk.Name)
+			}
+
+		}
+		spTable.Fks = fks
+		spSchema[tableName] = spTable
+	}
+
+	//remove interleave that are interleaved on the drop table as parent
+	for tableName, spTable := range spSchema {
+		if spTable.Parent == table {
+			spTable.Parent = ""
+			spSchema[tableName] = spTable
+		}
+	}
+
+	//remove interleavable suggestion on droping the parent table
+	for tableName, tableIssues := range issues {
+		for colName, colIssues := range tableIssues {
+			updatedColIssues := []internal.SchemaIssue{}
+			for _, val := range colIssues {
+				if val != internal.InterleavedOrder {
+					updatedColIssues = append(updatedColIssues, val)
+				}
+			}
+			if len(updatedColIssues) == 0 {
+				delete(issues[tableName], colName)
+			} else {
+				issues[tableName][colName] = updatedColIssues
+			}
+		}
+	}
+
+	convm := session.ConvWithMetadata{
+		SessionMetadata: sessionState.SessionMetadata,
+		Conv:            *sessionState.Conv,
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(convm)
+}
+
 func dropForeignKey(w http.ResponseWriter, r *http.Request) {
 	table := r.FormValue("table")
 	reqBody, err := ioutil.ReadAll(r.Body)
@@ -969,6 +1175,112 @@ func addIndexes(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(convm)
 }
 
+func getSourceDestinationSummary(w http.ResponseWriter, r *http.Request) {
+	sessionState := session.GetSessionState()
+	var sessionSummary sessionSummary
+	databaseType, err := helpers.GetSourceDatabaseFromDriver(sessionState.Driver)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Error while getting source database: %v", err), http.StatusBadRequest)
+		return
+	}
+	sessionSummary.DatabaseType = databaseType
+	sessionSummary.ConnectionType = sessionState.SourceDBConnDetails.ConnectionType
+	sessionSummary.SourceTableCount = len(sessionState.Conv.SrcSchema)
+	sessionSummary.SpannerTableCount = len(sessionState.Conv.SpSchema)
+
+	sourceIndexCount, spannerIndexCount := 0, 0
+	for _, spannerSchema := range sessionState.Conv.SpSchema {
+		spannerIndexCount = spannerIndexCount + len(spannerSchema.Indexes)
+	}
+	for _, sourceSchema := range sessionState.Conv.SrcSchema {
+		sourceIndexCount = sourceIndexCount + len(sourceSchema.Indexes)
+	}
+	sessionSummary.SourceIndexCount = sourceIndexCount
+	sessionSummary.SpannerIndexCount = spannerIndexCount
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(sessionSummary)
+}
+
+func migrate(w http.ResponseWriter, r *http.Request) {
+
+	log.Println("request started", "method", r.Method, "path", r.URL.Path)
+	reqBody, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		log.Println("request's body Read Error")
+		http.Error(w, fmt.Sprintf("Body Read Error : %v", err), http.StatusInternalServerError)
+	}
+
+	details := migrationDetails{}
+	err = json.Unmarshal(reqBody, &details)
+	if err != nil {
+		log.Println("request's Body parse error")
+		http.Error(w, fmt.Sprintf("Request Body parse error : %v", err), http.StatusBadRequest)
+		return
+	}
+
+	sessionState := session.GetSessionState()
+	ctx := context.Background()
+	sourceProfile, targetProfile, ioHelper, dbName, err := getSourceAndTargetProfiles(sessionState, details)
+	if err != nil {
+		log.Println("can't get source and target profile")
+		http.Error(w, fmt.Sprintf("Can't get source and target profiles: %v", err), http.StatusBadRequest)
+		return
+	}
+
+	if details.MigrationMode == utilities.SCHEMA_ONLY {
+		_, err = cmd.MigrateDatabase(ctx, targetProfile, sourceProfile, dbName, &ioHelper, &cmd.SchemaCmd{}, sessionState.Conv)
+	} else if details.MigrationMode == utilities.DATA_ONLY {
+		dataCmd := &cmd.DataCmd{
+			SkipForeignKeys: false,
+			WriteLimit:      cmd.DefaultWritersLimit,
+		}
+		_, err = cmd.MigrateDatabase(ctx, targetProfile, sourceProfile, dbName, &ioHelper, dataCmd, sessionState.Conv)
+	} else {
+		schemaAndDataCmd := &cmd.SchemaAndDataCmd{
+			SkipForeignKeys: false,
+			WriteLimit:      cmd.DefaultWritersLimit,
+		}
+		_, err = cmd.MigrateDatabase(ctx, targetProfile, sourceProfile, dbName, &ioHelper, schemaAndDataCmd, sessionState.Conv)
+	}
+	if err != nil {
+		log.Println("can't finish database migration")
+		http.Error(w, fmt.Sprintf("Can't finish database migration: %v", err), http.StatusBadRequest)
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	log.Println("migration completed", "method", r.Method, "path", r.URL.Path, "remoteaddr", r.RemoteAddr)
+}
+
+func getSourceAndTargetProfiles(sessionState *session.SessionState, details migrationDetails) (profiles.SourceProfile, profiles.TargetProfile, utils.IOStreams, string, error) {
+	var (
+		sourceProfileString string
+	)
+	sourceDBConnectionDetails := sessionState.SourceDBConnDetails
+	if sourceDBConnectionDetails.ConnectionType == utilities.DUMP_MODE {
+		sourceProfileString = fmt.Sprintf("file=%v,format=dump", sourceDBConnectionDetails.Path)
+	} else {
+		sourceProfileString = fmt.Sprintf("host=%v,port=%v,user=%v,password=%v,dbName=%v",
+			sourceDBConnectionDetails.Host, sourceDBConnectionDetails.Port, sourceDBConnectionDetails.User,
+			sourceDBConnectionDetails.Password, sessionState.DbName)
+	}
+	targetProfileString := fmt.Sprintf("project=%v,instance=%v,dbName=%v", sessionState.GCPProjectID, sessionState.SpannerInstanceID, details.TargetDetails.TargetDB)
+
+	if details.TargetDetails.StreamingCfg != "" {
+		sourceProfileString = sourceProfileString + fmt.Sprintf(",streamingCfg=%v", details.TargetDetails.StreamingCfg)
+	}
+	source, err := helpers.GetSourceDatabaseFromDriver(sessionState.Driver)
+	if err != nil {
+		return profiles.SourceProfile{}, profiles.TargetProfile{}, utils.IOStreams{}, "", fmt.Errorf("error while getting source database: %v", err)
+	}
+	sourceProfile, targetProfile, ioHelper, dbName, err := cmd.PrepareMigrationPrerequisites(sourceProfileString, targetProfileString, source)
+	if err != nil && sourceDBConnectionDetails.ConnectionType != utilities.SESSION_FILE_MODE {
+		return profiles.SourceProfile{}, profiles.TargetProfile{}, utils.IOStreams{}, "", fmt.Errorf("error while preparing prerequisites for migration: %v", err)
+	}
+	sourceProfile.Driver = sessionState.Driver
+	targetProfile.TargetDb = targetProfile.ToLegacyTargetDb()
+	return sourceProfile, targetProfile, ioHelper, dbName, nil
+}
+
 func updateIndexes(w http.ResponseWriter, r *http.Request) {
 	table := r.FormValue("table")
 	reqBody, err := ioutil.ReadAll(r.Body)
@@ -1324,15 +1636,12 @@ func checkPrimaryKeyPrefix(table string, refTable string, fk ddl.Foreignkey, tab
 
 			if len(schemaissue) > 0 {
 
-				if sessionState.Conv.Issues[table][caninterleaved[i]] == nil {
+				if sessionState.Conv.Issues[table] == nil {
 
 					s := map[string][]internal.SchemaIssue{
 						caninterleaved[i]: schemaissue,
 					}
-					sessionState.Conv.Issues = map[string]map[string][]internal.SchemaIssue{}
-
 					sessionState.Conv.Issues[table] = s
-
 				} else {
 					sessionState.Conv.Issues[table][caninterleaved[i]] = schemaissue
 				}


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"
diff --git a/webv2/web_test.go b/webv2/web_test.go
index 23c556f..d71652d 100644
--- a/webv2/web_test.go
+++ b/webv2/web_test.go
@@ -1101,6 +1101,7 @@ func TestSetParentTable(t *testing.T) {
 			name:       "no table name provided",
 			statusCode: http.StatusBadRequest,
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{"t1": {
 					Name:     "t1",
 					ColNames: []string{"a", "b", "c"},
@@ -1119,6 +1120,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "table with synthetic PK",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{"t1": {
 					Name:     "t1",
 					ColNames: []string{"a", "b", "c"},
@@ -1143,6 +1145,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "no valid prefix 1",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{
 					"t1": {
 						Name:     "t1",
@@ -1178,6 +1181,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "no valid prefix 2",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{
 					"t1": {
 						Name:     "t1",
@@ -1211,6 +1215,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "no valid prefix 3",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{
 					"t1": {
 						Name:     "t1",
@@ -1244,6 +1249,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "successful interleave",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{
 					"t1": {
 						Name:     "t1",
@@ -1278,6 +1284,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "successful interleave with same primary key",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{
 					"t1": {
 						Name:     "t1",
@@ -1312,6 +1319,7 @@ func TestSetParentTable(t *testing.T) {
 		{
 			name: "successful interleave with multiple fks refering multiple tables",
 			ct: &internal.Conv{
+				Issues: map[string]map[string][]internal.SchemaIssue{},
 				SpSchema: map[string]ddl.CreateTable{
 					"t1": {
 						Name:     "t1",
@@ -2388,6 +2396,231 @@ func TestDropSecondaryIndex(t *testing.T) {
 	}
 }
 
+func TestDropTable(t *testing.T) {
+	sessionState := session.GetSessionState()
+	sessionState.Driver = constants.MYSQL
+
+	c := &internal.Conv{
+		Issues: map[string]map[string][]internal.SchemaIssue{
+			"t1": {},
+			"t2": {},
+		},
+		SrcSchema: map[string]schema.Table{
+			"t1": {
+				Name:     "t1",
+				ColNames: []string{"a", "b", "c"},
+				ColDefs: map[string]schema.Column{
+					"a": {Name: "a", Type: schema.Type{Name: "bigint"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c4"},
+					"b": {Name: "b", Type: schema.Type{Name: "bigint"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c2"},
+					"c": {Name: "c", Type: schema.Type{Name: "varchar"}, NotNull: false, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c3"},
+				},
+				PrimaryKeys: []schema.Key{{Column: "a", Desc: false, Order: 1}},
+				Id:          "id1",
+			},
+
+			"t2": {
+				Name:     "t2",
+				ColNames: []string{"a", "b", "c"},
+				ColDefs: map[string]schema.Column{
+					"a": {Name: "a", Type: schema.Type{Name: "bigint"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c7"},
+					"b": {Name: "b", Type: schema.Type{Name: "varchar"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c8"},
+					"c": {Name: "c", Type: schema.Type{Name: "bigint"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c9"},
+				},
+				Id: "id2",
+			},
+		},
+		SpSchema: map[string]ddl.CreateTable{
+			"t1": {
+				Name:     "t1",
+				ColNames: []string{"a", "b", "c"},
+				ColDefs: map[string]ddl.ColumnDef{"a": {Name: "a", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+					"b": {Name: "b", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+					"c": {Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
+				},
+				Pks: []ddl.IndexKey{{Col: "a", Desc: false}},
+				Id:  "id1",
+			},
+			"t2": {
+				Name:     "t2",
+				ColNames: []string{"a", "b", "c"},
+				ColDefs: map[string]ddl.ColumnDef{"a": {Name: "a", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+					"b":        {Name: "b", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+					"c":        {Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
+					"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+				},
+				Pks: []ddl.IndexKey{{Col: "synth_id", Desc: false}},
+				Id:  "id2",
+			}},
+		Audit: internal.Audit{
+			MigrationType: migration.MigrationData_MIGRATION_TYPE_UNSPECIFIED.Enum(),
+		},
+	}
+
+	sessionState.Conv = c
+
+	payload := `{}`
+
+	req, err := http.NewRequest("POST", "/drop/table?tableId=id1", strings.NewReader(payload))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	req.Header.Set("Content-Type", "application/json")
+	rr := httptest.NewRecorder()
+
+	handler := http.HandlerFunc(dropTable)
+	handler.ServeHTTP(rr, req)
+
+	res := &internal.Conv{}
+
+	json.Unmarshal(rr.Body.Bytes(), &res)
+
+	expectedConv := &internal.Conv{
+
+		SpSchema: map[string]ddl.CreateTable{
+			"t2": {
+				Name:     "t2",
+				ColNames: []string{"a", "b", "c"},
+				ColDefs: map[string]ddl.ColumnDef{"a": {Name: "a", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+					"b":        {Name: "b", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+					"c":        {Name: "c", T: ddl.Type{Name: ddl.String, Len: ddl.MaxLength}, NotNull: true},
+					"synth_id": {Name: "synth_id", T: ddl.Type{Name: ddl.Int64}, NotNull: true},
+				},
+				Pks:     []ddl.IndexKey{{Col: "synth_id", Desc: false}},
+				Fks:     []ddl.Foreignkey{},
+				Indexes: []ddl.CreateIndex(nil),
+				Id:      "id2",
+			}},
+	}
+
+	assert.Equal(t, expectedConv.SpSchema, res.SpSchema)
+}
+
+func TestRestoreTable(t *testing.T) {
+	sessionState := session.GetSessionState()
+
+	sessionState.Driver = constants.MYSQL
+
+	c := &internal.Conv{
+
+		SpSchema: map[string]ddl.CreateTable{
+			"t2": {
+				Name:     "t2",
+				ColNames: []string{"a", "b"},
+				ColDefs: map[string]ddl.ColumnDef{"a": {Name: "a", T: ddl.Type{Name: "STRING", IsArray: false}, NotNull: true, Comment: "", Id: "c7"},
+					"b": {Name: "b", T: ddl.Type{Name: "STRING", IsArray: false}, NotNull: true, Comment: "", Id: "c8"},
+				},
+				Pks: []ddl.IndexKey{{Col: "a", Desc: false, Order: 1}},
+				Id:  "t6",
+			}},
+		SrcSchema: map[string]schema.Table{
+			"t1": {
+				Name:     "t1",
+				ColNames: []string{"a", "x", "y"},
+				ColDefs: map[string]schema.Column{
+					"a": {Name: "a", Type: schema.Type{Name: "varchar"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c4"},
+					"x": {Name: "x", Type: schema.Type{Name: "varchar"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c2"},
+					"y": {Name: "y", Type: schema.Type{Name: "bigint"}, NotNull: false, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c3"},
+				},
+				PrimaryKeys: []schema.Key{{Column: "a", Desc: false, Order: 1}},
+				Id:          "t1",
+			},
+
+			"t2": {
+				Name:     "t2",
+				ColNames: []string{"a", "b"},
+				ColDefs: map[string]schema.Column{
+					"a": {Name: "a", Type: schema.Type{Name: "varchar"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c7"},
+					"b": {Name: "b", Type: schema.Type{Name: "char"}, NotNull: true, Ignored: schema.Ignored{Check: false, Identity: false, Default: false, Exclusion: false, ForeignKey: false, AutoIncrement: false}, Id: "c8"},
+				},
+				PrimaryKeys: []schema.Key{{Column: "a", Desc: false, Order: 1}},
+				Id:          "t6",
+			},
+		},
+
+		UsedNames: map[string]bool{
+			"t2": true,
+		},
+
+		ToSource: map[string]internal.NameAndCols{
+			"t2": {Name: "t2", Cols: map[string]string{"a": "a", "b": "b"}},
+		},
+		ToSpanner: map[string]internal.NameAndCols{
+			"t2": {Name: "t2", Cols: map[string]string{"a": "a", "b": "b"}},
+		},
+
+		Audit: internal.Audit{
+			MigrationType: migration.MigrationData_MIGRATION_TYPE_UNSPECIFIED.Enum(),
+			ToSourceFkIdx: map[string]internal.FkeyAndIdxs{
+				"t2": {
+					Name:       "t2",
+					ForeignKey: map[string]string{},
+					Index:      map[string]string{},
+				},
+			},
+			ToSpannerFkIdx: map[string]internal.FkeyAndIdxs{
+				"t2": {
+					Name:       "t2",
+					ForeignKey: map[string]string{},
+					Index:      map[string]string{},
+				},
+			},
+		},
+
+		Issues: map[string]map[string][]internal.SchemaIssue{},
+	}
+
+	sessionState.Conv = c
+
+	payload := `{}`
+
+	req, err := http.NewRequest("POST", "/restore/table?tableId=t1", strings.NewReader(payload))
+
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	req.Header.Set("Content-Type", "application/json")
+	rr := httptest.NewRecorder()
+
+	handler := http.HandlerFunc(restoreTable)
+	handler.ServeHTTP(rr, req)
+
+	res := &internal.Conv{}
+
+	json.Unmarshal(rr.Body.Bytes(), &res)
+
+	expectedConv := &internal.Conv{
+
+		SpSchema: map[string]ddl.CreateTable{
+
+			"t1": {
+				Name:     "t1",
+				ColNames: []string{"a", "x", "y"},
+				ColDefs: map[string]ddl.ColumnDef{
+					"a": {Name: "a", T: ddl.Type{Name: "STRING", Len: 9223372036854775807, IsArray: false}, NotNull: true, Comment: "From: a varchar", Id: "c4"},
+					"x": {Name: "x", T: ddl.Type{Name: "STRING", Len: 9223372036854775807, IsArray: false}, NotNull: true, Comment: "From: x varchar", Id: "c2"},
+					"y": {Name: "y", T: ddl.Type{Name: "INT64", Len: 0, IsArray: false}, NotNull: false, Comment: "From: y bigint", Id: "c3"},
+				},
+				Pks:     []ddl.IndexKey{{Col: "a", Desc: false, Order: 1}},
+				Id:      "t1",
+				Comment: "Spanner schema for source table t1",
+			},
+
+			"t2": {
+				Name:     "t2",
+				ColNames: []string{"a", "b"},
+				ColDefs: map[string]ddl.ColumnDef{"a": {Name: "a", T: ddl.Type{Name: "STRING", Len: 0, IsArray: false}, NotNull: true, Comment: "", Id: "c7"},
+					"b": {Name: "b", T: ddl.Type{Name: "STRING", Len: 0, IsArray: false}, NotNull: true, Comment: "", Id: "c8"},
+				},
+				Pks: []ddl.IndexKey{{Col: "a", Desc: false, Order: 1}},
+				Id:  "t6",
+			}},
+	}
+	assert.Equal(t, expectedConv.SpSchema, res.SpSchema)
+
+}
+
 func buildConvMySQL(conv *internal.Conv) {
 	conv.SrcSchema = map[string]schema.Table{
 		"t1": {