Hibernate: java.sql.BatchUpdateException: ORA-01732 on immutable view - oracle

First, see the Hibernate mapping excerpts: there are mutable ParentObjects in an Oracle DB TABLE referencing immutable ChildObjects in an Oracle DB VIEW:
1) there is a set of ChildObjectInView inside a ParentObject, defined as not mutable, without cascading:
<class name="ParentObject" table="t_parentobject">
...
<set name="childObjectsInView" cascade="none" lazy="true" mutable="false">
<key column="coivId" />
<one-to-many class="com.it.ChildObjectInView"/>
</set>
</class>
2) the ChildObjectInView is defined as
<class name="ChildObjectInView" table="view_coiv" mutable="false" lazy="true">
...
<many-to-one name="parentObject" column="parentObjectId" update="false" insert="false" class="com.it.ParentObject" not-null="true" outer-join="true">
</many-to-one>
</class>
Calling com.it.TestServiceImpl.saveParentObject() results in an Oracle error ORA-01732: data manipulation operation not legal on this view, although mutable="false" attributes in the hibernate mappings are set. Why this error?
com.it.TestBean|could not delete collection: [com.it.ParentObject.childObjectsInView#398500]
org.hibernate.exception.SQLGrammarException: could not delete collection: [com.it.ParentObject.childObjectsInView#398500]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.collection.AbstractCollectionPersister.remove(AbstractCollectionPersister.java:1071)
at org.hibernate.action.CollectionRemoveAction.execute(CollectionRemoveAction.java:28)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at com.it.TestServiceImpl.saveParentObject(TestServiceImpl.java:418)
Caused by: java.sql.BatchUpdateException: ORA-01732: data manipulation operation not legal on this view
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10296)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:216)
at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.BatchingBatcher.addToBatch(BatchingBatcher.java:34)
at org.hibernate.persister.collection.AbstractCollectionPersister.remove(AbstractCollectionPersister.java:1048)
... 69 more

I finally found out by myself that there were cases in that a ParentObject was newly created with the set ParentObject.childObjectsInView being set to null.
Saving this newly created ParentObject Hibernate tried to run a DELETE FROM <view> WHERE id=<objectid>. This statement is like a reset of all objects inside ParentObject.childObjectsInView.
I think this default behavior of Hibernate is wrong at this place, a bug report should be opened: Hibernate has the information that the child is immutable so any manipulating SQL should be suppressed.
Workaround:
Assure that an empty collection is always set to ParentObject.childObjectsInView (instead of null).

Related

Ignite Cassandra cache configuration - CodecNotFoundException

I am trying to configure Cassandra as a persistent store for an Apache Ignite 2.0 cache. As a test, I am trying to map key-value pairs to this simple Cassandra table:
CREATE TABLE ignite.cache_test(
key text PRIMARY KEY,
value int)
That's the associated persistence configuration xml I am using:
<persistence keyspace="ignite" table="cache_test" ttl="86400">
<keyspaceOptions>
REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1}
AND DURABLE_WRITES = true
</keyspaceOptions>
<tableOptions>
comment = 'Cache test'
AND read_repair_chance = 0.2
</tableOptions>
<keyPersistence class="java.lang.String" strategy="PRIMITIVE" column="key" />
<valuePersistence class="java.lang.Integer" strategy="PRIMITIVE" column="value" />
</persistence>
When I try to put elements in the cache using the Ignite REST interface I get:
com.datastax.driver.core.exceptions.CodecNotFoundException: Codec not found for requested operation: [int <-> java.lang.String]
as if I am trying to map int to String type. I am sure it is a silly configuration error, but I tried several combinations with no success.
For completeness, that's the http call I am sending:
http://localhost:8080/ignite?cmd=put&key=testkey&val=1&cacheName=cache1
Thank you all for the help
Change the type of value to text
So the table schema :
CREATE TABLE ignite.cache_test(
key text PRIMARY KEY,
value text
);
And the configuration :
<persistence keyspace="ignite" table="cache_test" ttl="86400">
<keyspaceOptions>
REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1}
AND DURABLE_WRITES = true
</keyspaceOptions>
<tableOptions>
comment = 'Cache test'
AND read_repair_chance = 0.2
</tableOptions>
<keyPersistence class="java.lang.String" strategy="PRIMITIVE" column="key" />
<valuePersistence class="java.lang.String" strategy="PRIMITIVE" column="value" />
</persistence>

Mule: Invoking an Oracle stored procedure which returns a table of custom type

I am using Mule CE 3.6.1. I have the following Database connector configuration calling an Oracle stored procedure.
<db:stored-procedure config-ref="Oracle_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[call get_phone_email(:userId, :tPhoneRecord)]]></db:parameterized-query>
<db:in-param name="userId" type="NUMERIC" value="#[payload]" />
<db:out-param name="tPhoneRecord" type="ARRAY" />
</db:stored-procedure>
Parameter tPhoneRecord is defined as IS TABLE OF phone_email%ROWTYPE (i.e. table of records) in the stored procedure. I have tried specifying the parameter type ARRAY but get the error:
Message : Invalid argument(s) in call (java.sql.SQLException). Message payload is of type Object[]
Code : MULE_ERROR--2
I have also tried using other out-param types or not specifying a type without success.
Please let me know what out-param type I should use for an Oracle table of records, or if I should do this in Java instead. Many thanks in advance.
You can use the below solution for out parameter.
<db:oracle-config name="Oracle_Configuration" url="jdbc:oracle:thin:#54.175.245.218:1581:xe" user="user" password="4321" >
</db:oracle-config>
<db:data-type name="INtypename" id="12"/>
<!-- VARCHAR id=12 -->
<db:data-type name="OUTtypename" id="2002"/>
<!-- STRUCT id=2002 -->
</db:data-types>
...
<db:stored-procedure config-ref="Generic_Database_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[CALL storedprocfnc(:INtypename,:OUTtypename);]]></db:parameterized-query>
<db:in-param name="INtypename" value="#[payload]"/>
<db:out-param name="OUTtypename" />
</db:stored-procedure>

Mule exec Oracle Stored Procedure

Could someone share how to call a stored procedure under Mule CE, using named parameters?
I would like to use the JDBC component or the new one DB component under AnyPointConnect 3.5
Please find the Procedure calling syntax in Mule 3.6
<db:stored-procedure config-ref="Oracle_Configuration1" doc:name="Database">
<db:parameterized-query><![CDATA[{call apps.create_sales_Order(:p_header_rec_oper,:P_order_number,:P_ordered_date,:P_line_id,:p_flow_Status_code,:P_return_status)}]]></db:parameterized-query>
<db:in-param name="p_header_rec_oper" value="CREATE"/>
<db:out-param name="P_order_number" type="INTEGER"/>
<db:out-param name="P_ordered_date" type="DATE"/>
<db:out-param name="P_line_id" type="VARCHAR"/>
<db:out-param name="p_flow_Status_code" type="VARCHAR"/>
<db:out-param name="P_return_status" type="VARCHAR"/>
</db:stored-procedure>
{
• P_return_status: "S",
• P_line_id: "684229",
• p_flow_Status_code: "ENTERED",
• P_ordered_date: "2015-05-22",
• P_order_number: 69393
}
You can call store procedures using the Database element like this
<transactional action="ALWAYS_BEGIN" doc:name="My_Transaction">
<db:stored-procedure config-ref="My_Database_Configuration" doc:name="Database">
<db:parameterized-query><![CDATA[call my_procedure(:p_param1,:p_param2,:p_output)]]></db:parameterized-query>
<db:in-param name="p_param1" type="VARCHAR" value="#[flowVars.param]"/>
<db:in-param name="p_param2" type="VARCHAR" value="#['Hardcoded_value']"/>
<db:out-param name="p_output" type="VARCHAR"/>
</db:stored-procedure>
</transactional>
In this example I've put the procedure call in an transactional scope.
You also have to declare the db configuration before with the datasource

eXist db index not used in xquery

