Example #1
0
func makeIndexKeyVals(desc *structured.TableDescriptor,
	index structured.IndexDescriptor) ([]parser.Datum, error) {
	vals := make([]parser.Datum, len(index.ColumnIDs))
	for i, id := range index.ColumnIDs {
		col, err := desc.FindColumnByID(id)
		if err != nil {
			return nil, err
		}
		switch col.Type.Kind {
		case structured.ColumnType_BIT, structured.ColumnType_INT:
			vals[i] = parser.DInt(0)
		case structured.ColumnType_FLOAT:
			vals[i] = parser.DFloat(0)
		case structured.ColumnType_CHAR, structured.ColumnType_TEXT,
			structured.ColumnType_BLOB:
			vals[i] = parser.DString("")
		default:
			return nil, util.Errorf("TODO(pmattis): decoded index key: %s", col.Type.Kind)
		}
	}
	if !index.Unique {
		// Non-unique columns are suffixed by the primary index key.
		pkVals, err := makeIndexKeyVals(desc, desc.PrimaryIndex)
		if err != nil {
			return nil, err
		}
		vals = append(vals, pkVals...)
	}
	return vals, nil
}
Example #2
0
func (db *DB) getTableDesc(path string) (*structured.TableDescriptor, error) {
	nsID, name, err := db.lookupTable(path)
	if err != nil {
		return nil, err
	}
	if name == "" {
		return nil, fmt.Errorf("empty table name: %s", path)
	}
	gr, err := db.Get(keys.MakeNameMetadataKey(nsID, name))
	if err != nil {
		return nil, err
	}
	if !gr.Exists() {
		return nil, fmt.Errorf("unable to find table \"%s\"", path)
	}
	descKey := gr.ValueBytes()
	desc := structured.TableDescriptor{}
	if err := db.GetProto(descKey, &desc); err != nil {
		return nil, err
	}
	if err := desc.Validate(); err != nil {
		return nil, err
	}
	return &desc, nil
}
Example #3
0
func (s *Server) getTableDesc(database string, qname parser.QualifiedName) (
	*structured.TableDescriptor, error) {
	var err error
	qname, err = s.normalizeTableName(database, qname)
	if err != nil {
		return nil, err
	}
	dbID, err := s.lookupDatabase(qname.Database())
	if err != nil {
		return nil, err
	}
	gr, err := s.db.Get(keys.MakeNameMetadataKey(dbID, qname.Table()))
	if err != nil {
		return nil, err
	}
	if !gr.Exists() {
		return nil, fmt.Errorf("table \"%s\" does not exist", qname)
	}
	descKey := gr.ValueBytes()
	desc := structured.TableDescriptor{}
	if err := s.db.GetProto(descKey, &desc); err != nil {
		return nil, err
	}
	if err := desc.Validate(); err != nil {
		return nil, err
	}
	return &desc, nil
}
Example #4
0
func (s *Server) processColumns(desc *structured.TableDescriptor,
	node parser.Columns) ([]structured.ColumnDescriptor, error) {
	if node == nil {
		return desc.Columns, nil
	}

	cols := make([]structured.ColumnDescriptor, len(node))
	for i, n := range node {
		switch nt := n.(type) {
		case *parser.StarExpr:
			return s.processColumns(desc, nil)
		case *parser.NonStarExpr:
			switch et := nt.Expr.(type) {
			case *parser.ColName:
				// TODO(pmattis): If et.Qualifier is not empty, verify it matches the
				// table name.
				var err error
				col, err := desc.FindColumnByName(et.Name)
				if err != nil {
					return nil, err
				}
				cols[i] = *col
			default:
				return nil, fmt.Errorf("unexpected node: %T", nt.Expr)
			}
		}
	}

	return cols, nil
}
Example #5
0
func (c *conn) getTableDesc(table *parser.TableName) (*structured.TableDescriptor, error) {
	if err := c.normalizeTableName(table); err != nil {
		return nil, err
	}
	dbID, err := c.lookupDatabase(table.Qualifier)
	if err != nil {
		return nil, err
	}
	gr, err := c.db.Get(keys.MakeNameMetadataKey(dbID, table.Name))
	if err != nil {
		return nil, err
	}
	if !gr.Exists() {
		return nil, fmt.Errorf("table \"%s\" does not exist", table)
	}
	descKey := gr.ValueBytes()
	desc := structured.TableDescriptor{}
	if err := c.db.GetProto(descKey, &desc); err != nil {
		return nil, err
	}
	if err := desc.Validate(); err != nil {
		return nil, err
	}
	return &desc, nil
}
Example #6
0
// DropTable drops a table.
// Privileges: WRITE on table.
//   Notes: postgres allows only the table owner to DROP a table.
//          mysql requires the DROP privilege on the table.
func (p *planner) DropTable(n *parser.DropTable) (planNode, error) {
	// TODO(XisiHuang): should do truncate and delete descriptor in
	// the same txn
	for i, tableQualifiedName := range n.Names {
		if err := tableQualifiedName.NormalizeTableName(p.session.Database); err != nil {
			return nil, err
		}

		dbDesc, err := p.getDatabaseDesc(tableQualifiedName.Database())
		if err != nil {
			return nil, err
		}

		tbKey := tableKey{dbDesc.ID, tableQualifiedName.Table()}
		nameKey := tbKey.Key()
		gr, err := p.txn.Get(nameKey)
		if err != nil {
			return nil, err
		}

		if !gr.Exists() {
			if n.IfExists {
				// Noop.
				continue
			}
			// Key does not exist, but we want it to: error out.
			return nil, fmt.Errorf("table %q does not exist", tbKey.Name())
		}

		tableDesc := structured.TableDescriptor{}
		if err := p.txn.GetProto(gr.ValueBytes(), &tableDesc); err != nil {
			return nil, err
		}
		if err := tableDesc.Validate(); err != nil {
			return nil, err
		}

		if !tableDesc.HasPrivilege(p.user, parser.PrivilegeWrite) {
			return nil, fmt.Errorf("user %s does not have %s privilege on table %s",
				p.user, parser.PrivilegeWrite, tableDesc.Name)
		}

		if _, err = p.Truncate(&parser.Truncate{Tables: n.Names[i : i+1]}); err != nil {
			return nil, err
		}

		// Delete table descriptor
		descKey := gr.ValueBytes()
		b := &client.Batch{}
		b.Del(descKey)
		b.Del(nameKey)
		err = p.txn.Run(b)
		if err != nil {
			return nil, err
		}
	}
	return &valuesNode{}, nil
}
Example #7
0
// RenameTable renames a table. Old path and new path have the form
// "<namespace>.<table>".
func (db *DB) RenameTable(oldPath, newPath string) error {
	// TODO(pmattis): Should we allow both the old and new name to exist
	// simultaneously for a period of time? The thought is to allow an
	// application to access the table via either name while the application is
	// being upgraded. Alternatively, instead of a rename table operation perhaps
	// there should be a link table operation which adds a "hard link" to the
	// table. Similar to a file, a table would not be removed until all of the
	// hard links are removed.

	oldNSID, oldName, err := db.lookupTable(oldPath)
	if err != nil {
		return err
	}
	newNSID, newName, err := db.lookupTable(newPath)
	if err != nil {
		return err
	}
	if newName == "" {
		return fmt.Errorf("empty table name: %s", newPath)
	}

	return db.Txn(func(txn *Txn) error {
		oldNameKey := keys.MakeNameMetadataKey(oldNSID, oldName)
		gr, err := txn.Get(oldNameKey)
		if err != nil {
			return err
		}
		if !gr.Exists() {
			return fmt.Errorf("unable to find table \"%s\"", oldPath)
		}
		descKey := gr.ValueBytes()
		desc := structured.TableDescriptor{}
		if err := txn.GetProto(descKey, &desc); err != nil {
			return err
		}
		desc.Name = strings.ToLower(newPath)
		if err := structured.ValidateTableDesc(desc); err != nil {
			return err
		}
		newNameKey := keys.MakeNameMetadataKey(newNSID, newName)
		b := &Batch{}
		b.Put(descKey, &desc)
		// If the new name already exists the conditional put will fail causing the
		// transaction to fail.
		b.CPut(newNameKey, descKey, nil)
		b.Del(oldNameKey)
		return txn.Commit(b)
	})
}
Example #8
0
func decodeIndexKey(desc *structured.TableDescriptor,
	index structured.IndexDescriptor, vals map[string]parser.Datum, key []byte) ([]byte, error) {
	if !bytes.HasPrefix(key, keys.TableDataPrefix) {
		return nil, fmt.Errorf("%s: invalid key prefix: %q", desc.Name, key)
	}
	key = bytes.TrimPrefix(key, keys.TableDataPrefix)

	var tableID uint64
	key, tableID = encoding.DecodeUvarint(key)
	if uint32(tableID) != desc.ID {
		return nil, fmt.Errorf("%s: unexpected table ID: %d != %d", desc.Name, desc.ID, tableID)
	}

	var indexID uint64
	key, indexID = encoding.DecodeUvarint(key)
	if uint32(indexID) != index.ID {
		return nil, fmt.Errorf("%s: unexpected index ID: %d != %d", desc.Name, index.ID, indexID)
	}

	for _, id := range index.ColumnIDs {
		col, err := desc.FindColumnByID(id)
		if err != nil {
			return nil, err
		}
		switch col.Type.Kind {
		case structured.ColumnType_BIT, structured.ColumnType_INT:
			var i int64
			key, i = encoding.DecodeVarint(key)
			vals[col.Name] = parser.DInt(i)
		case structured.ColumnType_FLOAT:
			var f float64
			key, f = encoding.DecodeNumericFloat(key)
			vals[col.Name] = parser.DFloat(f)
		case structured.ColumnType_CHAR, structured.ColumnType_TEXT,
			structured.ColumnType_BLOB:
			var r []byte
			key, r = encoding.DecodeBytes(key, nil)
			vals[col.Name] = parser.DString(r)
		default:
			return nil, util.Errorf("TODO(pmattis): decoded index key: %s", col.Type.Kind)
		}
	}

	return key, nil
}
Example #9
0
func (p *planner) processColumns(desc *structured.TableDescriptor,
	node parser.QualifiedNames) ([]structured.ColumnDescriptor, error) {
	if node == nil {
		return desc.Columns, nil
	}

	cols := make([]structured.ColumnDescriptor, len(node))
	for i, n := range node {
		// TODO(pmattis): If the name is qualified, verify the table name matches
		// desc.Name.
		var err error
		col, err := desc.FindColumnByName(n.Column())
		if err != nil {
			return nil, err
		}
		cols[i] = *col
	}

	return cols, nil
}
Example #10
0
// CreateTable creates a table from the specified schema. Table creation will
// fail if the table name is already in use. The table name is required to have
// the form "<namespace>.<table>".
func (db *DB) CreateTable(desc *structured.TableDescriptor) error {
	desc.Name = strings.ToLower(desc.Name)
	if err := desc.AllocateIDs(); err != nil {
		return err
	}

	nsID, name, err := db.lookupTable(desc.Name)
	if err != nil {
		return err
	}
	if name == "" {
		return fmt.Errorf("empty table name: %s", desc.Name)
	}
	nameKey := keys.MakeNameMetadataKey(nsID, name)

	// This isn't strictly necessary as the conditional put below will fail if
	// the key already exists, but it seems good to avoid the table ID allocation
	// in most cases when the table already exists.
	if gr, err := db.Get(nameKey); err != nil {
		return err
	} else if gr.Exists() {
		return fmt.Errorf("table \"%s\" already exists", desc.Name)
	}

	ir, err := db.Inc(keys.DescIDGenerator, 1)
	if err != nil {
		return err
	}
	desc.ID = uint32(ir.ValueInt() - 1)

	// TODO(pmattis): Be cognizant of error messages when this is ported to the
	// server. The error currently returned below is likely going to be difficult
	// to interpret.
	return db.Txn(func(txn *Txn) error {
		descKey := keys.MakeDescMetadataKey(desc.ID)
		b := &Batch{}
		b.CPut(nameKey, descKey, nil)
		b.Put(descKey, desc)
		return txn.Commit(b)
	})
}
Example #11
0
func makeTableDesc(p *parser.CreateTable) (structured.TableDescriptor, error) {
	desc := structured.TableDescriptor{}
	desc.Name = p.Table.String()

	for _, def := range p.Defs {
		switch d := def.(type) {
		case *parser.ColumnTableDef:
			col := structured.ColumnDescriptor{
				Name:     d.Name,
				Nullable: (d.Nullable != parser.NotNull),
			}
			switch t := d.Type.(type) {
			case *parser.BitType:
				col.Type.Kind = structured.ColumnType_BIT
				col.Type.Width = int32(t.N)
			case *parser.IntType:
				col.Type.Kind = structured.ColumnType_INT
				col.Type.Width = int32(t.N)
			case *parser.FloatType:
				col.Type.Kind = structured.ColumnType_FLOAT
				col.Type.Precision = int32(t.Prec)
			case *parser.DecimalType:
				col.Type.Kind = structured.ColumnType_DECIMAL
				col.Type.Width = int32(t.Scale)
				col.Type.Precision = int32(t.Prec)
			case *parser.DateType:
				col.Type.Kind = structured.ColumnType_DATE
			case *parser.TimeType:
				col.Type.Kind = structured.ColumnType_TIME
			case *parser.TimestampType:
				col.Type.Kind = structured.ColumnType_TIMESTAMP
			case *parser.CharType:
				col.Type.Kind = structured.ColumnType_CHAR
				col.Type.Width = int32(t.N)
			case *parser.TextType:
				col.Type.Kind = structured.ColumnType_TEXT
			case *parser.BlobType:
				col.Type.Kind = structured.ColumnType_BLOB
			}
			desc.Columns = append(desc.Columns, col)

			// Create any associated index.
			if d.PrimaryKey || d.Unique {
				index := structured.IndexDescriptor{
					Unique:      true,
					ColumnNames: []string{d.Name},
				}
				if d.PrimaryKey {
					index.Name = "primary"
				}
				desc.Indexes = append(desc.Indexes, index)
			}
		case *parser.IndexTableDef:
			index := structured.IndexDescriptor{
				Name:        d.Name,
				Unique:      d.Unique,
				ColumnNames: d.Columns,
			}
			desc.Indexes = append(desc.Indexes, index)
		default:
			return desc, fmt.Errorf("unsupported table def: %T", def)
		}
	}
	return desc, nil
}
Example #12
0
func makeTableDesc(p *parser.CreateTable) (structured.TableDescriptor, error) {
	desc := structured.TableDescriptor{}
	desc.Name = p.Table.Table()
	for _, def := range p.Defs {
		switch d := def.(type) {
		case *parser.ColumnTableDef:
			col := structured.ColumnDescriptor{
				Name:     string(d.Name),
				Nullable: (d.Nullable != parser.NotNull),
			}
			switch t := d.Type.(type) {
			case *parser.BitType:
				col.Type.Kind = structured.ColumnType_BIT
				col.Type.Width = int32(t.N)
			case *parser.BoolType:
				col.Type.Kind = structured.ColumnType_BOOL
			case *parser.IntType:
				col.Type.Kind = structured.ColumnType_INT
				col.Type.Width = int32(t.N)
			case *parser.FloatType:
				col.Type.Kind = structured.ColumnType_FLOAT
				col.Type.Precision = int32(t.Prec)
			case *parser.DecimalType:
				col.Type.Kind = structured.ColumnType_DECIMAL
				col.Type.Width = int32(t.Scale)
				col.Type.Precision = int32(t.Prec)
			case *parser.DateType:
				col.Type.Kind = structured.ColumnType_DATE
			case *parser.TimeType:
				col.Type.Kind = structured.ColumnType_TIME
			case *parser.TimestampType:
				col.Type.Kind = structured.ColumnType_TIMESTAMP
			case *parser.CharType:
				col.Type.Kind = structured.ColumnType_CHAR
				col.Type.Width = int32(t.N)
			case *parser.TextType:
				col.Type.Kind = structured.ColumnType_TEXT
			case *parser.BlobType:
				col.Type.Kind = structured.ColumnType_BLOB
			default:
				panic(fmt.Sprintf("unexpected type %T", t))
			}
			desc.Columns = append(desc.Columns, col)

			// Create any associated index.
			if d.PrimaryKey || d.Unique {
				index := structured.IndexDescriptor{
					Unique:      true,
					ColumnNames: []string{string(d.Name)},
				}
				if d.PrimaryKey {
					index.Name = structured.PrimaryKeyIndexName
					desc.PrimaryIndex = index
				} else {
					desc.Indexes = append(desc.Indexes, index)
				}
			}
		case *parser.IndexTableDef:
			index := structured.IndexDescriptor{
				Name:        string(d.Name),
				Unique:      d.Unique,
				ColumnNames: d.Columns,
			}
			if d.PrimaryKey {
				// Only override the index name if it hasn't been set by the user.
				if index.Name == "" {
					index.Name = structured.PrimaryKeyIndexName
				}
				desc.PrimaryIndex = index
			} else {
				desc.Indexes = append(desc.Indexes, index)
			}
		default:
			return desc, fmt.Errorf("unsupported table def: %T", def)
		}
	}
	return desc, nil
}
Example #13
0
// Select selects rows from a single table.
func (s *Server) Select(session *Session, p *parser.Select, args []sqlwire.Datum, resp *sqlwire.Response) error {
	if len(p.Exprs) != 1 {
		return fmt.Errorf("TODO(pmattis): unsupported select exprs: %s", p.Exprs)
	}
	if _, ok := p.Exprs[0].(*parser.StarExpr); !ok {
		return fmt.Errorf("TODO(pmattis): unsupported select expr: %s", p.Exprs)
	}

	if len(p.From) != 1 {
		return fmt.Errorf("TODO(pmattis): unsupported from: %s", p.From)
	}
	var desc *structured.TableDescriptor
	{
		ate, ok := p.From[0].(*parser.AliasedTableExpr)
		if !ok {
			return fmt.Errorf("TODO(pmattis): unsupported from: %s", p.From)
		}
		table, ok := ate.Expr.(parser.QualifiedName)
		if !ok {
			return fmt.Errorf("TODO(pmattis): unsupported from: %s", p.From)
		}
		var err error
		desc, err = s.getTableDesc(session.Database, table)
		if err != nil {
			return err
		}
	}

	// Retrieve all of the keys that start with our index key prefix.
	startKey := proto.Key(encodeIndexKeyPrefix(desc.ID, desc.Indexes[0].ID))
	endKey := startKey.PrefixEnd()
	sr, err := s.db.Scan(startKey, endKey, 0)
	if err != nil {
		return err
	}

	// All of the columns for a particular row will be grouped together. We loop
	// over the returned key/value pairs and decode the key to extract the
	// columns encoded within the key and the column ID. We use the column ID to
	// lookup the column and decode the value. All of these values go into a map
	// keyed by column name. When the index key changes we output a row
	// containing the current values.
	//
	// The TODOs here are too numerous to list. This is only performing a full
	// table scan using the primary key.

	var rows []sqlwire.Result_Row
	var primaryKey []byte
	vals := valMap{}
	for _, kv := range sr {
		if primaryKey != nil && !bytes.HasPrefix(kv.Key, primaryKey) {
			if output, err := shouldOutputRow(p.Where, vals); err != nil {
				return err
			} else if output {
				rows = append(rows, outputRow(desc.Columns, vals))
			}
			vals = valMap{}
		}

		remaining, err := decodeIndexKey(desc, desc.Indexes[0], vals, kv.Key)
		if err != nil {
			return err
		}
		primaryKey = []byte(kv.Key[:len(kv.Key)-len(remaining)])

		_, colID := encoding.DecodeUvarint(remaining)
		if err != nil {
			return err
		}
		col, err := desc.FindColumnByID(uint32(colID))
		if err != nil {
			return err
		}
		vals[col.Name] = unmarshalValue(*col, kv)

		if log.V(2) {
			log.Infof("Scan %q -> %v", kv.Key, vals[col.Name])
		}
	}

	if output, err := shouldOutputRow(p.Where, vals); err != nil {
		return err
	} else if output {
		rows = append(rows, outputRow(desc.Columns, vals))
	}

	resp.Results = []sqlwire.Result{
		{
			Columns: make([]string, len(desc.Columns)),
			Rows:    rows,
		},
	}
	for i, col := range desc.Columns {
		resp.Results[0].Columns[i] = col.Name
	}
	return nil
}
Example #14
0
// SchemaFromModel allows the easy construction of a TableDescriptor from a Go
// struct. Columns are created for each exported field in the struct. The "db"
// struct tag is used to control the mapping of field name to column name and
// to indicate exported fields which should be skipped.
//
//   type User struct {
//     ID      int
//     Name    string `db:"old_name"`
//     Ignored int    `db:"-"`
//   }
//
// Indexes are specified using the "roach" struct tag declaration.
//
//   type User struct {
//     ID   int    `roach:"primary key"`
//     Name string `db:"old_name" roach:"index"`
//   }
//
// The following "roach" options are supported:
//
//   "primary key [(columns...)]" - creates a unique index on <columns> and
//   marks it as the primary key for the table. If <columns> is not specified
//   it defaults to the name of the column the option is associated with.
//
//   "index" [(columns...)]" - creates an index on <columns>.
//
//   "unique index" [(columns...)]" - creates a unique index on <columns>.
func SchemaFromModel(obj interface{}) (structured.TableDescriptor, error) {
	desc := structured.TableDescriptor{}
	m, err := getDBFields(deref(reflect.TypeOf(obj)))
	if err != nil {
		return desc, err
	}

	desc.Name = strings.ToLower(reflect.TypeOf(obj).Name())

	// Create the columns for the table.
	for name, sf := range m {
		colType := structured.ColumnType{}

		// TODO(pmattis): The mapping from Go-type Kind to column-type Kind is
		// likely not complete or correct, but this is probably going away pretty
		// soon with the move to SQL.
		switch sf.Type.Kind() {
		case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
			reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
			reflect.Uint64, reflect.Uintptr:
			colType.Kind = structured.ColumnType_INT

		case reflect.Float32, reflect.Float64:
			colType.Kind = structured.ColumnType_FLOAT

		case reflect.String:
			colType.Kind = structured.ColumnType_TEXT
		}

		col := structured.ColumnDescriptor{
			Name: name,
			Type: colType,
		}
		desc.Columns = append(desc.Columns, col)
	}

	// Create the indexes for the table.
	for name, f := range m {
		tag := f.Tag.Get("roach")
		if tag == "" {
			continue
		}
		for _, opt := range strings.Split(tag, ";") {
			match := schemaOptRE.FindStringSubmatch(opt)
			if match == nil {
				return desc, fmt.Errorf("invalid schema option: %s", opt)
			}
			cmd := match[1]
			var params []string
			if len(match[2]) > 0 {
				params = strings.Split(match[2], ",")
			} else {
				params = []string{name}
			}
			var index structured.IndexDescriptor
			switch strings.ToLower(cmd) {
			case "primary key":
				index.Name = structured.PrimaryKeyIndexName
				index.Unique = true
			case "unique index":
				index.Name = strings.Join(params, ":")
				index.Unique = true
			case "index":
				index.Name = strings.Join(params, ":")
			}
			index.ColumnNames = params
			desc.Indexes = append(desc.Indexes, index)
		}
	}

	// Normalize the column and index order.
	sort.Sort(columnsByName(desc.Columns))
	sort.Sort(indexesByName(desc.Indexes))
	return desc, nil
}
Example #15
0
// Select selects rows from a single table.
// Privileges: READ on table
//   Notes: postgres requires SELECT. Also requires UPDATE on "FOR UPDATE".
//          mysql requires SELECT.
func (p *planner) Select(n *parser.Select) (planNode, error) {
	var desc *structured.TableDescriptor
	var index *structured.IndexDescriptor
	var visibleCols []structured.ColumnDescriptor

	switch len(n.From) {
	case 0:
		// desc remains nil.

	case 1:
		var err error
		desc, err = p.getAliasedTableDesc(n.From[0])
		if err != nil {
			return nil, err
		}

		if !desc.HasPrivilege(p.user, parser.PrivilegeRead) {
			return nil, fmt.Errorf("user %s does not have %s privilege on table %s",
				p.user, parser.PrivilegeRead, desc.Name)
		}

		// This is only kosher because we know that getAliasedDesc() succeeded.
		qname := n.From[0].(*parser.AliasedTableExpr).Expr.(*parser.QualifiedName)
		indexName := qname.Index()
		if indexName != "" && !strings.EqualFold(desc.PrimaryIndex.Name, indexName) {
			for i := range desc.Indexes {
				if strings.EqualFold(desc.Indexes[i].Name, indexName) {
					// Remove all but the matching index from the descriptor.
					desc.Indexes = desc.Indexes[i : i+1]
					index = &desc.Indexes[0]
					break
				}
			}
			if index == nil {
				return nil, fmt.Errorf("index \"%s\" not found", indexName)
			}
			// If the table was not aliased, use the index name instead of the table
			// name for fully-qualified columns in the expression.
			if n.From[0].(*parser.AliasedTableExpr).As == "" {
				desc.Alias = index.Name
			}
			// Strip out any columns from the table that are not present in the
			// index.
			indexColIDs := map[structured.ColumnID]struct{}{}
			for _, colID := range index.ColumnIDs {
				indexColIDs[colID] = struct{}{}
			}
			for _, col := range desc.Columns {
				if _, ok := indexColIDs[col.ID]; !ok {
					continue
				}
				visibleCols = append(visibleCols, col)
			}
		} else {
			index = &desc.PrimaryIndex
			visibleCols = desc.Columns
		}

	default:
		return nil, util.Errorf("TODO(pmattis): unsupported FROM: %s", n.From)
	}

	// Loop over the select expressions and expand them into the expressions
	// we're going to use to generate the returned column set and the names for
	// those columns.
	exprs := make([]parser.Expr, 0, len(n.Exprs))
	columns := make([]string, 0, len(n.Exprs))
	for _, e := range n.Exprs {
		// If a QualifiedName has a StarIndirection suffix we need to match the
		// prefix of the qualified name to one of the tables in the query and
		// then expand the "*" into a list of columns.
		if qname, ok := e.Expr.(*parser.QualifiedName); ok {
			if err := qname.NormalizeColumnName(); err != nil {
				return nil, err
			}
			if qname.IsStar() {
				if desc == nil {
					return nil, fmt.Errorf("\"%s\" with no tables specified is not valid", qname)
				}
				if e.As != "" {
					return nil, fmt.Errorf("\"%s\" cannot be aliased", qname)
				}
				tableName := qname.Table()
				if tableName != "" && !strings.EqualFold(desc.Alias, tableName) {
					return nil, fmt.Errorf("table \"%s\" not found", tableName)
				}

				if index != &desc.PrimaryIndex {
					for _, col := range index.ColumnNames {
						columns = append(columns, col)
						exprs = append(exprs, &parser.QualifiedName{Base: parser.Name(col)})
					}
				} else {
					for _, col := range desc.Columns {
						columns = append(columns, col.Name)
						exprs = append(exprs, &parser.QualifiedName{Base: parser.Name(col.Name)})
					}
				}
				continue
			}
		}

		exprs = append(exprs, e.Expr)
		if e.As != "" {
			columns = append(columns, string(e.As))
			continue
		}

		// If the expression is a qualified name, use the column name, not the
		// full qualification as the column name to return.
		switch t := e.Expr.(type) {
		case *parser.QualifiedName:
			if err := t.NormalizeColumnName(); err != nil {
				return nil, err
			}
			columns = append(columns, t.Column())
		default:
			columns = append(columns, e.Expr.String())
		}
	}

	s := &scanNode{
		txn:         p.txn,
		desc:        desc,
		index:       index,
		visibleCols: visibleCols,
		columns:     columns,
		render:      exprs,
	}
	if index != nil {
		s.isSecondaryIndex = index != &desc.PrimaryIndex
	}
	if n.Where != nil {
		s.filter = n.Where.Expr
	}
	return s, nil
}
Example #16
0
// Select selects rows from a single table.
// Privileges: READ on table
//   Notes: postgres requires SELECT. Also requires UPDATE on "FOR UPDATE".
//          mysql requires SELECT.
func (p *planner) Select(n *parser.Select) (planNode, error) {
	var desc *structured.TableDescriptor

	switch len(n.From) {
	case 0:
		// desc remains nil.

	case 1:
		var err error
		desc, err = p.getAliasedTableDesc(n.From[0])
		if err != nil {
			return nil, err
		}

		if !desc.HasPrivilege(p.user, parser.PrivilegeRead) {
			return nil, fmt.Errorf("user %s does not have %s privilege on table %s",
				p.user, parser.PrivilegeRead, desc.Name)
		}

	default:
		return nil, util.Errorf("TODO(pmattis): unsupported FROM: %s", n.From)
	}

	// Loop over the select expressions and expand them into the expressions
	// we're going to use to generate the returned column set and the names for
	// those columns.
	exprs := make([]parser.Expr, 0, len(n.Exprs))
	columns := make([]string, 0, len(n.Exprs))
	for _, e := range n.Exprs {
		switch t := e.(type) {
		case *parser.StarExpr:
			if desc == nil {
				return nil, fmt.Errorf("* with no tables specified is not valid")
			}
			for _, col := range desc.Columns {
				columns = append(columns, col.Name)
				exprs = append(exprs, &parser.QualifiedName{Base: parser.Name(col.Name)})
			}
		case *parser.NonStarExpr:
			exprs = append(exprs, t.Expr)
			if t.As != "" {
				columns = append(columns, string(t.As))
			} else {
				// TODO(pmattis): Should verify at this point that any referenced
				// columns are represented in the tables being selected from.
				columns = append(columns, t.Expr.String())
			}
		}
	}

	s := &scanNode{
		db:      p.db,
		desc:    desc,
		columns: columns,
		render:  exprs,
	}
	if n.Where != nil {
		s.filter = n.Where.Expr
	}
	return s, nil
}