<commit_before>package queries

import (
	"bytes"
	"fmt"
	"regexp"
	"sort"
	"strings"

	"github.com/volatiletech/sqlboiler/strmangle"
)

var (
	rgxIdentifier = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(?:\."?[_a-z][_a-z0-9]*"?)*$`)
	rgxInClause   = regexp.MustCompile(`^(?i)(.*[\s|\)|\?])IN([\s|\(|\?].*)$`)
)

// BuildQuery builds a query object into the query string
// and it's accompanying arguments. Using this method
// allows query building without immediate execution.
func BuildQuery(q *Query) (string, []interface{}) {
	var buf *bytes.Buffer
	var args []interface{}

	switch {
	case len(q.rawSQL.sql) != 0:
		return q.rawSQL.sql, q.rawSQL.args
	case q.delete:
		buf, args = buildDeleteQuery(q)
	case len(q.update) > 0:
		buf, args = buildUpdateQuery(q)
	default:
		buf, args = buildSelectQuery(q)
	}

	defer strmangle.PutBuffer(buf)

	// Cache the generated query for query object re-use
	bufStr := buf.String()
	q.rawSQL.sql = bufStr
	q.rawSQL.args = args

	return bufStr, args
}

func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
	buf := strmangle.GetBuffer()
	var args []interface{}

	writeCTEs(q, buf, &args)

	buf.WriteString("SELECT ")

	if q.dialect.UseTopClause {
		if q.limit != 0 && q.offset == 0 {
			fmt.Fprintf(buf, " TOP (%d) ", q.limit)
		}
	}

	if q.count {
		buf.WriteString("COUNT(")
	}

	hasSelectCols := len(q.selectCols) != 0
	hasJoins := len(q.joins) != 0
	if hasJoins && hasSelectCols && !q.count {
		selectColsWithAs := writeAsStatements(q)
		// Don't identQuoteSlice - writeAsStatements does this
		buf.WriteString(strings.Join(selectColsWithAs, ", "))
	} else if hasSelectCols {
		buf.WriteString(strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.selectCols), ", "))
	} else if hasJoins && !q.count {
		selectColsWithStars := writeStars(q)
		buf.WriteString(strings.Join(selectColsWithStars, ", "))
	} else {
		buf.WriteByte('*')
	}

	// close SQL COUNT function
	if q.count {
		buf.WriteByte(')')
	}

	fmt.Fprintf(buf, " FROM %s", strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))

	if len(q.joins) > 0 {
		argsLen := len(args)
		joinBuf := strmangle.GetBuffer()
		for _, j := range q.joins {
			if j.kind != JoinInner {
				panic("only inner joins are supported")
			}
			fmt.Fprintf(joinBuf, " INNER JOIN %s", j.clause)
			args = append(args, j.args...)
		}
		var resp string
		if q.dialect.UseIndexPlaceholders {
			resp, _ = convertQuestionMarks(joinBuf.String(), argsLen+1)
		} else {
			resp = joinBuf.String()
		}
		fmt.Fprintf(buf, resp)
		strmangle.PutBuffer(joinBuf)
	}

	where, whereArgs := whereClause(q, len(args)+1)
	buf.WriteString(where)
	if len(whereArgs) != 0 {
		args = append(args, whereArgs...)
	}

	writeModifiers(q, buf, &args)

	buf.WriteByte(';')
	return buf, args
}

func buildDeleteQuery(q *Query) (*bytes.Buffer, []interface{}) {
	var args []interface{}
	buf := strmangle.GetBuffer()

	writeCTEs(q, buf, &args)

	buf.WriteString("DELETE FROM ")
	buf.WriteString(strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))

	where, whereArgs := whereClause(q, 1)
	if len(whereArgs) != 0 {
		args = append(args, whereArgs...)
	}
	buf.WriteString(where)

	writeModifiers(q, buf, &args)

	buf.WriteByte(';')

	return buf, args
}

func buildUpdateQuery(q *Query) (*bytes.Buffer, []interface{}) {
	buf := strmangle.GetBuffer()
	var args []interface{}

	writeCTEs(q, buf, &args)

	buf.WriteString("UPDATE ")
	buf.WriteString(strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))

	cols := make(sort.StringSlice, len(q.update))

	count := 0
	for name := range q.update {
		cols[count] = name
		count++
	}

	cols.Sort()

	for i := 0; i < len(cols); i++ {
		args = append(args, q.update[cols[i]])
		cols[i] = strmangle.IdentQuote(q.dialect.LQ, q.dialect.RQ, cols[i])
	}

	setSlice := make([]string, len(cols))
	for index, col := range cols {
		setSlice[index] = fmt.Sprintf("%s = %s", col, strmangle.Placeholders(q.dialect.UseIndexPlaceholders, 1, index+1, 1))
	}
	fmt.Fprintf(buf, " SET %s", strings.Join(setSlice, ", "))

	where, whereArgs := whereClause(q, len(args)+1)
	if len(whereArgs) != 0 {
		args = append(args, whereArgs...)
	}
	buf.WriteString(where)

	writeModifiers(q, buf, &args)

	buf.WriteByte(';')

	return buf, args
}

func writeParameterizedModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}, keyword, delim string, clauses []argClause) {
	argsLen := len(*args)
	modBuf := strmangle.GetBuffer()
	fmt.Fprintf(modBuf, keyword)

	for i, j := range clauses {
		if i > 0 {
			modBuf.WriteString(delim)
		}
		modBuf.WriteString(j.clause)
		*args = append(*args, j.args...)
	}

	var resp string
	if q.dialect.UseIndexPlaceholders {
		resp, _ = convertQuestionMarks(modBuf.String(), argsLen+1)
	} else {
		resp = modBuf.String()
	}

	buf.WriteString(resp)
	strmangle.PutBuffer(modBuf)
}

func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
	if len(q.groupBy) != 0 {
		fmt.Fprintf(buf, " GROUP BY %s", strings.Join(q.groupBy, ", "))
	}

	if len(q.having) != 0 {
		writeParameterizedModifiers(q, buf, args, " HAVING ", " AND ", q.having)
	}

	if len(q.orderBy) != 0 {
		writeParameterizedModifiers(q, buf, args, " ORDER BY ", ", ", q.orderBy)
	}

	if !q.dialect.UseTopClause {
		if q.limit != 0 {
			fmt.Fprintf(buf, " LIMIT %d", q.limit)
		}

		if q.offset != 0 {
			// This seems to be the latest version of mssql's syntax for offset
			// (the suffix ROWS)
			// This is true for latest sql server as well as their cloud offerings & the upcoming sql server 2019
			// https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017
			// https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-ver15
			fmt.Fprintf(buf, " OFFSET %d ROWS", q.offset)
		}
	} else {
		// From MS SQL 2012 and above: https://technet.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
		// ORDER BY ...
		// OFFSET N ROWS
		// FETCH NEXT M ROWS ONLY
		if q.offset != 0 {

			// Hack from https://www.microsoftpressstore.com/articles/article.aspx?p=2314819
			// ...
			// As mentioned, the OFFSET-FETCH filter requires an ORDER BY clause. If you want to use arbitrary order,
			// like TOP without an ORDER BY clause, you can use the trick with ORDER BY (SELECT NULL)
			// ...
			if len(q.orderBy) == 0 {
				buf.WriteString(" ORDER BY (SELECT NULL)")
			}

			fmt.Fprintf(buf, " OFFSET %d", q.offset)

			if q.limit != 0 {
				fmt.Fprintf(buf, " FETCH NEXT %d ROWS ONLY", q.limit)
			}
		}
	}

	if len(q.forlock) != 0 {<commit_msg>Fix syntax error OFFSET for MySQL<commit_after>package queries

import (
	"bytes"
	"fmt"
	"regexp"
	"sort"
	"strings"

	"github.com/volatiletech/sqlboiler/strmangle"
)

var (
	rgxIdentifier = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(?:\."?[_a-z][_a-z0-9]*"?)*$`)
	rgxInClause   = regexp.MustCompile(`^(?i)(.*[\s|\)|\?])IN([\s|\(|\?].*)$`)
)

