Java executed statement not returning string data in resultset - sql

I have a simple SQL code that returns one record but when I execute it from Java, it does not return the string portions of the record, only numerical. The fields are VARCHAR2 but do not get extracted into my resultset. Following is the code. The database connectivity portion has been edited out for posting in the forum but it does connect. I have also attached the output. Any guidance would be appreciated as my searches on the web have returned empty. -Greg
package testsql;
import java.sql.*;
public class TestSQL {
String SQLtracknbr;
int SQLtracklength;
int numberOfColumns;
String coltypename;
int coldispsize;
String SQLschemaname;
public static void main(String[] args)
throws ClassNotFoundException, SQLException
{
Class.forName("oracle.jdbc.driver.OracleDriver");
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
String url = "jdbc:oracle:thin:#oracam.corp.mot.com:1522:oracam";
String SQLcode = "select DISTINCT tracking_number from sfc_unit_process_track where tracking_number = 'CAH15F6WW9'";
System.out.println(SQLcode);
Connection conn =
DriverManager.getConnection(url,"report","report");
conn.setAutoCommit(false);
try (Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery(SQLcode)) {
ResultSetMetaData rsmd = rset.getMetaData();
while (rset.next()) {
int numberOfColumns = rsmd.getColumnCount();
boolean b = rsmd.isSearchable(1);
String coltypename = rsmd.getColumnTypeName(1);
int coldispsize = rsmd.getColumnDisplaySize(1);
String SQLschemaname = rsmd.getSchemaName(1);
String SQLtracknbr = rset.getString(1);
int SQLtracklength = SQLtracknbr.length();
if (SQLtracknbr == null)
System.out.println("NULL**********************.");
else
System.out.println("NOT NULL.");
System.out.println("numberOfColumns = " + numberOfColumns);
System.out.println("column type = " + coltypename);
System.out.println("column display size = " + coldispsize);
System.out.println("tracking_number = " + SQLtracknbr);
System.out.println("track number length = " + SQLtracklength);
System.out.println("schema name = " + SQLschemaname);
}
}
System.out.println ("*******End of code*******");
}
}
The result of what is executed in Java is below:
run:
select DISTINCT tracking_number from sfc_unit_process_track where tracking_number = 'CAH15F6WW9'
NOT NULL.
numberOfColumns = 1
column type = VARCHAR2
column display size = 30
tracking_number =
track number length = 0
schema name =
*******End of code*******
BUILD SUCCESSFUL (total time: 0 seconds)

This seems to be caused by an incompatibility between the driver you're using, ojdbc7.jar, and the version of the database you're connecting to, 9i.
According to the JDBC FAQ section "What are the various supported Oracle database version vs JDBC compliant versions vs JDK version supported?", the JDK 7/8 driver ojdbc7.jar that you're using is only support for Oracle 12c.
Oracle generally only support client/server versions two release apart (see My Oracle Support note 207303.1), and the Oracle 12c and 9i client and server have never been supported either way around. JDBC is slightly different of course, but it may be related, as drivers are installed with the Oracle software.
You will have to upgrade your database to a supported version, or - perhaps more practically in the short term - use an earlier driver. The Wayback Machine snapshot of the JDBC FAQ from 2013 says the 11.2.0 JDBC drivers - which includes ojdbc6.jar and ojcbd5.jar - can talk to RDBMS 9.2.0. So either of those ought to work...

Related

How to set large string as param without getting ORA-01460: unimplemented or unreasonable conversion error?

