コード例 #1
0
ファイル: set.go プロジェクト: nkhuyu/cockroach
// Set sets session variables.
// Privileges: None.
//   Notes: postgres/mysql do not require privileges for session variables (some exceptions).
func (p *planner) Set(n *parser.Set) (planNode, error) {
	// By using QualifiedName.String() here any variables that are keywords will
	// be double quoted.
	name := strings.ToLower(n.Name.String())
	switch name {
	case `"database"`: // Quoted: database is a reserved word
		if len(n.Values) != 1 {
			return nil, fmt.Errorf("database: requires a single string value")
		}
		val, err := parser.EvalExpr(n.Values[0])
		if err != nil {
			return nil, err
		}

		s, ok := val.(parser.DString)
		if !ok {
			return nil, fmt.Errorf("database: requires a single string value: %s is a %s",
				n.Values[0], val.Type())
		}

		dbName := string(s)
		if len(dbName) != 0 {
			// Verify database descriptor exists.
			if _, err := p.getDatabaseDesc(dbName); err != nil {
				return nil, err
			}
		}
		p.session.Database = dbName

	default:
		return nil, util.Errorf("unknown variable: %s", name)
	}
	return &valuesNode{}, nil
}
コード例 #2
0
ファイル: values.go プロジェクト: husttom/cockroach
// Values constructs a valuesNode from a VALUES expression.
func (p *planner) Values(n parser.Values) (planNode, error) {
	v := &valuesNode{
		rows: make([]parser.DTuple, 0, len(n)),
	}

	nCols := 0
	for _, tuple := range n {
		data, err := parser.EvalExpr(tuple)
		if err != nil {
			return nil, err
		}
		vals, ok := data.(parser.DTuple)
		if !ok {
			return nil, fmt.Errorf("expected a tuple, but found %T", data)
		}
		if len(v.rows) == 0 {
			nCols = len(vals)
		} else if nCols != len(vals) {
			return nil, errors.New("VALUES lists must all be the same length")
		}
		v.rows = append(v.rows, vals)
	}

	v.columns = make([]string, nCols)
	for i := 0; i < nCols; i++ {
		v.columns[i] = fmt.Sprintf("column%d", i+1)
	}
	return v, nil
}
コード例 #3
0
ファイル: scan.go プロジェクト: nkhuyu/cockroach
// filterRow checks to see if the current row matches the filter (i.e. the
// where-clause). May set n.err if an error occurs during expression
// evaluation.
func (n *scanNode) filterRow() bool {
	if n.desc != nil {
		for _, col := range n.visibleCols {
			if !col.Nullable {
				break
			}
			if qval, ok := n.qvals[col.ID]; ok && qval.datum == nil {
				qval.datum = parser.DNull
				continue
			}
		}
	}

	if n.filter == nil {
		return true
	}

	var d parser.Datum
	d, n.err = parser.EvalExpr(n.filter)
	if n.err != nil {
		return false
	}

	v, ok := d.(parser.DBool)
	if !ok {
		n.err = fmt.Errorf("WHERE clause did not evaluate to a boolean")
		return false
	}
	return bool(v)
}
コード例 #4
0
ファイル: scan.go プロジェクト: harryyeh/cockroach
// filterRow checks to see if the current row matches the filter (i.e. the
// where-clause). May set n.err if an error occurs during expression
// evaluation.
func (n *scanNode) filterRow() bool {
	if n.desc != nil {
		for _, col := range n.visibleCols {
			if !col.Nullable {
				break
			}
			if qval, ok := n.qvals[col.ID]; ok && qval.datum == nil {
				qval.datum = parser.DNull
				continue
			}
		}
	}

	if n.filter == nil {
		return true
	}

	var d parser.Datum
	d, n.err = parser.EvalExpr(n.filter)
	if n.err != nil {
		return false
	}

	return d != parser.DNull && bool(d.(parser.DBool))
}
コード例 #5
0
ファイル: main.go プロジェクト: cockroachdb/go-fuzz
func fuzzSingle(stmt parser.Statement) (interestingness int) {
	var lastExpr parser.Expr
	rcvr := func() {
		if r := recover(); r != nil {
			if !expected(fmt.Sprintf("%v", r)) {
				fmt.Printf("Stmt: %s\n%s", stmt, spew.Sdump(stmt))
				if lastExpr != nil {
					fmt.Printf("Expr: %s", spew.Sdump(lastExpr))
				}
				panic(r)
			}
			// Anything that has expected errors in it is fine, but not as
			// interesting as things that go through.
			interestingness = 1
		}
	}
	defer rcvr()

	data0 := stmt.String()
	// TODO(tschottdorf): again, this is since we're ignoring stuff in the
	// grammar instead of erroring out on unsupported language. See:
	// https://github.com/cockroachdb/cockroach/issues/1949
	if strings.Contains(data0, "%!s(<nil>)") {
		return 0
	}
	stmt1, err := parser.Parse(data0)
	if err != nil {
		fmt.Printf("AST: %s", spew.Sdump(stmt))
		fmt.Printf("data0: %q\n", data0)
		panic(err)
	}
	interestingness = 2

	data1 := stmt1.String()
	// TODO(tschottdorf): due to the ignoring issue again.
	// if !reflect.DeepEqual(stmt, stmt1) {
	if data1 != data0 {
		fmt.Printf("data0: %q\n", data0)
		fmt.Printf("AST: %s", spew.Sdump(stmt))
		fmt.Printf("data1: %q\n", data1)
		fmt.Printf("AST: %s", spew.Sdump(stmt1))
		panic("not equal")
	}

	var v visitorFunc = func(e parser.Expr) parser.Expr {
		lastExpr = e
		if _, err := parser.EvalExpr(e); err != nil {
			panic(err)
		}
		return e
	}
	parser.WalkStmt(v, stmt)
	return
}
コード例 #6
0
ファイル: scan.go プロジェクト: nkhuyu/cockroach
func (n *scanNode) initWhere(where *parser.Where) error {
	if where == nil {
		return nil
	}
	n.filter, n.err = n.resolveQNames(where.Expr)
	if n.err == nil {
		// Evaluate the expression once to memoize operators and functions.
		_, n.err = parser.EvalExpr(n.filter)
	}
	return n.err
}
コード例 #7
0
ファイル: analyze_test.go プロジェクト: harryyeh/cockroach
func checkEquivExpr(a, b parser.Expr, qvals qvalMap) error {
	// The expressions above only use the values 1 and 2. Verify that the
	// simplified expressions evaluate to the same value as the original
	// expression for interesting values.
	for _, v := range []parser.DInt{0, 1, 2, 3} {
		for _, q := range qvals {
			q.datum = v
		}
		da, err := parser.EvalExpr(a)
		if err != nil {
			return fmt.Errorf("%s: %v", a, err)
		}
		db, err := parser.EvalExpr(b)
		if err != nil {
			return fmt.Errorf("%s: %v", b, err)
		}
		if da != db {
			return fmt.Errorf("%s: %d: expected %s, but found %s", a, v, da, db)
		}
	}
	return nil
}
コード例 #8
0
ファイル: scan.go プロジェクト: routhcr/cockroach
func (n *scanNode) renderRow() error {
	if n.row == nil {
		n.row = make([]parser.Datum, len(n.render))
	}
	for i, e := range n.render {
		var err error
		n.row[i], err = parser.EvalExpr(e, n.vals)
		if err != nil {
			return err
		}
	}
	return nil
}
コード例 #9
0
ファイル: server.go プロジェクト: zmoon111/cockroach
func shouldOutputRow(where *parser.Where, vals valMap) (bool, error) {
	if where == nil {
		return true, nil
	}
	d, err := parser.EvalExpr(where.Expr, vals)
	if err != nil {
		return false, err
	}
	v, ok := d.(parser.DBool)
	if !ok {
		return false, fmt.Errorf("WHERE clause did not evaluate to a boolean")
	}
	return bool(v), nil
}
コード例 #10
0
ファイル: scan.go プロジェクト: elkingtoncode/LampDB
func (n *scanNode) filterRow() (bool, error) {
	if n.filter == nil {
		return true, nil
	}
	d, err := parser.EvalExpr(n.filter, n.vals)
	if err != nil {
		return false, err
	}
	v, ok := d.(parser.DBool)
	if !ok {
		return false, fmt.Errorf("WHERE clause did not evaluate to a boolean")
	}
	return bool(v), nil
}
コード例 #11
0
ファイル: limit.go プロジェクト: husttom/cockroach
// limit constructs a limitNode based on the LIMIT and OFFSET clauses.
func (*planner) limit(n *parser.Select, p planNode) (planNode, error) {
	if n.Limit == nil {
		return p, nil
	}

	var count, offset int64

	data := []struct {
		name       string
		src        parser.Expr
		dst        *int64
		defaultVal int64
	}{
		{"LIMIT", n.Limit.Count, &count, math.MaxInt64},
		{"OFFSET", n.Limit.Offset, &offset, 0},
	}

	for _, datum := range data {
		if datum.src == nil {
			*datum.dst = datum.defaultVal
		} else {
			if parser.ContainsVars(datum.src) {
				return nil, fmt.Errorf("argument of %s must not contain variables", datum.name)
			}

			normalized, err := parser.NormalizeExpr(datum.src)
			if err != nil {
				return nil, err
			}
			dstDatum, err := parser.EvalExpr(normalized)
			if err != nil {
				return nil, err
			}

			if dstDatum == parser.DNull {
				*datum.dst = datum.defaultVal
				continue
			}

			if dstDInt, ok := dstDatum.(parser.DInt); ok {
				*datum.dst = int64(dstDInt)
				continue
			}

			return nil, fmt.Errorf("argument of %s must be type %s, not type %s", datum.name, parser.DummyInt.Type(), dstDatum.Type())
		}
	}

	return &limitNode{planNode: p, count: count, offset: offset}, nil
}
コード例 #12
0
ファイル: set.go プロジェクト: husttom/cockroach
func getStringVal(name string, values parser.Exprs) (string, error) {
	if len(values) != 1 {
		return "", fmt.Errorf("%s: requires a single string value", name)
	}
	val, err := parser.EvalExpr(values[0])
	if err != nil {
		return "", err
	}
	s, ok := val.(parser.DString)
	if !ok {
		return "", fmt.Errorf("%s: requires a single string value: %s is a %s",
			name, values[0], val.Type())
	}
	return string(s), nil
}
コード例 #13
0
ファイル: scan.go プロジェクト: nkhuyu/cockroach
// renderRow renders the row by evaluating the render expressions. May set
// n.err if an error occurs during expression evaluation.
func (n *scanNode) renderRow() {
	if n.explain == explainDebug {
		n.explainDebug(true, true)
		return
	}

	if n.row == nil {
		n.row = make([]parser.Datum, len(n.render))
	}
	for i, e := range n.render {
		n.row[i], n.err = parser.EvalExpr(e)
		if n.err != nil {
			return
		}
	}
	n.rowIndex++
}
コード例 #14
0
ファイル: values.go プロジェクト: routhcr/cockroach
// Values constructs a valuesNode from a VALUES expression.
func (p *planner) Values(n parser.Values) (planNode, error) {
	v := &valuesNode{
		rows: make([]parser.DTuple, 0, len(n)),
	}
	for _, tuple := range n {
		data, err := parser.EvalExpr(tuple, nil)
		if err != nil {
			return nil, err
		}
		vals, ok := data.(parser.DTuple)
		if !ok {
			return nil, fmt.Errorf("expected a tuple, but found %T", data)
		}
		v.rows = append(v.rows, vals)
	}
	return v, nil
}
コード例 #15
0
ファイル: server.go プロジェクト: zmoon111/cockroach
// Set sets session variables.
func (s *Server) Set(session *Session, p *parser.Set, args []sqlwire.Datum,
	resp *sqlwire.Response) error {
	// By using QualifiedName.String() here any variables that are keywords will
	// be double quoted.
	name := strings.ToLower(p.Name.String())
	switch name {
	case `"database"`: // Quoted: database is a reserved word
		if len(p.Values) != 1 {
			return fmt.Errorf("database: requires a single string value")
		}
		val, err := parser.EvalExpr(p.Values[0], nil)
		if err != nil {
			return err
		}
		session.Database = val.String()
	default:
		return util.Errorf("unknown variable: %s", name)
	}
	return nil
}
コード例 #16
0
ファイル: server.go プロジェクト: zmoon111/cockroach
func (s *Server) processSelect(node parser.SelectStatement) (rows []sqlwire.Result_Row, _ error) {
	switch nt := node.(type) {
	// case *parser.Select:
	// case *parser.Union:
	// TODO(vivek): return s.query(nt.stmt, nil)
	case parser.Values:
		for _, tuple := range nt {
			data, err := parser.EvalExpr(tuple, nil)
			if err != nil {
				return rows, err
			}
			dTuple, ok := data.(parser.DTuple)
			if !ok {
				// A one-element DTuple is currently turned into whatever its
				// underlying element is, so we have to massage here.
				// See #1741.
				dTuple = parser.DTuple([]parser.Datum{data})
			}
			var vals []sqlwire.Datum
			for _, val := range dTuple {
				switch vt := val.(type) {
				case parser.DBool:
					vals = append(vals, sqlwire.Datum{BoolVal: (*bool)(&vt)})
				case parser.DInt:
					vals = append(vals, sqlwire.Datum{IntVal: (*int64)(&vt)})
				case parser.DFloat:
					vals = append(vals, sqlwire.Datum{FloatVal: (*float64)(&vt)})
				case parser.DString:
					vals = append(vals, sqlwire.Datum{StringVal: (*string)(&vt)})
				case parser.DNull:
					vals = append(vals, sqlwire.Datum{})
				default:
					return rows, util.Errorf("unsupported node: %T", val)
				}
			}
			rows = append(rows, sqlwire.Result_Row{Values: vals})
		}
		return rows, nil
	}
	return nil, util.Errorf("TODO(pmattis): unsupported node: %T", node)
}
コード例 #17
0
ファイル: group.go プロジェクト: husttom/cockroach
func (n *groupNode) Next() bool {
	if !n.needGroup {
		return false
	}
	n.needGroup = false

	// Loop over the rows passing the values into the corresponding aggregation
	// functions.
	for n.plan.Next() {
		values := n.plan.Values()
		for i, f := range n.funcs {
			if n.err = f.impl.Add(values[i]); n.err != nil {
				return false
			}
		}
	}

	n.err = n.plan.Err()
	if n.err != nil {
		return false
	}

	// Fill in the aggregate function result value.
	for _, f := range n.funcs {
		if f.val.datum, n.err = f.impl.Result(); n.err != nil {
			return false
		}
	}

	// Render the results.
	n.row = make([]parser.Datum, len(n.render))
	for i, r := range n.render {
		n.row[i], n.err = parser.EvalExpr(r)
		if n.err != nil {
			return false
		}
	}

	return n.err == nil
}
コード例 #18
0
ファイル: server.go プロジェクト: zhengchen1208/cockroach
func (s *Server) processSelect(node parser.SelectStatement) (rows []sqlwire.Result_Row, _ error) {
	switch nt := node.(type) {
	// case *parser.Select:
	// case *parser.Union:
	// TODO(vivek): return s.query(nt.stmt, nil)
	case parser.Values:
		for _, tuple := range nt {
			data, err := parser.EvalExpr(tuple, nil)
			if err != nil {
				return rows, err
			}
			dTuple, ok := data.(parser.DTuple)
			if !ok {
				return nil, fmt.Errorf("expected a tuple, but found %T", data)
			}
			var vals []sqlwire.Datum
			for _, val := range dTuple {
				switch vt := val.(type) {
				case parser.DBool:
					vals = append(vals, sqlwire.Datum{BoolVal: (*bool)(&vt)})
				case parser.DInt:
					vals = append(vals, sqlwire.Datum{IntVal: (*int64)(&vt)})
				case parser.DFloat:
					vals = append(vals, sqlwire.Datum{FloatVal: (*float64)(&vt)})
				case parser.DString:
					vals = append(vals, sqlwire.Datum{StringVal: (*string)(&vt)})
				case parser.DNull:
					vals = append(vals, sqlwire.Datum{})
				default:
					return rows, util.Errorf("unsupported node: %T", val)
				}
			}
			rows = append(rows, sqlwire.Result_Row{Values: vals})
		}
		return rows, nil
	}
	return nil, util.Errorf("TODO(pmattis): unsupported node: %T", node)
}
コード例 #19
0
ファイル: scan.go プロジェクト: elkingtoncode/LampDB
func (n *scanNode) renderRow() error {
	if n.row == nil {
		n.row = make([]parser.Datum, len(n.render))
	}
	if n.desc != nil {
		for _, col := range n.desc.Columns {
			if _, ok := n.vals[col.Name]; ok {
				continue
			}
			if col.Nullable {
				n.vals[col.Name] = parser.DNull
			}
		}
	}
	for i, e := range n.render {
		var err error
		n.row[i], err = parser.EvalExpr(e, n.vals)
		if err != nil {
			return err
		}
	}
	return nil
}
コード例 #20
0
ファイル: insert.go プロジェクト: harryyeh/cockroach
// Insert inserts rows into the database.
// Privileges: INSERT on table
//   Notes: postgres requires INSERT. No "on duplicate key update" option.
//          mysql requires INSERT. Also requires UPDATE on "ON DUPLICATE KEY UPDATE".
func (p *planner) Insert(n *parser.Insert) (planNode, error) {
	tableDesc, err := p.getTableDesc(n.Table)
	if err != nil {
		return nil, err
	}

	if err := p.checkPrivilege(tableDesc, privilege.INSERT); err != nil {
		return nil, err
	}

	// Determine which columns we're inserting into.
	cols, err := p.processColumns(tableDesc, n.Columns)
	if err != nil {
		return nil, err
	}

	// Construct a map from column ID to the index the value appears at within a
	// row.
	colIDtoRowIndex := map[ColumnID]int{}
	for i, c := range cols {
		colIDtoRowIndex[c.ID] = i
	}

	// Add any column not already present that has a DEFAULT expression.
	for _, col := range tableDesc.Columns {
		if _, ok := colIDtoRowIndex[col.ID]; ok {
			continue
		}
		if col.DefaultExpr != nil {
			colIDtoRowIndex[col.ID] = len(cols)
			cols = append(cols, col)
		}
	}

	// Verify we have at least the columns that are part of the primary key.
	primaryKeyCols := map[ColumnID]struct{}{}
	for i, id := range tableDesc.PrimaryIndex.ColumnIDs {
		if _, ok := colIDtoRowIndex[id]; !ok {
			return nil, fmt.Errorf("missing %q primary key column", tableDesc.PrimaryIndex.ColumnNames[i])
		}
		primaryKeyCols[id] = struct{}{}
	}

	// Construct the default expressions. The returned slice will be nil if no
	// column in the table has a default expression.
	defaultExprs, err := makeDefaultExprs(cols)
	if err != nil {
		return nil, err
	}

	// Replace any DEFAULT markers with the corresponding default expressions.
	if n.Rows, err = p.fillDefaults(defaultExprs, cols, n.Rows); err != nil {
		return nil, err
	}

	// Transform the values into a rows object. This expands SELECT statements or
	// generates rows from the values contained within the query.
	rows, err := p.makePlan(n.Rows)
	if err != nil {
		return nil, err
	}

	primaryIndex := tableDesc.PrimaryIndex
	primaryIndexKeyPrefix := MakeIndexKeyPrefix(tableDesc.ID, primaryIndex.ID)

	var b client.Batch
	for rows.Next() {
		rowVals := rows.Values()

		// The values for the row may be shorter than the number of columns being
		// inserted into. Generate default values for those columns using the
		// default expressions.
		for i := len(rowVals); i < len(cols); i++ {
			if defaultExprs == nil {
				rowVals = append(rowVals, parser.DNull)
				continue
			}
			d, err := parser.EvalExpr(defaultExprs[i])
			if err != nil {
				return nil, err
			}
			rowVals = append(rowVals, d)
		}

		// Check to see if NULL is being inserted into any non-nullable column.
		for _, col := range tableDesc.Columns {
			if !col.Nullable {
				if i, ok := colIDtoRowIndex[col.ID]; !ok || rowVals[i] == parser.DNull {
					return nil, fmt.Errorf("null value in column %q violates not-null constraint", col.Name)
				}
			}
		}

		primaryIndexKey, _, err := encodeIndexKey(
			primaryIndex.ColumnIDs, colIDtoRowIndex, rowVals, primaryIndexKeyPrefix)
		if err != nil {
			return nil, err
		}

		// Write the secondary indexes.
		secondaryIndexEntries, err := encodeSecondaryIndexes(
			tableDesc.ID, tableDesc.Indexes, colIDtoRowIndex, rowVals)
		if err != nil {
			return nil, err
		}

		for _, secondaryIndexEntry := range secondaryIndexEntries {
			if log.V(2) {
				log.Infof("CPut %q -> %v", secondaryIndexEntry.key, secondaryIndexEntry.value)
			}
			b.CPut(secondaryIndexEntry.key, secondaryIndexEntry.value, nil)
		}

		// Write the row sentinel.
		if log.V(2) {
			log.Infof("CPut %q -> NULL", primaryIndexKey)
		}
		b.CPut(primaryIndexKey, nil, nil)

		// Write the row columns.
		for i, val := range rowVals {
			col := cols[i]

			// Make sure the value can be written to the column before proceeding.
			primitive, err := convertDatum(col, val)
			if err != nil {
				return nil, err
			}

			if _, ok := primaryKeyCols[col.ID]; ok {
				// Skip primary key columns as their values are encoded in the row
				// sentinel key which is guaranteed to exist for as long as the row
				// exists.
				continue
			}

			if primitive != nil {
				// We only output non-NULL values. Non-existent column keys are
				// considered NULL during scanning and the row sentinel ensures we know
				// the row exists.

				key := MakeColumnKey(col.ID, primaryIndexKey)
				if log.V(2) {
					log.Infof("CPut %q -> %v", key, primitive)
				}

				b.CPut(key, primitive, nil)
			}
		}
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	if IsSystemID(tableDesc.GetID()) {
		// Mark transaction as operating on the system DB.
		p.txn.SetSystemDBTrigger()
	}
	if err := p.txn.Run(&b); err != nil {
		return nil, convertBatchError(tableDesc, b, err)
	}
	// TODO(tamird/pmattis): return the number of affected rows
	return &valuesNode{}, nil
}
コード例 #21
0
ファイル: scan.go プロジェクト: nkhuyu/cockroach
func (n *scanNode) addRender(target parser.SelectExpr) error {
	// 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 := target.Expr.(*parser.QualifiedName); ok {
		if n.err = qname.NormalizeColumnName(); n.err != nil {
			return n.err
		}
		if qname.IsStar() {
			if n.desc == nil {
				return fmt.Errorf("\"%s\" with no tables specified is not valid", qname)
			}
			if target.As != "" {
				return fmt.Errorf("\"%s\" cannot be aliased", qname)
			}
			tableName := qname.Table()
			if tableName != "" && !equalName(n.desc.Alias, tableName) {
				return fmt.Errorf("table \"%s\" not found", tableName)
			}

			if n.isSecondaryIndex {
				for i, col := range n.index.ColumnNames {
					n.columns = append(n.columns, col)
					var col *ColumnDescriptor
					if col, n.err = n.desc.FindColumnByID(n.index.ColumnIDs[i]); n.err != nil {
						return n.err
					}
					n.render = append(n.render, n.getQVal(*col))
				}
			} else {
				for _, col := range n.desc.Columns {
					n.columns = append(n.columns, col.Name)
					n.render = append(n.render, n.getQVal(col))
				}
			}
			return nil
		}
	}

	// Resolve qualified names. This has the side-effect of normalizing any
	// qualified name found.
	var resolved parser.Expr
	if resolved, n.err = n.resolveQNames(target.Expr); n.err != nil {
		return n.err
	}
	// Evaluate the expression once to memoize operators and functions.
	if _, n.err = parser.EvalExpr(resolved); n.err != nil {
		return n.err
	}
	n.render = append(n.render, resolved)

	if target.As != "" {
		n.columns = append(n.columns, string(target.As))
		return nil
	}

	switch t := target.Expr.(type) {
	case *parser.QualifiedName:
		// If the expression is a qualified name, use the column name, not the
		// full qualification as the column name to return.
		n.columns = append(n.columns, t.Column())
	default:
		n.columns = append(n.columns, target.Expr.String())
	}
	return nil
}
コード例 #22
0
ファイル: select.go プロジェクト: wuguojun/cockroach
// analyzeComparisonExpr analyzes the comparison expression, restricting the
// start and end info for any qvalues found within it.
func (m qvalueRangeMap) analyzeComparisonExpr(node *parser.ComparisonExpr) {
	op := node.Operator
	switch op {
	case parser.EQ, parser.LT, parser.LE, parser.GT, parser.GE:
		break

	default:
		// TODO(pmattis): For parser.LIKE we could extract the constant prefix and
		// treat as a range restriction.
		return
	}

	qval, ok := node.Left.(*qvalue)
	var constExpr parser.Expr
	if ok {
		if !isConst(node.Right) {
			// qvalue <op> non-constant.
			return
		}
		constExpr = node.Right
		// qval <op> constant.
	} else {
		qval, ok = node.Right.(*qvalue)
		if !ok {
			// non-qvalue <op> non-qvalue.
			return
		}
		if !isConst(node.Left) {
			// non-constant <op> qvalue.
			return
		}
		constExpr = node.Left
		// constant <op> qval: invert the operation.
		switch op {
		case parser.LT:
			op = parser.GT
		case parser.LE:
			op = parser.GE
		case parser.GT:
			op = parser.LT
		case parser.GE:
			op = parser.LE
		}
	}

	// Evaluate the constant expression.
	datum, err := parser.EvalExpr(constExpr)
	if err != nil {
		// TODO(pmattis): Should we pass the error up the stack?
		return
	}

	// Ensure the resulting datum matches the column type.
	if _, err := convertDatum(qval.col, datum); err != nil {
		// TODO(pmattis): Should we pass the error up the stack?
		return
	}

	if log.V(2) {
		log.Infof("analyzeComparisonExpr: %s %s %s",
			qval.col.Name, op, datum)
	}

	r := m.getRange(qval.col.ID)

	// Restrict the start element.
	switch startOp := op; startOp {
	case parser.EQ:
		startOp = parser.GE
		fallthrough
	case parser.GE, parser.GT:
		r.start.intersect(qvalueInfo{datum, startOp}, true)
	}

	// Restrict the end element.
	switch endOp := op; endOp {
	case parser.EQ:
		endOp = parser.LE
		fallthrough
	case parser.LE, parser.LT:
		r.end.intersect(qvalueInfo{datum, endOp}, false)
	}
}
コード例 #23
0
ファイル: update.go プロジェクト: ajayaa/cockroach
// Update updates columns for a selection of rows from a table.
// Privileges: WRITE and READ on table. We currently always use a select statement.
//   Notes: postgres requires UPDATE. Requires SELECT with WHERE clause with table.
//          mysql requires UPDATE. Also requires SELECT with WHERE clause with table.
func (p *planner) Update(n *parser.Update) (planNode, error) {
	tableDesc, err := p.getAliasedTableDesc(n.Table)
	if 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)
	}

	// Determine which columns we're inserting into.
	var names parser.QualifiedNames
	for _, expr := range n.Exprs {
		names = append(names, expr.Name)
	}
	cols, err := p.processColumns(tableDesc, names)
	if err != nil {
		return nil, err
	}

	// Set of columns being updated
	colIDSet := map[structured.ColumnID]struct{}{}
	for _, c := range cols {
		colIDSet[c.ID] = struct{}{}
	}
	// Don't allow updating any column that is part of the primary key.
	for i, id := range tableDesc.PrimaryIndex.ColumnIDs {
		if _, ok := colIDSet[id]; ok {
			return nil, fmt.Errorf("primary key column %q cannot be updated", tableDesc.PrimaryIndex.ColumnNames[i])
		}
	}

	// Query the rows that need updating.
	// TODO(vivek): Avoid going through Select.
	row, err := p.Select(&parser.Select{
		Exprs: parser.SelectExprs{parser.StarSelectExpr},
		From:  parser.TableExprs{n.Table},
		Where: n.Where,
	})
	if err != nil {
		return nil, err
	}

	// Construct a map from column ID to the index the value appears at within a
	// row.
	colIDtoRowIndex := map[structured.ColumnID]int{}
	for i, name := range row.Columns() {
		c, err := tableDesc.FindColumnByName(name)
		if err != nil {
			return nil, err
		}
		colIDtoRowIndex[c.ID] = i
	}

	primaryIndex := tableDesc.PrimaryIndex
	primaryIndexKeyPrefix := structured.MakeIndexKeyPrefix(tableDesc.ID, primaryIndex.ID)

	// Evaluate all the column value expressions.
	vals := make([]parser.Datum, 0, 10)
	for _, expr := range n.Exprs {
		val, err := parser.EvalExpr(expr.Expr)
		if err != nil {
			return nil, err
		}
		vals = append(vals, val)
	}

	// Secondary indexes needing updating.
	var indexes []structured.IndexDescriptor
	for _, index := range tableDesc.Indexes {
		for _, id := range index.ColumnIDs {
			if _, ok := colIDSet[id]; ok {
				indexes = append(indexes, index)
				break
			}
		}
	}

	// Update all the rows.
	b := client.Batch{}
	for row.Next() {
		rowVals := row.Values()
		primaryIndexKeySuffix, _, err := encodeIndexKey(primaryIndex.ColumnIDs, colIDtoRowIndex, rowVals, nil)
		if err != nil {
			return nil, err
		}
		primaryIndexKey := bytes.Join([][]byte{primaryIndexKeyPrefix, primaryIndexKeySuffix}, nil)
		// Compute the current secondary index key:value pairs for this row.
		secondaryIndexEntries, err := encodeSecondaryIndexes(tableDesc.ID, indexes, colIDtoRowIndex, rowVals, primaryIndexKeySuffix)
		if err != nil {
			return nil, err
		}
		// Compute the new secondary index key:value pairs for this row.
		//
		// Update the row values.
		for i, col := range cols {
			val := vals[i]

			if !col.Nullable && val == parser.DNull {
				return nil, fmt.Errorf("null value in column %q violates not-null constraint", col.Name)
			}
			rowVals[colIDtoRowIndex[col.ID]] = val
		}
		newSecondaryIndexEntries, err := encodeSecondaryIndexes(tableDesc.ID, indexes, colIDtoRowIndex, rowVals, primaryIndexKeySuffix)
		if err != nil {
			return nil, err
		}
		// Update secondary indexes.
		for i, newSecondaryIndexEntry := range newSecondaryIndexEntries {
			secondaryIndexEntry := secondaryIndexEntries[i]
			if !bytes.Equal(newSecondaryIndexEntry.key, secondaryIndexEntry.key) {
				if log.V(2) {
					log.Infof("CPut %q -> %v", newSecondaryIndexEntry.key, newSecondaryIndexEntry.value)
				}
				b.CPut(newSecondaryIndexEntry.key, newSecondaryIndexEntry.value, nil)
				if log.V(2) {
					log.Infof("Del %q", secondaryIndexEntry.key)
				}
				b.Del(secondaryIndexEntry.key)
			}
		}

		// Add the new values.
		for i, val := range vals {
			col := cols[i]

			primitive, err := convertDatum(col, val)
			if err != nil {
				return nil, err
			}

			key := structured.MakeColumnKey(col.ID, primaryIndexKey)
			if primitive != nil {
				// We only output non-NULL values. Non-existent column keys are
				// considered NULL during scanning and the row sentinel ensures we know
				// the row exists.
				if log.V(2) {
					log.Infof("Put %q -> %v", key, val)
				}

				b.Put(key, primitive)
			} else {
				// The column might have already existed but is being set to NULL, so
				// delete it.
				if log.V(2) {
					log.Infof("Del %q", key)
				}

				b.Del(key)
			}
		}
	}

	if err := row.Err(); err != nil {
		return nil, err
	}

	if err := p.txn.Run(&b); err != nil {
		if tErr, ok := err.(*proto.ConditionFailedError); ok {
			return nil, fmt.Errorf("duplicate key value %q violates unique constraint %s", tErr.ActualValue.Bytes, "TODO(tamird)")
		}
		return nil, err
	}

	// TODO(tamird/pmattis): return the number of affected rows.
	return &valuesNode{}, nil
}