0

I am trying to create a user in postgres. currently trying to use https://github.com/jackc/pgx as the driver to connect to the db. I have the below

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/jackc/pgx/v4"
)

func main() {
    ctx := context.Background()
    conn, err := pgx.Connect(ctx, "host=localhost port=5432 user=postgres password=postgres dbname=postgres")
    if err != nil {
        panic(err)
    }
    defer conn.Close(ctx)

    // create user
    _, err = conn.Exec(ctx, "CREATE USER $1 WITH PASSWORD $2", "moulick", "testpass")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

But I get this ERROR: syntax error at or near "$1" (SQLSTATE 42601)

I don't get what's the problem here ?

Moulick
  • 4,342
  • 1
  • 13
  • 19

1 Answers1

3

"I don't get what's the problem here ?" -- The problem is that positional parameters can be used only for values, and not for identifiers.

A positional parameter reference is used to indicate a value that is supplied externally to an SQL statement.

You cannot use positional parameters in CREATE USER <user_name> the same way you cannot use them in SELECT t.<column_name> FROM <table_name> AS t.

user_name := "moulick"
_, err = conn.Exec(ctx, "CREATE USER "+user_name+" WITH PASSWORD $1", "testpass")
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}

If the user_name is not hardcoded, but instead comes from an unknown user input, you need to validate it yourself to avoid the possibility of SQL injections. This is not a difficult task since the lexical structure of identifiers is limited to a small set of rules, which you can further reduce to an even smaller subset if you like (e.g. disallowing diacritical marks and non-Latin letters):

SQL identifiers and key words must begin with a letter (a-z, but also letters with diacritical marks and non-Latin letters) or an underscore (_). Subsequent characters in an identifier or key word can be letters, underscores, digits (0-9), or dollar signs ($). Note that dollar signs are not allowed in identifiers according to the letter of the SQL standard, so their use might render applications less portable. The SQL standard will not define a key word that contains digits or starts or ends with an underscore, so identifiers of this form are safe against possible conflict with future extensions of the standard.

mkopriva
  • 35,176
  • 4
  • 57
  • 71
  • Please use some function to concatenate strings. On this example, ok, but it can lead to sql injection – Tiago Peczenyj Mar 26 '22 at 12:05
  • @TiagoPeczenyj What is the point you are trying to make? The answer already explicitly addresses SQL injections and how to avoid them in this specific case, does it not? And OP seemingly already knows that it's important to use positional parameters, wherever possible, to avoid SQL injections. – mkopriva Mar 26 '22 at 12:09
  • I was thinking in something like this: https://github.com/feiin/sqlstring – Tiago Peczenyj Mar 26 '22 at 12:15
  • Yeah, SQL injection was what I was afraid of. But seems that pgx/v4 has a Sanitize function that I can probably use to prevent against SQL injection. – Moulick Mar 26 '22 at 17:55