What does "=?" represent when used in an SQL query - java

I'm fairly new to SQL and I'm currently reworking a java program that another
programmer has developed. When I print one of his query select statements the script contains sql syntax:
SELECT * from database WHERE id = ?
I just want know what =? is supposed to do? I've been googling around and I can't find any relevant answer.

It's not a SQL notation, but a JDBC (Java Database Connectivity) notation. The ? gets replaced with a parameter that is specified separately. Using this approach, instead of trying to substitute the parameter yourself into the string, helps prevent the risk of SQL injection.

The ? is a place holder, a parameter, so that you can pass it in dynamically and return different results for different parameters.
Somewhere in the code you should see that he adds the parameter to the Statement object and execute it.

Most likely you are using a tool that will replace the "?" with an actual value. I've seen this in other tools before such as SQL DTS (Data Transformation Services)... but that's showing how old I am :)
The ? is not part of the SQL language.

The ? is a place holder used in SQL queries when used with JDBC Prepared statement. Using a prepared statement has advantages over the normal statement specially when you use it repeatedly (say in a loop).

Here is an example :
PreparedStatement ps =
connection.prepareStatement("select name from users where user_name = ?");
ps.setString(1, "user1");
the "?" gets replace by "user1" when the query is run and the first name of the user with user name "user1" is returned.

Related

How to get rid of many placeholders (question marks) in java sql statements

I want to insert a row to table using JDBC. But table has a big number of columns, so I don't want to specify all of them into a statement. Is there another way of specifying column values?
INSERT INTO TABLE_NAME VALUES(?, ?, ?, ..., ?)
I hope there is another way to do it without a big number of placeholders.
EDITED:
I mean, can I just edit query like ... meaning that it expects a many values and dynamically set values with incremented index or something else. And yes as #f1sh mentioned the problem is in the number of placeholders, but not in case of laziness, more in case of convenience and cleanliness.
P.S.: for some funny enterprise requirements reasons I can not use JPA frameworks :)
EDIT
Another option is to write your own or use SqlBuilder
SqlBuilder changes that whole scenario by wrapping the SQL syntax within very lightweight and easy to use Java objects which follow the "builder" paradigm (similar to StringBuilder). This changes many common SQL syntactical, runtime errors into Java compile-time errors! Let's dive right in to some quick examples to to see how it all works.
You can use Spring's NamedParameterJdbcTemplate and use variable names
String SQL = INSERT INTO TABLE_NAME VALUES((:id),...);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("id", "idValue");
//...
namedParameterJdbcTemplate.update(SQL, parameters) > 0;
Template class with a basic set of JDBC operations, allowing the use of named parameters rather than traditional '?' placeholders.
If you can (safely) use dynamic query using Statement:
Statement stmt = (Statement) con.createStatement(“SELECT username, password FROM users WHERE username='” + user + “‘ AND password='” + pass + “‘ limit 0,1”);
ResultSet rs = stmt.executeQuery();
You can use it only on closed values so there will be no option for SQL injection

Using Variable as a column in sql query

Here is my code. I am trying to use a variable instead of a column name in here
But I get below exception. How can I resolve this error?
You can't bind table/column names in a prepared statement, nor would you normally want to allow this. Here is a working version of your code:
String query = "UPDATE report SET itemno = ?";
pst = (PreparedStatement) con.prepareStatement(query);
pst.setInt(1, dqty);
pst.executeUpdate();
Notes:
You almost certainly want to add a WHERE clause to your update, without which it would affect every record in the table. With prepared statements, you don't need to worry about escaping your literal data. Just let Java handle this for you.
If you really need the ability to update other table/column combinations, then just create other statements for that. One size fits all works at 7-Eleven, but not JDBC, since you might SQL injected.

How are we still vulnerable to sql injection even when using prepared statements with parameters? [duplicate]

