JDBC setObject with String type only - java

I am working with JDBC template(SPRING) which wrraps JDBC. during runtime all my variables values (bind variables) are held as strings(with some recognition of their actual type: bigint\varchar etc.).
While I'm using setObject, I'm not sure if I need to cast the variable value to it's real type or I can send the variable as string to setObject and the database will convert it according to the column name in the database(i.e. if it is compared with BigInt then it will convert the string to big int and then query and etc.)
Thanks,

If I am understanding your question correctly then I think you CAN NOT use setObject to pass a String that will be converted to a non-String SQL type (int, bigint).
Look at this question. Below is the answer from that question.
It is not the job of setObject to determine the correct conversion to the
column type. The setObject javadoc says, "The JDBC specification
specifies a standard mapping from Java Object types to SQL types. The
given argument will be converted to the corresponding SQL type before
being sent to the database." So it is solely looking at the Java type of
the object passed to it and converting that to a SQL type. So you pass it
a String and it converts it to a varchar which is appropriate. If you
want setObject to do a conversion to a different type, that is the reason
for the additional setObject variant which takes a target sql type to
convert to, but that doesn't help your situation where you don't know what
the target type is.

Related

How to properly convert oracle data types to java types using JDBC?

I need to know data types of columns in a JDBC ResultSet.
I was able to get JDBC types, which are generated from Oracle types:
ResultSet rs = databaseMetaData.getColumns(null, "C##TMPUSER", null, null);
rs.next();
int code = rs.getInt(5);
String sqlJavaType = JDBCType.valueOf(code).getName();
which for example returns NUMERIC if the column in oracle is NUMBER.
This is the java sql Type, but I need the corresponding Java types, eg String, int, float, etc.
How I can get these data types?
Inspect the class of the object returned from ResultSet's getObject(i) method:
Class<?> javaColumnType = rs.getObject(n).getClass();
which works for all column types.
Note that if the column contains a null, the call to getClass() will throw a NullPointerException, so you may need to guard against that.

Retrieving data from associative array of custom object type from Oracle DB using CallableStatement

