From ad4763a8838cad3416778fe36aa9253372e70a60 Mon Sep 17 00:00:00 2001 From: Azareal Date: Tue, 21 Apr 2020 09:39:35 +1000 Subject: [PATCH] use string builder pool for mysql query strings get more mysql queries to use string builders use consts instead of vars for growth hint variables --- query_gen/mysql.go | 265 ++++++++++++++++++++++++++++++++++-------- query_gen/querygen.go | 2 + 2 files changed, 216 insertions(+), 51 deletions(-) diff --git a/query_gen/mysql.go b/query_gen/mysql.go index 617437b3..41ccb996 100644 --- a/query_gen/mysql.go +++ b/query_gen/mysql.go @@ -336,19 +336,27 @@ func (a *MysqlAdapter) AddForeignKey(name, table, column, ftable, fcolumn string return q, nil } -var silen1 = len("INSERT INTO ``() VALUES () ") +const silen1 = len("INSERT INTO ``() VALUES () ") func (a *MysqlAdapter) SimpleInsert(name, table, columns, fields string) (string, error) { if table == "" { return "", errors.New("You need a name for this table") } - var sb strings.Builder + var sb *strings.Builder + ii := queryStrPool.Get() + if ii == nil { + sb = &strings.Builder{} + } else { + sb = ii.(*strings.Builder) + sb.Reset() + } + sb.Grow(silen1 + len(table)) sb.WriteString("INSERT INTO `") sb.WriteString(table) - sb.WriteString("`(") if columns != "" { + sb.WriteString("`(") sb.WriteString(a.buildColumns(columns)) sb.WriteString(") VALUES (") fs := processFields(fields) @@ -359,20 +367,25 @@ func (a *MysqlAdapter) SimpleInsert(name, table, columns, fields string) (string } nameLen := len(field.Name) if field.Name[0] == '"' && field.Name[nameLen-1] == '"' && nameLen >= 3 { - field.Name = "'" + field.Name[1:nameLen-1] + "'" + sb.WriteRune('\'') + sb.WriteString(field.Name[1 : nameLen-1]) + sb.WriteRune('\'') + } else if field.Name[0] == '\'' && field.Name[nameLen-1] == '\'' && nameLen >= 3 { + sb.WriteRune('\'') + sb.WriteString(strings.Replace(field.Name[1:nameLen-1], "'", "''", -1)) + sb.WriteRune('\'') + } else { + sb.WriteString(field.Name) } - if field.Name[0] == '\'' && field.Name[nameLen-1] == '\'' && nameLen >= 3 { - field.Name = "'" + strings.Replace(field.Name[1:nameLen-1], "'", "''", -1) + "'" - } - sb.WriteString(field.Name) } sb.WriteString(")") } else { - sb.WriteString(") VALUES ()") + sb.WriteString("`() VALUES ()") } // TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator q := sb.String() + queryStrPool.Put(sb) a.pushStatement(name, "insert", q) return q, nil } @@ -382,12 +395,19 @@ func (a *MysqlAdapter) SimpleBulkInsert(name, table, columns string, fieldSet [] return "", errors.New("You need a name for this table") } - var sb strings.Builder + var sb *strings.Builder + ii := queryStrPool.Get() + if ii == nil { + sb = &strings.Builder{} + } else { + sb = ii.(*strings.Builder) + sb.Reset() + } sb.Grow(silen1 + len(table)) sb.WriteString("INSERT INTO `") sb.WriteString(table) - sb.WriteString("`(") if columns != "" { + sb.WriteString("`(") sb.WriteString(a.buildColumns(columns)) sb.WriteString(") VALUES (") for oi, fields := range fieldSet { @@ -412,11 +432,12 @@ func (a *MysqlAdapter) SimpleBulkInsert(name, table, columns string, fieldSet [] sb.WriteString(")") } } else { - sb.WriteString(") VALUES ()") + sb.WriteString("`() VALUES ()") } // TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator q := sb.String() + queryStrPool.Put(sb) a.pushStatement(name, "bulk-insert", q) return q, nil } @@ -503,7 +524,7 @@ func (a *MysqlAdapter) SimpleUpsert(name, table, columns, fields, where string) return q, nil } -var sulen1 = len("UPDATE `` SET ") +const sulen1 = len("UPDATE `` SET ") func (a *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) { if up.table == "" { @@ -512,7 +533,15 @@ func (a *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) { if up.set == "" { return "", errors.New("You need to set data in this update statement") } - var sb strings.Builder + + var sb *strings.Builder + ii := queryStrPool.Get() + if ii == nil { + sb = &strings.Builder{} + } else { + sb = ii.(*strings.Builder) + sb.Reset() + } sb.Grow(sulen1 + len(up.table)) sb.WriteString("UPDATE `") sb.WriteString(up.table) @@ -545,18 +574,20 @@ func (a *MysqlAdapter) SimpleUpdate(up *updatePrebuilder) (string, error) { } } - whereStr, err := a.buildFlexiWhere(up.where, up.dateCutoff) - sb.WriteString(whereStr) + err := a.buildFlexiWhereSb(sb, up.where, up.dateCutoff) if err != nil { return sb.String(), err } // TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator q := sb.String() + queryStrPool.Put(sb) a.pushStatement(up.name, "update", q) return q, nil } +const sdlen1 = len("DELETE FROM `` WHERE") + func (a *MysqlAdapter) SimpleDelete(name, table, where string) (string, error) { if table == "" { return "", errors.New("You need a name for this table") @@ -564,31 +595,52 @@ func (a *MysqlAdapter) SimpleDelete(name, table, where string) (string, error) { if where == "" { return "", errors.New("You need to specify what data you want to delete") } - q := "DELETE FROM `" + table + "` WHERE" + var sb *strings.Builder + ii := queryStrPool.Get() + if ii == nil { + sb = &strings.Builder{} + } else { + sb = ii.(*strings.Builder) + sb.Reset() + } + sb.Grow(sdlen1 + len(table)) + sb.WriteString("DELETE FROM `") + sb.WriteString(table) + sb.WriteString("` WHERE") // Add support for BETWEEN x.x - for _, loc := range processWhere(where) { + for i, loc := range processWhere(where) { + if i != 0 { + sb.WriteString(" AND") + } for _, token := range loc.Expr { switch token.Type { case TokenFunc, TokenOp, TokenNumber, TokenSub, TokenOr, TokenNot: - q += " " + token.Contents + sb.WriteRune(' ') + sb.WriteString(token.Contents) case TokenColumn: - q += " `" + token.Contents + "`" + sb.WriteString(" `") + sb.WriteString(token.Contents) + sb.WriteRune('`') case TokenString: - q += " '" + token.Contents + "'" + sb.WriteString(" '") + sb.WriteString(token.Contents) + sb.WriteRune('\'') default: panic("This token doesn't exist o_o") } } - q += " AND" } - q = strings.TrimSpace(q[0 : len(q)-4]) + q := strings.TrimSpace(sb.String()) + queryStrPool.Put(sb) // TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator a.pushStatement(name, "delete", q) return q, nil } +const cdlen1 = len("DELETE FROM ``") + func (a *MysqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) { if b.table == "" { return "", errors.New("You need a name for this table") @@ -596,13 +648,25 @@ func (a *MysqlAdapter) ComplexDelete(b *deletePrebuilder) (string, error) { if b.where == "" && b.dateCutoff == nil { return "", errors.New("You need to specify what data you want to delete") } - q := "DELETE FROM `" + b.table + "`" - - whereStr, err := a.buildFlexiWhere(b.where, b.dateCutoff) - if err != nil { - return q, err + var sb *strings.Builder + ii := queryStrPool.Get() + if ii == nil { + sb = &strings.Builder{} + } else { + sb = ii.(*strings.Builder) + sb.Reset() } - q += whereStr + sb.Grow(cdlen1 + len(b.table)) + sb.WriteString("DELETE FROM `") + sb.WriteString(b.table) + sb.WriteRune('`') + + err := a.buildFlexiWhereSb(sb, b.where, b.dateCutoff) + if err != nil { + return sb.String(), err + } + q := sb.String() + queryStrPool.Put(sb) // TODO: Shunt the table name logic and associated stmt list up to the a higher layer to reduce the amount of unnecessary overhead in the builder / accumulator a.pushStatement(b.name, "delete", q) @@ -653,7 +717,7 @@ func (a *MysqlAdapter) buildWhere(where string, sb *strings.Builder) error { } // The new version of buildWhere() currently only used in ComplexSelect for complex OO builder queries -const FlexiHint1 = len(` < UTC_TIMESTAMP() - interval ? `) +const FlexiHint1 = len(`