Mapping to varchar and nvarchar in hibernate - sql

If there are 2 columns in database, eg.
code varchar(3)
name nvarchar(50)
How to tell hibernate to pass varchar for searching by code?
In the hibernate mappings string is mapped to nvarchar and it produces queries like:
Select code, name From table where code=N'AAA' (instead of code='AAA')
This is very bad as it causes index scan instead of index seek operation (scanning all index nodes instead of directly going to requested one)
As code is used in millions of rows as well as in several indexes and foreign keys, changing it from varchar to nvarchar will cause performance degradation (more IO operations as nvarchar uses twice more space than varchar).
Is there any way to tell hibernate to do mapping according to database type, not to Java type?
Thanks

Probably you already solved this, but I had a similar problem.
I'm using jTDS JDBC driver and I solved the index scan problem by adding:
;sendStringParametersAsUnicode=false;prepareSQL=0
to the end of the jTDS connection string.
Probably it would not had solved your problem because by doing this, jTDS will only use VARCHAR (no NVARCHAR anymore).
Also, I had to disable the prepared SQL, because Hibernate is using 'like' instead of '=' when generating the queries and by using 'like' combined with a variable (SELECT ... WHERE column LIKE #var) causes an index scan (MSSQL 2000).

I'm assuming you're talking about NHibernate rather than Hibernate because the latter does not use nvarchar in its default SqlServer dialect.
The way to solve your problem is to specify column type as "AnsiString" in your mapping:
<property name="Code" type="AnsiString"/>
Take a look at this post for more details.

<type-mapping>
<sql-type jdbc-type="NVARCHAR" hibernate-type="string" />
</type-mapping>
Add the above code in the hibernate reveng file.

In hibernate.properties set the property hibernate.connection.defaultNChar=false.
You can either hide your tables behind views or use nstring type. This type is available in hibernate-core 4.x. In hibernate-core 3.6.10.Final you will need to define the custom type nstring - see the comment in the url:
Getting Hibernate and SQL Server to play nice with VARCHAR and NVARCHAR.

Related

Oracle to SQL Server (SSIS) special character problems

I am trying to import data from Oracle to SQL Server through SSIS package data flow task.
One column has special characters and that column is also part of composite key in that table.
So after loading the data on SQL when I am trying to enforce the uniqueness it fails as while loading the data the special characters are getting converted to something else.
Is there any property or alternative so that the special characters are imported the way they are in Oracle.
Thanks in advance.
This seems to be a common issue from my experience.
I will try to describe some steps that might help you.
First, you need to disable the primary key column and run the dtsx again.
Second, you must locate the identical values which cause the primary key violation.
This means that two different chars are mapped to the same char probably and produces the error.
Take in mind that SSIS cannot read with UTF-8 from Oracle, you can see it for your self if you go to Advanced View in Oracle Source Object and inspect the input/output columns, usually, the code page is 1251.
The only solution is to use a Derived Column and replace the problematic character manually before the insert. Also, it will help more if you do this solution.
OracleDB->File->Derived Column->SQLServer

Hibernate native sql query

Perfectly fine ms-sql statement
SELECT distinct ProductLineCode ,
(SELECT CAST(ItemName + ', ' AS VARCHAR(MAX)) FROM Product spt
where spt.ProductLineCode = pt.ProductLineCode FOR XML PATH (''))
as ItemNames FROM Product pt where ProductLineCode is not null
cause error when executed as native query in hibernate.
org.hibernate.MappingException: No Dialect mapping for JDBC type: -16
I guess that JDBC type: -16 is boolean but that says me nothing. Product table has xml mapping and works well for months.
Could you please guide me what to try next?
You might as advised in comments be able to get something similar to work by changing the types in the sql.
But if that doesn't bring success, you might also be able to tell hibernate how to deal with this type by changing the Dialect class used by your application, possibly even extending the one currently used and adding a registration for the missing type.
It appears that your missing type mapping is for the type java.sql.Types.LONGNVARCHAR (by code grep, the value is -16), so a Dialect extension with a call something like
registerColumnType( Types.LONGNVARCHAR, "text" );
in the constructor may convince hibernate to treat this field as text.
If you do this you'll have to change the configuration to use your dialect by modifying the line
<property name="dialect">org.hibernate.dialect.SQLServer2012Dialect</property>
to use your own dialect class. (Note: the class in there is just a guess at what you might have there now.)
It's also possible that you just have hibernate using the wrong dialect for your DB, in which case just changing the configuration to the appropriate one would be better.
It's rarely necessary to use a custom Dialect, but this may be one of those times.

Get Hibernate to bind parameter type "char(1)" instead of "nvarchar(4000)"?

DB side: SQL Server 2012. A data column is char(1) datatype.
ORM: Hibernate
Intention: Hibernate Query can bind a parameter properly, so no implicit datatype conversion in the query.
//not working as I intend. DB side still sees nvarchar(4000)
Query.setCharacter("paramName", myChar)
Query.setParameter("paramName", myChar, Hibernate.Type.CHARACTER)
Query.setString("paramName", myCharStr)
None of above variation works. SQL server profiler indicates that the bound parameter type is navarchar(4000). SQL server ends up doing some implicit datatype conversion when running the query, and it messed up some of my initial intention. (Rare and elusive deadlocks (select for update; then update) in case of multiple concurrent transactions)
Also it came to my attention that JDBC PreparedStatement API does not even have "setCharacter()". Not sure if this means anything. (http://docs.oracle.com/javase/7/docs/api/java/sql/PreparedStatement.html )
Is there a way to achieve the intention to bind a fixed length char, not nvarchar?
Actually it is not a Hibernate issue. Rather it is that collation set on this particular db column is different than DB collation. Once collation on this data column is fixed, then any of above Hibernate method variation can bind proper parameter type. In case anyone else runs into similar issue.
Edit: another important setting is "sendStringParametersAsUnicode". SQL server JDBC driver by default sent character as "nvarchar" or "nchar", unless you append "sendStringParametersAsUnicode=false" in your connection string;
http://technet.microsoft.com/en-us/library/ms378988.aspx
http://blogs.msdn.com/b/sqlcat/archive/2010/04/05/character-data-type-conversion-when-using-sql-server-jdbc-drivers.aspx

performance of parameterised SQL

I have a query like
SELECT *
FROM myTable
WHERE key LIKE 'XYZ'
The value 'XYZ' is entered by users (and may include % and _)
If I construct the query using string concatenation it runs in 10 seconds.
But this is unsafe, and I should use a parameterised query.
So I'm constructing the query using the odbc command object and it's execute method, and passing a parameter.
SELECT *
FROM myTable
WHERE key LIKE ?
Unfortunately the parameterised SQL execute method takes a full minute.
This query is one of many that are part of a drill-down / investigation package, and I've had similar slow downs with all the parameterised queries (compared to string concatenation).
How do I find out where the time is going (and fix it) ?
Here's my guess without further information.
I've had similar problems on SQL Server. In SQL Server when the column on your table is 'varchar' and the parameterised query parameter is 'nvarchar' (or vice versa), this causes SQL Server to ignore an available index because the parameter type doesn't match the index type, which in turn results in a table scan.
It's possible the same thing happens for Sybase. If you can see the generated query you can confirm if there's a type mismatch.
If this is the case, then two solutions would be
explicitly set the type of the parameter to match the column type
change the type of the column to match the parameter type being generated
Mitch had the right suggestion.
I had to change the connection string to use the OLEDB driver, then I could set the options:
Optimize Prepare=None
Select Method=Direct

Can you explain this SQL injection?

The website i worked was recently attempted to be hacked by the following SQL injection script
boys' and 3=8 union
select 1,
concat(0x232425,ifnull(`table_name`,0x30),char(9),ifnull(`table_rows`,0x30), char(9),0x252423),
3,4,5,6,7,8,9
from `information_schema`.`tables`
where table_schema=0x62646B3032 limit 44,1 -- And '8'='8
This injection returned the mysql table name. This was reported by the error reporting system on that website and we managed to fix that part however I am not able to understand what does the above injection mean?
Anyone can explain this?
Penuel
They're using a select from the Information Schema views in mysql server :
http://dev.mysql.com/doc/refman/5.0/en/information-schema.html
They use some clever hacks to rout out simple sql injection prevention techniques.
According to this the MySQL concat()
Returns the string that results from
concatenating the arguments. May have
one or more arguments. If all
arguments are nonbinary strings, the
result is a nonbinary string. If the
arguments include any binary strings,
the result is a binary string. A
numeric argument is converted to its
equivalent binary string form
So 0x232425 is converted to #$% which is simply added to the begining and end of the table_name field. Maybe just to make it easier for them to pull out the Table names later using Regex.
Later on the char(9) is equivalent to a tab as you can see here and is just there to format the output nicer.
The 3,4,5,6,7,8,9 is just there so that the columns match the boys table that they are performing the Union on.
This injection returned the mysql table name.
Do you mean that your website displayed the table name when you gave it this input, or that the query returns that when run from the mysql client? If it showed on your website, then the attacker has the ability to inject much more harmful queries. Check your data.