From ebfd47249c9c30219d13196f1eb9630e7145cec6 Mon Sep 17 00:00:00 2001 From: Neil Macneale IV Date: Thu, 25 Jul 2024 13:14:08 -0700 Subject: [PATCH] Revive ability to read dolt_schema table which predates 0.19.0 --- go/libraries/doltcore/sqle/database.go | 2 +- go/libraries/doltcore/sqle/schema_table.go | 41 ++++++++++++----- .../doltcore/sqle/schema_table_test.go | 45 +++++++++++++++++-- integration-tests/bats/triggers.bats | 19 ++++++++ 4 files changed, 91 insertions(+), 16 deletions(-) diff --git a/go/libraries/doltcore/sqle/database.go b/go/libraries/doltcore/sqle/database.go index 1428f3a3823..b5a4e04129a 100644 --- a/go/libraries/doltcore/sqle/database.go +++ b/go/libraries/doltcore/sqle/database.go @@ -525,7 +525,7 @@ func (db Database) getTableInsensitive(ctx *sql.Context, head *doltdb.Commit, ds dt = NewEmptySchemaTable() } else { writeTable := backingTable.(*WritableDoltTable) - dt, err = NewSchemaTable(ctx, db, writeTable) + dt, err = NewSchemaTable(writeTable) if err != nil { return nil, false, err } diff --git a/go/libraries/doltcore/sqle/schema_table.go b/go/libraries/doltcore/sqle/schema_table.go index e3b20ed7083..faf7e5dfc01 100644 --- a/go/libraries/doltcore/sqle/schema_table.go +++ b/go/libraries/doltcore/sqle/schema_table.go @@ -57,10 +57,15 @@ func (st *SchemaTable) String() string { func (st *SchemaTable) Schema() sql.Schema { if st.backingTable == nil { - // No backing table; return an current schema. + // No backing table; return a current schema. return SchemaTableSqlSchema().Schema } + if !st.backingTable.Schema().Contains(doltdb.SchemasTablesExtraCol, doltdb.SchemasTableName) { + // No Extra column; return an ancient schema. + return SchemaTableAncientSqlSchema() + } + if !st.backingTable.Schema().Contains(doltdb.SchemasTablesSqlModeCol, doltdb.SchemasTableName) { // No SQL_MODE column; return an old schema. return SchemaTableV1SqlSchema() @@ -163,6 +168,22 @@ func SchemaTableV1SqlSchema() sql.Schema { return sqlSchema.Schema } +// dolt_schemas columns, for dolt_schemas <= 0.19.0. +func SchemaTableAncientSqlSchema() sql.Schema { + var schemasTableCols = schema.NewColCollection( + mustNewColWithTypeInfo(doltdb.SchemasTablesTypeCol, schema.DoltSchemasTypeTag, typeinfo.CreateVarStringTypeFromSqlType(mustCreateStringType(query.Type_VARCHAR, 64, sql.Collation_utf8mb4_0900_ai_ci)), true, "", false, ""), + mustNewColWithTypeInfo(doltdb.SchemasTablesNameCol, schema.DoltSchemasNameTag, typeinfo.CreateVarStringTypeFromSqlType(mustCreateStringType(query.Type_VARCHAR, 64, sql.Collation_utf8mb4_0900_ai_ci)), true, "", false, ""), + mustNewColWithTypeInfo(doltdb.SchemasTablesFragmentCol, schema.DoltSchemasFragmentTag, typeinfo.CreateVarStringTypeFromSqlType(gmstypes.LongText), false, "", false, ""), + ) + + legacy := schema.MustSchemaFromCols(schemasTableCols) + sqlSchema, err := sqlutil.FromDoltSchema("", doltdb.SchemasTableName, legacy) + if err != nil { + panic(err) // should never happen + } + return sqlSchema.Schema +} + // dolt_schemas columns func SchemaTableSchema() schema.Schema { var schemasTableCols = schema.NewColCollection( @@ -180,11 +201,7 @@ func NewEmptySchemaTable() sql.Table { return &SchemaTable{} } -func NewSchemaTable(ctx *sql.Context, db Database, backingTable *WritableDoltTable) (sql.Table, error) { - if !backingTable.Schema().Contains(doltdb.SchemasTablesExtraCol, doltdb.SchemasTableName) { - return nil, fmt.Errorf("cannot migrate dolt_schemas table from v0.19.1 or earlier") - } - +func NewSchemaTable(backingTable *WritableDoltTable) (sql.Table, error) { return &SchemaTable{backingTable: backingTable}, nil } @@ -221,10 +238,9 @@ func getOrCreateDoltSchemasTable(ctx *sql.Context, db Database) (retTbl *Writabl if wrapper.backingTable != nil { schemasTable := wrapper.backingTable - // Old schemas are missing the `extra` column. Very ancient. Provide error message and bail. - if !schemasTable.Schema().Contains(doltdb.SchemasTablesExtraCol, doltdb.SchemasTableName) { - return nil, fmt.Errorf("cannot migrate dolt_schemas table from v0.19.1 or earlier") - } else if !schemasTable.Schema().Contains(doltdb.SchemasTablesSqlModeCol, doltdb.SchemasTableName) { + + if !schemasTable.Schema().Contains(doltdb.SchemasTablesExtraCol, doltdb.SchemasTableName) || + !schemasTable.Schema().Contains(doltdb.SchemasTablesSqlModeCol, doltdb.SchemasTableName) { return migrateOldSchemasTableToNew(ctx, db, schemasTable) } else { return schemasTable, nil @@ -288,8 +304,9 @@ func migrateOldSchemasTableToNew(ctx *sql.Context, db Database, schemasTable *Wr newRow[0] = sqlRow[typeIdx] newRow[1] = sqlRow[nameIdx] newRow[2] = sqlRow[fragmentIdx] - newRow[3] = sqlRow[extraIdx] - + if extraIdx >= 0 { + newRow[3] = sqlRow[extraIdx] + } if sqlModeIdx >= 0 { newRow[4] = sqlRow[sqlModeIdx] } diff --git a/go/libraries/doltcore/sqle/schema_table_test.go b/go/libraries/doltcore/sqle/schema_table_test.go index cb115bede76..5f47fe0bf37 100644 --- a/go/libraries/doltcore/sqle/schema_table_test.go +++ b/go/libraries/doltcore/sqle/schema_table_test.go @@ -16,10 +16,12 @@ package sqle import ( "context" + "io" "testing" "github.com/dolthub/go-mysql-server/sql" gmstypes "github.com/dolthub/go-mysql-server/sql/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" @@ -45,10 +47,47 @@ func TestAncientSchemaTableError(t *testing.T) { }), sql.Collation_Default, "") require.NoError(t, err) - _, _, err = db.GetTableInsensitive(ctx, doltdb.SchemasTableName) - require.Error(t, err) - require.Contains(t, err.Error(), "cannot migrate dolt_schemas table from v0.19.1 or earlier") + sqlTbl, found, err := db.GetTableInsensitive(ctx, doltdb.SchemasTableName) + require.NoError(t, err) + require.True(t, found) + + wrapper, ok := sqlTbl.(*SchemaTable) + require.True(t, ok) + require.NotNil(t, wrapper.backingTable) + // unmodified dolt_schemas table. + require.Equal(t, 3, len(wrapper.backingTable.Schema())) + + inserter := wrapper.backingTable.Inserter(ctx) + err = inserter.Insert(ctx, sql.Row{"view", "view1", "SELECT v1 FROM test;"}) + require.NoError(t, err) + err = inserter.Insert(ctx, sql.Row{"view", "view2", "SELECT v2 FROM test;"}) + require.NoError(t, err) + err = inserter.Close(ctx) + require.NoError(t, err) + + tbl, err := getOrCreateDoltSchemasTable(ctx, db) // removes the old table and recreates it with the new schema + require.NoError(t, err) + + iter, err := SqlTableToRowIter(ctx, tbl.DoltTable, nil) + require.NoError(t, err) + var rows []sql.Row + for { + row, err := iter.Next(ctx) + if err == io.EOF { + break + } + + require.NoError(t, err) + rows = append(rows, row) + } + + require.NoError(t, iter.Close(ctx)) + expectedRows := []sql.Row{ + {"view", "view1", "SELECT v1 FROM test;", nil, nil}, + {"view", "view2", "SELECT v2 FROM test;", nil, nil}, + } + assert.Equal(t, expectedRows, rows) } func TestV1SchemasTable(t *testing.T) { diff --git a/integration-tests/bats/triggers.bats b/integration-tests/bats/triggers.bats index 79b2d998f25..4ec8b81641b 100644 --- a/integration-tests/bats/triggers.bats +++ b/integration-tests/bats/triggers.bats @@ -184,3 +184,22 @@ SQL [ "$status" -eq "0" ] [[ "$output" =~ "type,name,fragment,extra,sql_mode" ]] || false } + +@test "triggers: Upgrade oldest dolt_schemas" { + rm -rf .dolt + + # old_old_dolt_schemas was created using v0.19.0, which is pre-extra column. + cp -a $BATS_TEST_DIRNAME/helper/old_old_dolt_schemas/. ./.dolt/ + + run dolt sql -q "SELECT * FROM dolt_schemas" -r=csv + [ "$status" -eq "0" ] + + [[ "$output" =~ "type,name,fragment" ]] || false + [[ "$output" =~ "view,view1,SELECT 2+2 FROM dual" ]] || false + + dolt sql -q "CREATE VIEW another_view AS SELECT 3+3" + + run dolt sql -q "SELECT * FROM dolt_schemas" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "type,name,fragment,extra,sql_mode" ]] || false +}