예제 #1
0
func (c *Conn) newEmptyResultset(stmt *sqlparser.Select) *mysql.Resultset {
	r := &mysql.Resultset{}
	r.Fields = make([]*mysql.Field, len(stmt.SelectExprs))

	for i, expr := range stmt.SelectExprs {
		r.Fields[i] = &mysql.Field{}
		switch e := expr.(type) {
		case *sqlparser.StarExpr:
			r.Fields[i].Name = []byte("*")
		case *sqlparser.NonStarExpr:
			if e.As != nil {
				r.Fields[i].Name = e.As
				r.Fields[i].OrgName = hack.Slice(nstring(e.Expr, c.alloc))
			} else {
				r.Fields[i].Name = hack.Slice(nstring(e.Expr, c.alloc))
			}
		default:
			r.Fields[i].Name = hack.Slice(nstring(e, c.alloc))
		}
	}

	r.Values = make([]mysql.RowValue, 0)
	r.RowDatas = make([]mysql.RowData, 0)

	return r
}
예제 #2
0
func (c *Conn) handleExec(stmt sqlparser.Statement, sql string, args []interface{}, skipCache bool) error {
	if !skipCache {
		// handle cache
		plan, ti, err := c.getPlanAndTableInfo(stmt)
		if err != nil {
			return errors.Trace(err)
		}

		if ti == nil {
			return errors.Errorf("sql: %s not support", sql)
		}

		c.server.IncCounter(plan.PlanId.String())

		if ti.CacheType != schema.CACHE_NONE {
			if len(ti.PKColumns) != len(plan.PKValues) {
				return errors.Errorf("updated/delete/replace without primary key not allowed %+v", plan.PKValues)
			}

			if len(plan.PKValues) == 0 {
				return errors.Errorf("pk not exist, sql: %s", sql)
			}

			log.Debugf("%s %+v, %+v", sql, plan, plan.PKValues)
			pks := pkValuesToStrings(ti.PKColumns, plan.PKValues)

			ti.Lock.Lock(hack.Slice(pks[0]))
			defer ti.Lock.Unlock(hack.Slice(pks[0]))

			invalidCache(ti, pks)
		}
	}

	bindVars := makeBindVars(args)
	conns, err := c.getShardConns(false, stmt, bindVars)
	if err != nil {
		return errors.Trace(err)
	} else if len(conns) == 0 { //todo:handle error
		return errors.Errorf("not server found %s", sql)
	}

	var rs []*mysql.Result
	rs, err = c.executeInShard(conns, sql, args)

	c.closeShardConns(conns)

	if err == nil {
		err = c.mergeExecResult(rs)
	}

	return errors.Trace(err)
}
예제 #3
0
func (c *Conn) fillCacheAndReturnResults(plan *planbuilder.ExecPlan, ti *tabletserver.TableInfo, keys []string) error {
	rowsql, err := generateSelectSql(ti, plan)
	log.Info(rowsql)

	ti.Lock.Lock(hack.Slice(keys[0]))
	defer ti.Lock.Unlock(hack.Slice(keys[0]))

	conns, err := c.getShardConns(true, nil, nil)
	if err != nil {
		return errors.Trace(err)
	} else if len(conns) == 0 {
		return errors.Errorf("not enough connection for %s", rowsql)
	}

	rs, err := c.executeInShard(conns, rowsql, nil)
	defer c.closeShardConns(conns)
	if err != nil {
		return errors.Trace(err)
	}

	//todo:fix hard code
	result := rs[0]

	if len(result.Values) == 0 {
		log.Debug("empty set")
		return c.writeResultset(result.Status, result.Resultset)
	}

	//log.Debugf("%+v", result.Values[0])

	retValues := applyFilter(plan.ColumnNumbers, result.Values[0])
	//log.Debug(len(retValues), len(keys))

	r, err := c.buildResultset(getFieldNames(plan, ti), []mysql.RowValue{retValues})
	if err != nil {
		log.Error(err)
		return errors.Trace(err)
	}

	//just do simple cache now
	if len(result.Values) == 1 && len(keys) == 1 && ti.CacheType != schema.CACHE_NONE {
		pks := pkValuesToStrings(ti.PKColumns, plan.PKValues)
		log.Debug("fill cache", pks)
		c.server.IncCounter("fill")
		ti.Cache.Set(pks[0], result.RowDatas[0], 0)
	}

	return c.writeResultset(c.status, r)
}
예제 #4
0
//compare value using asc
func cmpValue(v1 interface{}, v2 interface{}) int {
	if v1 == nil && v2 == nil {
		return 0
	} else if v1 == nil {
		return -1
	} else if v2 == nil {
		return 1
	}

	switch v := v1.(type) {
	case string:
		s := v2.(string)
		return bytes.Compare(hack.Slice(v), hack.Slice(s))
	case []byte:
		s := v2.([]byte)
		return bytes.Compare(v, s)
	case int64:
		s := v2.(int64)
		if v < s {
			return -1
		} else if v > s {
			return 1
		} else {
			return 0
		}
	case uint64:
		s := v2.(uint64)
		if v < s {
			return -1
		} else if v > s {
			return 1
		} else {
			return 0
		}
	case float64:
		s := v2.(float64)
		if v < s {
			return -1
		} else if v > s {
			return 1
		} else {
			return 0
		}
	default:
		//can not go here
		panic(fmt.Sprintf("invalid type %T", v))
	}
}
예제 #5
0
func Raw(t byte, val Value, isUnsigned bool) []byte {
	if val == nil {
		return nil
	}

	var ret []byte
	switch t {
	case MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_INT24, MYSQL_TYPE_LONG,
		MYSQL_TYPE_LONGLONG, MYSQL_TYPE_YEAR:
		if isUnsigned {
			ret = []byte(strconv.FormatUint(val.(uint64), 10))
		} else {
			ret = []byte(strconv.FormatInt(val.(int64), 10))
		}

	case MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE:
		ret = []byte(strconv.FormatFloat(val.(float64), 'f', 16, 64))
	case MYSQL_TYPE_VARCHAR:
		str, ok := val.(string)
		if ok {
			ret = hack.Slice(str)
			break
		}

		fallthrough
	default:
		var ok bool
		ret, ok = val.([]byte)
		if !ok {
			log.Errorf("%v, %+v, %T", t, val, val)
		}
	}

	return ret
}
예제 #6
0
파일: shard.go 프로젝트: sdgdsffdsfff/cm
func HashValue(value interface{}) uint64 {
	switch val := value.(type) {
	case int:
		return uint64(val)
	case uint64:
		return uint64(val)
	case int64:
		return uint64(val)
	case string:
		return uint64(crc32.ChecksumIEEE(hack.Slice(val)))
	case []byte:
		return uint64(crc32.ChecksumIEEE(val))
	}
	panic(NewKeyError("Unexpected key variable type %T", value))
}
예제 #7
0
func (c *Conn) buildResultset(nameTypes []schema.TableColumn, values []mysql.RowValue) (*mysql.Resultset, error) {
	r := &mysql.Resultset{Fields: make([]*mysql.Field, len(nameTypes))}

	var b []byte
	var err error

	for i, vs := range values {
		if len(vs) != len(r.Fields) {
			return nil, errors.Errorf("row %d has %d column not equal %d", i, len(vs), len(r.Fields))
		}

		var row []byte
		for j, value := range vs {
			field := &mysql.Field{}
			if i == 0 {
				r.Fields[j] = field
				//log.Warningf("%+v", nameTypes[i])
				field.Name = hack.Slice(nameTypes[j].Name)
				if err = formatField(field, value); err != nil {
					return nil, errors.Trace(err)
				}
				field.Type = nameTypes[j].SqlType
				field.Charset = uint16(mysql.CollationNames[nameTypes[j].Collation])
				field.IsUnsigned = nameTypes[j].IsUnsigned
			}

			if value == nil {
				row = append(row, "\xfb"...)
			} else {
				b = mysql.Raw(byte(field.Type), value, field.IsUnsigned)
				row = append(row, mysql.PutLengthEncodedString(b, c.alloc)...)
			}
		}

		r.RowDatas = append(r.RowDatas, row)
	}

	return r, nil
}