In spring-boot using namedParameterJdbcTemplate (Oracle db version 12 and odbc8 driver 12.2)
I am getting the following error while executing a SELECT query bound with a parameter larger than 4000 character whereas update queries working fine.
ORA-01460: unimplemented or unreasonable conversion requested
The unit test I am trying to execute;
#Test
public void testSqlSelectQueryLargeStringParameter() {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("param", theLargeStr);
// #formatter:off
String sql =
"SELECT NULL id, NULL text FROM DUAL WHERE 'X' != :param ";
// #formatter:on
namedParameterJdbcTemplate.queryForRowSet(sql, params);
}
Is there any way to set this large param via MapSqlParameterSource?
I am #ahmet-orhan 's colleague, we've found a solution.
Thanks #kfinity for your suggestion, It is working for insert and update but we are still getting this error when we set clob or blob as "paremeter" in select statements.
If using a driver that supports JDBC4.0, the right solution is create a DefaultLobHandler and set streamAsLob or createTemporaryLob to true.
MapSqlParameterSource params = new MapSqlParameterSource();
String myString = "";
for (int i = 0; i < MAX_CLOB_BLOB_SIZE_IN_SELECT; i++) {
myString = myString + "1";
}
DefaultLobHandler lobHandler = new DefaultLobHandler();
lobHandler.setStreamAsLob(true);
params.addValue("param", new SqlLobValue(myString, lobHandler), Types.CLOB);
// #formatter:off
String sql =
"SELECT 1 id FROM DUAL WHERE :param IS NOT NULL ";
// #formatter:on
Integer id = namedParameterJdbcTemplate.queryForObject(sql, params, Integer.class);
We prefer streamAsLob but to be honest we have no idea which one is better.
This comment points out that ORA-01460 in JDBC queries is the same as "ORA-01704: string literal too long". (You can't have string literals longer than 4000 characters.) Maybe try this solution?
params.addValue("param", theLargeStr, Types.CLOB);
Although also != won't work for clob comparison, so you'll also need to change your query to
SELECT NULL id, NULL text FROM DUAL WHERE dbms_lob.compare('X',:param) != 0

Why do SQL joins fail in Oracle?

I just try simple joins with C# using oracle db. Should be no big deal. But it ALWAYS fails. It works in MS-Access. Where is the problem ? (OleDb or Odbc makes no difference here, I tried both)
Edit:
Might Oracle version be the problem ? (seems we are using 8.1.7.0.0 and 8.1.5.0.0 modules)
Code:
using System;
using System.Data.Odbc;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string n = Environment.NewLine + "--------------------------------" + Environment.NewLine + Environment.NewLine;
// connect
string connectionString = "dsn=TEST;uid=read;pwd=myPwd";
OdbcConnection connection = new OdbcConnection(connectionString);
connection.Open();
// select (key is actually text not numeral)
string query = "select * from INFOR.ZEITEN where (KEY = 0)";
query = "select a.KEY, b.GREG from INFOR.ZEITEN a inner join INFOR.ZEITEN b on (a.AUSWEIS = b.AUSWEIS) where (a.KEY like '1')";
try
{
query = query.Replace(Environment.NewLine, " ");
Console.WriteLine(n + query);
OdbcCommand command = new OdbcCommand(query, connection);
OdbcDataReader reader = command.ExecuteReader(); // throws exception
if (reader != null)
Console.WriteLine(n + "success, now read with reader!");
}
catch (Exception e)
{
Console.WriteLine(n + e.Message + n + e.StackTrace);
}
// wait
Console.ReadKey();
}
}
}
Output:
And the successful, simple select:
ANSI joins (ex. inner join) were first supported in 9i. You will need to use the old syntax:
select a.KEY, b.GREG
from INFOR.ZEITEN a,
INFOR.ZEITEN b
where (a.AUSWEIS = b.AUSWEIS)
and (a.KEY like '1')
Note that the like operator is equivalent to = in this case, but you probably know that
I think the KEY is numeric then you can't use LIKE. It is because the WHERE KEY = 0 works fine.
The word key is a reserved word. That means that it is a very poor choice for an identity. You need to escape it with a double quote. This might work:
query = "select a.\"KEY\", b.GREG
from INFOR.ZEITEN a inner join
INFOR.ZEITEN b
on (a.AUSWEIS = b.AUSWEIS)
where (a.\"KEY\" like '1')";
I am guessing the \" will work in this context, but there might be another method to insert this character.
What's the error? Could you edit your question and add the actual error the system's throwing at you?
Firstly, I would personally recommend using the ODP .NET (Oracle Data provider for .NET). You can download the latest version for Oracle 12c here. Or look it up for the version you need.
ODBC is a very old driver written in C and works using the native Windows RPC technique.
For full .NET support you're better off with ODP .NET.
Secondly, check if you have any constraints on the tables that's causing the sql to fail.

ResultSet coming as empty after executing query

I have a query
SELECT instance_guid FROM service_instances WHERE service_template_guid='E578F99360A86E4EE043C28DE50A1D84' AND service_family_name='TEST'
Directly executing this returns me
4FEFDE7671A760A8DC8FC63CFBFC8316
F2F9DF641D8E2CACC03175A7A628D51D
Now I am trying same code from JDBC.
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = executionContext.getConnection();
if (conn != null) {
ps = (PreparedStatement)conn.prepareStatement(query);
if (params == null) params = new Object[0];
for (int i=0;i<params.length;i++) {
if (params[i] instanceof Integer) {
ps.setInt(i+1, ((Integer)params[i]).intValue());
} else if (params[i] instanceof java.util.Date) {
((PreparedStatement)ps).setDATE(i+1, new oracle.sql.DATE((new java.sql.Timestamp(((Date)params[i]).getTime()))));
//ps.setObject(i+1, new oracle.sql.DATE(new Time(((Date)params[i]).getTime())));
} else {
if (params[i] == null) params[i] = "";
ps.setString(i+1, params[i].toString());
}
}
rs = ps.executeQuery();
I see params[0] =E578F99360A86E4EE043C28DE50A1D84 and params[1]=TEST
But the resultSet is empty and not getting the result.I debugged but not much help?
Can you please let me know Am i trying right?
In java its defined as below
final static private String INSTANCE_GUID_BY_TEMPLATE_GUID =
"SELECT instance_guid FROM service_instances WHERE service_template_guid=? AND service_family_name=? "
SERVICE_FAMILY_NAME NOT NULL VARCHAR2(256)
SERVICE_TEMPLATE_GUID NOT NULL RAW(16 BYTE)
First and foremost this breaks every sql mapping pattern I have ever seen.
String sql = "SELECT instance_guid FROM service_instances WHERE service_template_guid=? AND service_family_name=?";
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = executionContext.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1,guid);
ps.setString(2,family);
rs = ps.executeQuery();
while(rs.next(){...}
...
}
You should not be dynamically figuring out the data types as they come in, unless you are trying to write some code to port from database X to database Y.
UPDATE
I see you are using RAW as a datatype, from this post:
As described in the Oracle JDBC Developer's guide and reference 11g,
when using a RAW column, you can treat it as a BINARY or VARBINARY
JDBC type, which means you can use the JDBC standard methods
getBytes() and setBytes() which returns or accepts a byte[]. The other
options is to use the Oracle driver specific extensions getRAW() and
setRAW() which return or accept a oracle.sql.RAW. Using these two will
require you to unwrap and/or cast to the specific Oracle
implementation class.
Further from a code readability standpoint, your solution makes it painful for a new developer to take over. Far too often I see people making sql be "dynamic" when in reality 99% of the time you don't need this level of dynamic query building. It sounds good in most people's heads but it just causes pain and suffering in the SDLC.

How to get database version through Hibernate?

Is there a way to get some information of the underlying database version through the Hibernate 3.2 API? I failed to find relevant bits both here and the javadoc.
Getting the version of your database engine is implementation specific. This means that there's no shared method for getting the version and so Hibernate cannot really provide an API since it is not bound to any particular RDBMS. For example, here are some different ways you get the version with SELECT statements from some well-known RDBMSs:
Oracle: SELECT * FROM v$version;
SQL Server: SELECT ##version
MySQL: SELECT VERSION()
...
You could create a view that reports the version and then add that to your ORM which would then be accessible as any other Hibernate object.
public static void testConnection() {
Session session = null;
try {
session = getSessionFactory().openSession();
session.doWork(connection -> {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT VERSION()");
resultSet.next();
System.out.println("DB test: " + resultSet.getString(1));
});
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
}
An easier approach than the accepted answer is to use the java.sql.DatabaseMetaData class:
try (Session session = sessionFactory.openSession()) {
session.doWork(connection -> {
DatabaseMetaData metaData = connection.getMetaData();
System.out.println("Product version: " + metaData.getDatabaseProductVersion());
System.out.println("Major version: " + metaData.getDatabaseMajorVersion());
System.out.println("Minor version: " + metaData.getDatabaseMinorVersion());
});
}
For my MySQL 5.5 instance, this outputs:
Product version: 5.5.62-log
Major version: 5
Minor version: 5
The Product version is identical to the value returned by SELECT VERSION();
Possible with some unwraps:
Session hibSession = ... // session is taken from wherever is possible
String dbVersion = hibSession.unwrap(SharedSessionContractImplementor.class)
.getJdbcCoordinator()
.getLogicalConnection()
.getPhysicalConnection()
.getMetadata()
.getDatabaseProductVersion();
There are also separate methods for major/minor versions available, as well as JDBC protocol version, DB vendor name etc.

Is it possible to run native sql with entity framework?

I am trying to search an XML field within a table, This is not supported with EF.
Without using pure Ado.net is possible to have native SQL support with EF?
For .NET Framework version 4 and above: use ObjectContext.ExecuteStoreCommand() if your query returns no results, and use ObjectContext.ExecuteStoreQuery if your query returns results.
For previous .NET Framework versions, here's a sample illustrating what to do. Replace ExecuteNonQuery() as needed if your query returns results.
static void ExecuteSql(ObjectContext c, string sql)
{
var entityConnection = (System.Data.EntityClient.EntityConnection)c.Connection;
DbConnection conn = entityConnection.StoreConnection;
ConnectionState initialState = conn.State;
try
{
if (initialState != ConnectionState.Open)
conn.Open(); // open connection if not already open
using (DbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
}
finally
{
if (initialState != ConnectionState.Open)
conn.Close(); // only close connection if not initially open
}
}
Using Entity Framework 5.0 you can use ExecuteSqlCommand to execute multi-line/multi-command pure SQL statements. This way you won't need to provide any backing object to store the returned value since the method returns an int (the result returned by the database after executing the command).
Sample:
context.Database.ExecuteSqlCommand(#
"-- Script Date: 10/1/2012 3:34 PM - Generated by ExportSqlCe version 3.5.2.18
SET IDENTITY_INSERT [Students] ON;
INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (12,N'First Name',N'SecondName',{ts '1988-03-02 00:00:00.000'},N'RUA 19 A, 60',N'MORADA DO VALE',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3346-7125',NULL,NULL,{ts '2011-06-04 21:25:26.000'},2,1);
INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (13,N'FirstName',N'LastName',{ts '1976-04-12 00:00:00.000'},N'RUA 201, 2231',N'RECANTO FELIZ',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3341-6892',NULL,NULL,{ts '2011-06-04 21:38:38.000'},2,1);
");
For more on this, take a look here: Entity Framework Code First: Executing SQL files on database creation
For Entity Framework 5 use context.Database.SqlQuery.
And for Entity Framework 4 use context.ExecuteStoreQuery
the following code:
public string BuyerSequenceNumberMax(int buyerId)
{
string sequenceMaxQuery = "SELECT TOP(1) btitosal.BuyerSequenceNumber FROM BuyerTakenItemToSale btitosal " +
"WHERE btitosal.BuyerID = " + buyerId +
"ORDER BY CONVERT(INT,SUBSTRING(btitosal.BuyerSequenceNumber,7, LEN(btitosal.BuyerSequenceNumber))) DESC";
var sequenceQueryResult = context.Database.SqlQuery<string>(sequenceMaxQuery).FirstOrDefault();
string buyerSequenceNumber = string.Empty;
if (sequenceQueryResult != null)
{
buyerSequenceNumber = sequenceQueryResult.ToString();
}
return buyerSequenceNumber;
}
To return a List use the following code:
public List<PanelSerialList> PanelSerialByLocationAndStock(string locationCode, byte storeLocation, string itemCategory, string itemCapacity, byte agreementType, string packageCode)
{
string panelSerialByLocationAndStockQuery = "SELECT isws.ItemSerialNo, im.ItemModel " +
"FROM Inv_ItemMaster im " +
"INNER JOIN " +
"Inv_ItemStockWithSerialNoByLocation isws " +
" ON im.ItemCode = isws.ItemCode " +
" WHERE isws.LocationCode = '" + locationCode + "' AND " +
" isws.StoreLocation = " + storeLocation + " AND " +
" isws.IsAvailableInStore = 1 AND " +
" im.ItemCapacity = '" + itemCapacity + "' AND " +
" isws.ItemSerialNo NOT IN ( " +
" Select sp.PanelSerialNo From Special_SpecialPackagePriceForResale sp " +
" Where sp.PackageCode = '" + packageCode + "' )";
return context.Database.SqlQuery<PanelSerialList>(panelSerialByLocationAndStockQuery).ToList();
}
Keep it simple
using (var context = new MyDBEntities())
{
var m = context.ExecuteStoreQuery<MyDataObject>("Select * from Person", string.Empty);
//Do anything you wonna do with
MessageBox.Show(m.Count().ToString());
}
public class RaptorRepository<T>
where T : class
{
public RaptorRepository()
: this(new RaptorCoreEntities())
{
}
public RaptorRepository(ObjectContext repositoryContext)
{
_repositoryContext = repositoryContext ?? new RaptorCoreEntities();
_objectSet = repositoryContext.CreateObjectSet<T>();
}
private ObjectContext _repositoryContext;
private ObjectSet<T> _objectSet;
public ObjectSet<T> ObjectSet
{
get
{
return _objectSet;
}
}
public void DeleteAll()
{
_repositoryContext
.ExecuteStoreCommand("DELETE " + _objectSet.EntitySet.ElementType.Name);
}
}
So what do we say about all this in 2017? 80k consultations suggests that running a SQL request in EF is something a lot of folk want to do. But why? For what benefit?
Justin, a guru with 20 times my reputation, in the accepted answer gives us a static method that looks line for line like the equivalent ADO code. Be sure to copy it well because there are a few subtleties to not get wrong. And you're obliged to concatenate your query with your runtime parameters since there's no provision for proper parameters. So all users of this method will be constructing their SQL with string methods (fragile, untestable, sql injection), and none of them will be unit testing.
The other answers have the same faults, only moreso. SQL buried in double quotes. SQL injection opportunities liberally scattered around. Esteemed peers, this is absolutely savage behaviour. If this was C# being generated, there would be a flame war. We don't even accept generating HTML this way, but somehow its OK for SQL. I know that query parameters were not the subject of the question, but we copy and reuse what we see, and the answers here are both models and testaments to what folk are doing.
Has EF melted our brains? EF doesn't want you to use SQL, so why use EF to do SQL.
Wanting to use SQL to talk to a relational DB is a healthy, normal impulse in adults. QueryFirst shows how this could be done intelligently, your sql in .sql file, validated as you type, with intellisense for tables and columns. The C# wrapper is generated by the tool, so your queries become discoverable in code, with intellisense for your inputs and results. End to end strong typing, without ever having to worry about a type. No need to ever remember a column name, or its index. And there are numerous other benefits... The temptation to concatenate is removed. The possibility of mishandling your connections also. All your queries and the code that accesses them are continuously integration-tested against your dev DB. Schema changes in your DB pop up as compile errors in your app. We even generate a self test method in the wrapper, so you can test new versions of your app against existing production databases, rather than waiting for the phone to ring. Anyone still need convincing?
Disclaimer: I wrote QueryFirst :-)