Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql: add virtual table pushdown infrastructure, and add to several spots #47316

Merged
merged 3 commits into from
Apr 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 78 additions & 138 deletions pkg/sql/crdb_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/cockroach/pkg/util/hlc"
Expand All @@ -46,10 +47,9 @@ import (
"github.com/cockroachdb/cockroach/pkg/util/protoutil"
"github.com/cockroachdb/cockroach/pkg/util/timeutil"
"github.com/cockroachdb/errors"
"gopkg.in/yaml.v2"
)

const crdbInternalName = "crdb_internal"
const crdbInternalName = sessiondata.CRDBInternalSchemaName

// Naming convention:
// - if the response is served from memory, prefix with node_
Expand Down Expand Up @@ -1371,13 +1371,18 @@ CREATE TABLE crdb_internal.builtin_functions (
},
}

// Prepare the row populate function.
var typeView = tree.NewDString("view")
var typeTable = tree.NewDString("table")
var typeSequence = tree.NewDString("sequence")

// crdbInternalCreateStmtsTable exposes the CREATE TABLE/CREATE VIEW
// statements.
//
// TODO(tbg): prefix with kv_.
var crdbInternalCreateStmtsTable = virtualSchemaTable{
comment: `CREATE and ALTER statements for all tables accessible by current user in current database (KV scan)`,
schema: `
var crdbInternalCreateStmtsTable = makeAllRelationsVirtualTableWithDescriptorIDIndex(
`CREATE and ALTER statements for all tables accessible by current user in current database (KV scan)`,
`
CREATE TABLE crdb_internal.create_statements (
database_id INT,
database_name STRING,
Expand All @@ -1390,148 +1395,83 @@ CREATE TABLE crdb_internal.create_statements (
create_nofks STRING NOT NULL,
alter_statements STRING[] NOT NULL,
validate_statements STRING[] NOT NULL,
zone_configuration_statements STRING[] NOT NULL
has_partitions BOOL NOT NULL,
INDEX(descriptor_id)
)
`,
populate: func(ctx context.Context, p *planner, dbContext *DatabaseDescriptor, addRow func(...tree.Datum) error) error {
`, virtualOnce, false, /* includesIndexEntries */
func(ctx context.Context, p *planner, h oidHasher, db *sqlbase.DatabaseDescriptor, scName string,
table *sqlbase.TableDescriptor, lookup simpleSchemaResolver, addRow func(...tree.Datum) error) error {
contextName := ""
if dbContext != nil {
contextName = dbContext.Name
}

// Prepare the row populate function.
typeView := tree.NewDString("view")
typeTable := tree.NewDString("table")
typeSequence := tree.NewDString("sequence")

// Hold the configuration statements for each table
zoneConfigStmts := make(map[string][]string)
// Prepare a query used to see zones configuations on this table.
configStmtsQuery := `
SELECT
table_name, raw_config_yaml, raw_config_sql
FROM
crdb_internal.zones
WHERE
database_name = '%[1]s'
AND table_name IS NOT NULL
AND raw_config_yaml IS NOT NULL
AND raw_config_sql IS NOT NULL
ORDER BY
database_name, table_name, index_name, partition_name
`
// The create_statements table is used at times where other internal
// tables have not been created, or are unaccessible (perhaps during
// certain tests (TestDumpAsOf in pkg/cli/dump_test.go)). So if something
// goes wrong querying this table, proceed without any constraint data.
zoneConstraintRows, err := p.ExtendedEvalContext().ExecCfg.InternalExecutor.Query(
ctx, "zone-constraints-for-show-create-table", p.txn,
fmt.Sprintf(configStmtsQuery, contextName))
if err != nil {
log.VEventf(ctx, 1, "%q", err)
parentNameStr := tree.DNull
if db != nil {
contextName = db.Name
parentNameStr = tree.NewDString(db.Name)
}
scNameStr := tree.NewDString(scName)

var descType tree.Datum
var stmt, createNofk string
alterStmts := tree.NewDArray(types.String)
validateStmts := tree.NewDArray(types.String)
var err error
if table.IsView() {
descType = typeView
stmt, err = ShowCreateView(ctx, (*tree.Name)(&table.Name), table)
} else if table.IsSequence() {
descType = typeSequence
stmt, err = ShowCreateSequence(ctx, (*tree.Name)(&table.Name), table)
} else {
for _, row := range zoneConstraintRows {
tableName := string(tree.MustBeDString(row[0]))
var zoneConfig zonepb.ZoneConfig
yamlString := string(tree.MustBeDString(row[1]))
err := yaml.UnmarshalStrict([]byte(yamlString), &zoneConfig)
if err != nil {
return err
}
// If all constraints are default, then don't show anything.
if !zoneConfig.Equal(zonepb.ZoneConfig{}) {
sqlString := string(tree.MustBeDString(row[2]))
zoneConfigStmts[tableName] = append(zoneConfigStmts[tableName], sqlString)
}
descType = typeTable
tn := (*tree.Name)(&table.Name)
createNofk, err = ShowCreateTable(ctx, p, tn, contextName, table, lookup, OmitFKClausesFromCreate)
if err != nil {
return err
}
allIdx := append(table.Indexes, table.PrimaryIndex)
if err := showAlterStatementWithInterleave(ctx, tn, contextName, lookup, allIdx, table, alterStmts,
validateStmts); err != nil {
return err
}
stmt, err = ShowCreateTable(ctx, p, tn, contextName, table, lookup, IncludeFkClausesInCreate)
}
if err != nil {
return err
}

return forEachTableDescWithTableLookupInternal(ctx, p, dbContext, virtualOnce, true, /*allowAdding*/
func(db *DatabaseDescriptor, scName string, table *TableDescriptor, lCtx tableLookupFn) error {
parentNameStr := tree.DNull
if db != nil {
parentNameStr = tree.NewDString(db.Name)
}
scNameStr := tree.NewDString(scName)

var descType tree.Datum
var stmt, createNofk string
alterStmts := tree.NewDArray(types.String)
validateStmts := tree.NewDArray(types.String)
var err error
if table.IsView() {
descType = typeView
stmt, err = ShowCreateView(ctx, (*tree.Name)(&table.Name), table)
} else if table.IsSequence() {
descType = typeSequence
stmt, err = ShowCreateSequence(ctx, (*tree.Name)(&table.Name), table)
} else {
descType = typeTable
tn := (*tree.Name)(&table.Name)
createNofk, err = ShowCreateTable(ctx, p, tn, contextName, table, lCtx, OmitFKClausesFromCreate)
if err != nil {
return err
}
allIdx := append(table.Indexes, table.PrimaryIndex)
if err := showAlterStatementWithInterleave(ctx, tn, contextName, lCtx, allIdx, table, alterStmts, validateStmts); err != nil {
return err
}
stmt, err = ShowCreateTable(ctx, p, tn, contextName, table, lCtx, IncludeFkClausesInCreate)
}
if err != nil {
return err
}

zoneRows := tree.NewDArray(types.String)
if val, ok := zoneConfigStmts[table.Name]; ok {
for _, s := range val {
if err := zoneRows.Append(tree.NewDString(s)); err != nil {
return err
}
}
} else {
// If there are partitions applied to this table and no zone configurations, display a warning.
hasPartitions := false
for i := range table.Indexes {
if table.Indexes[i].Partitioning.NumColumns != 0 {
hasPartitions = true
break
}
}
hasPartitions = hasPartitions || table.PrimaryIndex.Partitioning.NumColumns != 0
if hasPartitions {
stmt += "\n-- Warning: Partitioned table with no zone configurations."
}
}

descID := tree.NewDInt(tree.DInt(table.ID))
dbDescID := tree.NewDInt(tree.DInt(table.GetParentID()))
if createNofk == "" {
createNofk = stmt
}
return addRow(
dbDescID,
parentNameStr,
scNameStr,
descID,
descType,
tree.NewDString(table.Name),
tree.NewDString(stmt),
tree.NewDString(table.State.String()),
tree.NewDString(createNofk),
alterStmts,
validateStmts,
zoneRows,
)
})
},
}
descID := tree.NewDInt(tree.DInt(table.ID))
dbDescID := tree.NewDInt(tree.DInt(table.GetParentID()))
if createNofk == "" {
createNofk = stmt
}
hasPartitions := false
for i := range table.Indexes {
if table.Indexes[i].Partitioning.NumColumns != 0 {
hasPartitions = true
break
}
}
hasPartitions = hasPartitions || table.PrimaryIndex.Partitioning.NumColumns != 0
return addRow(
dbDescID,
parentNameStr,
scNameStr,
descID,
descType,
tree.NewDString(table.Name),
tree.NewDString(stmt),
tree.NewDString(table.State.String()),
tree.NewDString(createNofk),
alterStmts,
validateStmts,
tree.MakeDBool(tree.DBool(hasPartitions)),
)
})

func showAlterStatementWithInterleave(
ctx context.Context,
tn *tree.Name,
contextName string,
lCtx tableLookupFn,
lCtx simpleSchemaResolver,
allIdx []sqlbase.IndexDescriptor,
table *sqlbase.TableDescriptor,
alterStmts *tree.DArray,
Expand Down Expand Up @@ -1574,7 +1514,7 @@ func showAlterStatementWithInterleave(
var err error
var parentName tree.TableName
if lCtx != nil {
parentName, err = lCtx.getParentAsTableName(parentTableID, contextName)
parentName, err = getParentAsTableName(lCtx, parentTableID, contextName)
if err != nil {
return err
}
Expand All @@ -1586,7 +1526,7 @@ func showAlterStatementWithInterleave(

var tableName tree.TableName
if lCtx != nil {
tableName, err = lCtx.getTableAsTableName(table, contextName)
tableName, err = getTableAsTableName(lCtx, table, contextName)
if err != nil {
return err
}
Expand Down
10 changes: 6 additions & 4 deletions pkg/sql/delayed.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package sql
import (
"context"

"github.com/cockroachdb/cockroach/pkg/sql/opt/constraint"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
)
Expand All @@ -21,10 +22,11 @@ import (
// constructor must be delayed during query execution (as opposed to
// SQL prepare) for resource tracking purposes.
type delayedNode struct {
name string
columns sqlbase.ResultColumns
constructor nodeConstructor
plan planNode
name string
columns sqlbase.ResultColumns
indexConstraint *constraint.Constraint
constructor nodeConstructor
plan planNode
}

type nodeConstructor func(context.Context, *planner) (planNode, error)
Expand Down
32 changes: 20 additions & 12 deletions pkg/sql/delegate/show_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,30 @@ import (

func (d *delegator) delegateShowCreate(n *tree.ShowCreate) (tree.Statement, error) {
sqltelemetry.IncrementShowCounter(sqltelemetry.Create)

const showCreateQuery = `
WITH zone_configs AS (
SELECT string_agg(raw_config_sql, e';\n') FROM crdb_internal.zones
WHERE database_name = %[1]s
AND table_name = %[2]s
AND raw_config_yaml IS NOT NULL
AND raw_config_sql IS NOT NULL
)
SELECT
%[3]s AS table_name,
array_to_string(
array_cat(
ARRAY[create_statement],
zone_configuration_statements
),
e';\n'
)
AS create_statement
concat(create_statement,
CASE
WHEN NOT has_partitions
THEN NULL
WHEN (SELECT * FROM zone_configs) IS NULL
THEN e'\n-- Warning: Partitioned table with no zone configurations.'
ELSE concat(e';\n', (SELECT * FROM zone_configs))
END
) AS create_statement
FROM
%[4]s.crdb_internal.create_statements
WHERE
(database_name IS NULL OR database_name = %[1]s)
AND schema_name = %[5]s
AND descriptor_name = %[2]s
descriptor_id = %[6]d
`

return d.showTableDetails(n.Name, showCreateQuery)
Expand Down Expand Up @@ -164,6 +171,7 @@ func (d *delegator) delegateShowConstraints(n *tree.ShowConstraints) (tree.State
// %[3]s the given table name as SQL string literal.
// %[4]s the database name as SQL identifier.
// %[5]s the schema name as SQL string literal.
// %[6]s the table ID.
func (d *delegator) showTableDetails(
name *tree.UnresolvedObjectName, query string,
) (tree.Statement, error) {
Expand All @@ -185,7 +193,7 @@ func (d *delegator) showTableDetails(
lex.EscapeSQLString(resName.String()),
resName.CatalogName.String(), // note: CatalogName.String() != Catalog()
lex.EscapeSQLString(resName.Schema()),
dataSource.ID(),
dataSource.PostgresDescriptorID(),
)

return parse(fullQuery)
Expand Down
Loading