1

I am trying to accomplish a simple licensing system in golang and have tried numerous ways to get it to work. Basically, I have input a couple of random licensing keys into my database and my golang program should check to see if the user-input key exists and if it does then add the user specified username and password into the database to login later.

This is the code that I have that hasn't been working:

"IF EXISTS (SELECT * FROM login WHERE LK = "+reglicenceEntry.Text()+") THEN 
 INSERT INTO `login` (`Username`, `Password`, `LK`) VALUES 
 ('"+regusernameEntry.Text()+"', '"+regpasswordEntry.Text()+"', ''); "

This is the golang error:

Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF EXISTS (SELECT * FROM login WHERE LK = '5qp515YHXEmSDzwqgoJh') THEN INSERT IN' at line 1

Thanks so much!

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
David Vega
  • 13
  • 5
  • In `WHERE LK = "+reglicenceEntry.Text()+")`, there are no single quotes around the value. But i assume `LK` is some `char`variant, as you use single quotes in the insert. But you should use parametrized queries anyway, to prevent SQL injection and other benefits. – sticky bit May 06 '18 at 17:55
  • @stickybit LK is the licence key vaue in my database. I have it set as a text value. Thanks for the suggestion! – David Vega May 06 '18 at 17:58

1 Answers1

1

MySQL syntax doesn't support IF...THEN constructs except within stored routines and triggers and events. See https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-compound-statements.html

I suggest an alternative solution for your code:

INSERT INTO `login` (`Username`, `Password`, `LK`)
SELECT ?, ?, ''
FROM `login`
WHERE `LK` = ?
LIMIT 1

If your login table does not have the LK value, the SELECT above will return 0 rows, therefore it will not insert anything.

If your login table has the LK value, the SELECT above will return at least 1 row (and I limit it to 1), therefore it will insert a row. The row it inserts is comprised of your username and password, and a blank string for the LK.

I showed use of parameter placeholders. You should use parameters in SQL instead of concatenating variables into your query. This is good practice to avoid accidental SQL injection. See http://go-database-sql.org/prepared.html for examples.


The purpose of using parameters is to avoid SQL injection problems. See my answer to What is SQL injection? for an explanation of SQL injection.

Or my presentation SQL Injection Myths and Fallacies (or youtube video).

When using parameters, you do two steps.

  • The first step to prepare a query with placeholders (?) where you would otherwise concatenate variables into your SQL query.
  • The second step is to execute the prepared query, and this is the time you pass the variables to fill in the placeholders.

The point is to keep variables separate from your query, so if there's anything in the variable that could unintentionally change your SQL syntax (like imbalanced quotes), it is never combined with the SQL. After you do the prepare, the SQL has already been parsed by the MySQL server, and there's no way to change the syntax after that.

MySQL remembers which parts of the query need to be filled in, and when you pass variables during the execute step, MySQL fills in the missing parts of the query using your values — but this happens within the MySQL server, not in your application.

Thus the dynamic parts of the query — your variables — are kept separate from the SQL syntax and you avoid SQL injection problems.

For your task described in your question, it would look something like this (I have not tested this Go code, but it should put you on the right path).

stmt, err := tx.Prepare("INSERT INTO `login` (`Username`, `Password`, `LK`) SELECT ?, ?, '' FROM `login` WHERE `LK` = ? LIMIT 1")
if err != nil {
    log.Fatal(err)
}
defer stmt.Close()

_, err = stmt.Exec(regusernameEntry.Text(), regpasswordEntry.Text(), reglicenceEntry.Text())
if err != nil {
    log.Fatal(err)
}

The order of parameters is important. The variables you pass to Exec() must be in the same order that the ? placeholders appear in your prepared SQL statement. They are matched up, one for one, in the same order, by the MySQL server.

Do not put quotes around the placeholders in your prepared SQL statement. That will work as a literal string '?' in SQL. Use an unquoted ? character for a placeholder. When it gets combined by MySQL in the server, it will work as if you had put quotes around the value like a string — but with no risk of SQL injection even if that string value containing special characters.

Here's another site that gives more code examples: https://github.com/go-sql-driver/mysql/wiki/Examples

The Exec() function is for executing SQL that has no result set, like INSERT, UPDATE, DELETE. There are other functions in the Go SQL driver like Query() and QueryRow() that also accept parameter arguments. You'd use these if your SQL returns a result set.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • Ok, Thanks for the suggestion, do I replace my current code with this? What are the question marks for? I get the following error: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?, ?, ''FROM `login`WHERE `LK` = ? LIMIT 1' at line 1 – David Vega May 06 '18 at 18:17
  • You need to use prepared statements to use parameters. I gave a link at the end of my answer. Please go read it. – Bill Karwin May 06 '18 at 18:35
  • I don't understand. I have to specify my username, password, and lk parameters. Do I replace the question marks with those parameters. You didn't ever mention my regusernameEntry.text() etc. I read the article but don't understand. Thanks – David Vega May 06 '18 at 18:40
  • Wow, great explanation and fixed my issue. Thanks so much! – David Vega May 06 '18 at 20:06