How do I create an index online with liquibase? - oracle

I have a migration that will create an index in a table of our Oracle database. The DBA would like the index to be created ONLINE. (Something like CREATE INDEX ..... ONLINE;) Is there something I can add to the tag below to accomplish what I want or do I need to write the SQL into the migration?
<createIndex tableName="USER" indexName="IX_USER_TX_ID">
<column name="TX_ID" />
</createIndex>

There is no standard tag to specify it as ONLINE. Your 3 options to create it as ONLINE are:
Fall back to the tag where you specify the exact SQL you want
Use the modifySql tag to append to the generated SQL.
Create an extension to createIndex that always generates ONLINE at the end of the SQL or adds a parameter to createIndex that allows you to control if it is added or not.
Option #2 is probably the best mix of easy yet flexible and would look something like this:
<changeSet id="1" author="nvoxland">
<createIndex tableName="USER" indexName="IX_USER_TX_ID">
<column name="TX_ID" />
</createIndex>
<modifySql dbms="oracle">
<append value=" ONLINE"/>
</modifySql>
</changeSet>
Notice the space in the value tag. Append does a very simple text append with no built-in logic.

Related

How to write a custom where clause in JPA orm.xml file

My Springboot application has orm.xml file in my WEB-INF folder.
I have few named native queries in the orm.xml file.
I want to add a where condition in the query based on the values in the parameter to the query.
I am looking for some thing like this:
<named-native-query name="MyReport.countInventory">
<query>
SELECT COUNT(*) AS COUNT
FROM
Inventory
WHERE
<if :date>
add_date = :date
</if>
</query>
</named-native-query>
This is not possible with JPA.
It just allows straight-forward SQL statements without any conditional processing.
In many cases, one can actually implement the required conditional logic in SQL itself as Turo described in his/her comment.
Since you are seeming to be using Spring Data JPA you can also use Specifications to dynamically create conditions.
Another alternative would be to use MyBatis which allows constructing SQL statements in a way similar to what you outline in your question.
The following example is taken from http://www.mybatis.org/mybatis-3/dynamic-sql.html
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>

CRM Configuration Migration - Currency

I create a record in CRM that contains an option set and 4 currency fields, I export the record using the CRM Configuration Migration tool, I delete the record in CRM, and finally I import the record that I just exported. After the import I was expecting to see a record identical to the one that I exported and deleted however the option set field is populated but none of the currency fields are populated - weird. I open the zip file that was created by the export process, I open the data.xml file within it, and I locate one of the currency fields:
<field name="new_rate1" value="&#163;‎1.00" />
<field name="new_rate1_base" value="&#163;‎1.00" />
If I manually remove the '£' from the first row, i.e.
<field name="new_rate1" value="‎1.00" />
<field name="new_rate1_base" value="&#163;‎1.00" />
and import the data the currency field value will be imported correctly. Surely I shouldn't have to manually edit the XML file. I believe that this is either a bug in Configuration Migration tool or that I am doing something wrong, but I can't think what. Does anyone have any thoughts or ideas?

DB Insert if not present - Spring Integration

We have a int-jms:message-driven-channel-adapter --> a transformer --> a filter --> another transformer --> int-jdbc:outbound-channel-adapter (to insert in table_1)
(considering --> as channels)
I want to change this flow to insert into 2 tables instead of 1 but for table_2 I want to insert only if data corresponding to some fields in the message is already not present in the table i.e. insert if not present.
One thing I figured is that I will now need a pub-sub-channel with ignore-failures=false to split the flow into 2 tables.
My question is that what component should I use to select the data to check if data exists in table_2? I first thought inbound-channel-adapter is the right choice but couldn't figure out how to slide it between 2 components i.e. say a transformer and outbound-channel-adapter.
Some things I can think of are:
1. Use a filter, passing it jdbcTemplate so that the filter itself can fire a JDBC query to accept if record doesn't exist.
2. Use a outbound-channel-adapter and the insert query should have the check for data existence also, something like insert-if. I am not sure if Oracle has something like this. I am researching.
Please point me to an example or documentation or tell me the best way.
Thanks
Actually you can use
<chain>
<header-enricher>
<header name="original" expression="payload"/>
</header-enricher>
<int-jdbc:outbound-gateway query="SELECT count(*) from TABLE where ..."/>
<filter expression="payload == 0"/>
<transformer expression="headers.original"/>
</chain>
From other side <filter> with JdbcTemplate direct usage is good choice too.
Re. insert-if. It can work too if you have a unique constraint on the table. In this case an Exception will be thrown. And if you have <publish-subscribe-channel ignore-failures=false>, it would work too.

Hibernate reverse engineers (oracle) NUMBER to zero-precision big_decimal

When reverse engineering a column in an Oracle view with data type "NUMBER", the resultant column in *.hbm.xml is a big_decimal with precision="0".
I also use these mapping files with Derby to do acceptance tests, but from the Derby docs:
The precision must be between 1 and 31.
I do not have control over the definition of the view. I read through the reverse engineering docs and I can't see a way of controlling the precision.
How do I instruct hibernate to give me a valid (derby) precision?
you should modify hibernate.reveng.xml as example below with your needs (precision,scale) and set output type (hibernate-type) then generate classess and mapping files.
<hibernate-reverse-engineering>
<type-mapping>
<sql-type jdbc-type="NUMERIC" precision="1" scale="0" hibernate-type="boolean"/>
<sql-type jdbc-type="NUMERIC" precision="22" scale="0" hibernate-type="long"/>
<sql-type jdbc-type="OTHER" hibernate-type="..."/>
</type-mapping>
....

Mapping a long text string in Oracle and NHibernate

Using NHibernate 3.1 with both SQL Server and Oracle DBs, we need to store a text string that is longer than 4000 characters. The text is actually XML, but that is not important - we just want to treat it as raw text. With SQL Server, this is easy. We declare the column as NVARCHAR(MAX) and map it thusly:
<property name="MyLongTextValue" length="100000"/>
The use of the length property tells NHibernate to expect a string that may be longer than 4000 characters.
For the life of me, I cannot figure out how to make this work on Oracle 11g. I've tried declaring the column as both XMLTYPE and LONG with no success. In the first case, we end up with ORA-01461: can bind a LONG value only for insert into a LONG column when trying to insert a row. In the second case, the data is inserted correctly but comes back as an empty string when querying.
Does anyone know how to make this work? The answer has to be compatible with both SQL Server and Oracle. I'd rather not have to write custom extensions such as user types and driver subclasses. Thanks.
You should use something like this
<property name="MyLongTextValue" length="100000" type="StringClob"
not-null="false"/>
This should work with Oracle CLOB type and SqlServer NTEXT type.
Make sure the property on your model is nullable
public virtual string MyLongTextValue {get;set;}
You should always use the Oracle.DataAccess when dealing with CLOBs
For whom this may interest, I solved my problem following the step 3 of this article:
3. Using correct Mapping attributes: type="AnsiString"
Normally we can use type="String" default for CLOB/NCLOB. Try to use > type="AnsiString" if two steps above not work.
<property name="SoNhaDuongPho" column="SO_NHA_DUONG_PHO" type="AnsiString"/>
In my case I set it with FluentNHibernate:
.CustomType("AnsiString")
You might be interested in this article.
<property column="`LARGE_STRING`" name="LargeString" type="StringClob" sql-type="NCLOB" />

Resources