Documentation
¶
Overview ¶
Package sqlutil solves a common SQL string-construction problem: safely quoting identifiers and string literals when generating query fragments dynamically.
Problem ¶
Applications that build SQL fragments at runtime often need to quote table, schema, and column identifiers, as well as string values. Doing this ad hoc across a codebase is error-prone and can lead to malformed SQL or inconsistent escaping behavior.
sqlutil centralizes quoting behavior behind a small configurable API.
What It Provides ¶
New returns a configurable SQLUtil instance exposing:
- SQLUtil.QuoteID for quoting identifiers (schema/table/column names).
- SQLUtil.QuoteValue for quoting string literal values.
The default implementation is mysql-like:
- identifiers are split by "." and each segment is wrapped in backticks, with embedded backticks escaped as doubled backticks (no other escaping: inside backtick quotes only the backtick is special).
- values are wrapped in single quotes, with embedded single quotes doubled and control characters escaped (`\0`, `\n`, `\r`, `\\`, `\Z`); the empty string yields an empty quoted literal (two single quotes).
Customization ¶
Use options to adapt quoting rules for different SQL dialects:
- WithQuoteIDFunc replaces identifier quoting behavior.
- WithQuoteValueFunc replaces value quoting behavior.
This allows Postgres/SQLite/other dialect-specific quoting while preserving the same calling pattern throughout the codebase.
Important Boundary ¶
This package is intended for quoting identifiers and string literals in dynamic query generation. It is not a replacement for prepared statements and query parameterization. Continue using placeholders and bound parameters for runtime data whenever possible.
Limitations ¶
The default value quoting is correct for MySQL-like databases running in the default SQL mode over an ASCII-compatible, single-byte-safe connection charset (for example utf8mb4 or latin1). It is NOT safe for untrusted input in two situations:
- NO_BACKSLASH_ESCAPES SQL mode: backslash is not an escape character, so the backslash escaping applied here (\n, \\, \Z, ...) is interpreted literally and silently corrupts the stored value.
- Non-self-synchronizing multibyte charsets (GBK, Big5, SJIS, ...): byte-wise escaping is the classic vector for escape-function SQL injection because a lead byte can consume the escaping backslash.
Use bound parameters for untrusted data, and supply WithQuoteValueFunc / WithQuoteIDFunc to match the exact rules of another dialect or charset.
Usage ¶
u, err := sqlutil.New()
if err != nil {
return err
}
col := u.QuoteID("users.email") // `users`.`email`
val := u.QuoteValue("o'reilly") // 'o''reilly'
query := "SELECT " + col + " FROM " + u.QuoteID("users") + " WHERE " + col + " = " + val
_ = query
Index ¶
- Variables
- type Option
- type SQLQuoteFunc
- type SQLUtil
- func (c *SQLUtil) BuildInClauseInt(field string, values []int) string
- func (c *SQLUtil) BuildInClauseInt64(field string, values []int64) string
- func (c *SQLUtil) BuildInClauseString(field string, values []string) string
- func (c *SQLUtil) BuildInClauseUint(field string, values []uint64) string
- func (c *SQLUtil) BuildNotInClauseInt(field string, values []int) string
- func (c *SQLUtil) BuildNotInClauseInt64(field string, values []int64) string
- func (c *SQLUtil) BuildNotInClauseString(field string, values []string) string
- func (c *SQLUtil) BuildNotInClauseUint(field string, values []uint64) string
- func (c *SQLUtil) QuoteID(s string) string
- func (c *SQLUtil) QuoteValue(s string) string
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNilQuoteIDFunc is returned when the identifier quoting function is nil. ErrNilQuoteIDFunc = errors.New("the QuoteID function must be set") // ErrNilQuoteValueFunc is returned when the value quoting function is nil. ErrNilQuoteValueFunc = errors.New("the QuoteValue function must be set") )
Functions ¶
This section is empty.
Types ¶
type Option ¶
type Option func(*SQLUtil)
Option configures a SQLUtil instance.
func WithQuoteIDFunc ¶
func WithQuoteIDFunc(fn SQLQuoteFunc) Option
WithQuoteIDFunc customizes the identifier quoting function, e.g. double-quoted identifiers for Postgres/SQLite instead of the default MySQL-style backticks.
Example ¶
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/sqlutil"
)
func main() {
// define custom quote function
fn := func(s string) string { return "TEST-" + s }
q, err := sqlutil.New(
sqlutil.WithQuoteIDFunc(fn),
)
if err != nil {
log.Fatal(err)
}
o := q.QuoteID("6971")
fmt.Println(o)
}
Output: TEST-6971
func WithQuoteValueFunc ¶
func WithQuoteValueFunc(fn SQLQuoteFunc) Option
WithQuoteValueFunc customizes value quoting function for different SQL dialects.
Example ¶
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/sqlutil"
)
func main() {
// define custom quote function
fn := func(s string) string { return "TEST-" + s }
q, err := sqlutil.New(
sqlutil.WithQuoteValueFunc(fn),
)
if err != nil {
log.Fatal(err)
}
o := q.QuoteValue("4987")
fmt.Println(o)
}
Output: TEST-4987
type SQLQuoteFunc ¶
SQLQuoteFunc is the type of function called to quote a string (ID or value).
type SQLUtil ¶
type SQLUtil struct {
// contains filtered or unexported fields
}
SQLUtil is the structure that helps to manage a SQL DB connection.
func New ¶
New constructs SQL utility with configurable identifier and value quoting functions (default: MySQL-style).
func (*SQLUtil) BuildInClauseInt ¶
BuildInClauseInt prepares a SQL IN clause with the given list of signed integer values. An empty list yields a never-matching predicate (1 = 0).
func (*SQLUtil) BuildInClauseInt64 ¶
BuildInClauseInt64 prepares a SQL IN clause with the given list of 64-bit signed integer values. An empty list yields a never-matching predicate (1 = 0).
func (*SQLUtil) BuildInClauseString ¶
BuildInClauseString prepares a SQL IN clause with the given list of string values. An empty list yields a never-matching predicate (1 = 0).
func (*SQLUtil) BuildInClauseUint ¶
BuildInClauseUint prepares a SQL IN clause with the given list of unsigned integer values. An empty list yields a never-matching predicate (1 = 0).
func (*SQLUtil) BuildNotInClauseInt ¶
BuildNotInClauseInt prepares a SQL NOT IN clause with the given list of signed integer values. An empty list yields an always-matching predicate (1 = 1).
func (*SQLUtil) BuildNotInClauseInt64 ¶
BuildNotInClauseInt64 prepares a SQL NOT IN clause with the given list of 64-bit signed integer values. An empty list yields an always-matching predicate (1 = 1).
func (*SQLUtil) BuildNotInClauseString ¶
BuildNotInClauseString prepares a SQL NOT IN clause with the given list of string values. An empty list yields an always-matching predicate (1 = 1).
func (*SQLUtil) BuildNotInClauseUint ¶
BuildNotInClauseUint prepares a SQL NOT IN clause with the given list of unsigned integer values. An empty list yields an always-matching predicate (1 = 1).
func (*SQLUtil) QuoteID ¶
QuoteID quotes identifiers (schema/table/column names) with configurable SQL dialect rules.
Example ¶
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/sqlutil"
)
func main() {
q, err := sqlutil.New()
if err != nil {
log.Fatal(err)
}
o := q.QuoteID("7919")
fmt.Println(o)
}
Output: `7919`
func (*SQLUtil) QuoteValue ¶
QuoteValue quotes string literal values with configurable SQL dialect escape rules; includes surrounding quotes.
Example ¶
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/sqlutil"
)
func main() {
q, err := sqlutil.New()
if err != nil {
log.Fatal(err)
}
o := q.QuoteValue("5867")
fmt.Println(o)
}
Output: '5867'