예제 #1
0
파일: analyzer.go 프로젝트: sdgdsffdsfff/cm
// AsInterface converts the ValExpr to an interface. It converts
// ValTuple to []interface{}, ValArg to string, StrVal to sqltypes.String,
// NumVal to sqltypes.Numeric, NullVal to nil.
// Otherwise, it returns an error.
func AsInterface(node ValExpr) (interface{}, error) {
	switch node := node.(type) {
	case ValTuple:
		vals := make([]interface{}, 0, len(node))
		for _, val := range node {
			v, err := AsInterface(val)
			if err != nil {
				return nil, err
			}
			vals = append(vals, v)
		}
		return vals, nil
	case ValArg:
		return hack.String(node), nil
	case ListArg:
		return hack.String(node), nil
	case StrVal:
		return sqltypes.MakeString(node), nil
	case NumVal:
		n, err := sqltypes.BuildNumeric(hack.String(node))
		if err != nil {
			return nil, fmt.Errorf("type mismatch: %s", err)
		}
		return n, nil
	case *NullVal:
		return nil, nil
	}
	return nil, fmt.Errorf("unexpected node %v", node)
}
예제 #2
0
파일: conn.go 프로젝트: sdgdsffdsfff/cm
func (c *Conn) dispatch(data []byte) error {
	cmd := data[0]
	data = data[1:]

	log.Debug(c.connectionId, cmd, hack.String(data))
	c.lastCmd = hack.String(data)

	token := c.server.GetToken()

	c.server.GetRWlock().RLock()
	defer func() {
		c.server.GetRWlock().RUnlock()
		c.server.ReleaseToken(token)
	}()

	c.server.IncCounter(mysql.MYSQL_COMMAND(cmd).String())

	switch mysql.MYSQL_COMMAND(cmd) {
	case mysql.COM_QUIT:
		c.Close()
		return nil
	case mysql.COM_QUERY:
		return c.handleQuery(hack.String(data))
	case mysql.COM_PING:
		return c.writeOkFlush(nil)
	case mysql.COM_INIT_DB:
		log.Debug(cmd, hack.String(data))
		if err := c.useDB(hack.String(data)); err != nil {
			return errors.Trace(err)
		}

		return c.writeOkFlush(nil)
	case mysql.COM_FIELD_LIST:
		return c.handleFieldList(data)
	case mysql.COM_STMT_PREPARE:
		// not support server side prepare yet
	case mysql.COM_STMT_EXECUTE:
		log.Fatal("not support", data)
	case mysql.COM_STMT_CLOSE:
		return c.handleStmtClose(data)
	case mysql.COM_STMT_SEND_LONG_DATA:
		log.Fatal("not support", data)
	case mysql.COM_STMT_RESET:
		log.Fatal("not support", data)
	default:
		msg := fmt.Sprintf("command %d not supported now", cmd)
		return mysql.NewError(mysql.ER_UNKNOWN_ERROR, msg)
	}

	return nil
}
예제 #3
0
func getPKValues(conditions []sqlparser.BoolExpr, pkIndex *schema.Index) (pkValues []interface{}, err error) {
	pkIndexScore := NewIndexScore(pkIndex)
	pkValues = make([]interface{}, len(pkIndexScore.ColumnMatch))
	for _, condition := range conditions {
		condition, ok := condition.(*sqlparser.ComparisonExpr)
		if !ok {
			return nil, nil
		}
		if !sqlparser.StringIn(condition.Operator, sqlparser.AST_EQ, sqlparser.AST_IN) {
			return nil, nil
		}
		index := pkIndexScore.FindMatch(hack.String(condition.Left.(*sqlparser.ColName).Name))
		if index == -1 {
			return nil, nil
		}
		switch condition.Operator {
		case sqlparser.AST_EQ, sqlparser.AST_IN:
			var err error
			pkValues[index], err = sqlparser.AsInterface(condition.Right)
			if err != nil {
				return nil, err
			}
		default:
			panic("unreachable")
		}
	}

	if pkIndexScore.GetScore() == PERFECT_SCORE {
		return pkValues, nil
	}

	return nil, nil
}
예제 #4
0
파일: conn.go 프로젝트: sdgdsffdsfff/cm
func (c *MySqlConn) readResultColumns(result *Result) (err error) {
	var i int
	var data []byte

	for {
		data, err = c.readPacket()
		if err != nil {
			return
		}

		// EOF Packet
		if c.isEOFPacket(data) {
			if c.capability&CLIENT_PROTOCOL_41 > 0 {
				//result.Warnings = binary.LittleEndian.Uint16(data[1:])
				//todo add strict_mode, warning will be treat as error
				result.Status = binary.LittleEndian.Uint16(data[3:])
				c.status = result.Status
			}

			if i != len(result.Fields) {
				err = ErrMalformPacket
			}

			return
		}

		result.Fields[i], err = FieldData(data).Parse()
		if err != nil {
			return
		}

		result.FieldNames[hack.String(result.Fields[i].Name)] = i
		i++
	}
}
예제 #5
0
파일: token.go 프로젝트: sdgdsffdsfff/cm
func (tkn *Tokenizer) scanIdentifier() (int, []byte) {
	buffer := bytes.NewBuffer(tkn.alloc.AllocBytes(128))
	buffer.WriteByte(byte(tkn.lastChar))
	for tkn.next(); isLetter(tkn.lastChar) || isDigit(tkn.lastChar); tkn.next() {
		buffer.WriteByte(byte(tkn.lastChar))
	}

	if keywordId, found := keywords[hack.String(buffer.Bytes())]; found {
		return keywordId, buffer.Bytes()
	}

	return ID, buffer.Bytes()
}
예제 #6
0
파일: analyzer.go 프로젝트: sdgdsffdsfff/cm
// GetTableName returns the table name from the SimpleTableExpr
// only if it's a simple expression. Otherwise, it returns "".
func GetTableName(node SimpleTableExpr) string {
	n, ok := node.(*TableName)
	if ok {
		if len(n.Qualifier) > 0 {
			return string(n.Qualifier) + "." + string(n.Name)
		} else {
			return hack.String(n.Name)
		}
	}

	// sub-select or '.' expression
	return ""
}
예제 #7
0
func (c *Conn) limitSelectResult(r *mysql.Resultset, stmt *sqlparser.Select) error {
	if stmt.Limit == nil {
		return nil
	}

	var offset, count int64
	var err error
	if stmt.Limit.Offset == nil {
		offset = 0
	} else {
		if o, ok := stmt.Limit.Offset.(sqlparser.NumVal); !ok {
			return errors.Errorf("invalid select limit %s", nstring(stmt.Limit, c.alloc))
		} else {
			if offset, err = strconv.ParseInt(hack.String([]byte(o)), 10, 64); err != nil {
				return errors.Trace(err)
			}
		}
	}

	if o, ok := stmt.Limit.Rowcount.(sqlparser.NumVal); !ok {
		return errors.Errorf("invalid limit %s", nstring(stmt.Limit, c.alloc))
	} else {
		if count, err = strconv.ParseInt(hack.String([]byte(o)), 10, 64); err != nil {
			return errors.Trace(err)
		} else if count < 0 {
			return errors.Errorf("invalid limit %s", nstring(stmt.Limit, c.alloc))
		}
	}

	if offset+count > int64(len(r.Values)) {
		count = int64(len(r.Values)) - offset
	}

	r.Values = r.Values[offset : offset+count]
	r.RowDatas = r.RowDatas[offset : offset+count]

	return nil
}
예제 #8
0
파일: shard.go 프로젝트: sdgdsffdsfff/cm
func EncodeValue(value interface{}) string {
	switch val := value.(type) {
	case int:
		return Uint64Key(val).String()
	case uint64:
		return Uint64Key(val).String()
	case int64:
		return Uint64Key(val).String()
	case string:
		return val
	case []byte:
		return hack.String(val)
	}
	panic(NewKeyError("Unexpected key variable type %T", value))
}
예제 #9
0
func (c *Conn) handleFieldList(data []byte) error {
	index := bytes.IndexByte(data, 0x00)
	table := hack.String(data[0:index])
	wildcard := hack.String(data[index+1:])
	shardIds, err := c.getShardIds(table)
	if err != nil {
		return err
	}

	//todo: pass through
	if len(shardIds) == 0 {
		return errors.Errorf("no rule for table %s, %+v, please check config file", table, c.schema)
	}

	//hard code, assume all of the shard has the same schema
	n := c.server.GetShard(shardIds[0])
	if n == nil {
		return errors.Errorf("shard %s not found, %+v", shardIds, c.schema)
	}

	co, err := n.getMasterConn()
	if err != nil {
		return errors.Trace(err)
	}
	defer co.Close()

	if err = co.UseDB(c.db); err != nil {
		return errors.Trace(err)
	}

	if fs, err := co.FieldList(table, wildcard); err != nil {
		return errors.Trace(err)
	} else {
		return errors.Trace(c.writeFieldList(c.status, fs))
	}
}
예제 #10
0
파일: shard.go 프로젝트: sdgdsffdsfff/cm
func NumValue(value interface{}) int64 {
	switch val := value.(type) {
	case int:
		return int64(val)
	case uint64:
		return int64(val)
	case int64:
		return int64(val)
	case string:
		if v, err := strconv.ParseInt(val, 10, 64); err != nil {
			panic(NewKeyError("invalid num format %s", v))
		} else {
			return v
		}
	case []byte:
		if v, err := strconv.ParseInt(hack.String(val), 10, 64); err != nil {
			panic(NewKeyError("invalid num format %s", v))
		} else {
			return v
		}
	}
	panic(NewKeyError("Unexpected key variable type %T", value))
}
예제 #11
0
func (r *Resultset) GetString(row, column int) (string, error) {
	d, err := r.GetValue(row, column)
	if err != nil {
		return "", err
	}

	switch v := d.(type) {
	case string:
		return v, nil
	case []byte:
		return hack.String(v), nil
	case int64:
		return strconv.FormatInt(v, 10), nil
	case uint64:
		return strconv.FormatUint(v, 10), nil
	case float64:
		return strconv.FormatFloat(v, 'f', -1, 64), nil
	case nil:
		return "", nil
	default:
		return "", fmt.Errorf("data type is %T", v)
	}
}
예제 #12
0
func (buf *TrackedBuffer) ParsedQuery() *ParsedQuery {
	return &ParsedQuery{Query: hack.String(buf.Bytes()), bindLocations: buf.bindLocations}
}
예제 #13
0
파일: sqltypes.go 프로젝트: sdgdsffdsfff/cm
// String returns the raw value as a string
func (v Value) String() string {
	if v.Inner == nil {
		return ""
	}
	return hack.String(v.Inner.raw())
}
예제 #14
0
파일: analyzer.go 프로젝트: sdgdsffdsfff/cm
// GetColName returns the column name, only if
// it's a simple expression. Otherwise, it returns "".
func GetColName(node Expr) string {
	if n, ok := node.(*ColName); ok {
		return hack.String(bytes.ToLower(n.Name))
	}
	return ""
}