예제 #1
0
파일: database.go 프로젝트: knz/cockroach
// 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
}
예제 #2
0
// 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
}
예제 #3
0
// 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
}
예제 #4
0
// 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
}
예제 #5
0
// 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
}