I know that PreparedStatements avoid/prevent SQL Injection. How does it do that? Will the final form query that is constructed using PreparedStatements be a string or otherwise?
Consider two ways of doing the same thing:
PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();
Or
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
If "user" came from user input and the user input was
Robert'); DROP TABLE students; --
Then in the first instance, you'd be hosed. In the second, you'd be safe and Little Bobby Tables would be registered for your school.
To understand how PreparedStatement prevents SQL Injection, we need to understand phases of SQL Query execution.
1. Compilation Phase.
2. Execution Phase.
Whenever SQL server engine receives a query, it has to pass through below phases,
Parsing and Normalization Phase:
In this phase, Query is checked for syntax and semantics. It checks whether references table and
columns used in query exist or not.
It also has many other tasks to do, but let's not go in detail.
Compilation Phase:
In this phase, keywords used in query like select, from, where etc are converted into format
understandable by machine.
This is the phase where query is interpreted and corresponding action to be taken is decided.
It also has many other tasks to do, but let's not go in detail.
Query Optimization Plan:
In this phase, Decision Tree is created for finding the ways in which query can be executed.
It finds out the number of ways in which query can be executed and the cost associated with each way
of executing Query.
It chooses the best plan for executing a query.
Cache:
Best plan selected in Query optimization plan is stored in cache, so that whenever next
time same query comes in, it doesn't have to pass through Phase 1, Phase 2 and Phase 3 again.
When next time query come in, it will be checked directly in Cache and picked up from there
to execute.
Execution Phase:
In this phase, supplied query gets executed and data is returned to user as ResultSet object.
Behaviour of PreparedStatement API on above steps
PreparedStatements are not complete SQL queries and contain placeholder(s),
which at run time are replaced by actual user-provided data.
Whenever any PreparedStatment containing placeholders is passed in to SQL Server engine,
It passes through below phases
Parsing and Normalization Phase
Compilation Phase
Query Optimization Plan
Cache (Compiled Query with placeholders are stored in Cache.)
UPDATE user set username=? and password=? WHERE id=?
Above query will get parsed, compiled with placeholders as special treatment, optimized and
get Cached.
Query at this stage is already compiled and converted in machine understandable format.
So we can say that Query stored in cache is Pre-Compiled and
only placeholders need to be replaced with user-provided data.
Now at run-time when user-provided data comes in, Pre-Compiled Query is picked up from Cache and placeholders are replaced with user-provided data.
(Remember, after place holders are replaced with user data, final query is not
compiled/interpreted again and SQL Server engine treats user data as pure data and not a
SQL that needs to be parsed or compiled again; that is the beauty of PreparedStatement.)
If the query doesn't have to go through compilation phase again, then whatever data replaced on the
placeholders are treated as pure data and has no meaning to SQL Server engine and it directly
executes the query.
Note: It is the compilation phase after parsing phase, that understands/interprets the query
structure and gives meaningful behavior to it. In case of PreparedStatement, query is
compiled only once and cached compiled query is picked up all the time to replace
user data and execute.
Due to one time compilation feature of PreparedStatement, it is free of SQL Injection
attack.
You can get detailed explanation with example here:
https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
The problem with SQL injection is, that a user input is used as part of the SQL statement. By using prepared statements you can force the user input to be handled as the content of a parameter (and not as a part of the SQL command).
But if you don't use the user input as a parameter for your prepared statement but instead build your SQL command by joining strings together, you are still vulnerable to SQL injections even when using prepared statements.
The SQL used in a PreparedStatement is precompiled on the driver. From that point on, the parameters are sent to the driver as literal values and not executable portions of SQL; thus no SQL can be injected using a parameter. Another beneficial side effect of PreparedStatements (precompilation + sending only parameters) is improved performance when running the statement multiple times even with different values for the parameters (assuming that the driver supports PreparedStatements) as the driver does not have to perform SQL parsing and compilation each time the parameters change.
I guess it will be a string. But the input parameters will be sent to the database & appropriate cast/conversions will be applied prior to creating an actual SQL statement.
To give you an example, it might try and see if the CAST/Conversion works.
If it works, it could create a final statement out of it.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Try an example with a SQL statement accepting a numeric parameter.
Now, try passing a string variable (with numeric content that is acceptable as numeric parameter). Does it raise any error?
Now, try passing a string variable (with content that is not acceptable as numeric parameter). See what happens?
Prepared statement is more secure. It will convert a parameter to the specified type.
For example stmt.setString(1, user); will convert the user parameter to a String.
Suppose that the parameter contains a SQL string containing an executable command: using a prepared statement will not allow that.
It adds metacharacter (a.k.a. auto conversion) to that.
This makes it is more safe.
SQL injection: when user has the chance to input something that could be part of the sql statement
For example:
String query = “INSERT INTO students VALUES(‘” + user + “‘)”
when user input “Robert’); DROP TABLE students; –” as the input, it causes SQL injection
How prepared statement prevents this?
String query = “INSERT INTO students VALUES(‘” + “:name” + “‘)”
parameters.addValue(“name”, user);
=> when user input again “Robert’); DROP TABLE students; –“, the input string is precompiled on the driver as literal values and I guess it may be casted like:
CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
So at the end, the string will be literally inserted as the name to the table.
http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/
PreparedStatement:
1) Precompilation and DB-side caching of the SQL statement leads to overall faster execution and the ability to reuse the same SQL statement in batches.
2) Automatic prevention of SQL injection attacks by builtin escaping of quotes and other special characters. Note that this requires that you use any of the PreparedStatement setXxx() methods to set the value.
PreparedStatement alone does not help you if you are still concatenating Strings.
For instance, one rogue attacker can still do the following:
call a sleep function so that all your database connections will be busy, therefore making your application unavailable
extracting sensitive data from the DB
bypassing the user authentication
Not only SQL, but even JPQL or HQL can be compromised if you are not using bind parameters.
Bottom line, you should never use string concatenation when building SQL statements. Use a dedicated API for that purpose, like JPA Criteria API.
In Prepared Statements the user is forced to enter data as parameters . If user enters some vulnerable statements like DROP TABLE or SELECT * FROM USERS then data won't be affected as these would be considered as parameters of the SQL statement

