sqlutil

package
v1.148.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 4 Imported by: 0

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:

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:

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

Examples

Constants

This section is empty.

Variables

View Source
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

type SQLQuoteFunc func(s string) string

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

func New(opts ...Option) (*SQLUtil, error)

New constructs SQL utility with configurable identifier and value quoting functions (default: MySQL-style).

func (*SQLUtil) BuildInClauseInt

func (c *SQLUtil) BuildInClauseInt(field string, values []int) string

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

func (c *SQLUtil) BuildInClauseInt64(field string, values []int64) string

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

func (c *SQLUtil) BuildInClauseString(field string, values []string) string

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

func (c *SQLUtil) BuildInClauseUint(field string, values []uint64) string

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

func (c *SQLUtil) BuildNotInClauseInt(field string, values []int) string

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

func (c *SQLUtil) BuildNotInClauseInt64(field string, values []int64) string

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

func (c *SQLUtil) BuildNotInClauseString(field string, values []string) string

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

func (c *SQLUtil) BuildNotInClauseUint(field string, values []uint64) string

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

func (c *SQLUtil) QuoteID(s string) string

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

func (c *SQLUtil) QuoteValue(s string) string

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'

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL