How to call a table function in jpa - java

I have been trying to call a function that i created using jpa but i keep getting this error
(org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: 'udf_searchEmployeeLeaves' is not a recognized built-in function name.
Error Code: 195)
public List<EmployeeLeaves> searchEmployeeLeaves(String str) throws EmployeeLeavesException {
try {
Query query = em.createNativeQuery("SELECT udf_searchEmployeeLeaves(?1) FROM LAB ");
query.setParameter(1, str);
return query.getResultList();
} catch (Exception e) {
throw new EmployeeLeavesException("[searchEmployeeLeaves-ERROR]: " + e.getMessage());
}
}

I think the call is incorrect.
You have to call the table function like this:
Query query = em.createNativeQuery("SELECT * FROM udf_searchEmployeeLeaves(?1)");

Related

Parameterize Java JPA ALTER SESSION SQL

I am having a problem with setting a parameter in an SQL Query statement created from a JPA EntityManager.
I am working in an EJB and the EntityManager object for the session is valid.
import javax.persistence.EntityManager;
import javax.persistence.Query;
pubic void methodWorks(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = " + schema;
try {
em.createNativeQuery(sqlStmt).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
pubic void methodFails1(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = ?";
try {
em.createNativeQuery(sqlStmt).setParameter(1, schema).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
pubic void methodFails2(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = ?1";
try {
em.createNativeQuery(sqlStmt).setParameter(1, schema).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
pubic void methodFails3(EntityManager em, String schema) {
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = :inputSchema";
try {
em.createNativeQuery(sqlStmt).setParameter("inputSchema", schema).executeUpdate();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
The problem is that a Fortify Scan (which this must pass) identifies the sqlStmt in the methodWorks method as being vulnerable to an SQL Injection Attack (from Fortify). The failed methods all report
Internal Exception java.sql.SQLSyntaxErrorException: ORA:-02421 mission or invalid schema authorization identifier.
Error Code 2421
Call: ALTER SESSION SET CURRENT_SCHEMA = ?
bind => [1 parameter bound]
Merely sanitizing the input parameter "isn't good enough" to pass the Fortify and QA.
Setting it as a parameter (which hint-hint: CAN be easily fooled) will pass the Fortify scan and QA requirements.
This query is indeed open to SQL injection because you're using string concatenation.
The safe way to handle a query like this is to use parameters.
String sqlStmt = "ALTER SESSION SET CURRENT_SCHEMA = ?";
Query updateQuery = em.createNativeQuery(sqlStmt);
updateQuery.setParameter(0, schema);
updateQuery.executeUpdate();
Parameter values are automatically escaped for you. This saves you time as you don't need to worry about SQL injection any longer. This is solved in the Query/EntityManager class.
Also, it makes the query a lot easier to read.

Error while querying for a column in database using spring

I am trying to query an entire column data for eg:
SELECT USER_USERNAME FROM xxxx WHERE USER_USERNAME=?
I'm getting error
org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
My Dao
#Override
public String getAllUsers(UserRegistration uname) {
System.out.println(uname.getUserName());
return template.queryForObject(GET_USER_USERNAME, new Object[] { uname.getUserName() },
new BeanPropertyRowMapper<String>(String.class));
}
I'm injecting the properties through xml file.
my controller
#RequestMapping(method = RequestMethod.POST,value = "/checkUserName", headers = "Accept=application/json")
public org.weber.nag.model.UserRegistration checkUserName(#RequestBody org.weber.nag.model.UserRegistration userReg) {
userDao.getAllUsers(userReg);
return userReg;
}
So from the above when i am trying to pass the username from postman it takes the values to controller and from there I'm passing it to my dao to compare whether the name exits or not.The name successfully reaches my dao but I get an error.
So I tried to catch the exception
#Override
public String getAllUsers(UserRegistration uname) {
System.out.println(uname.getUserName());
try {
return template.queryForObject(GET_USER_USERNAME, new Object[] { uname.getUserName() },
new BeanPropertyRowMapper<String>(String.class));
} catch (EmptyResultDataAccessException e) {
System.out.println("uname already exists");
return "user exists";
}
}
But every time it prints
"uname already exists"
irrespective of the username given whether it is there in db or not.
In JdbcTemplate , queryForInt, queryForLong, queryForObject all such methods expects that executed query will return one and only one row.
If you get no rows that will result in EmptyResultDataAccessException.
From the javadoc of EmptyResultDataAccessException
Data access exception thrown when a result was expected to have at
least one row (or element) but zero rows (or elements) were actually
returned.
Make sure the query you are using should return only one row.
If at all it is not possible then use query method instead of queryForObject.
Tip: To debug this, run the same query in an SQL IDE directly.
#Override
public String getAllUsers(UserRegistration uname) {
try {
template.queryForObject(GET_USER_USERNAME, new Object[] { uname.getUserName() },
new BeanPropertyRowMapper<String>(String.class));
System.out.println("uname exists");
return "user name is NOT available.";
} catch (EmptyResultDataAccessException e) {
System.out.println("uname do not exists");
}
return "user is available";
}

Removing/deleting from google datastore using endpoints, illegal arguement exception, delete with non-zero content length not supported

I'm trying to delete objects from the datastore (using cloud endpoints)
I know the connection is valid because I'm pulling/inserting objects with no problem
However when I try to delete using various approaches I get the same exception
java.lang.illegalArgumentException:DELETE with non-zero content length is not supported
approach 1(using the raw datastore service and the key I stored when inserting the item):
#ApiMethod(name = "removeRPurchase")
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
DatastoreService d=DatastoreServiceFactory.getDatastoreService();
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
try {
d.delete(k);
} catch (Exception e) {
e.printStackTrace();
purchase=null;
}
return purchase;
}
Approach 2
#ApiMethod(name = "removeRPurchase")
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
EntityManager mgr = getEntityManager();
RPurchase removed=null;
try {
RPurchase rpurchase = mgr.find(RPurchase.class, k);
mgr.remove(rpurchase);
removed=rpurchase;
} finally {
mgr.close();
}
return removed;
}
Ive also tried various variations with the entity manager and the Id, but all with the same exception
The object that i've passed in does contain the namespace in the account, and it does contain the 'KeytoString' of the key associated with the object
the endpoint is called as it should in an AsyncTask endpoint.removeRPurchase(p).execute();
Any help suggestions are appreciated
Make your API method a POST method like this:
#ApiMethod(name = "removeRPurchase" path = "remove_r_purchase", httpMethod = ApiMethod.HttpMethod.POST)
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
DatastoreService d=DatastoreServiceFactory.getDatastoreService();
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
try {
d.delete(k);
} catch (Exception e) {
e.printStackTrace();
purchase=null;
}
return purchase;
}
I had the same problem because I was using httpMethod = ApiMethod.HttpMethod.DELETE. The error it gives is correct. Simply change it to a POST and do whatever you want inside that API method like delete entities, return entities, etc.
How about trying out the following :
#ApiMethod(
name = "removeRPurchase",
httpMethod = HttpMethod.DELETE
)
public void removeRPurchase(#Named("id") String id) {
//Now take the id and plugin in your datastore code to retrieve / delete
}

JPA & PostgreSQL: How do I call a stored procedure using NamedNativeQuery Annotation

Using Postgresql 8.1, Spring 3.0, Hibernate 3.6.
I have a method that calls a stored procedure that works without using Annotations, essentially it is
....
return (Integer) getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em) {
// Query query = em.createNamedQuery("checkZone");
Query query = em.createNativeQuery("select zoneArea from zoneArea(:pId, :zId)");
query.setParameter("pId", p.getId());
query.setParameter("zId", z.getId());
try {
return query.getSingleResult(); // Integer expected
} catch (NoResultException e) {
return 0;
}
}
});
....
How can I do this with Annotations, here's my attempt that does not work.
#NamedNativeQueries({
#NamedNativeQuery(
name = "checkZone",
query = "select zoneArea from zoneArea(:pId, :zId)",
hints = {
#QueryHint(name = "org.hibernate.callable", value = "true")
},
resultSetMapping = "scalar",
resultClass = Integer.class)})
#SqlResultSetMapping(name="scalar",columns=#ColumnResult(name="result"))
#Entity
and here is the Exception
Caused by: org.postgresql.util.PSQLException: This statement does not declare an OUT parameter. Use { ?= call ... } to declare one.
at org.postgresql.jdbc2.AbstractJdbc2Statement.registerOutParameter(AbstractJdbc2Statement.java:1849)
at org.postgresql.jdbc3.AbstractJdbc3Statement.registerOutParameter(AbstractJdbc3Statement.java:1513)
at org.hibernate.dialect.PostgreSQLDialect.registerResultSetOutParameter(PostgreSQLDialect.java:335)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1713)
at org.hibernate.loader.Loader.doQuery(Loader.java:801)
I have working code but would like to get this working with Annotations, any ideas appreciated.

