Variable column names using prepared statements

54,041

Solution 1

This indicates a bad DB design. The user shouldn't need to know about the column names. Create a real DB column which holds those "column names" and store the data along it instead.

And any way, no, you cannot set column names as PreparedStatement values. You can only set column values as PreparedStatement values

If you'd like to continue in this direction, you need to sanitize the column names (to avoid SQL Injection) and concatenate/build the SQL string yourself. Quote the separate column names and use String#replace() to escape the same quote inside the column name.

Solution 2

Prepare a whitelist of allowed column names. Use the 'query' to look up in the whitelist to see if the column name is there. If not, reject the query.

Solution 3

The accepted answer is not actually correct. While the OP approach indicated a bad DB design, it might be required by the business logic (for instance a MySQL IDE)

Anyway, for MySQL prepared statements, what you need to know is that ? is for values, but if you need to escape column names, table names etc, use ?? instead.

Something like this will work:

SELECT ??, ??, ?? FROM ?? WHERE ?? < ? 

Set values to ['id', 'name', 'address', 'user', 'id', 100]

Solution 4

I think this case can't work because the whole point of the prepared statement is to prevent the user from putting in unescaped query bits - so you're always going to have the text quoted or escaped.

You'll need to sanitize this input in Java if you want to affect the query structure safely.

Share:
54,041
KLee1
Author by

KLee1

Note: My views are not necessarily representative of my company's.

Updated on July 09, 2022

Comments

  • KLee1
    KLee1 almost 2 years

    I was wondering if there was any way to specify returned column names using prepared statements.

    I am using MySQL and Java.

    When I try it:

    String columnNames="d,e,f"; //Actually from the user...
    String name = "some_table"; //From user...
    String query = "SELECT a,b,c,? FROM " + name + " WHERE d=?";//...
    stmt = conn.prepareStatement(query);
    stmt.setString(1, columnNames);
    stmt.setString(2, "x");
    

    I get this type of statement (printing right before execution).

    SELECT a,b,c,'d,e,f' FROM some_table WHERE d='x'
    

    I would, however, like to see:

    SELECT a,b,c,d,e,f FROM some_table WHERE d='x'
    

    I know that I cannot do this for table names, as discussed here, but was wondering if there was some way to do it for column names.

    If there is not, then I will just have to try and make sure that I sanitize the input so it doesn't lead to SQL injection vulnerabilities.

  • KLee1
    KLee1 almost 14 years
    Well, the user doesn't actually need to know the column names, but the column names needed are deduced based on forms submitted by the user. This is handled on the client side, though, so I wanted to see if there was some way to ensure the data is safe. Should I then just move the whole lot to the server-side, thereby ensuring the column data is untainted?
  • BalusC
    BalusC almost 14 years
    Handle it on the server side instead. Don't do business stuff in client side.
  • specializt
    specializt almost 9 years
    @BalusC : "you cannot set column names as PreparedStatement values" - thats completely made up. Using column names inside of prepared statement value-lists is of course possible - but that doesnt mean it should be used that way, it still is bad design.
  • npn_or_pnp
    npn_or_pnp about 8 years
    I'd like to see you dynamically limit fields for a given resource using REST with JSON. Not everybody wants the whole resource returned, and not everybody wants to create 1,000 queries for every permutation of said columns.
  • Insac
    Insac over 7 years
    You're right on the "it can't work". However the first reason for PreparedStatement was because of resource efficiency, allowing to keep a statement cached and submitting it multiple times just changing the values (great especially for OLTP). Its resilience to SQL Injection attempts is a very desiderable side effect.
  • Anil Agrawal
    Anil Agrawal about 7 years
    Your answer looks ok, but you should describe your code as well
  • Clement Cherlin
    Clement Cherlin almost 7 years
    This answer leads directly to an SQL injection attack.
  • Admin
    Admin over 6 years
    What about dynamic ordering for a query utilizing variable column name? Would that also be considered bad design?
  • Guillaume Husta
    Guillaume Husta almost 6 years
    Yes this is an example of vulnerable code, as described here : find-sec-bugs.github.io/bugs.htm#SQL_INJECTION_JPA
  • nanosoft
    nanosoft about 5 years
    The question is about leveraging preparedStatement(). Your solution doesn't use it. It is prone to sql injection.
  • where_
    where_ about 4 years
    It's a very interesting comment. I couldn't find any reference to that escaped parameter value syntax (??). Could you, possibly, point me to one?
  • DraganescuValentin
    DraganescuValentin about 4 years
    I don't remember where I've seen this, definitely not in the official docs. However, I'm using this successfully in a toy project.
  • ceving
    ceving over 3 years
    Ouch! SQL code generation by string concatenation without escaping! Please delete this before you boss recognizes, that you wrote this.
  • Yami Odymel
    Yami Odymel over 2 years
    I think this is a specified usage for Node.js packaged named mysqljs/mysql
  • DraganescuValentin
    DraganescuValentin over 2 years
    @YamiOdymel Indeed this might only work on the mysqljs/mysql Node.js package. It looks like the select is not valid when run from MySQLWorkbench This statements do not work because ?? is not recognised PREPARE stmt1 FROM 'SELECT ??, ?? FROM ?? WHERE ?? = ?'; SET @a = 'foo'; SET @b = 'bar'; SET @c = 'Foos'; SET @d = 'foo'; SET @e = 'fooooo'; EXECUTE stmt1 USING @a, @b, @c, @d, @e;