I have stored in my eXist db nodes of the following type:
<Order ID="170473" LnkID="8288374995" OrignDt="2003-07-08" TrdDt="2003-07-09" Acct="104158163" AcctIDSrc="99" DayBkngInst="ingrated" BkngUnit="hobbyhorse" SettlDt="2003-07-28" ClrFeeInd="B" HandlInst="3" MinQty="2088.58" ProcCode="1" Side="2"
LocReqd="N" TxnTm="2003-07-06T08:44:24" QtyTyp="0" Typ="A" PxTyp="4" Px="4258.33" Ccy="USD" SolFlag="N" IOIID="8596226323" ExpireDt="2003-06-19" GTBkngInst="2" Cpcty="A" Rstctions="A" CustCpcty="1660" ForexReq="Y" SettlCcy="inclination" Txt="eats" EncTxt="pendulous" Qty2="4028.86" MaxShow="1636.80" CxllationRights="M" MnyLaunderingStat="N" Designation="tied" >
<Hdr SID="997453497" D2ID="5969180787" SSub="swiftest" D2Sub="flay" PosDup="N" Snt="2003-10-24T12:13:50" OrigSnt="2003-07-19T00:23:46" MsgEncd="lechery" ><Hop ID="9148044310" Ref="33787" Snt="2003-08-24T21:26:11"></Hop>
</Hdr><Pty ID="8059449011" Src="H" ><Sub ID="228" ></Sub></Pty>
<Instrmt Sym="VRTS" Sfx="CD" ID="8962619773" Src="5" CFI="entrances" MatDt="2003-12-09" CpnPmt="2004-06-12" Issued="2004-05-14" RepoTrm="2749" CrdRtg="dad" IssuCtry="purpose" Redeem="2003-10-17" Strk="2028.23" StrkCcy="posterns" Exch="religiously" EncSecDescLen="4238" Pool="separation" IntAcrl="2003-08-17" ></Instrmt>
<OrdQty Qty="3652" Cash="3036.44" Pct="3882.34" RndDir="2" RndMod="1819.70" ></OrdQty>
</Order>
I would like to have an index for the ID attribute. My configuration file is:
<collection xmlns="http://exist-db.org/collection-config/1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<index>
<create qname="#ID" type="xs:string"/>
</index>
<triggers>
<trigger class="org.exist.extensions.exquery.restxq.impl.RestXqTrigger"/>
</triggers>
The index I have created is only used in pure xpath queries, such as
//Order[#ID ="170475"]
but not in xquery queries such as:
for $ord in//Order/#ID
where $ord = "150985"
return $ord
Is there any way to fix this?
Please try to change your query into
for $ord in//Order
where $ord/#ID = "150985"
return $ord
The query engine tries to rewrite your expression in order to use the index. It will fail analyzing your previous formulation, but should succeed on the one above.
The general recommendation is to use XPath statements with filters where possible, because they are easier to rewrite automatically.
It is documented that the eXist-db xquery processor has difficulties to optimize queries with the where clause.
Although your second query is syntactically correct, it is recommended to use the XPATH equivalent.

camel-mybatis - issues with calling Oracle Stored procedure with multiple resultsets

I am using camel-mybatis (version 2.12) component in Fuse 6.1 environment to invoke an oracle SP with 2 resultsets. The request is a HashMap and once mybatis maps the resultsets to java beans, the List is again saved in the original HashMap itself.
Here is the snippet of SqlMap:
<select
id="searchUsers"
parameterType="java.util.HashMap"
statementType="CALLABLE">
{call ORACLE.SP_NAME_1(
#{userId,mode=IN,jdbcType=VARCHAR},
#{maxResultsCount,mode=IN,jdbcType=DECIMAL},
#{view,mode=IN,jdbcType=VARCHAR},
#{statusInfo,mode=OUT,jdbcType=CURSOR,resultMap=statusInfoRowMap},
#{memberInfo,mode=OUT,jdbcType=CURSOR,resultMap=claimInfoRowMap})}
And here is how I invoke the mybatis component:
<setBody>
<groovy>
[
userId:'ID-1234',
maxResultsCount:20,
view:'MEMBER',
]
</groovy>
</setBody>
<to uri="mybatis:searchUsers?statementType=SelectOne" />
Since there are no result object (all the results are stored in the original requested HashMap itself), MyBatisProducer is setting null to exchange OUT message. The original body which contains the results from stored procedure is lost.
The Question is: is this the expected behaviour? mybatis component already stores the result in exchange header, so why to update the body as well?
The workaround I had to do was - to store the original body to a header, invoke mybatis and reset body from the header (which has the stored procedure result now) :
<setBody>
<groovy>
[
userId:'ID1234',
maxResultsCount:20,
view:'MEMBER'
]
</groovy>
</setBody>
<setHeader headerName="originalRequest">
<simple>${body}</simple>
</setHeader>
<to uri="mybatis:searchUsers?statementType=SelectOne" />
<setBody>
<simple>${in.headers.originalRequest}</simple>
</setBody>
<log message="status: ${body[statusInfo]}" />
Any help would be appreciated.. Thanks.
Ah well spotted. Log a JIRA ticket so we can improve this and avoid setting the body to null, when you use a stored procedure.
There is a link to the issue tracker here
http://camel.apache.org/support

Resources