Summary
I am calling a stored procedure(SP) in an Oracle 12c database from a Spring-boot application. I am using CallableStatement to do this. One of the OUT parameters of the SP is an associative array with elements of a custom object type. I am having trouble retrieving the data in a proper method.
Code
TYPE trans_list IS TABLE OF T_RPT_TXN_DTLS_OBJ INDEX BY PLS_INTEGER;
TYPE T_RPT_TXN_DTLS_OBJ AS OBJECT( id VARCHAR2(20), amount NUMBER(10,2), desc VARCHAR2(100))
Connection connection = jdbcTemplate.getDataSource().getConnection();
OracleCallableStatement callableStatement = connection.prepareCall("{call SAMPLE_PROC(?,?)}").unwrap(OracleCallableStatement.class);
callableStatement.setString(1, ID);
--Here I don't know what to do--
callableStatement.registerIndexTableOutParameter(2, 500, OracleTypes.OTHER, 0);
--------------------------------
Things I have tried
I looked through different websites using google. Went through stackoverflow as well. The above code is where I am stuck at. Since the 3rd argument is the datatype of the array elements, I put in OracleTypes.OTHER but that throws an SQLException: invalid column type 1111.
I read in the official docs that for custom object types, we can map them to Java objects. I have no idea how to do that either. Please refer to User_defined types in https://docs.oracle.com/cd/B19306_01/java.102/b14355/datacc.htm#BHCGCBJC
What I am asking in brief
Any sample code, detailed docmentation, links to online examples that fits my case. I specifically need to know arg[2] of the out parameter registration, and how I might go about mapping to a custom Java object from the callableStatement (perhaps using .getObject(int) but I don't know about the mapping).
See this answer.
You cannot.
You need to define the data type in the SQL scope (using CREATE TYPE) rather than in the PL/SQL scope, in a package as JDBC can only work with SQL defined data types.
A consequence of point 1 is that JDBC does not support associative arrays, as they are a PL/SQL only data type, and you need to use collections (unlike C#, which only supports associative arrays and does not support collections). So you need to remove the INDEX BY clause from the type.
You need to be able to map from the type in the array to a Java data structure; one way of doing this is to use the SQLData interface. An example is in this answer.
Define:
callableStatement.registerOutParameter(2, OracleTypes.ARRAY,"trans_list");
Call proc:
callableStatement.executeUpdate();
Then get out parameter as
java.sql.Array array = callableStatement.getArray(2);
Object outputParamValue = array.getArray();
Type Caste outputParamValue if needed.

Should I just disable UInteger type on JOOQ?

I've been trying to write some queries (for MySQL) and I'm not sure how to write this particular one that involves Integer and UInteger types:
DSL.position(T1.FIELD, ":", -1).eq(T2.UINTFIELD)
position returns a Field<Integer>, so I can't simply compare this result to my Field<UInteger>. Is there a simple way to achieve it? I'd like to keep the correct field types for further validation.
You can use DSL.cast() or DSL.coerce() for this. I recommend coerce.
DSL.cast() produces a SQL cast expression and a jOOQ field reference of the desired type
DSL.coerce() does not affect the generated SQL but still produces a jOOQ filed reference of the desired type.
For example:
position(T1.FIELD, ":", -1).eq(coerce(T2.UINTFIELD, SQLDataType.INTEGER))

java.io.NotSerializableException: org.json.JSONObject

JDBCTemplate and MYSQL JSON
I am writing a rest service where i need to add few details at mysql table.
My mysql table as a column area_json as type json.
I got a pojo object from post call in rest service and i tried to insert it using jdbctemplate like
jdbcTemplate.update("insert into site(area_id,area_json) values(?,?)", area.getareaID(), area.getareaJson());
Once I do a post call using post man i get the below error
Invalid argument value: java.io.NotSerializableException;
nested exception is java.sql.SQLException: Invalid argument value: java.io.NotSerializableException"
Please help
In the first place, be sure to use a version of Connector/J no older than v5.1.37, where support for the JSON datatype was added, and preferrably no older than v5.1.40, which fixed some JSON-related bugs. But if that's an issue for you, then it is at best secondary.
Before that even matters, JdbcTemplate needs to understand your JSONObject argument. The particular method you are using documents that the variable arguments, including your JSONObject are
arguments to bind to the query (leaving it to the PreparedStatement to
guess the corresponding SQL type); may also contain SqlParameterValue
objects which indicate not only the argument value but also the SQL
type and optionally the scale
When it says the PreparedStatement will guess, it can only mean the two-arg version of PreparedStatement.setObject() which documents:
The JDBC specification specifies a standard mapping from Java Object
types to SQL types. The given argument will be converted to the
corresponding SQL type before being sent to the database.
Note that this method may be used to pass datatabase- specific
abstract data types, by using a driver-specific Java type. If the
object is of a class implementing the interface SQLData, the JDBC
driver should call the method SQLData.writeSQL to write it to the SQL
data stream. If, on the other hand, the object is of a class
implementing Ref, Blob, Clob, NClob, Struct, java.net.URL, RowId,
SQLXML or Array, the driver should pass it to the database as a value
of the corresponding SQL type.
(Emphasis added.)
JDBC does not have built-in support for a JSON datatype. The docs do allow for Connector/J to provide a driver-specific type corresponding to the JSON SQL datatype, but just because MySQL and Connector/J support JSON does not mean you can pull a random JSON-representing object off the shelf and present it to them, nor indeed that they provide or accommodate a JSON-specific Java datatype at all. Inasmuch as MySQL seems not to publish or reference any documentation of JDBC extension APIs in its Connector/J developer guide, I'm inclined to doubt that it recognizes any such type.
It seems, then, that you should rely on the same technique that you would do when programming directly in MySQL's SQL dialect:
In MySQL, JSON values are written as strings. MySQL parses any string
used in a context that requires a JSON value, and produces an error if
it is not valid as JSON. These contexts include inserting a value into
a column that has the JSON data type and passing an argument to a
function that expects a JSON value [...].
(MySQL 5.7 Reference Manual, section 11.6)
That is, convert your JSONObject to a JSON-format String, and present it to your template that way. On retrieval, expect to have to do the reverse.

Convert java.util.List<String> into java.sql.Array

How would you convert a java.util.List<String> instance into a java.sql.Array?
Use connection.createArrayOf(...)
For example:
final String[] data = yourList.toArray(new String[yourList.size()]);
final java.sql.Array sqlArray = connection.createArrayOf(typeName, data);
statement.setArray(position, sqlArray);
Where typeName is:
the SQL name of the type the elements of the array map to. The typeName is a database-specific name which may be the name of a built-in type, a user-defined type or a standard SQL type supported by this database. This is the value returned by Array.getBaseTypeName
As noted in the comments, this is Java 1.6. For older versions you can't create this in a driver-independent way. You are only supposed to get arrays, not create them. If you want to, you can instantiate the implementing class from your jdbc driver, but this is non-portable.
The type argument to createArrayOf is the element type, not the array type, so you probably want something like "varchar" or "text". VARIADIC is a function argument modifier, not a type specifier.

Categories

Resources