how to create table if it doesn't exist using Derby Db

I am new to apache derby and I cant seem to make work
CREATE TABLE IF NOT EXISTS table1 ...
as can be achieved in MySql etc. I am getting a 'Syntax error: Encountered "NOT" at line 1, column 17.', when I try to run this SQL statement in my Java program.
I checked in the documentation page for Derby Db Create Statements, but couldn't find such an alternative.
Create the table, catch the SQLException and check SQL status code.
The full list of error codes can be found here but I couldn't find Table <value> already exists; it's probably X0Y68. The code you need is X0Y32.
Just run the code once and print the error code. Don't forget to add a test to make sure the code works; this way, you can catch changes in the error code (should not happen ...).
In my projects, I usually add a helper class with static methods so I can write:
} catch( SQLException e ) {
if( DerbyHelper.tableAlreadyExists( e ) ) {
return; // That's OK
}
throw e;
}
Another option is to run a SELECT against the table and check the status code (which should be 42X05). But that's a second command you need to send and it doesn't offer any additional information.
What's worse, it can fail for other reasons than "Table doesn't exist", so the "create-and-ignore-error" is better IMO.
Derby does not support that sql-statement.
In my program I parse all the Tables from the Database into a Set and check if the table exists there.
Like this:
private Set<String> getDBTables(Connection targetDBConn) throws SQLException
{
Set<String> set = new HashSet<String>();
DatabaseMetaData dbmeta = targetDBConn.getMetaData();
readDBTable(set, dbmeta, "TABLE", null);
readDBTable(set, dbmeta, "VIEW", null);
return set;
}
private void readDBTable(Set<String> set, DatabaseMetaData dbmeta, String searchCriteria, String schema)
throws SQLException
{
ResultSet rs = dbmeta.getTables(null, schema, null, new String[]
{ searchCriteria });
while (rs.next())
{
set.add(rs.getString("TABLE_NAME").toLowerCase());
}
}
the query you are executing does not supported by Derby db. Instead, if you know the name of the table you can find if table exists or not quite easily.
public boolean isTableExist(String sTablename) throws SQLException{
if(connection!=null)
{
DatabaseMetaData dbmd = connection.getMetaData();
ResultSet rs = dbmd.getTables(null, null, sTablename.toUpperCase(),null);
if(rs.next())
{
System.out.println("Table "+rs.getString("TABLE_NAME")+"already exists !!");
}
else
{
System.out.println("Write your create table function here !!!");
}
return true;
}
return false;
}
Catch is to specify name of the table in Uppercase else you won't be able to find table name in metadata.
to check if table is exist :
Connection con = DriverManager.getConnection(url);
ResultSet res = con.getMetaData().getTables(null, Schema_Name, table_name.toUpperCase(), null);//Default schema name is "APP"
if(res.next())
{
//do some thing;
}else{
JOptionPane.showMessageDialog(null, table_name +" not exist");
}
to show all tables name :
Connection con = DriverManager.getConnection(url);
ResultSet res = con.getMetaData().getTables(null, Schema_Name, "%", null);//Default schema name is "APP"
while(res.next())
{
JOptionPane.showMessageDialog(null, res.getString(3) + " is exist");//Show table name
}else{
JOptionPane.showMessageDialog(null, table_name +" not exist");
}
Following Aaron Digulla's lead with a DerbyUtils class to check if the table exists, this is the solution I came up with :
Calling class
public void createTable(String name) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = daoFactory.getConnection();
String sql = String.format(SQL_CREATE_TABLE, name);
preparedStatement = connection.prepareStatement(sql, Statement.NO_GENERATED_KEYS);
preparedStatement.execute();
} catch (SQLException e) {
if(DerbyUtils.tableAlreadyExists(e)) { //check if the exception is because of pre-existing table.
logger.info("Talbe " + name + " already exists. No need to recreate");
} else {
logger.error(e.getMessage() + " : " + e.getStackTrace());
}
} finally {
close(connection, preparedStatement); //DAOUtils silently closes
}
}
DerbyUtils
public class DerbyUtils {
public DerbyUtils() {
//empty constructor -- helper class
}
public static boolean tableAlreadyExists(SQLException e) {
boolean exists;
if(e.getSQLState().equals("X0Y32")) {
exists = true;
} else {
exists = false;
}
return exists;
}
}
See also
https://db.apache.org/derby/docs/10.2/ref/rrefexcept71493.html
I know this was marked with an answer but in case anyone wanted another way of checking I wanted to post anyway. Here I check the table metadata with a method that returns a boolean, true if exists, false if it doesn't. Hope it helps others if they are looking.
private static Connection conn = null;
private static Statement st = null;
private static ResultSet rs = null;
private static DatabaseMetaData dmd;
public Boolean firstTime()
{
try
{
dmd = conn.getMetaData();
rs = dmd.getTables(null, "APP", "LOGIN", null);
return !rs.next();
} catch (SQLException ex)
{
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}
Another solution with 2 conditions:
Willing to drop table before creating each time, with the same being present in a .sql file
Are using Spring and hence willing to use spring-test as a Maven dependency, your life can become much simpler with it's #Sql annotation
So, firstly adding this as a dependency to your pom:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
<scope>test</scope>
</dependency>
Secondly, assuming you have an sql that drops, creates table a in a file
rectangle.sql:
DROP TABLE rectangles;
CREATE TABLE rectangles (
id INTEGER NOT NULL PRIMARY KEY,
width INTEGER NOT NULL,
height INTEGER NOT NULL
);
And you have a test class BlahTest that should run this sql before doing whatever test it is to run, simply add the following #Sql annotation to your class:
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.context.jdbc.SqlConfig.ErrorMode;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=XyzClientConfig.class)
#Sql(scripts="/sql/ddl/rectangle.sql", config=#SqlConfig (errorMode=ErrorMode.IGNORE_FAILED_DROPS))
public class BlahTest {
...
}
The specified config attribute value's #SqlConfig has the magic that makes it skip the drop statement errors in case the table doesn't exist. I believe it's been written to specifically target these types of databases that don't support IF EXISTS for dropping / table creation (which derby really should, even if it's not part of the SQL standard at the moment)
This answer is way late, but it might be helpful for someone.
The following Java (standard JDBC) code can be used to check whether a table exists or not, and if it does then it can be created;
String query = "SELECT TRUE FROM SYS.SYSTABLES WHERE TABLENAME = ? AND TABLETYPE = 'T'"; // Leave TABLETYPE out if you don't care about it
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, "TABLE_NAME"); // Must be in capitals
ResultSet rs = ps.executeQuery();
if ( rs.next() && rs.getBoolean(1) )
{
// Table exists
}
else
{
// Table does NOT exist ... create it
}
Here is a solution that will you can script in SQL.
Create a Class like the following:
package user.fenris.spring.extensions;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
public class SqlCreateIfNotExists {
private static Log log = LogFactory.getLog(SqlCreateIfNotExists.class);
public static void createTableIfNotExists(String tablename, String ddl) throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:default:connection");
if (conn != null) {
JdbcTemplate template = new JdbcTemplate(new SingleConnectionDataSource(conn, true));
int count = template.queryForInt("select count(*) from SYS.SYSTABLES where TABLENAME = ?", tablename);
log.debug("Count: " + count);
if (count == 0) {
log.debug("Executing sql statement: " + ddl);
template.execute(sql);
} else {
log.debug("Table exists. Skipping sql execution...");
}
}
}
}
Note: you don't have to use spring, you can write it in straight JDBC, but then you have to know how to do it correctly. (Left as an exercise for the reader). Also, you could rewrite this to parse out the table name from the ddl parameter. Another thing would be to do proper error handling.
Make sure the class is compiled and placed in the classpath of the VM the database will be running in.
Write your SQL script:
-- 2K for ddl statement should be enough. You want more? Seriously?
create procedure CreateTableIfNotExists(in tablename varchar(128), in ddl varchar(2048))
PARAMETER STYLE JAVA
MODIFIES SQL DATA
language java
external name 'user.fenris.spring.extensions.SqlCreateIfNotExists.createTableIfNotExists';
call CreateTableIfNotExists('TABLE_NAME_MUST_BE_ALL_CAPS',
'create table TABLE_NAME_MUST_BE_ALL_CAPS
(entry_id int generated always as identity not null,
entry_timestamp timestamp,
username varchar(128) not null,
note varchar(1024) not null,
primary key (entry_id))');
-- you don't have to drop this, but you would have to create a similar
-- procedure to create the CreateTableIfNotExists procedure,
-- (i.e. CreateProcedureIfNotExists) but then it's turtles all the way down
drop procedure CreateIfNotExists;
???
profit
try {
connection.createStatement().execute("create table channels(channel varchar(20),topic varchar(20))");
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
Surround the create statement by try-catch.and make sure comment the e.printstacktace();
if it is already exists it does not show error ,otherwise it create table..!!

Categories