// BuildQuery builds a query object into the query string
// and it's accompanying arguments. Using this method
// allows query building without immediate execution.
func BuildQuery(q *Query) (string, []interface{}) {
	var buf *bytes.Buffer
	var args []interface{}

	switch {
	case len(q.rawSQL.sql) != 0:
		return q.rawSQL.sql, q.rawSQL.args
	case q.delete:
		buf, args = buildDeleteQuery(q)
	case len(q.update) > 0:
		buf, args = buildUpdateQuery(q)
	default:
		buf, args = buildSelectQuery(q)
	}

	defer strmangle.PutBuffer(buf)

	// Cache the generated query for query object re-use
	bufStr := buf.String()
	q.rawSQL.sql = bufStr
	q.rawSQL.args = args

	return bufStr, args
}

func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
	buf := strmangle.GetBuffer()
	var args []interface{}

	writeCTEs(q, buf, &args)

	buf.WriteString("SELECT ")

	if q.dialect.UseTopClause {
		if q.limit != 0 && q.offset == 0 {
			fmt.Fprintf(buf, " TOP (%d) ", q.limit)
		}
	}

	if q.count {
		buf.WriteString("COUNT(")
	}

	hasSelectCols := len(q.selectCols) != 0
	hasJoins := len(q.joins) != 0
	if hasJoins && hasSelectCols && !q.count {
		selectColsWithAs := writeAsStatements(q)
		// Don't identQuoteSlice - writeAsStatements does this
		buf.WriteString(strings.Join(selectColsWithAs, ", "))
	} else if hasSelectCols {
		buf.WriteString(strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.selectCols), ", "))
	} else if hasJoins && !q.count {
		selectColsWithStars := writeStars(q)
		buf.WriteString(strings.Join(selectColsWithStars, ", "))
	} else {
		buf.WriteByte('*')
	}

	// close SQL COUNT function
	if q.count {
		buf.WriteByte(')')
	}

	fmt.Fprintf(buf, " FROM %s", strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))

	if len(q.joins) > 0 {
		argsLen := len(args)
		joinBuf := strmangle.GetBuffer()
		for _, j := range q.joins {
			if j.kind != JoinInner {
				panic("only inner joins are supported")
			}
			fmt.Fprintf(joinBuf, " INNER JOIN %s", j.clause)
			args = append(args, j.args...)
		}
		var resp string
		if q.dialect.UseIndexPlaceholders {
			resp, _ = convertQuestionMarks(joinBuf.String(), argsLen+1)
		} else {
			resp = joinBuf.String()
		}
		fmt.Fprintf(buf, resp)
		strmangle.PutBuffer(joinBuf)
	}

	where, whereArgs := whereClause(q, len(args)+1)
	buf.WriteString(where)
	if len(whereArgs) != 0 {
		args = append(args, whereArgs...)
	}

	writeModifiers(q, buf, &args)

	buf.WriteByte(';')
	return buf, args
}

