taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

quote.go (2749B)


      1 package pq
      2 
      3 import (
      4 	"bytes"
      5 	"strings"
      6 )
      7 
      8 // QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be
      9 // used as part of an SQL statement. For example:
     10 //
     11 //	tblname := "my_table"
     12 //	data := "my_data"
     13 //	quoted := pq.QuoteIdentifier(tblname)
     14 //	err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data)
     15 //
     16 // Any double quotes in name will be escaped. The quoted identifier will be case
     17 // sensitive when used in a query. If the input string contains a zero byte, the
     18 // result will be truncated immediately before it.
     19 func QuoteIdentifier(name string) string {
     20 	end := strings.IndexRune(name, 0)
     21 	if end > -1 {
     22 		name = name[:end]
     23 	}
     24 	return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
     25 }
     26 
     27 // BufferQuoteIdentifier satisfies the same purpose as QuoteIdentifier, but backed by a
     28 // byte buffer.
     29 func BufferQuoteIdentifier(name string, buffer *bytes.Buffer) {
     30 	// TODO(v2): this should have accepted an io.Writer, not *bytes.Buffer.
     31 	end := strings.IndexRune(name, 0)
     32 	if end > -1 {
     33 		name = name[:end]
     34 	}
     35 	buffer.WriteRune('"')
     36 	buffer.WriteString(strings.Replace(name, `"`, `""`, -1))
     37 	buffer.WriteRune('"')
     38 }
     39 
     40 // QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal
     41 // to DDL and other statements that do not accept parameters) to be used as part
     42 // of an SQL statement. For example:
     43 //
     44 //	exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z")
     45 //	err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date))
     46 //
     47 // Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be
     48 // replaced by two backslashes (i.e. "\\") and the C-style escape identifier
     49 // that PostgreSQL provides ('E') will be prepended to the string.
     50 func QuoteLiteral(literal string) string {
     51 	// This follows the PostgreSQL internal algorithm for handling quoted literals
     52 	// from libpq, which can be found in the "PQEscapeStringInternal" function,
     53 	// which is found in the libpq/fe-exec.c source file:
     54 	// https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c
     55 	//
     56 	// substitute any single-quotes (') with two single-quotes ('')
     57 	literal = strings.Replace(literal, `'`, `''`, -1)
     58 	// determine if the string has any backslashes (\) in it.
     59 	// if it does, replace any backslashes (\) with two backslashes (\\)
     60 	// then, we need to wrap the entire string with a PostgreSQL
     61 	// C-style escape. Per how "PQEscapeStringInternal" handles this case, we
     62 	// also add a space before the "E"
     63 	if strings.Contains(literal, `\`) {
     64 		literal = strings.Replace(literal, `\`, `\\`, -1)
     65 		literal = ` E'` + literal + `'`
     66 	} else {
     67 		// otherwise, we can just wrap the literal with a pair of single quotes
     68 		literal = `'` + literal + `'`
     69 	}
     70 	return literal
     71 }