func (Mysql) ApplyLimitAndOffset(w query.Writer, limit, offset uint64) { w.WriteString(" LIMIT ") if limit == 0 { // In MYSQL, OFFSET cannot be used alone. Set the limit to the max possible value. w.WriteString("18446744073709551615") } else { fmt.Fprint(w, limit) } if offset > 0 { fmt.Fprintf(w, " OFFSET %d", offset) } }
// Invariant: only called when len(fragments) > 0. func writeWhereFragmentsToSql(w query.Writer, fragments []*whereFragment, args *[]interface{}) { anyConditions := false for _, f := range fragments { if f.Condition == "" { panic("invalid condition expression") } if anyConditions { w.WriteString(" AND ") } anyConditions = true w.WriteString("(" + f.Condition + ")") if len(f.Values) > 0 { *args = append(*args, f.Values...) } } }
func (b *baseBuilder) buildOrder(w query.Writer) { if len(b.OrderBys) > 0 { w.WriteString(" ORDER BY ") for i, s := range b.OrderBys { if i > 0 { w.WriteString(", ") } w.WriteString(s) } } }
func (b *baseBuilder) buildWhere(w query.Writer, args *[]interface{}) { if len(b.WhereFragments) > 0 { w.WriteString(" WHERE ") writeWhereFragmentsToSql(w, b.WhereFragments, args) } }
// Need to turn \x00, \n, \r, \, ', " and \x1a. // Returns an escaped, quoted string. eg, "hello 'world'" -> "'hello \'world\''". func (Mysql) EscapeString(w query.Writer, s string) { w.WriteRune('\'') for _, char := range s { switch char { case '\'': w.WriteString(`\'`) case '"': w.WriteString(`\"`) case '\\': w.WriteString(`\\`) case '\n': w.WriteString(`\n`) case '\r': w.WriteString(`\r`) case 0: w.WriteString(`\x00`) case 0x1a: w.WriteString(`\x1a`) default: w.WriteRune(char) } } w.WriteRune('\'') }
func (Mysql) EscapeIdent(w query.Writer, ident string) { w.WriteRune('`') r := strings.NewReplacer("`", "``", ".", "`.`") w.WriteString(r.Replace(ident)) w.WriteRune('`') }
func interpolate(w query.Writer, v interface{}) error { valuer, ok := v.(driver.Valuer) if ok { val, err := valuer.Value() if err != nil { return err } v = val } valueOfV := reflect.ValueOf(v) kindOfV := valueOfV.Kind() switch { case v == nil: w.WriteString("NULL") case isInt(kindOfV): var ival = valueOfV.Int() w.WriteString(strconv.FormatInt(ival, 10)) case isUint(kindOfV): var uival = valueOfV.Uint() w.WriteString(strconv.FormatUint(uival, 10)) case kindOfV == reflect.String: var str = valueOfV.String() if !utf8.ValidString(str) { return ErrNotUTF8 } D.EscapeString(w, str) case isFloat(kindOfV): var fval = valueOfV.Float() w.WriteString(strconv.FormatFloat(fval, 'f', -1, 64)) case kindOfV == reflect.Bool: D.EscapeBool(w, valueOfV.Bool()) case kindOfV == reflect.Struct: if typeOfV := valueOfV.Type(); typeOfV == typeOfTime { t := valueOfV.Interface().(time.Time) D.EscapeTime(w, t) } else { return ErrInvalidValue } case kindOfV == reflect.Slice: typeOfV := reflect.TypeOf(v) subtype := typeOfV.Elem() kindOfSubtype := subtype.Kind() sliceLen := valueOfV.Len() stringSlice := make([]string, 0, sliceLen) switch { case sliceLen == 0: return ErrInvalidSliceLength case isInt(kindOfSubtype): for i := 0; i < sliceLen; i++ { var ival = valueOfV.Index(i).Int() stringSlice = append(stringSlice, strconv.FormatInt(ival, 10)) } case isUint(kindOfSubtype): for i := 0; i < sliceLen; i++ { var uival = valueOfV.Index(i).Uint() stringSlice = append(stringSlice, strconv.FormatUint(uival, 10)) } case kindOfSubtype == reflect.String: for i := 0; i < sliceLen; i++ { var str = valueOfV.Index(i).String() if !utf8.ValidString(str) { return ErrNotUTF8 } buf := new(bytes.Buffer) D.EscapeString(buf, str) stringSlice = append(stringSlice, buf.String()) } default: return ErrInvalidSliceValue } w.WriteRune('(') w.WriteString(strings.Join(stringSlice, ",")) w.WriteRune(')') default: return ErrInvalidValue } return nil }