Blog do projektu Open Source JavaHotel

poniedziałek, 25 lutego 2013

Byliśmy na koncercie

Dnia 16 lutego 2013 roku byliśmy w Filharmonii Narodowej na wykonaniu oratorium Haendla "Saul". Podobało nam się bardzo. "Saul" to ogromne i niezwykle efektowne dzieło, tutaj wykonywane przez połączone siły chóru i orkiestry Filharmonii Narodowej i solistów z Warszawskiej Opery Kameralnej, których prowadził znakomity dyrygent Helmuth Rilling. Bardzo się podobał Jan Monowid (kontratenor) śpiewający rolę Dawida. Wykonanie arii "O Lord, whose mercies numberless", gdzie w drugiej połowie dołącza się harfa, zapadało w pamięć.  Solistów śpiewających główne role protagonistów biblijnego dramatu wspierali z ogromnym powodzeniem chórzyści, np. w dramatycznej partii czarownicy z Endoru wezwanej przez Saula przed decydującą bitwą z Filistynami, tutaj śpiewanej bardziej zgodnie z rzeczywistością przez sopran, a nie przez tenor (jak jest w partyturze). Wspaniałe było wysłuchanie na żywo rzadko spotykanego karylionu w środkowej części, gdzie kobiety z Izraela śpiewają unisono z tym instrumentem "Pobił Saul tysiące, a Dawid dziesiątki tysięcy".
"Saula" można wykonywać w formie dramatycznej, tutaj było przestawienie statyczne. Na scenie Filharmonii Narodowej, gdzie z trudem się mieścili wszyscy wykonawcy, raczej niemożliwe byłoby wygospodarowanie dodatkowej przestrzeni na zainscenizowanie widowiska. Dramatyzm był jedynie sygnalizowany przez ruchy solistów, którzy w trakcie śpiewania zwracali się do siebie. Nie był to jednak dobry pomysł, gdyż sprawiał wrażenie sztuczności.
"Saul" to wspaniałe widowisko, niezbyt często wykonywane ze względu na złożoność przedstawienia. Trzeba się cieszyć, że Filharmonia Narodowa podjęła się tego trudu, kto był na pewno nie żałował.

niedziela, 10 lutego 2013

Jython, DB2 and overloaded stored procedures

Problem
DB2 allows stored procedure overloading.

CREATE TABLE TMESSAGE (WHAT CHAR(1), MESS VARCHAR(200))@

CREATE OR REPLACE PROCEDURE PUTM (IN MESS VARCHAR(200))
P1: BEGIN
  INSERT INTO TMESSAGE VALUES('A',MESS);
END P1
@

CREATE OR REPLACE PROCEDURE PUTM (IN MESS1 VARCHAR(200), IN MESS2 VARCHAR(200))
P1: BEGIN
  INSERT INTO TMESSAGE VALUES('B',MESS1 || ' ' || MESS2);
END P1
@

CALL PUTM('Hello')@

CALL PUTM('Another hello','Wow')@
Jython,zxJDBC 
But if one tried to execute this procedure from jython a nasty message would appear (make sure that you have a db2 JDBC driver somewhere in the classpath)
from com.ziclix.python.sql import zxJDBC

url = "jdbc:db2://think:50004/SAMPLE"
driver = "com.ibm.db2.jcc.DB2Driver"
conn =  zxJDBC.connect(url, "db2inst2", "db2inst2", driver)
cur = conn.cursor()
cur.callproc('PUTM',['Hello'])
conn.commit()
   cur.callproc('PUTM',['Hello'])
zxJDBC.Error: error setting index [3], type [12] [SQLCode: 0]
DB2 SQL Error: SQLCODE=-440, SQLSTATE=42884, SQLERRMC=PUTM;PROCEDURE, DRIVER=4.15.82 [SQLCode: -440], [SQLState: 42884]
DB2 SQL Error: SQLCODE=-727, SQLSTATE=56098, SQLERRMC=2;-440;42884;PUTM|PROCEDURE, DRIVER=4.15.82 [SQLCode: -727], [SQLState: 56098]
To find a clue it is necessary to run 'procedurecolumns' method:
cur.procedurecolumns(None,'DB2INST2','PUTM',None)
for r in cur.fetchall():
     print r
(None, u'DB2INST2', u'PUTM', u'MESS', 1, 12, u'VARCHAR', 200, 200, None, None, 1, None, None, 12, None, 200, 1, u'YES', u'SQL130209104619000')
(None, u'DB2INST2', u'PUTM', u'MESS1', 1, 12, u'VARCHAR', 200, 200, None, None, 1, None, None, 12, None, 200, 1, u'YES', u'SQL130209104619400')
(None, u'DB2INST2', u'PUTM', u'MESS2', 1, 12, u'VARCHAR', 200, 200, None, None, 1, None, None, 12, None, 200, 2, u'YES', u'SQL130209104619400')
zxJDBC does not differentiate between parameters from overloaded procedures and takes the whole output from 'procedurecolumns' to make a prepared statement '{ call PUTM(?,?,?) }' which obviously does not match any procedure signature. In order to get it running zxJDBC should group parameters by the last column  SPECIFIC_NAME and match against number of parameters in 'callproc' method to prepare a valid function call.
Workaround 
The temporary solution is simply do not use 'callproc' method and use the call escape sequence directly.
query = '{ call PUTM(?) }'
cur.executemany(query,['Hello'])
query = '{ call PUTM(?, ?) }'
cur.executemany(query,['Hello with two','Wow'])
Jython, DB2 stored procedure and CLOB 
I run into another problem also.
CREATE PROCEDURE CALLCB (IN PARAM CLOB(2M))
P1: BEGIN
  INSERT INTO TMESSAGE VALUES('E',PARAM);
END P1
cur = conn.cursor()
cur.callproc('CALLCB',['Hello'])
I fails with the DB2 error message:
   cur.callproc('CALLCB',['Hello'])
zxJDBC.Error: DB2 SQL Error: SQLCODE=-301, SQLSTATE=07006, SQLERRMC=1, DRIVER=4.15.82 [SQLCode: -301], [SQLState: 07006]
It seems that zxJDBC does not map string to clob parameter correctly. But after applying zxJDBC enhancer it works as expected.
class PyHandler(DataHandler):
    def __init__(self, handler):
        self.handler = handler
#        print 'Inside DataHandler'
    def getPyObject(self, set, col, datatype):
        return self.handler.getPyObject(set, col, datatype)
    def getJDBCObject(self, object, datatype):
#        print "handling prepared statement"
        return self.handler.getJDBCObject(object, datatype)
    def preExecute(self, stmt):
#        print "calling pre-execute to alter behavior"
        return self.handler.preExecute(stmt)

cur = conn.cursor()
cur.datahandler = PyHandler(cur.datahandler)
cur.callproc('CALLCB',['Hello'])
But I cannot explain that because the code above does not anything specific, it simply passes execution through.