DB2 for z/OS: node comparison in XQuery - db2

We have a view as below
CREATE VIEW CORE_V_LOG_OUTPUT AS
select SERIAL, xtab.OUTPUT_ROW, xtab.OUTPUT_NAME, xtab.OUTPUT_VALUE
FROM bizzcore_log, XMLTable('declare namespace s="http://xml.snow.com/bizz/logging";
for $i in $x/s:Info/s:Output/s:rowValues/s:value
return document { <row> <num>{count($i/../../s:rowValues[. << $i/../.]) +1} </num>
<col>{$i/../../s:columnNames/s:name[count($i/../*[. << $i]) +1]}</col>
{if (($i/.)[1]/#value) then <val>{ string(($i/.)[1]/#value)} </val>
else <dummy></dummy>} </row> }'
PASSING Info as "x" COLUMNS OUTPUT_NAME VARCHAR(256) PATH '/row/col',
OUTPUT_VALUE VARCHAR(256) PATH '/row/val',OUTPUT_ROW INT PATH '/row/num') xtab;
We can create the view on DB2 LUW and DB2/400 successfully. But creating the view on DB2 V10 for z/OS will get below error:
SQLCODE=-16031, SQLSTATE=10509, SQLERRMC=node comparison
So node comparison is not supported by DB2 for z/OS. Now my question is how can I write the view in other ways using XQuery (or not)?
Please show me some light on this, appreciated!

Apprantely DB2 V10 for z/OS doesn't support node comparison for now. So no easy solution for this issue.

Related

Trigger to PostgreSQL JDBC writes successfuly first time, fails after

I have a project for sending data from DB2 on an IBM system over to a PostgreSQL server on a RHEL system. I am using a trigger that sends information to a data queue, which then gets read and sent over to the PostgreSQL server using a SQL statement through a JDBC connection on RPGLE.
The code is (more or less) as follows (I had to remove actual column and table names for security reasons):
dcl-proc doPostgreConn export;
dcl-pi doPostgreConn like(connection) end-pi;
//Code to change and set CLASSPATH variable, if necessary is here
//...
prop = JDBC_Properties();
JDBC_setProp(prop: 'user' : 'user');
JDBC_setProp(prop: 'password' : 'password');
JDBC_setProp(prop: 'databaseName' : 'database');
JDBC_setProp(prop: 'loggerLevel' : 'TRACE' );
JDBC_setProp(prop: 'loggerFile' : '/home/PostgreSQL/log');
pgconn = JDBC_ConnProp('org.postgresql.Driver'
:'jdbc:postgresql://[some_IP]:5432/database'
: prop );
JDBC_freeProp(prop);
return pgconn;
end-proc;
dcl-proc doPGWriteMyTable export;
dcl-pi doPGWriteMyTable like(success);
i#schm char(10);
i#rec char(334);
end-pi;
dcl-ds record extname('MYTABLE') end-ds;
dcl-s prepStmtTxt varchar(10000);
record = i#rec;
pgconn = doPostgreConn;
if pgconn = *NULL;
//Custom Error Handling
endif;
prepStmtTxt = 'INSERT INTO ' + %trim(i#schm) + '.MYTABLE ' +
' VALUES (?, ?, ?) ';
if PGWriteMYTABLEPrep = *NULL;
PGWriteMYTABLEPrep = JDBC_PrepStmt(pgconn:prepStmtTxt);
if PGWriteMYTABLEPrep = *NULL;
endif;
endif;
JDBC_setString (PGWriteMYTABLEPrep: 1: StrCol);
JDBC_setDecimal (PGWriteMYTABLEPrep: 2: DecCol);
JDBC_setDate (PGWriteMYTABLEPrep: 75: DateCol);
if JDBC_execPrepUpd( PGWriteMYTABLEPrep ) < 0;
//Custom Error Handling
endif;
JDBC_Close(pgconn);
return *on;
end-proc;
dcl-proc doPGDeleteMYTABLE export;
dcl-pi doPGDeleteMYTABLE like(success);
i#schm char(10);
i#rec char(334);
end-pi;
dcl-ds record extname('MYTABLE') end-ds;
dcl-s sqlstmt varchar(32000);
dcl-s deleteSuccess ind;
record = i#rec;
sqlstmt = 'DELETE FROM ' + %trim(i#schm) + '.MYTABLE WHERE '; //Basically the key
pgconn = doPostgreConn;
if JDBC_ExecUpd(pgconn:sqlstmt) < 0;
//Custom error handling
endif;
DoPostgreClose(pgconn);
return *on;
end-proc;
The data queue read program essentially calls DoPGDeleteMYTABLE and then DoPGWriteMYTABLE, in that order (There is no unique key, so we simply delete all of the matching records on the PostgreSQL server and then re-add them).
The problem is, while the data queue read program is running, the first loop works perfectly fine, and then fails. The order goes like this:
Record updated
Delete any existing PG records: successful
Prepare the write statement: successful
Write any existing DB2 records to PG: successful
Record updated
Delete any existing PG records: successful
Prepare the statement: successful
Write any existing DB2 records to PG: unsuccessful
repeat 5 through 8 until data queue job is restarted
The errors I receive are not very helpful. The job log on the AS400 simply tells me
org.postgresql.util.PSQLException: This connection has been closed.
even though I can see the open connection on the PostgreSQL server, and closing it from RPGLE does still work.
The JDBC job log does not tell me any information around the time the write happens. It just says that the prepare was successful, and then nothing.
Version information:
IBM OS 7.4
PostgreSQL 13.7 on x86_64-redhat-linux-gnu, compiled by gcc (GCC) 11.2.1 20220127 (Red Hat 11.2.1-9), 64-bit
PostgreSQL JDBC Driver postgresql-42.2.19
RPGLE is utilizing Scott Klement's JDBCR4
Nothing I have found online has yet to help with the issue. If there is anything else I can provide or try in order to get more information, please let me know.
I don't see anything that jumps out in the code you've posted, but given that it works the first time an fails the second, I'd guess something is reset (or not reset) between loops.
Personally, I'd recommend opening the connection once outside the DELETE/WRITE procs; but I don't think it's a fix.
The "connection closed" is interesting...might be worthwhile to run a comm trace to see if in fact the connection is being closed and if so from what side.
Note, while I love RPG, I'm not a fan of calling Java from RPG. I did some benchmarking long, long ago and it was much faster to have a small java app handle JDBC rather than using it from RPG.
You might also consider an Open Source alternative to calling Java directly from RPG.
AppServer4RPG
Application Server to make Java Components available for IBM i RPG programs, runs on IBM i or any other Java platform. Packaged with ArdGate to access any JDBC database using all native SQL interfaces from IBM i.
ArdGate basically registers itself as a DRDA Application Requester Driver (ARD) and allow you to talk to any JDBC database like you would any other remote DRDA (aka Db2) database.
Which means, you could read/write to PostgreSQL from the green screen STRSQL.
I finally got it figured out. It was a dumb thing that I didn't realize I needed to do - turns out you have to free the prepared statement after using it the first time.
Using JDBCR4, you just call (using my example)
JDBC_FreePrepStmt(PGWriteMYTABLEPrep);
Which looks like this, if anybody needs info that doesn't use JDBCR4:
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* JDBC_FreePrepStmt(): Free prepared statement
*
* prep = (input) Prepared Statement to Free
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P JDBC_FreePrepStmt...
P B export
D JDBC_FreePrepStmt...
D PI
D prep like(PreparedStatement)
/free
stmt_close(prep);
DeleteLocalRef(JNIENV_P: prep);
prep = *NULL;
/end-free
P E
In the end, a very poorly worded error, with a very simple solution.

Reading multiple child nodes in XML using openxml (SQL Server 2005)

XML Tree is -
<OrderLine>
<Item>ABC</Item>
<Lot>
<Serial>SR1</Serial>
<Quantity>1</Quantity>
</Lot>
<Lot>
<Serial>SR1</Serial>
<Quantity>1</Quantity>
</Lot>
</OrderLine>
While trying to parse this tree for element values using openxml in SQL Server 2005 (stored procedure) only one is read.
Here's the code -
select item, lots
from openxml(#intDataAreaRoot, 'OrderLine', 2)
with ( item nvarchar(31) 'Item',
lots xml 'Lot'
)
I use this to declare a cursor and then parse & process as many lines as there may be in the tree. But each "fetch" brings only one "Lot" node. I need to process all "Lot" nodes under the "OrderLine" node.
Appreciate any help.
Try something like this, using the native XQuery support in SQL Server 2005:
DECLARE #intDataAreaRoot XML = '<OrderLine>
<Item>ABC</Item>
<Lot>
<Serial>SR1</Serial>
<Quantity>1</Quantity>
</Lot>
<Lot>
<Serial>SR2</Serial>
<Quantity>21</Quantity>
</Lot>
</OrderLine>'
SELECT
Item = #intDataAreaRoot.value('(/OrderLine/Item)[1]', 'varchar(25)'),
xc.value('(Serial)[1]', 'varchar(20)'),
xc.value('(Quantity)[1]', 'int')
FROM
#intDataAreaRoot.nodes('/OrderLine/Lot') AS XT(XC)
This gives me an output of :
Item (No column name) (No column name)
---------------------------------------------
ABC SR1 1
ABC SR2 21

PostgreSQL jsonb, `?` and JDBC

I am using PostgreSQL 9.4 and the awesome JSONB field type. I am trying to query against a field in a document. The following works in the psql CLI
SELECT id FROM program WHERE document -> 'dept' ? 'CS'
When I try to run the same query via my Scala app, I'm getting the error below. I'm using Play framework and Anorm, so the query looks like this
SQL(s"SELECT id FROM program WHERE document -> 'dept' ? {dept}")
.on('dept -> "CS")
....
SQLException: : No value specified for parameter 5.
(SimpleParameterList.java:223)
(in my actual queries there are more parameters)
I can get around this by casting my parameter to type jsonb and using the #> operator to check containment.
SQL(s"SELECT id FROM program WHERE document -> 'dept' #> {dept}::jsonb")
.on('dept -> "CS")
....
I'm not too keen on the work around. I don't know if there are performance penalties for the cast, but it's extra typing, and non-obvious.
Is there anything else I can do?
As a workaround to avoid the ? operator, you could create a new operator doing exactly the same.
This is the code of the original operator:
CREATE OPERATOR ?(
PROCEDURE = jsonb_exists,
LEFTARG = jsonb,
RIGHTARG = text,
RESTRICT = contsel,
JOIN = contjoinsel);
SELECT '{"a":1, "b":2}'::jsonb ? 'b'; -- true
Use a different name, without any conflicts, like #-# and create a new one:
CREATE OPERATOR #-#(
PROCEDURE = jsonb_exists,
LEFTARG = jsonb,
RIGHTARG = text,
RESTRICT = contsel,
JOIN = contjoinsel);
SELECT '{"a":1, "b":2}'::jsonb #-# 'b'; -- true
Use this new operator in your code and it should work.
Check pgAdmin -> pg_catalog -> Operators for all the operators that use a ? in the name.
In JDBC (and standard SQL) the question mark is reserved as a parameter placeholder. Other uses are not allowed.
See Does the JDBC spec prevent '?' from being used as an operator (outside of quotes)? and the discussion on jdbc-spec-discuss.
The current PostgreSQL JDBC driver will transform all occurrences (outside text or comments) of a question mark to a PostgreSQL specific parameter placeholder. I am not sure if the PostgreSQL JDBC project has done anything (like introducing an escape as discussed in the links above) to address this yet. A quick look at the code and documentation suggests they didn't, but I didn't dig too deep.
Addendum: As shown in the answer by bobmarksie, current versions of the PostgreSQL JDBC driver now support escaping the question mark by doubling it (ie: use ?? instead of ?).
I had the same issue a couple of days ago and after some investigation I found this.
https://jdbc.postgresql.org/documentation/head/statement.html
In JDBC, the question mark (?) is the placeholder for the positional parameters of a PreparedStatement. There are, however, a number of PostgreSQL operators that contain a question mark. To keep such question marks in a SQL statement from being interpreted as positional parameters, use two question marks (??) as escape sequence. You can also use this escape sequence in a Statement, but that is not required. Specifically only in a Statement a single (?) can be used as an operator.
Using 2 question marks seemed to work well for me - I was using the following driver (illustrated using maven dependency) ...
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
</dependency>
... and MyBatis for creating the SQL queries and it seemed to work well. Seemed easier / cleaner than creating an PostgreSQL operator.
SQL went from e.g.
select * from user_docs where userTags ?| array['sport','property']
... to ...
select * from user_docs where userTags ??| array['sport','property']
Hopefully this works with your scenario!
As bob said just use ?? instead of ?
SQL(s"SELECT id FROM program WHERE document -> 'dept' ?? {dept}")
.on('dept -> "CS")

How to insert unicode string in PowerBuilder when using datastore/datawindow?

The SQL Insert statement below is used to insert unicode string and it is working successfully when executed in SQL Server Management Studio or Query Analyzer.
Column Specs:
SONUM VARCHAR(50)
CONTRACTNUM NVARCHAR(150)
FNAME VARCHAR(70)
INSERT INTO SCH_EDI_3B12RHDR ( SONUM, CONTRACTNUM, FNAME )
VALUES ( 'DPH11309160073CC' , N'Globe MUX Project(客户合同号:NA)' , 'TEST' )
Is it possible to implement the prefix N when using a datastore/datawindow for insert operation? If yes, how? Below is the current script in PB which successfully insert the data but the chinese character/s was replaced by '?'(question mark).
ls_sonum = String(dw_1.Object.shipmentOrderNum[1]) //This holds the value : DPH11309160073CC
ls_chinesechar = String(dw_1.Object.contractnum[1]) // This holds the value : Globe MUX Project(客户合同号:NA)
dw_1.SetItem(1,'sonum',ls_sonum)
dw_1.SetItem(1,'contractnum',ls_chinesechar)
dw_1.SetItem(1,'fname','TEST')
dw.AcceptText( )
IF dw.Update( ) = 1 THEN
Commit Using SQLCA ;
END IF
You need to hook yourself on the sqlpreview event of dw/ds and add the N' yourself. Or if you use static (or disable?) bind you don't need to do anything at all.
It's all explained in the online docs.
I verified that the OLE DB driver for PB version 10 supports Unicode. You can find the information in this Sybase document on page nine.
ODBC/ JDBC /OLEDB/ ADO.NET DATABASE SUPPORT
Client/Server PowerBuilder 10 applications can exchange Unicode and ANSI data with databases
supported by the ODBC, JDBC, OleDB, and ADO.NET database interfaces without requiring
special settings.
Suggestion would be to try forcing a different encoding when using the string function, there are four choices (see code example below)
The encoding parameter is one of the following:
■ EncodingANSI!
■ Encoding UTF8!
■ EncodingUTF16LE! – UTF-16 Little Endian encoding (PowerBuilder 10 default)
■ EncodingUTF16BE! – UTF-16 Big Endian encoding
// use the correct encoding for your actual data
ls_sonum = String(dw_1.Object.shipmentOrderNum[1], EncodingUTF16BE! ) //holds DPH11309160073CC
ls_chinesechar = String(dw_1.Object.contractnum[1], EncodingANSI!) // holds Globe MUX Project(客户合同号:NA)
It is possible that I'm leading you down the wrong path but I think this would be worth trying out and may solve the problem.

Text Search inside XML nodes with a specific Attribute in DB2 express-C

Have installed DB2 express-C 9.7 on Win7, and am using the DB2 Text Search engine.
I have one requirement to search inside all XML nodes having a specific attribute. Have tried these options:
statement.executeQuery("xquery " +
"for $i in db2-fn:sqlquery(\"SELECT doc FROM orders WHERE CONTAINS(doc, '#xpath:''/order//#key[. contains (\"\"java\"\")]''') = 1\")/order " + "return $i/customer");
statement.executeQuery("xquery " +
"for $i in db2-fn:sqlquery(\"SELECT doc FROM orders WHERE CONTAINS(doc, '#xpath:''/order//#key[.. contains (\"\"java\"\")]''') = 1\")/order " + "return $i/customer");
Here am unsuccessfully trying to search for all those xml documents which have 'java' inside all child elements (of 'order' node) having an attribute 'key'.
May anyone please tell me what should be the right query for this.
Thanks.