// getDatabaseDesc implements the DatabaseAccessor interface. func (p *planner) mustGetDatabaseDesc(name string) (*sqlbase.DatabaseDescriptor, error) { desc, err := p.getDatabaseDesc(name) if err != nil { return nil, err } if desc == nil { return nil, sqlbase.NewUndefinedDatabaseError(name) } return desc, nil }
// MustGetDatabaseDesc looks up the database descriptor given its name, // returning an error if the descriptor is not found. func MustGetDatabaseDesc( txn *client.Txn, vt VirtualTabler, name string, ) (*sqlbase.DatabaseDescriptor, error) { desc, err := getDatabaseDesc(txn, vt, name) if err != nil { return nil, err } if desc == nil { return nil, sqlbase.NewUndefinedDatabaseError(name) } return desc, nil }
// ShowTables returns all the tables. // Privileges: None. // Notes: postgres does not have a SHOW TABLES statement. // mysql only returns tables you have privileges on. func (p *planner) ShowTables(n *parser.ShowTables) (planNode, error) { name := p.session.Database if n.Database != "" { name = string(n.Database) } if name == "" { return nil, errNoDatabase } columns := ResultColumns{{Name: "Table", Typ: parser.TypeString}} return &delayedNode{ p: p, name: "SHOW TABLES FROM " + name, columns: columns, constructor: func(p *planner) (planNode, error) { { // Check if the database exists by using the security.RootUser. values, err := p.queryRowsAsRoot(checkSchema, name) if err != nil { return nil, err } if len(values) == 0 { return nil, sqlbase.NewUndefinedDatabaseError(name) } } // Temporarily set the current database to get visibility into // information_schema if the current user isn't root. origDatabase := p.evalCtx.Database p.evalCtx.Database = name defer func() { p.evalCtx.Database = origDatabase }() // Get the tables of database from information_schema.tables. const getTables = `SELECT TABLE_NAME FROM information_schema.tables WHERE tables.TABLE_SCHEMA=$1 ORDER BY tables.TABLE_NAME` rows, err := p.queryRows(getTables, name) if err != nil { return nil, err } v := p.newContainerValuesNode(columns, 0) for _, r := range rows { if _, err := v.rows.AddRow(r); err != nil { v.rows.Close() return nil, err } } return v, nil }, }, nil }
// ShowGrants returns grant details for the specified objects and users. // TODO(marc): implement no targets (meaning full scan). // Privileges: None. // Notes: postgres does not have a SHOW GRANTS statement. // mysql only returns the user's privileges. func (p *planner) ShowGrants(n *parser.ShowGrants) (planNode, error) { if n.Targets == nil { return nil, errors.Errorf("TODO(marc): implement SHOW GRANT with no targets") } objectType := "Database" if n.Targets.Tables != nil { objectType = "Table" } columns := ResultColumns{ {Name: objectType, Typ: parser.TypeString}, {Name: "User", Typ: parser.TypeString}, {Name: "Privileges", Typ: parser.TypeString}, } return &delayedNode{ p: p, name: "SHOW GRANTS", columns: columns, constructor: func(p *planner) (planNode, error) { v := p.newContainerValuesNode(columns, 0) // Check if the target exists. checkFn := func(sql string, args ...interface{}) (bool, error) { values, err := p.queryRowsAsRoot(sql, args...) if err != nil { return false, err } if len(values) > 0 { return true, nil } return false, nil } queryFn := func(sql string, args ...interface{}) error { rows, err := p.queryRows(sql, args...) if err != nil { return err } for _, r := range rows { if _, err := v.rows.AddRow(r); err != nil { return err } } return nil } // Get grants of database from information_schema.schema_privileges // if the type of target is database. if n.Targets.Databases != nil { // TODO(nvanbenschoten): Clean up parameter assignment throughout. var params []interface{} var paramHolders []string paramSeq := 1 for _, db := range n.Targets.Databases.ToStrings() { exists, err := checkFn(checkSchema, db) if err != nil { v.rows.Close() return nil, err } if !exists { v.rows.Close() return nil, sqlbase.NewUndefinedDatabaseError(db) } paramHolders = append(paramHolders, fmt.Sprintf("$%d", paramSeq)) paramSeq++ params = append(params, db) } schemaGrants := fmt.Sprintf(`SELECT TABLE_SCHEMA AS "Database", GRANTEE AS "User", PRIVILEGE_TYPE AS "Privileges" FROM information_schema.schema_privileges WHERE TABLE_SCHEMA IN (%s)`, strings.Join(paramHolders, ",")) if n.Grantees != nil { paramHolders = paramHolders[:0] for _, grantee := range n.Grantees.ToStrings() { paramHolders = append(paramHolders, fmt.Sprintf("$%d", paramSeq)) params = append(params, grantee) paramSeq++ } schemaGrants = fmt.Sprintf(`%s AND GRANTEE IN(%s)`, schemaGrants, strings.Join(paramHolders, ",")) } if err := queryFn(schemaGrants, params...); err != nil { v.rows.Close() return nil, err } } // Get grants of table from information_schema.table_privileges // if the type of target is table. if n.Targets.Tables != nil { // TODO(nvanbenschoten): Clean up parameter assignment throughout. var params []interface{} var paramHolders []string paramSeq := 1 for _, tableTarget := range n.Targets.Tables { tableGlob, err := tableTarget.NormalizeTablePattern() if err != nil { v.rows.Close() return nil, err } tables, err := p.expandTableGlob(tableGlob) if err != nil { v.rows.Close() return nil, err } for i := range tables { exists, err := checkFn(checkTable, tables[i].Database(), tables[i].Table()) if err != nil { v.rows.Close() return nil, err } if !exists { v.rows.Close() return nil, sqlbase.NewUndefinedTableError(tables[i].String()) } paramHolders = append(paramHolders, fmt.Sprintf("($%d,$%d)", paramSeq, paramSeq+1)) params = append(params, tables[i].Database(), tables[i].Table()) paramSeq += 2 } } tableGrants := fmt.Sprintf(`SELECT TABLE_NAME, GRANTEE, PRIVILEGE_TYPE FROM information_schema.table_privileges WHERE (TABLE_SCHEMA, TABLE_NAME) IN (%s)`, strings.Join(paramHolders, ",")) if n.Grantees != nil { paramHolders = paramHolders[:0] for _, grantee := range n.Grantees.ToStrings() { paramHolders = append(paramHolders, fmt.Sprintf("$%d", paramSeq)) params = append(params, grantee) paramSeq++ } tableGrants = fmt.Sprintf(`%s AND GRANTEE IN(%s)`, tableGrants, strings.Join(paramHolders, ",")) } if err := queryFn(tableGrants, params...); err != nil { v.rows.Close() return nil, err } } // Sort the result by target name, user name and privileges. sort := &sortNode{ ctx: p.ctx(), p: p, ordering: sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, {ColIdx: 1, Direction: encoding.Ascending}, {ColIdx: 2, Direction: encoding.Ascending}, }, columns: v.columns, } return &selectTopNode{source: v, sort: sort}, nil }, }, nil }
// ShowColumns of a table. // Privileges: Any privilege on table. // Notes: postgres does not have a SHOW COLUMNS statement. // mysql only returns columns you have privileges on. func (p *planner) ShowColumns(n *parser.ShowColumns) (planNode, error) { tn, err := n.Table.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } columns := ResultColumns{ {Name: "Field", Typ: parser.TypeString}, {Name: "Type", Typ: parser.TypeString}, {Name: "Null", Typ: parser.TypeBool}, {Name: "Default", Typ: parser.TypeString}, } return &delayedNode{ p: p, name: "SHOW COLUMNS FROM " + tn.String(), columns: columns, constructor: func(p *planner) (planNode, error) { const getColumns = `SELECT COLUMN_NAME AS "Field", DATA_TYPE AS "Type", (IS_NULLABLE!='NO') AS "Null",` + ` COLUMN_DEFAULT AS "Default" FROM information_schema.columns WHERE TABLE_SCHEMA=$1 AND TABLE_NAME=$2` + ` ORDER BY ORDINAL_POSITION` { // Check if the database exists by using the security.RootUser. values, err := p.queryRowsAsRoot(checkSchema, tn.Database()) if err != nil { return nil, err } if len(values) == 0 { return nil, sqlbase.NewUndefinedDatabaseError(tn.Database()) } } { // Check if the table exists by using the security.RootUser. values, err := p.queryRowsAsRoot(checkTable, tn.Database(), tn.Table()) if err != nil { return nil, err } if len(values) == 0 { return nil, sqlbase.NewUndefinedTableError(tn.String()) } } // Check if the user has been granted. // Skip the checking if the table is a virtual table. { virDesc, err := p.session.virtualSchemas.getVirtualTableDesc(tn) if err != nil { return nil, err } if virDesc == nil { values, err := p.QueryRow(checkTablePrivilege, tn.Database(), tn.Table(), p.session.User) if err != nil { return nil, err } if len(values) == 0 { return nil, fmt.Errorf("user %s has no privileges on table %s", p.session.User, tn.String()) } } } // Temporarily set the current database to get visibility into // information_schema if the current user isn't root. origDatabase := p.evalCtx.Database p.evalCtx.Database = tn.Database() defer func() { p.evalCtx.Database = origDatabase }() // Get columns of table from information_schema.columns. rows, err := p.queryRows(getColumns, tn.Database(), tn.Table()) if err != nil { return nil, err } v := p.newContainerValuesNode(columns, 0) for _, r := range rows { if _, err := v.rows.AddRow(r); err != nil { v.rows.Close() return nil, err } } return v, nil }, }, nil }