Is it possible to running sql file with parameter and getting result set?

Hi dear stackoverflow users,
Firstly,i want to specify that my platforms are JAVA, ORACLE and TOAD.
I have some SELECT queries that include parameters and i have stored them in properties file to make them more readable. I can use them with '?' and setTYPE in JAVA.
But i have to use (:) operator to define parameters in TOAD. So, when i want to run my query in TOAD, i copy the query from JAVA properties file and paste it to TOAD editor and add parameters manuelly. This is not professional i think. I want to store my queries with : operator and in JAVA platform. Is this possible ? Are there any framework or something like it ?
NOTE :
1-) i want to store my queries with my JAVA code, not in stored procedure.
2-) i want to store my queries that can run that two platform without change anything.
Thank you.
You can use the OraclePreparedStatement:
String query = myProperties.getProperty("some_key");
//Suppose query is 'SELECT * FROM MY_TBL WHERE ID=:myId'
OraclePreparedStatement statement = (OraclePreparedStatement) myConnection.prepareStatement(query);
statement.setStringAtName("myId", "abc2");
someResultSet = statement.executeQuery();

Calling stored procedure

Good Night in my timezone.
I am using Sybase ase 15, and I have a stored procedure with two input parameters both VARCHAR, basically inside the stored procedure I use dynamic SQL, something like this:
#cmd = 'select * from TABLE where COL IN'+#PARAM1+'AND COL2=#PARAM2
EXEC(#cmd)
I call this procedure using JDBC like this way:
CallableStatement stmt = conn.prepareCall("{call MyStoredProcedure(?,?)}");
stmt.setString(1, "'''0'',''1'''");
stmt.setString(2, '''fr''');
stmt.executeQuery();
It throws me an error informing that the call is malformed.
But if I run the call directly in the IDE like this :
EXEC MyStoredProcedure'''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7''','''fr'''
It runs without any problem, so i guess that there is some problem with the character escaping i guess.
Anyone had experience this problem ?
With the best regards
Thanks in advance
You don't specify IN and OUT parameters:
http://docs.oracle.com/javase/tutorial/jdbc/basics/storedprocedures.html
See if following the tutorial helps.
I would also comment that you only have two parameters, but your query passes in strings that appear to be more. It's ugly, misleading, and appears to break first normal form.

Categories