PostgreSQL : getting the Results of a Function - java

I have an PostgreSQL Function which returns me an XML where the whole infos of my table are.
This is my function:
/* get all cat names */
create function cat_names() returns xml as $$
select to_xml('select name FROM cat_Infos;');
$$ language sql;
to get the results I do the following:
ResultSet rs = sql.executeQuery("select cat_names()");
while (rs.next()) {
// This is where I actually thought that I could pass the XML I get, to my DOMParser.
// I thought about something like this:
DOMParser dom = new DOMParser();
dom.setImputString(//Xml I get from the resultset)
}
The problem is, I actually have no idea how to get the Xml from the ResultSet.

You should be able to use
String xml = rs.getString(1)
to get the XML String

Related

JDBC SQL Server Stored Procedure with ResultSet, return value, and output parameters

I am in the process of converting an application from Jython to compiled Java. The application uses a host of SQL Server stored procedures to do CRUD operations. All of the procedures are defined with a return value that indicates status, and some output parameters used to provide feedback to the application. Most of the procedures also return a result set. I'm struggling with how to retrieve the return value and the result set and the output parameters.
I normally work with C# so the nuances of JDBC are new to me. I've been testing with one of the procedures that does an insert to the database and then does a select on the inserted object.
Here's a simplified example procedure just to use for the purpose of illustration. The actual procedures are more complex than this.
CREATE PROCEDURE [dbo].[sp_Thing_Add]
(
#Name NVARCHAR(50),
#Description NVARCHAR(100),
#ResultMessage NVARCHAR(200) = N'' OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #Result INT = -1
DECLARE #ResultMessage = 'Procedure incomplete'
BEGIN TRY
INSERT INTO Things (Name, Description) VALUES (#Name, #Description)
SELECT * FROM Things WHERE ThingID = SCOPE_IDENTITY()
END TRY
BEGIN CATCH
SELECT #Result = CASE WHEN ERROR_NUMBER() <> 0 THEN ERROR_NUMBER() ELSE 1 END,
#ResultMessage = ERROR_MESSAGE()
GOTO EXIT_SUB
END CATCH
SUCCESS:
SET #Result = 0
SET #ResultMessage = N'Procedure completed successfully'
RETURN #Result
EXIT_SUB:
IF #Result <> 0
BEGIN
-- Do some error handling stuff
END
RETURN #Result
I can successfully retrieve the ResultSet using the following code.
var conn = myConnectionProvider.getConnection();
String sql = "{? = call dbo.sp_Thing_Add(?, ?, ?)}"
call = conn.prepareCall(sql);
call.registerOutParameter(1, TYPES.Integer); // Return value
call.setString("Name", thing.getName());
call.setString("Description", thing.getDescription());
call.registerOutParameter("ResultMessage", TYPES.NVARCHAR);
ResultSet rs = call.executeQuery();
// Try to get the return value. This appears to close the ResultSet and prevents data retrieval.
//int returnValue = call.getInt(1);
// Normally there'd be a check here to make sure things executed properly,
// and if necessary the output parameter(s) may also be leveraged
if (rs.next()) {
thing.setId(rs.getLong("ThingID"));
// Other stuff actually happens here too...
}
If I try retrieving the return value using the line that's commented out, I get an error stating that the ResultSet is closed.
com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed.
I've been through the documentation and have seen how to do return values, output parameters, and result sets. But how can I leverage all 3?
Given the order of processing in your stored procedure (insert, select, then populate result parameters), you need to process the result set before you retrieve the return value with CallableStatement.getXXX.
The output is in the ResultSet rs retrieved from executeQuery().
You may want to use the excute method as such:
call.execute();
String returnValue = call.getString("ResultMessage");
You also want to map correctly to the output type.
Your connection got closed once the execute query is executed. Basically mysql jdbc connection extends to AutoCloseable implicitly. Since your result is only entity from procedure,please get the value by index 0 and do a proper index out of bound exception handling.

How do PostgreeSQL functions return multiple columns and rows to a Java application?

I am trying to get 3 fields from 1 table using a function and I am getting errors:
CREATE OR REPLACE FUNCTION sp_search_test_ui_test_prog_revision(dev TEXT)
RETURNS table (dev_op_test_id BIGINT, test_program_name TEXT, test_program_revision TEXT)
AS $$
BEGIN
RETURN QUERY
SELECT dev_op_test_id, test_program_name, test_program_revision
FROM dev_op_test
WHERE device = dev
ORDER BY dev_op_test_id;
END;
$$ LANGUAGE plpgsql;
The JAVA code is below: (device is a String passed to this method) Is this where the error is?
// Get unique devices from dev_op_test
String sql = " SELECT sp_search_test_ui_test_prog_revision(" + device + ") ";
PreparedStatement statement = pgConn.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
// Clear from previous run
cboTestProgDev.getItems().clear();
while (rs.next()) {
TestProgRev tpr = new TestProgRev();
tpr.setDevOpTestId(rs.getLong(1));
tpr.setTestProgramName(rs.getString(2));
tpr.setTestProgramRevision(rs.getString(3));
testProgs.add(tpr);
cboTestProgDev.getItems().add(tpr.toString());
}
And this is the error I keep getting. Notice it's telling me the column doesn't exist, which is true because that is a value not a column name. Any ideas??? I know it may be something simple, I just can't seem to ding the anwser.
The query you are sending is
SELECT sp_search_test_ui_test_prog_revision(mnf0306aa)
Do you notice the missing single quotes around the string? That is why PostgreSQL interprets it as a column name and complains that the column does not exist.
Composing queries with string concatenation is dangerous, it exposes you to the dangers of SQL injection. If device contains a single quote, your statement would cause an error or worse – a skilled attacker could do anything with your database.
Use the power of prepared statements to avoid that danger:
java.sql.PreparedStatement statement =
pgConn.prepareStatement("SELECT * FROM sp_search_test_ui_test_prog_revision(?)";
statement.setString(1, device);
java.sql.ResultSet rs = statement.executeQuery();

passing parameter in sql server script file in java

I have sql files in my pc:
Example: C:\Users\User\Desktop\Queries\test.sql
Query in test.sql example :
Select * from table where colname like '%me%';
I am running this in a java program like this:
FileReader SomeName = new FileReader("C:\Users\User\Desktop\Queries\test.sql");
ResultSet rsjs = null;
rsjs = jsscript.runScript(myconn, SomeName);
This is working fine, but now I need a way to pass parameter in this sql file so that the query will be like:
Select * from table where colname like #parameter;
Is it possible?
PS: I cannot use query directly in java program. I know how to pass the parameter in query but this question is related to pass parameter in sql file. store procedure is also out of option.
You should look into StrSubstitutor https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/text/StrSubstitutor.html.
The sql string can have variables as:
String query = "Select * from table where colname like ${parameter};"
Then create a map like:
Map<String, String> values = new HashMap<>();
values.put("parameter", "%me%");
Now you can replace the variables using:
StrSubstitutor sub = new StrSubstitutor(values);
return sub.replace(query);
Edit 1:
If the query is coming from a file, you can read the file and store it in a string. Look into Files.readAllLines(path, charset)

Retrieving Data from multiple tables from Database

I have some tables in a database. They have some particular pattern. For example, consider I have table employee, then some other table with same pattern like:
table 1:employee
table 2:employee_X
table 3:employee_Y
I want to check if these tables contain data or not and if they do then I have to call some method for each table. I am using following code to retrieve.
DatabaseMetaData meta = con.getMetaData();
ResultSet res = meta.getTables(null, null, "My_Table_Name", new String[] {"TABLE"});
while (res.next()) {
if(rs.getStrin(3).equals(employee)){
//my code to write data of this table to a file
}
if(rs.getString(3).equals(employee_X)){
//my code to write data to the same file
}
if(rs.getString(3).equals(employee_Y)){
//code to write data to the same file from this table
}
}
The code is working fine, but how I can retrieve data from all these tables at once instead of using three checks. If any of these table contains data I want to write it to my file. How I can perform this operation in less lines of code and efficiently?
It would be great if anyone can suggest way to check each of these table either contain data or not in a single statement and then I can call my code to write data to file.
You can use UNION statement in your complex query. Please, check example:
SELECT id, name FROM employee WHERE id = ?
UNION
SELECT id, name FROM employee_x WHERE id = ?
UNION
...
Also you can use UNION ALL statement instead of UNION. The main difference that UNION returns unique result set without duplicates, UNION ALL allows duplicates. Please, check this link https://www.w3schools.com/sql/sql_union.asp for detailed explanation about union statement.
If you need create UNION query with custom filtered tables, please check example:
Set<String> requiredTables = new HashSet<>();
// fill set with required tables for result query
requiredTables.add("employee");
ResultSet res = meta.getTables(null, null, "My_Table_Name",
new String[] {"TABLE"});
List<String> existentTables = new LinkedList<>();
while(res.next()) {
if (requiredTables.contains(res.getString(3)) {
existentTables.add(res.getString(3));
}
}
String query = existentTables.stream().map(table -> String.format("SELECT * FROM %s", table)).collect(Collectors.joinning(" UNION "));

Multipoint from database using Geotools

I just want to know how to create an instance of a Multipoint from a PostGIS database.
I do the query, then get a ResultSet named area. The column with MultiPolygon attributes is named geom, so I do the following:
MultiPolygon m = (MultiPolygon)area.getObject("geom");
Forced cast doesn't work though!
You shouldn't be referencing the ResultSet directly but should work through the datastore interface which takes care of the conversion for you. See the Query Tutorial for an example of searching a dataset and retrieving geometries.
You'll need something like:
SimpleFeatureSource source = dataStore.getFeatureSource(typeName);
FeatureType schema = source.getSchema();
String name = schema.getGeometryDescriptor().getLocalName();
Filter filter = CQL.toFilter(text.getText());
Query query = new Query(typeName, filter, new String[] { name });
SimpleFeatureCollection features = source.getFeatures(query);

Categories