implementing SQLDriver.AlterTableAddColumn (#65)

This commit is contained in:
Neil O'Toole 2020-08-20 21:08:59 -06:00 committed by GitHub
parent 9746f726f6
commit b3667d60cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 85 additions and 24 deletions

View File

@ -377,7 +377,7 @@ ORDER BY c.TABLE_NAME ASC, c.ORDINAL_POSITION ASC`
tblMetas = append(tblMetas, curTblMeta) tblMetas = append(tblMetas, curTblMeta)
rowCountTbl, rowCount, i := curTblName.String, &curTblMeta.RowCount, len(tblMetas) rowCountTbl, rowCount, i := curTblName.String, &curTblMeta.RowCount, len(tblMetas)-1
gRowCount.Go(func() error { gRowCount.Go(func() error {
err := db.QueryRowContext(gctx, "SELECT COUNT(*) FROM `"+rowCountTbl+"`").Scan(rowCount) err := db.QueryRowContext(gctx, "SELECT COUNT(*) FROM `"+rowCountTbl+"`").Scan(rowCount)
if err != nil { if err != nil {
@ -394,7 +394,6 @@ ORDER BY c.TABLE_NAME ASC, c.ORDINAL_POSITION ASC`
} }
return nil return nil
}) })
} }
col := &source.ColMetadata{ col := &source.ColMetadata{

View File

@ -102,6 +102,18 @@ func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.
return errz.Err(err) return errz.Err(err)
} }
// AlterTableAddColumn implements driver.SQLDriver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db *sql.DB, tbl string, col string, kind sqlz.Kind) error {
q := fmt.Sprintf("ALTER TABLE %q ADD COLUMN %q ", tbl, col) + dbTypeNameFromKind(kind)
_, err := db.ExecContext(ctx, q)
if err != nil {
return errz.Wrapf(err, "alter table: failed to add column %q to table %q", col, tbl)
}
return nil
}
// PrepareInsertStmt implements driver.SQLDriver. // PrepareInsertStmt implements driver.SQLDriver.
func (d *driveri) PrepareInsertStmt(ctx context.Context, db sqlz.DB, destTbl string, destColNames []string, numRows int) (*driver.StmtExecer, error) { func (d *driveri) PrepareInsertStmt(ctx context.Context, db sqlz.DB, destTbl string, destColNames []string, numRows int) (*driver.StmtExecer, error) {
destColsMeta, err := d.getTableRecordMeta(ctx, db, destTbl, destColNames) destColsMeta, err := d.getTableRecordMeta(ctx, db, destTbl, destColNames)
@ -316,11 +328,6 @@ func (d *driveri) Truncate(ctx context.Context, src *source.Source, tbl string,
return beforeCount, errz.Err(tx.Commit()) return beforeCount, errz.Err(tx.Commit())
} }
// AlterTableAddColumn implements driver.Driver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db sqlz.DB, tbl string, col string, kind sqlz.Kind, ordinal int) error {
return errz.New("not implemented")
}
// database implements driver.Database. // database implements driver.Database.
type database struct { type database struct {
log lg.Log log lg.Log

View File

@ -157,6 +157,18 @@ func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.
return errz.Err(err) return errz.Err(err)
} }
// AlterTableAddColumn implements driver.SQLDriver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db *sql.DB, tbl string, col string, kind sqlz.Kind) error {
q := fmt.Sprintf("ALTER TABLE %q ADD COLUMN %q ", tbl, col) + dbTypeNameFromKind(kind)
_, err := db.ExecContext(ctx, q)
if err != nil {
return errz.Wrapf(err, "alter table: failed to add column %q to table %q", col, tbl)
}
return nil
}
// PrepareInsertStmt implements driver.SQLDriver. // PrepareInsertStmt implements driver.SQLDriver.
func (d *driveri) PrepareInsertStmt(ctx context.Context, db sqlz.DB, destTbl string, destColNames []string, numRows int) (*driver.StmtExecer, error) { func (d *driveri) PrepareInsertStmt(ctx context.Context, db sqlz.DB, destTbl string, destColNames []string, numRows int) (*driver.StmtExecer, error) {
// Note that the pgx driver doesn't support res.LastInsertId. // Note that the pgx driver doesn't support res.LastInsertId.
@ -396,11 +408,6 @@ func (d *driveri) RecordMeta(colTypes []*sql.ColumnType) (sqlz.RecordMeta, drive
return recMeta, mungeFn, nil return recMeta, mungeFn, nil
} }
// AlterTableAddColumn implements driver.Driver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db sqlz.DB, tbl string, col string, kind sqlz.Kind, ordinal int) error {
return errz.New("not implemented")
}
// database is the postgres implementation of driver.Database. // database is the postgres implementation of driver.Database.
type database struct { type database struct {
log lg.Log log lg.Log

View File

@ -249,6 +249,18 @@ func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.
return errz.Err(stmt.Close()) return errz.Err(stmt.Close())
} }
// AlterTableAddColumn implements driver.SQLDriver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db *sql.DB, tbl string, col string, kind sqlz.Kind) error {
q := fmt.Sprintf("ALTER TABLE %q ADD COLUMN %q ", tbl, col) + DBTypeForKind(kind)
_, err := db.ExecContext(ctx, q)
if err != nil {
return errz.Wrapf(err, "alter table: failed to add column %q to table %q", col, tbl)
}
return nil
}
// PrepareInsertStmt implements driver.SQLDriver. // PrepareInsertStmt implements driver.SQLDriver.
func (d *driveri) PrepareInsertStmt(ctx context.Context, db sqlz.DB, destTbl string, destColNames []string, numRows int) (*driver.StmtExecer, error) { func (d *driveri) PrepareInsertStmt(ctx context.Context, db sqlz.DB, destTbl string, destColNames []string, numRows int) (*driver.StmtExecer, error) {
destColsMeta, err := d.getTableRecordMeta(ctx, db, destTbl, destColNames) destColsMeta, err := d.getTableRecordMeta(ctx, db, destTbl, destColNames)
@ -356,11 +368,6 @@ func (d *driveri) TableColumnTypes(ctx context.Context, db sqlz.DB, tblName stri
return colTypes, nil return colTypes, nil
} }
// AlterTableAddColumn implements driver.Driver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db sqlz.DB, tbl string, col string, kind sqlz.Kind, ordinal int) error {
return errz.New("not implemented")
}
func (d *driveri) getTableRecordMeta(ctx context.Context, db sqlz.DB, tblName string, colNames []string) (sqlz.RecordMeta, error) { func (d *driveri) getTableRecordMeta(ctx context.Context, db sqlz.DB, tblName string, colNames []string) (sqlz.RecordMeta, error) {
colTypes, err := d.TableColumnTypes(ctx, db, tblName, colNames) colTypes, err := d.TableColumnTypes(ctx, db, tblName, colNames)
if err != nil { if err != nil {

Binary file not shown.

View File

@ -248,6 +248,18 @@ func (d *driveri) CreateTable(ctx context.Context, db sqlz.DB, tblDef *sqlmodel.
return errz.Err(err) return errz.Err(err)
} }
// AlterTableAddColumn implements driver.SQLDriver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db *sql.DB, tbl string, col string, kind sqlz.Kind) error {
q := fmt.Sprintf("ALTER TABLE %q ADD %q ", tbl, col) + dbTypeNameFromKind(kind)
_, err := db.ExecContext(ctx, q)
if err != nil {
return errz.Wrapf(err, "alter table: failed to add column %q to table %q", col, tbl)
}
return nil
}
// CopyTable implements driver.SQLDriver. // CopyTable implements driver.SQLDriver.
func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable string, copyData bool) (int64, error) { func (d *driveri) CopyTable(ctx context.Context, db sqlz.DB, fromTable, toTable string, copyData bool) (int64, error) {
var stmt string var stmt string
@ -317,11 +329,6 @@ func (d *driveri) PrepareUpdateStmt(ctx context.Context, db sqlz.DB, destTbl str
return execer, nil return execer, nil
} }
// AlterTableAddColumn implements driver.Driver.
func (d *driveri) AlterTableAddColumn(ctx context.Context, db sqlz.DB, tbl string, col string, kind sqlz.Kind, ordinal int) error {
return errz.New("not implemented")
}
func (d *driveri) getTableColsMeta(ctx context.Context, db sqlz.DB, tblName string, colNames []string) (sqlz.RecordMeta, error) { func (d *driveri) getTableColsMeta(ctx context.Context, db sqlz.DB, tblName string, colNames []string) (sqlz.RecordMeta, error) {
// SQLServer has this unusual incantation for its LIMIT equivalent: // SQLServer has this unusual incantation for its LIMIT equivalent:
// //

View File

@ -143,8 +143,10 @@ type SQLDriver interface {
// or equivalent clause is added, if supported. // or equivalent clause is added, if supported.
DropTable(ctx context.Context, db sqlz.DB, tbl string, ifExists bool) error DropTable(ctx context.Context, db sqlz.DB, tbl string, ifExists bool) error
// AlterTableAddColumn adds column col to tbl at position ordinal. // AlterTableAddColumn adds column col to tbl. The column is appended
AlterTableAddColumn(ctx context.Context, db sqlz.DB, tbl string, col string, kind sqlz.Kind, ordinal int) error // to the list of columns (that is, the column position cannot be
// specified).
AlterTableAddColumn(ctx context.Context, db *sql.DB, tbl string, col string, kind sqlz.Kind) error
} }
// Database models a database handle. It is conceptually equivalent to // Database models a database handle. It is conceptually equivalent to

View File

@ -9,6 +9,7 @@ import (
"github.com/neilotoole/sq/drivers/sqlite3" "github.com/neilotoole/sq/drivers/sqlite3"
"github.com/neilotoole/sq/drivers/sqlserver" "github.com/neilotoole/sq/drivers/sqlserver"
"github.com/neilotoole/sq/drivers/xlsx" "github.com/neilotoole/sq/drivers/xlsx"
"github.com/neilotoole/sq/libsq/sqlz"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -437,3 +438,34 @@ func TestDatabase_SourceMetadata(t *testing.T) {
}) })
} }
} }
func TestSQLDriver_AlterTableAddColumn(t *testing.T) {
testCases := []string{sakila.SL3, sakila.Pg, sakila.MS}
for _, handle := range testCases {
handle := handle
t.Run(handle, func(t *testing.T) {
th, src, dbase, drvr := testh.NewWith(t, handle)
// Make a copy of the table to play with
tbl := th.CopyTable(true, src, sakila.TblActor, "", true)
const wantCol, wantKind = "col_int", sqlz.KindInt
wantCols := append(sakila.TblActorCols(), wantCol)
wantKinds := append(sakila.TblActorColKinds(), wantKind)
err := drvr.AlterTableAddColumn(th.Context, dbase.DB(), tbl, wantCol, wantKind)
require.NoError(t, err)
sink, err := th.QuerySQL(src, "SELECT * FROM "+tbl)
require.NoError(t, err)
gotCols := sink.RecMeta.Names()
require.Equal(t, wantCols, gotCols)
gotKinds := sink.RecMeta.Kinds()
require.Equal(t, wantKinds, gotKinds)
})
}
}