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 }