How to retrieve sequences metadata from JDBC? - java

I am trying to retrieve different kind of metadata of my Oracle DB from Java code (using basic JDBC). For example, if I want to retrieve the list of tables with _FOO suffix, I can do something like:
Connection connection = dataSource.getConnection();
DatabaseMetaData meta = connection.getMetaData();
ResultSet tables = meta.getTables(connection.getCatalog(), null, "%_FOO", new String[] { "TABLE" });
// Iterate on the ResultSet to get information on tables...
Now, I want to retrieve all the sequences from my database (for example all sequence named S_xxx_FOO).
How would I do that, as I don't see anything in DatabaseMetaData related to sequences?
Do I have to run a query like select * from user_sequences ?

Had the same question. It's fairly easy. Just pass in "SEQUENCE" into the getMetaData().getTables() types param.
In your specific case it would be something like:
meta.getTables(connection.getCatalog(), null, "%_FOO", new String[] { "SEQUENCE" });

You can't do this through the JDBC API, because some databases (still) do not support sequences.
The only way to get them is to query the system catalog of your DBMS (I guess it's Oracle in your case as you mention user_sequences)

You can use the hibernate dialect api for retrieving sequence Name. see : http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/dialect/Dialect.html
From below example, you can see how to use dialect to get sequence names
public static void main(String[] args) {
Connection jdbcConnection = null;
try {
jdbcConnection = DriverManager.getConnection("", "", "");
printAllSequenceName(jdbcConnection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(jdbcConnection != null) {
try {
jdbcConnection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void printAllSequenceName(Connection conn) throws JDBCConnectionException, SQLException {
DialectResolver dialectResolver = new StandardDialectResolver();
Dialect dialect = dialectResolver.resolveDialect(conn.getMetaData());
if ( dialect.supportsSequences() ) {
String sql = dialect.getQuerySequencesString();
if (sql!=null) {
Statement statement = null;
ResultSet rs = null;
try {
statement = conn.createStatement();
rs = statement.executeQuery(sql);
while ( rs.next() ) {
System.out.println("Sequence Name : " + rs.getString(1));
}
}
finally {
if (rs!=null) rs.close();
if (statement!=null) statement.close();
}
}
}
}
If you don't desire to use hibernate, then you have to crate custom sequential specific implementation.
Sample code for custom implementation
interface SequenceQueryGenerator {
String getSelectSequenceNextValString(String sequenceName);
String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize);
String getDropSequenceStrings(String sequenceName);
String getQuerySequencesString();
}
class OracleSequenceQueryGenerator implements SequenceQueryGenerator {
#Override
public String getSelectSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from dual";
}
#Override
public String getCreateSequenceString(String sequenceName,
int initialValue, int incrementSize) {
return "create sequence " + sequenceName + " start with " + initialValue + " increment by " + incrementSize;
}
#Override
public String getDropSequenceStrings(String sequenceName) {
return "drop sequence " + sequenceName;
}
#Override
public String getQuerySequencesString() {
return "select sequence_name from user_sequences";
}
}
class PostgresSequenceQueryGenerator implements SequenceQueryGenerator {
#Override
public String getSelectSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName );
}
#Override
public String getCreateSequenceString(String sequenceName,
int initialValue, int incrementSize) {
return "create sequence " + sequenceName + " start " + initialValue + " increment " + incrementSize;
}
#Override
public String getDropSequenceStrings(String sequenceName) {
return "drop sequence " + sequenceName;
}
#Override
public String getQuerySequencesString() {
return "select relname from pg_class where relkind='S'";
}
}
public void printSequenceName (SequenceQueryGenerator queryGenerator, Connection conn) throws SQLException {
String sql = queryGenerator.getQuerySequencesString();
if (sql!=null) {
Statement statement = null;
ResultSet rs = null;
try {
statement = conn.createStatement();
rs = statement.executeQuery(sql);
while ( rs.next() ) {
System.out.println("Sequence Name : " + rs.getString(1));
}
}
finally {
if (rs!=null) rs.close();
if (statement!=null) statement.close();
}
}
}
public static void main(String[] args) {
Connection jdbcConnection = null;
try {
jdbcConnection = DriverManager.getConnection("", "", "");
printAllSequenceName(new OracleSequenceQueryGenerator(), jdbcConnection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(jdbcConnection != null) {
try {
jdbcConnection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

Given that recent versions of the Oracle JDBC drivers (e.g. 12.1.0.2) don't return sequence information when you call DatabaseMetaData#getTables with types set to ["SEQUENCE"], your best bet is to run the necessary query yourself, e.g.:
SELECT o.owner AS sequence_owner,
o.object_name AS sequence_name
FROM all_objects o
WHERE o.owner LIKE 'someOwnerPattern' ESCAPE '/'
AND o.object_name LIKE 'someNamePattern' ESCAPE '/'
AND o.object_type = 'SEQUENCE'
ORDER BY 1, 2
... where someOwnerPattern and someNamePattern are SQL patterns like the ones you'd use with the LIKE operator (e.g. % matches anything).
This is basically the same as the query run by the driver itself, except that it queries for objects of type SEQUENCE.

Related

Is the MySQL procedure in this Minecraft plugin correct?

To get an idea of what the basic structure looks like, I downloaded a money system including MySQL from Spigot and looked at the code.
public static boolean playerExists(String uuid) {
try {
ResultSet rs = Simplecoinsystem.mysql.query("SELECT * FROM CoinData WHERE UUID= '" + uuid + "'");
if (rs.next())
return (rs.getString("UUID") != null);
return false;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public static void createPlayer(String uuid) {
if (!playerExists(uuid))
Simplecoinsystem.mysql.update("INSERT INTO CoinData (UUID, COINS) VALUES ('" + uuid +
"', '" + Simplecoinsystem.getInstance().getConfig().getInt("startcoins") + "');");
}
public static Integer getCoins(String uuid) {
Integer i = Integer.valueOf(0);
if (playerExists(uuid)) {
try {
ResultSet rs = Simplecoinsystem.mysql.query("SELECT * FROM CoinData WHERE UUID= '" + uuid + "'");
if (rs.next())
Integer.valueOf(rs.getInt("COINS"));
i = Integer.valueOf(rs.getInt("COINS"));
} catch (SQLException e) {
e.printStackTrace();
}
} else {
createPlayer(uuid);
}
return i;
}
public static void setCoins(String uuid, Integer coins) {
if (playerExists(uuid)) {
Simplecoinsystem.mysql.update("UPDATE CoinData SET COINS= '" + coins + "' WHERE UUID= '" + uuid + "';");
} else {
createPlayer(uuid);
}
}
Am I correct that it is actually impractical to create a new entry with the uuid of the non-existent player after each query of the coins if the player does not exist?
Wouldn't this make it possible to flood the database with thousands of unnecessary entries by issuing, for example, a "/money (player)" command as an evil player/admin?
Couldn't I just ask when entering the server if the uuid is already stored and if not, just enter it? This way there would only be entries from players who have already been on the server before. Whether this needs great server performance, I'm not sure.
This is my first own MySQL class.
public class MySQL {
private String host, database, user, password;
private int port;
private Connection con;
public MySQL(String host, int port, String database, String user, String password) {
this.host = host;
this.port = port;
this.database = database;
this.user = user;
this.password = password;
connect();
}
public void connect() {
try {
con = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database + "?autoReconnect=true", user, password);
System.out.println("&cDie MySQL Verbindung wurde erfolgreich aufgebaut!");
} catch (SQLException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
if(this.con != null) {
this.con.close();
System.out.println("§cDie MySQL Verbindung wurde erfolgreich beendet!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void update(String query) {
try {
Statement st = con.createStatement();
st.executeUpdate(query);
st.close();
} catch (Exception e) {
e.printStackTrace();
connect();
}
}
public ResultSet qry(String query) {
ResultSet rs = null;
try {
Statement st = con.createStatement();
rs = st.executeQuery(query);
} catch (Exception e) {
e.printStackTrace();
connect();
}
return rs;
}
public Connection getConnection() {
return this.con;
}
}
Except for this part, both MySQL classes are built relatively the same.
This is the part that is in the MySQL class of the Spigot plugin.
Your code have multiple issues.
When the connection will be closed, next time you will have an error. In your Mysql class, I suggest you to do:
public Connection getConnection() {
if(con == null || con.isClosed())
connect();
return con;
}
Then, use it in all method like getConnection().prepareStatement().
You can be attacked with SQL Injection. To fix this, try to do something like:
PreparedStatement st = con.prepareStatement("SELECT * FROM CoinData WHERE UUID = ?");
st.setString(1, uuid.toString()); // Yes it start at 1 !!
st.executeUpdate();
With this, even with all values, you can't be attacked with injections.
You will have an error while getting coins:
if (rs.next()) // go to good line
Integer.valueOf(rs.getInt("COINS")); // useless convertion
i = Integer.valueOf(rs.getInt("COINS")); // error if no line.
You can just do:
if(rs.next())
i = rs.getInt("COINS");
If the column "UUID" is unique, you will not have duplicated lines.
Finally, about performance, it's better to do it one time: at login, instead of all time. You can also create an object stored in an hashmap to easier access to it, without using SQL, like that:
public static HashMap<UUID, Integer> coinsByPlayer = new HashMap<>();
OR:
public static HashMap<UUID, MyObject> coinsByPlayer = new HashMap<>();
public class MyObject {
private int coins = 0;
public MyObject(UUID uuid) {
// make SQL request to get data
}
public int getCoins() {
return coins;
}
public void setCoins(int next){
coins = next;
// here make "UPDATE" sql query
}
}
What do you say? Is it ok with the try/catch function? #Elikill58
public Connection getConnection() {
try {
if(con == null || con.isClosed()) {
connect();
}
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
edit:
public Connection getConnection_one() throws SQLException {
if(con == null || con.isClosed()) {
connect();
return con;
} else {
return con;
}
}

JSP mysql connections not closing, however in Java class it does

I am developing a web application using Java, JSP, MySQL. I cannot get the MySQL connections to close in the JSP, yet it works in a Java class. I have the following code:
A. First I have a class to get the ResultSet when running a get query as follows:
public static ResultSet get(String query) {
ResultSet rs = null;
try {
Class.forName(JDBC_DRIVER);
connection = DriverManager.getConnection(DB_URL + DB_NAME, USERNAME, PASSWORD);
statement = connection.createStatement();
rs = statement.executeQuery(query);
} catch (ClassNotFoundException | SQLException ex) {
ex.printStackTrace();
}
return rs;
}
B. I have a java class using the above to return the MySQL results in objects as follows:
public static <E> E getByFromOtherRS(E element, List<String> columns, String tableName, String whereColumn, String whereValue, Method getFromRS) {
try {
String query = "Select * from " + tableName + " where " + whereColumn + "='" + whereValue + "';";
ResultSet rs = SQLAccessor.get(query);
while (rs.next()) {
try {
element = (E) getFromRS.invoke(element, rs);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (SQLException ex) {
} finally {
try {
SQLAccessor.getConnection().close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return element;
}
C. I then use the above in the below class. When I run the main method I get the result as expected. Also, when I do
show status like '%onn%'
in the MySQL shell the number of Threads_connected are the same as before running the code.
public static void main(String[] args) {
Gson gson = new Gson();
System.out.println(gson.toJson(getUserByUsername()));
}
public static User getUserByUsername() {
User user = Accessor.getByFromOtherRS(new User(), Accessor.getColumns("user"), "user", "username", "linda", Accessor.getFromRSMethod(UserAccessor.class));
return user;
}
D. The problem is with the JSP. I have the below code in the JSP. I get the user email correctly, but the problem is with the MySQL - when I run the same command as above the number of Threads_connected are now 17 more.
<%
User user = DatabaseAccessor.getUserByUsername();
System.out.println(user.getEmail());
%>
Any help in this regard will be greatly appreciated.
Can't see the full code...
Given the code snippet, it will be better if you issue 'close' to the connection in a finally block to ensure it gets closed.
finally {
if (connection!=null) { connection.close();}
}

How to increase Testcoverage for Class that interacts with a Database?

I got a Java class called PatientRepositoryImpl, which contains some methods, that insert, delete or update Data in a MySql Database.
I've also written some Unit Tests for this class.
When i check the Coverage of my tests, i only get 59%, although almost every line of Code is marked green by the Coverage tool, except the SQL Exceptions.
I am new here and hope i did everything right, would be very thankful if someone could help me.
Here the code for my Repository and the Tests.
public class PatientRepositoryMySqlImpl implements PatientRepository {
private DatabaseConnection connection;
private PatientGenerator patientGenerator;
public PatientRepositoryMySqlImpl(DatabaseConnection connection, PatientGenerator patientGenerator) {
this.connection = connection;
this.patientGenerator = patientGenerator;
}
/* (non-Javadoc)
* #see com.id.hl7sim.PatientRepository#insertPatient()
*/
#Override
public void insertPatient(Patient patient) {
if (!patient.isValid()) {
throw new IllegalArgumentException("Incomplete Patient");
} else {
String insert = "INSERT INTO tbl_patient(lastname, firstname, gender, birthday) VALUES('"
+ patient.getLastname() + "', '" + patient.getFirstname() + "', '" + patient.getGender() + "', '"
+ patient.getBirthday().toString() + "');";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.prepareStatement(insert)) {
statement.executeUpdate(insert);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}
/* (non-Javadoc)
* #see com.id.hl7sim.PatientRepository#insertListOfPatients()
*/
#Override
public void insertListOfPatients(List<Patient> allPatients) {
for (Patient patient : allPatients) {
insertPatient(patient);
}
}
/* (non-Javadoc)
* #see com.id.hl7sim.PatientRepository#getRandomPatient()
*/
#Override
public Patient getRandomPatient() {
Patient patient = new Patient.Builder().build();
String query = "SELECT * FROM tbl_patient ORDER BY RAND() LIMIT 1";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.createStatement();) {
ResultSet rs = statement.executeQuery(query);
rs.next();
setPatientBasicData(patient, rs);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return patient;
}
private void setPatientBasicData(Patient patient, ResultSet rs) {
try {
patient.setId(rs.getInt("id"));
patient.setLastname(rs.getString("lastname"));
patient.setFirstname(rs.getString("firstname"));
patient.setGender(rs.getString("gender"));
patient.setBirthday(parseBirthday(rs.getString("birthday")));
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public LocalDate parseBirthday(String birthday) {
LocalDate localDate = LocalDate.parse(birthday);
return localDate;
}
/* (non-Javadoc)
* #see com.id.hl7sim.PatientRepository#admitRandomPatient()
*/
#Override
public Patient admitRandomPatient() {
Patient patient = getRandomPatient();
patient.setDepartment(patientGenerator.getRandomDepartment());
patient.setWard(patientGenerator.getRandomWard());
patient.setAdmissionDateTime(LocalDateTime.now());
patient.setStatus("I");
String insert = "INSERT INTO tbl_inpatients(id, ward, department, admissionDate, patientStatus) VALUES('"
+ patient.getId() + "', '" + patient.getWard() + "', '" + patient.getDepartment() + "', '"
+ patient.getAdmissionDateTime().toString() + "', '" + patient.getStatus() + "')";
try (Connection dbConnection = connection.getDBConnection();
PreparedStatement statement = dbConnection.prepareStatement(insert)) {
statement.executeUpdate(insert, Statement.RETURN_GENERATED_KEYS);
ResultSet keys = statement.getGeneratedKeys();
keys.next();
patient.setCaseId(keys.getInt(1));
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return patient;
}
public Patient getRandomInpatient() {
Patient patient = new Patient.Builder().build();
String query = "SELECT * FROM tbl_inpatients ip, tbl_patient p WHERE p.id = ip.id ORDER BY RAND() LIMIT 1";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.createStatement();) {
ResultSet rs = statement.executeQuery(query);
rs.next();
setPatientBasicData(patient, rs);
setPatientCaseData(patient, rs);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return patient;
}
public void setPatientCaseData(Patient patient, ResultSet rs) {
try {
patient.setWard(rs.getString("ward"));
patient.setDepartment(rs.getString("department"));
patient.setAdmissionDateTime(parseLocalDateTime(rs.getString("admissionDate")));
patient.setStatus(rs.getString("patientStatus"));
patient.setCaseId(rs.getInt("case"));
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public LocalDateTime parseLocalDateTime(String localdatetime) {
localdatetime = localdatetime.replace("T", "");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss.SSS");
LocalDateTime formattedLocalDateTime = LocalDateTime.parse(localdatetime, formatter);
return formattedLocalDateTime;
}
/* (non-Javadoc)
* #see com.id.hl7sim.PatientRepository#transferRandomPatient()
*/
#Override
public Patient transferRandomPatient() {
Patient patient = getRandomInpatient();
patient.setPriorWard(patient.getWard());
patient.setPriorDepartment(patient.getPriorDepartment());
patient.setDepartment(patientGenerator.getRandomDepartment());
patient.setWard(patientGenerator.getRandomWard());
String update = "UPDATE tbl_inpatients SET ward='" + patient.getWard() + "', department='"
+ patient.getDepartment() + "' WHERE id='" + patient.getId() + "'";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.prepareStatement(update)) {
statement.executeUpdate(update);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return patient;
}
/* (non-Javadoc)
* #see com.id.hl7sim.PatientRepository#dischargeRandomPatient()
*/
#Override
public Patient dischargeRandomPatient() {
Patient patient = getRandomInpatient();
patient.setDischargeDateTime(LocalDateTime.now());
insertFormerPatient(patient);
String delete = "DELETE FROM tbl_inpatients WHERE `case`=" + patient.getCaseId();
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.prepareStatement(delete)) {
statement.executeUpdate(delete);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return patient;
}
public void insertFormerPatient(Patient patient) {
String insert = "INSERT INTO tbl_formerpatients(`case`, `id`, ward, department, admissionDate, dischargeDate) VALUES('"
+ patient.getCaseId() + "', '" + patient.getId() + "', '" + patient.getWard() + "', '"
+ patient.getDepartment() + "', '" + patient.getAdmissionDateTime().toString() + "', '"
+ patient.getDischargeDateTime().toString() + "')";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.prepareStatement(insert)) {
statement.executeUpdate(insert);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public int countInpatients() {
int numberOfPatients = 0;
String query = "SELECT COUNT(id) AS numberOfPatients FROM tbl_inpatients";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.createStatement();) {
ResultSet rs = statement.executeQuery(query);
while (rs.next()) {
numberOfPatients = rs.getInt(1);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return numberOfPatients;
}
public int countPatients() {
int numberOfPatients = 0;
String query = "SELECT COUNT(id) AS numberOfPatients FROM tbl_patient";
try (Connection dbConnection = connection.getDBConnection();
Statement statement = dbConnection.createStatement();) {
ResultSet rs = statement.executeQuery(query);
while (rs.next()) {
numberOfPatients = rs.getInt(1);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return numberOfPatients;
}
Tests
public class PatientRepositoryMySqlImplTest {
PatientRepository testPatientRepository;
Patient testPatient;
Patient testPatientTwo;
List<Patient> testBothPatients;
DatabaseConnection testConnection;
PatientGenerator testPatientGenerator;
Firstnames testFirstnames;
Lastnames testLastnames;
Departments testDepartments;
Wards testWards;
#Before
public void setUp() throws Exception {
testDepartments = JAXB.unmarshal(ClassLoader.getSystemResource("departments.xml"), Departments.class);
testWards = JAXB.unmarshal(ClassLoader.getSystemResource("wards.xml"), Wards.class);
testLastnames = JAXB.unmarshal(ClassLoader.getSystemResource("lastnames.xml"), Lastnames.class);
testFirstnames = JAXB.unmarshal(ClassLoader.getSystemResource("firstnames.xml"), Firstnames.class);
testPatientGenerator = new PatientGeneratorImpl(testFirstnames, testLastnames, testDepartments, testWards);
testPatient = testPatientGenerator.randomizeNewPatient();
testPatientTwo = testPatientGenerator.randomizeNewPatient();
testBothPatients = new ArrayList<Patient>();
testConnection = new MySqlConnection();
testPatientRepository = new PatientRepositoryMySqlImpl(testConnection, testPatientGenerator);
testPatientRepository.admitRandomPatient();
}
#Test
public void testAdmitRandomPatient() {
testPatient = testPatientRepository.admitRandomPatient();
assertTrue(testPatient.isValid());
}
#Test
public void testGetRandomInpatient() {
testPatient = testPatientRepository.getRandomInpatient();
assertTrue(testPatient.isValid());
}
#Test
public void testDischargeRandomPatientValid() {
testPatient = testPatientRepository.dischargeRandomPatient();
assertTrue(testPatient.isValid());
assertTrue(testPatient.getCaseId() != 0);
}
#Test
public void testDischargeRandomPatientDatabase() {
int beforeDischarge = testPatientRepository.countInpatients();
testPatient = testPatientRepository.dischargeRandomPatient();
int afterDischarge = testPatientRepository.countInpatients();
assertTrue(afterDischarge == beforeDischarge - 1);
}
#Test(expected = IllegalArgumentException.class)
public void testInsertPatientWitIncompletePatient() {
testPatient.setFirstname("");
testPatientRepository.insertPatient(testPatient);
}
#Test
public void testTransferRandomPatient() {
testPatient = testPatientRepository.transferRandomPatient();
assertTrue(testPatient.getDepartment() != testPatient.getPriorDepartment());
}
#Test
public void testInsertPatient() {
int numberOfPatients = testPatientRepository.countInpatients();
testPatientRepository.insertPatient(testPatient);
assertTrue(testPatientRepository.countInpatients() >= numberOfPatients);
}
#Test
public void testInsertListOfPatients() {
testBothPatients.add(testPatient);
testBothPatients.add(testPatientTwo);
int countInpatientsBeforeInsertion = testPatientRepository.countPatients();
testPatientRepository.insertListOfPatients(testBothPatients);
int countInpatientsAfterInsertion = testPatientRepository.countPatients();
assertTrue(countInpatientsAfterInsertion > countInpatientsBeforeInsertion);
}
Edit:
#Test
public void mockThrowsException() {
PatientRepository testPatientRepository = mock(PatientRepositoryMySqlImpl.class);
when(testPatientRepository.getRandomPatient()).thenThrow(SQLException.class);
testPatientRepository.admitRandomPatient();
}
While I completely agree that in order to increase the coverage you should definitely "simulate" the scenario that something goes wrong and SQLExceptions are thrown, let me introduce another approach that will also answer the question but hopefully give you another perspective.
JDBC is pretty cumbersome, and the tests that will throw SQL exceptions will probably not be the most pleasant tests to write. In addition, I see that you don't really deal with exceptions, and just log them in a console.
So maybe instead of trying to struggle with this, maybe you should consider to not work directly with JDBC but use some library that will wrap the hassle of JDBC usage for you. For example of such a library, take a look onto Spring JDBC Template, I know it's a pretty old stuff, but hey, working directly with JDBC is also probably not the most modern approach, so I'm trying to make fewer changes but still gain a value. Moreover one may say that its old and not fancy, I would say, a battle-tested library, that can be even without Spring itself.
Now since it wraps the JDBC Exception handling, among other things, the point is that you won't have to cover these cases at all. So your coverage will increase naturally.
Of course other low level and no-so-low level alternatives exist (like JDBI, or JOOQ to name a few), but this a different story, all of them will increase the coverage in a sense of a question you've asked.

Why does Bluemix dashDB operation throws a SqlSyntaxErrorException with SQLCODE=-1667?

I'm getting this error even though I am not trying to edit the table/column:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: The operation failed because the operation is not supported with the type of the specified table. Specified table: "DASH103985.wajihs". Table type: "ORGANIZE BY COLUMN". Operation: "WITH RS".. SQLCODE=-1667, SQLSTATE=42858
#MultipartConfig
public class DemoServlet extends HttpServlet {
private static Logger logger = Logger.getLogger(DemoServlet.class.getName());
private static final long serialVersionUID = 1L;
#Resource(lookup="jdbc/db2")DataSource dataSource;
private String getDefaultText() {
TweetsCombined = new String(" ");
try {
// Connect to the Database
Connection con = null;
try {
System.out.println("Connecting to the database");
} catch (SQLException e) {
TweetsCombined = "first" +e;
}
// Try out some dynamic SQL Statements
Statement stmt = null;
try {
stmt = con.createStatement();
String tableName = "wajihs";// change table name here to one
// chosen in the first website
String columnName = "msgBody";// msgBody is where the tweets
// are stored
String query = "SELECT * FROM \"" + tableName + "\"";
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
content = rs.getString(columnName) + ". ";
if (content.toLowerCase().contains("RT".toLowerCase())
|| content.toLowerCase().contains("Repost: ".toLowerCase())) {
// do nothing
}
else {
TweetsCombined.concat(content);
}
}
// Close everything off
// Close the Statement
stmt.close();
// close
con.commit();
// Close the connection
con.close();
} catch (Exception e) {
TweetsCombined = "second" +e;
System.out.println(e.getMessage());
}
} catch (Exception e) {
TweetsCombined = "third" + e;
System.out.println(e);
}
return TweetsCombined;
}
As I explained here, dashDB, with its BLU Acceleration features, has certain limitations compared to DB2 without BLU Acceleration. In your case it is that you can only run queries with the CS isolation level against column-organized tables.
Either change your connection configuration to use CS isolation level or create your table(s) while explicitly specifying ORGANIZE BY ROW.

JAVA JDBC SQL updating a new database based on the old database records

I am trying to write a runnable jar file that can be able to connect to 2 different databases informix old database and oracle new database. It should be able to update the new database(oracle) with the old database(informix) records.
I re-edit my java code I added separate methods for my select, update and connections I am not getting an error but its not updating my db. My select works but my update statement is not working. This is my result i get - SELECT profile_id, ingress_flag, egress_flag, ce_ingress_flag, ce_egress_flag from COS_PROFILE where profile_id = 102
profileid : 102
ingressflag : Y
egress_flag : Y
ceingressflag : Y
ceegressflag : Y
ResultSet not open, operation 'next' not permitted. Verify that autocommit is OFF
I am not sure how can I fixed the ResultSet not open, operation 'next' not permitted. Verify that autocommit is OFF
public class TestConnection {
static ResultSet rs;
public static void main (String[] args) throws Exception {
try{
selectRecordsIcore();
updateRecordIntoBids();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
public static void selectRecordsIcore() throws SQLException {
Connection dbConnection = null;
Statement statement = null;
String selectTableSQL = "SELECT profile_id, ingress_flag, egress_flag, ce_ingress_flag, ce_egress_flag from COS_PROFILE";
try {
dbConnection = getInformixConnection();
statement = dbConnection.createStatement();
System.out.println(selectTableSQL);
// execute select SQL stetement
rs = statement.executeQuery(selectTableSQL);
while (rs.next()) {
int profileid = rs.getInt("profile_id");
String ingressflag = rs.getString("ingress_flag");
String egress_flag = rs.getString("egress_flag");
String ceingressflag = rs.getString("ce_ingress_flag");
String ceegressflag = rs.getString("ce_egress_flag");
System.out.println("profileid : " + profileid);
System.out.println("ingressflag : " + ingressflag);
System.out.println("egress_flag : " + egress_flag);
System.out.println("ceingressflag : " + ceingressflag);
System.out.println("ceegressflag : " + ceegressflag);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (statement != null) {
statement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
private static void updateRecordIntoBids() throws SQLException {
Connection dbConnection = null;
Statement statement = null;
ArrayList<TempStorageRecords> updateSQL = new ArrayList<TempStorageRecords>();
while (rs.next()) {
int profileid = rs.getInt("profile_id");
String ingressflag = rs.getString("ingress_flag");
String egress_flag = rs.getString("egress_flag");
String ceingressflag = rs.getString("ce_ingress_flag");
String ceegressflag = rs.getString("ce_egress_flag");
String updateTableSQL = "UPDATE traffic_profile SET ingress_flag = " + ingressflag
+ " ,egress_flag = " + egress_flag
+ " ,ce_ingress_flag = " + ceingressflag
+ " ,ce_egress_flag = " + ceegressflag
+ " WHERE profile_id = " + profileid + ";";
try {
dbConnection = getOracleConnection();
statement = dbConnection.createStatement();
System.out.println("updateTableSQL 1 :" + updateTableSQL);
// execute update SQL stetement
statement.execute(updateTableSQL);
System.out.println("updateTableSQL 2: " + updateTableSQL);
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (statement != null) {
statement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
}
public static Connection getOracleConnection() throws SQLException {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:#oracle_host:1521:BIDS";
String username = "username";
String password = "password";
try {
Class.forName(driver);
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} // load Oracle driver
Connection dbConnection = null;
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
try {
dbConnection = DriverManager.getConnection(
url, username,password);
return dbConnection;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return dbConnection;
}
public static Connection getInformixConnection() throws SQLException {
String driver = "com.informix.jdbc.IfxDriver";
String url = "jdbc:informix-sqli://informix_host:1615/icore:INFORMIXSERVER=icit";
String username = "user";
String password = "pass";
try {
Class.forName(driver);
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} // load Informix driver
Connection dbConnection = null;
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
try {
dbConnection = DriverManager.getConnection(
url, username,password);
return dbConnection;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return dbConnection;
}
}
At first try to export data from source database into text file.
Your code uses hard coded column names, but I think it could read table names to export from some config file and column names from metadata from SELECT * FROM [table_name]. In JDBC there is getMetaData() for RecordSet. Use it.
When you export data into text files without problems you can do the next step: import such data directly from the source database to the destination database.
For destination database create prepareStatement with:
'INSERT INTO ' + table_name_dest + ' (' + column_names +') VALUES ('+ question_marks + ')'
(there question_marks are '?' chars which maps to columns).
Then for each record from source table and for each record (row) do:
insert_stmt.setObject(i, rs_in.getObject(i))
For big tables you can also use setFetchSize() and addBatch()/executeBatch()

Categories