I confronted with the fact that this parameter substitution construction (: 1) works with the Oracle driver:

try { Class.forName("oracle.jdbc.driver.OracleDriver"); try (Connection con = DriverManager.getConnection("HOST", "USER", "PASS")) { try (PreparedStatement preparedStatement = con.prepareStatement("select * from TABLE where name = :1")) { preparedStatement.setString(1, "NAME"); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { System.out.println(resultSet.getObject(1)); } } } } } catch (Exception e) { e.printStackTrace(); } 

The JSR specifies the use of the? Sign.
Is this a driver implementation feature?

UPD:

DB Version:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production PL / SQL Release 12.1.0.2.0 - Production

What else is noticed:

  try (PreparedStatement preparedStatement = con.prepareStatement("select * from TABLE where name = :abc and id = :dcf")) { preparedStatement.setString(1, "PARAM"); preparedStatement.setInt(2, 173); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { System.out.println(resultSet.getObject(1)); } } } 

Please pay attention to the name of substitutions, this code works.
But this one no longer works:

  try (PreparedStatement preparedStatement = con.prepareStatement("select * from TABLE where name = :abc and id = :dcf")) { preparedStatement.setString(2, "NAME"); preparedStatement.setInt(1, 173); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { System.out.println(resultSet.getObject(1)); } } } java.sql.SQLSyntaxErrorException: ORA-01722: неверное число 

That is, there is no reaction to the name at all, only on the ":" order.

  • I reworked the answer. See if he answers your question. - 0xdb
  • Exhaustive answer, thank you very much) - ezhov_da

1 answer 1

The JSR specifies the use of the? Sign.

Character ? this is not a wildcard parameter, it is only a placeholder, all the characters of the placeholders, the prepareStatement() function will be replaced by substitution variables (or bind variables ) using the syntax for the wildcard variables of the target DBMS.

If you specify the wildcard parameters in the SQL expression immediately in the form in which the target DBMS is prepared and compiled ( parse ), then the prepareStatement() function prepareStatement() not make any replacement and will not notice that it has been “deprived of work”.

Is this a driver implementation feature?

Yes, or better to say, this is a feature of the target DBMS that this driver supports. Regarding substitution variables, different DBMSs have different syntax for these variables:

  • Oracle:: :var ( colon )

  • MySQL, DB2 and Firebird ? ( question marks )

  • Sybase, MS SQL Server: @var ( at sign )

  • PostgreSQL: $var ( dollar sign )

To confirm the above, consider the following example.

Perform the same query several times with different use of placeholders and wildcard parameters:

 create or replace and compile java source named TestPrepared as import java.sql.*; public class TestPrepared { public static void selectValue (int id, String item) { String[] stmts = { /*#1*/"/* ? */ select id, item from items where id = ? and item = ?", /*#2*/"/* ? */ select id, item from items where id = :1 and item = :2", /*#3*/"/* ? */ select id, item from items where id = :2 and item = :3", /*#4*/"/* ? */ select id, item from items where id = :id and item = :item"}; try { Connection con = DriverManager.getConnection("jdbc:oracle:thin:@dbsrv:1521/pdb1","sh","sh"); for (int i=0; i<stmts.length; i++) { PreparedStatement ps = con.prepareStatement(stmts[i]); ps.setInt (1, id); ps.setString (2, item); ResultSet resultSet = ps.executeQuery(); while (resultSet.next()) { System.out.println("id=" + resultSet.getObject(1) + ",item=" + resultSet.getObject(2)); } } } catch (Exception e) { e.printStackTrace(); } } } / create or replace procedure selectValue (id number, item varchar2) as language java name 'TestPrepared.selectValue (int, java.lang.String)'; / exec selectValue (2, 'item2') id=2,item=item2 id=2,item=item2 id=2,item=item2 id=2,item=item2 

Which SQL expressions were sent to the database server:

 select sql_id, parse_calls parses, substr (sql_text,1,78) text from v$sql where parsing_schema_name = user and sql_text like '/*%' ; SQL_ID PARSES TEXT ------------- ------ ------------------------------------------------------------------- dvc53b7ugwu0q 1 /* :1 */ select id, item from items where id = :1 and item = :2 8zbzysz5m53wf 2 /* :1 */ select id, item from items where id = :2 and item = :3 872ztnzx59hm8 1 /* :1 */ select id, item from items where id = :id and item = :item 

In the original SQL expression # 1, the prepareStatement() function replaced the placeholders ? into substitution variables :1, :2, :3 . In # 3, the replacement did not happen (not counting in the comments). Both SQL expressions, # 1 and # 3, completely matched and are considered by the DB as one, prepared and compiled ( parses=2 ) SQL expression.

That is, there is no reaction to the name at all, only on the ":" order.

Yes, in the JDBC standard, only order is important ( bind by index ). In the code of the question to which this quotation relates, the order is broken, which led to an error. In the example examined above, the replacement was made taking into account only the order (ie, by the index), which names / numbers stood after the symbol : did not play any role.

If the substitution by name is interesting ( bind by name ), then as mentioned in of. documentation ch. Binding by name

It doesn’t support it.

Oracle does not support substitution by name when using the method, as in the question setString() . That is, it is not supported in the standard PreparedStatement JDBC interface.

But you can use, for example, an extension to this interface OraclePreparedStatement :

 create or replace and compile java source named TestPreparedOra as import java.sql.*; import oracle.jdbc.*; public class TestPreparedOra { public static void selectValue (int id, String item) { try { Connection con = DriverManager.getConnection("jdbc:default:connection"); OraclePreparedStatement ps = (OraclePreparedStatement) con.prepareStatement ( "select id, item from items where item = :item and id = :id"); ps.setStringAtName("item", item); ps.setIntAtName( "id", id); ResultSet resultSet = ps.executeQuery(); while (resultSet.next()) { System.out.println("id=" + resultSet.getObject(1) + ",item=" + resultSet.getObject(2)); } } catch (Exception e) { e.printStackTrace(); } } } / create or replace procedure selectValueOraEx (id number, item varchar2) as language java name 'TestPreparedOra.selectValue (int, java.lang.String)'; / exec selectValueOraEx (2, 'item2') PL/SQL procedure successfully completed. id=2,item=item2 
  • In the dock of your link is a useful reference to the ability to explicitly use the setXXXAtName methods: "Starting from Oracle Database 10g JDBC drivers, bind by name is supported using the setXXXAtName methods." - maybe worth adding to the answer? - MaxU
  • one
    By the way, I can’t find descriptions of the numbered parameters (as the author of the question :1 ,: :2 ) for JAVA - it looks like this is really a feature of the Oracle driver implementation ... - MaxU
  • @MaxU Yes, there was also a thought, but a question like "why is that?" And not "how to?". - 0xdb
  • 2
    @ Mach As I understand it, these are not numbered parameters, these are binds , i.e. they will be searched by names - setStringAtName("1", "value") . And the old drivers fool them in order. - 0xdb
  • one
    This explains why I could not find anything :) - MaxU