func buildDeleteQuery(q *Query) (*bytes.Buffer, []interface{}) {
	var args []interface{}
	buf := strmangle.GetBuffer()

	writeCTEs(q, buf, &args)

	buf.WriteString("DELETE FROM ")
	buf.WriteString(strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))

	where, whereArgs := whereClause(q, 1)
	if len(whereArgs) != 0 {
		args = append(args, whereArgs...)
	}
	buf.WriteString(where)

	writeModifiers(q, buf, &args)

	buf.WriteByte(';')

	return buf, args
}

func buildUpdateQuery(q *Query) (*bytes.Buffer, []interface{}) {
	buf := strmangle.GetBuffer()
	var args []interface{}

	writeCTEs(q, buf, &args)

	buf.WriteString("UPDATE ")
	buf.WriteString(strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))

	cols := make(sort.StringSlice, len(q.update))

	count := 0
	for name := range q.update {
		cols[count] = name
		count++
	}

	cols.Sort()

	for i := 0; i < len(cols); i++ {
		args = append(args, q.update[cols[i]])
		cols[i] = strmangle.IdentQuote(q.dialect.LQ, q.dialect.RQ, cols[i])
	}

	setSlice := make([]string, len(cols))
	for index, col := range cols {
		setSlice[index] = fmt.Sprintf("%s = %s", col, strmangle.Placeholders(q.dialect.UseIndexPlaceholders, 1, index+1, 1))
	}
	fmt.Fprintf(buf, " SET %s", strings.Join(setSlice, ", "))

	where, whereArgs := whereClause(q, len(args)+1)
	if len(whereArgs) != 0 {
		args = append(args, whereArgs...)
	}
	buf.WriteString(where)

	writeModifiers(q, buf, &args)

	buf.WriteByte(';')

	return buf, args
}

func writeParameterizedModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}, keyword, delim string, clauses []argClause) {
	argsLen := len(*args)
	modBuf := strmangle.GetBuffer()
	fmt.Fprintf(modBuf, keyword)

	for i, j := range clauses {
		if i > 0 {
			modBuf.WriteString(delim)
		}
		modBuf.WriteString(j.clause)
		*args = append(*args, j.args...)
	}

	var resp string
	if q.dialect.UseIndexPlaceholders {
		resp, _ = convertQuestionMarks(modBuf.String(), argsLen+1)
	} else {
		resp = modBuf.String()
	}

	buf.WriteString(resp)
	strmangle.PutBuffer(modBuf)
}

func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
	if len(q.groupBy) != 0 {
		fmt.Fprintf(buf, " GROUP BY %s", strings.Join(q.groupBy, ", "))
	}

	if len(q.having) != 0 {
		writeParameterizedModifiers(q, buf, args, " HAVING ", " AND ", q.having)
	}

	if len(q.orderBy) != 0 {
		writeParameterizedModifiers(q, buf, args, " ORDER BY ", ", ", q.orderBy)
	}

	if !q.dialect.UseTopClause {
		if q.limit != 0 {
			fmt.Fprintf(buf, " LIMIT %d", q.limit)
		}

		if q.offset != 0 {
			fmt.Fprintf(buf, " OFFSET %d", q.offset)
		}
	} else {
		// From MS SQL 2012 and above: https://technet.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
		// ORDER BY ...
		// OFFSET N ROWS
		// FETCH NEXT M ROWS ONLY
		if q.offset != 0 {

			// Hack from https://www.microsoftpressstore.com/articles/article.aspx?p=2314819
			// ...
			// As mentioned, the OFFSET-FETCH filter requires an ORDER BY clause. If you want to use arbitrary order,
			// like TOP without an ORDER BY clause, you can use the trick with ORDER BY (SELECT NULL)
			// ...
			if len(q.orderBy) == 0 {
				buf.WriteString(" ORDER BY (SELECT NULL)")
			}

			// This seems to be the latest version of mssql's syntax for offset
			// (the suffix ROWS)
			// This is true for latest sql server as well as their cloud offerings & the upcoming sql server 2019
			// https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017
			// https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-ver15
			fmt.Fprintf(buf, " OFFSET %d ROWS", q.offset)

			if q.limit != 0 {
				fmt.Fprintf(buf, " FETCH NEXT %d ROWS ONLY", q.limit)
			}
		}
	}

	if len(q.forlock) != 0 {
{'fraction_non_alphanumeric': 0.1697828709288299, 'fraction_numerical': 0.009650180940892641, 'mean_word_length': 3.683968926553672, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 8, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5492814', 'n_tokens_mistral': 5520, 'n_tokens_neox': 4996, 'n_words': 1105}