0

I want to fetch data from an MariaDB database and installed the MariaDB JDBC connector via Maven. The following code adds (see code snippet, line 10) the parameters of the PreparedStatement pstmt data instead of the actual row/cell data to the combo box. This is the problem I want to fix. If it matters, my table consists of 1 int and 4 varchars.

Code snippet (with line count):

// WRITTEN IN NORMAL JAVA 11
 1| Connection db = DriverManager.getConnection("jdbc:mariadb://localhost:3306/DB", "USER", "PASSWORD");
 2| PreparedStatement pstmt = db.prepareStatement("SELECT ? FROM companies;");
 3| pstmt.setString(1, ((JComboItem) companySelectFilterCategoryComboBox.getSelectedItem()).getValue()); // getValue() returns "email"; Combo Box is JComboBox<ComboItem>, ComboItem.groovy is below
 4| System.out.println(pstmt); // OUTPUT: sql : 'SELECT ? from companies;', parameters : ['email']
 5| ResultSet rs = pstmt.executeQuery();
 6| ArrayList<ArrayList<String>> list = ResultSetService.resultSetToArrayLists(rs); // This returns an ResultSet as an deep ArrayList (as ArrayList<ArrayList<String>>), see below
 7| System.out.println(ResultSetService.toString(rs)); //OUTPUT: [[email], [email]]

// This output is already wrong, should be: [[mail1@localhost], [mail2@localhost]]
// This is the above mentioned problem I want to fix.

 8| companySelectOptionsComboBox.removeAllItems();
 9| for (ArrayList<String> arr: list) {
10|    companySelectOptionsComboBox.addItem(arr.get(0));
11| }

The ComboItem class is basically just an object with 2 strings, one key and one value. The key is the String being displayed and the value is used in the backend (see code snippet, line 3):

// WRITTEN IN GROOVY
class JComboItem {
    private String key;
    private String value;

    JComboItem(String key, String value)
    {
        this.key = key;
        this.value = value;
    }

    @Override
    String toString()
    {
        return key;
    }

    String getValue()
    {
        return value;
    }
}

This translates every cell of a row in an ArrayList and puts those in another ArrayList and returns it (List of rows). The error might be here, but this works flawlessly in another part of the script (If asked, I will gladly provide this part, but don't want to bloat this post). The only difference are the tables, the table of the working script consists of 3 varchars:

// WRITTEN IN GROOVY
class ResultSetService {

    static ArrayList<ArrayList<String>> resultSetToArrayLists(ResultSet rs) throws SQLException {
        ArrayList<ArrayList<String>> list = new ArrayList<>()
        rs.beforeFirst()
        while (rs.next()) {
            ArrayList<String> row = new ArrayList<>()
            for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                row.add(rs.getString(i))
            }
            list.add(row)
        }
        return list
    }
}

I've looked this problem up for the last 2 days but couldn't find anything about it or similar ones. My best guesses are either an error at ResultSetService.resultSetToArrayLists() or wrong usage of PreparedStatement/ResultSet (Even though it works at another point in the script). Or an actual bug somewhere in the library.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Probastian
  • 33
  • 9
  • You cannot parameterize object names, your query is literally asking to output the string value `email` for each row in `companies`. – Mark Rotteveel Jan 21 '21 at 16:46
  • Related: [Safe way to use table name as parameter in JDBC query](https://stackoverflow.com/questions/39892449/safe-way-to-use-table-name-as-parameter-in-jdbc-query) – Mark Rotteveel Jan 21 '21 at 16:48

1 Answers1

4

You can not use a placeholder to insert a column name. The effective query is: select 'email' from something. You have to concat the name of column into the sql string. So be tripple careful a malicious user can not inject sql there (e.g. use an enum or some other sort of allow-list).

cfrick
  • 35,203
  • 6
  • 56
  • 68