HHH-3892 : Add support for "text" and "image" Hibernate types for native SQL queries
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16823 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
2d457208c0
commit
2c04648372
|
@ -216,6 +216,8 @@ public abstract class Dialect {
|
|||
registerHibernateType( Types.TIMESTAMP, Hibernate.TIMESTAMP.getName() );
|
||||
registerHibernateType( Types.VARCHAR, Hibernate.STRING.getName() );
|
||||
registerHibernateType( Types.VARBINARY, Hibernate.BINARY.getName() );
|
||||
registerHibernateType( Types.LONGVARCHAR, Hibernate.TEXT.getName() );
|
||||
registerHibernateType( Types.LONGVARBINARY, Hibernate.IMAGE.getName() );
|
||||
registerHibernateType( Types.NUMERIC, Hibernate.BIG_DECIMAL.getName() );
|
||||
registerHibernateType( Types.DECIMAL, Hibernate.BIG_DECIMAL.getName() );
|
||||
registerHibernateType( Types.BLOB, Hibernate.BLOB.getName() );
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.sql.hand;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class ImageHolder {
|
||||
private Long id;
|
||||
private byte[] photo;
|
||||
|
||||
public ImageHolder(byte[] photo) {
|
||||
this.photo = photo;
|
||||
}
|
||||
|
||||
public ImageHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id The id to set.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the photo.
|
||||
*/
|
||||
public byte[] getPhoto() {
|
||||
return photo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param photo The photo to set.
|
||||
*/
|
||||
public void setPhoto(byte[] photo) {
|
||||
this.photo = photo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.sql.hand;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class TextHolder {
|
||||
private Long id;
|
||||
private String description;
|
||||
|
||||
public TextHolder(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public TextHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id The id to set.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the description.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description The description to set.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
|
@ -7,9 +7,12 @@ import java.util.Iterator;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.util.ArrayHelper;
|
||||
import org.hibernate.test.sql.hand.Employment;
|
||||
import org.hibernate.test.sql.hand.Organization;
|
||||
import org.hibernate.test.sql.hand.Person;
|
||||
import org.hibernate.test.sql.hand.TextHolder;
|
||||
import org.hibernate.test.sql.hand.ImageHolder;
|
||||
import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
|
||||
|
||||
/**
|
||||
|
@ -91,4 +94,81 @@ public abstract class CustomSQLTestSupport extends DatabaseSpecificFunctionalTes
|
|||
s.close();
|
||||
}
|
||||
|
||||
public void testTextProperty() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
String description = buildLongString( 15000, 'a' );
|
||||
TextHolder holder = new TextHolder( description );
|
||||
s.save( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
holder = ( TextHolder ) s.get( TextHolder.class, holder.getId() );
|
||||
assertEquals( description, holder.getDescription() );
|
||||
description = buildLongString( 15000, 'b' );
|
||||
holder.setDescription( description );
|
||||
s.save( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
holder = ( TextHolder ) s.get( TextHolder.class, holder.getId() );
|
||||
assertEquals( description, holder.getDescription() );
|
||||
s.delete( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testImageProperty() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
byte[] photo = buildLongByteArray( 15000, true );
|
||||
ImageHolder holder = new ImageHolder( photo );
|
||||
s.save( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
holder = ( ImageHolder ) s.get( ImageHolder.class, holder.getId() );
|
||||
assertTrue( ArrayHelper.isEquals( photo, holder.getPhoto() ) );
|
||||
photo = buildLongByteArray( 15000, false );
|
||||
holder.setPhoto( photo );
|
||||
s.save( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
holder = ( ImageHolder ) s.get( ImageHolder.class, holder.getId() );
|
||||
assertTrue( ArrayHelper.isEquals( photo, holder.getPhoto() ) );
|
||||
s.delete( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
private String buildLongString(int size, char baseChar) {
|
||||
StringBuffer buff = new StringBuffer();
|
||||
for( int i = 0; i < size; i++ ) {
|
||||
buff.append( baseChar );
|
||||
}
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
private byte[] buildLongByteArray(int size, boolean on) {
|
||||
byte[] data = new byte[size];
|
||||
data[0] = mask( on );
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
data[i] = mask( on );
|
||||
on = !on;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private byte mask(boolean on) {
|
||||
return on ? ( byte ) 1 : ( byte ) 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,36 @@
|
|||
<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="TextHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="description" type="text" length="15000"/>
|
||||
<loader query-ref="textholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO TEXTHOLDER
|
||||
(DESCRIPTION, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE TEXTHOLDER SET DESCRIPTION=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM TEXTHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="ImageHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="photo" type="image" length="15000"/>
|
||||
<loader query-ref="imageholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO IMAGEHOLDER
|
||||
(PHOTO, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE IMAGEHOLDER SET PHOTO=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM IMAGEHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<resultset name="org-emp-regionCode">
|
||||
<return-scalar column="regionCode" type="string"/>
|
||||
<return alias="org" class="Organization"/>
|
||||
|
@ -183,6 +213,16 @@
|
|||
{ call HIBDB2TST.selectAllEmployments() }
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="textholder">
|
||||
<return alias="h" class="TextHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, DESCRIPTION AS {h.description} FROM TEXTHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="imageholder">
|
||||
<return alias="h" class="ImageHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, PHOTO AS {h.photo} FROM IMAGEHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<!-- DB2 seem to *require* users to specify explicit schema/location when executing a stored procedure *stupid* -->
|
||||
<database-object>
|
||||
<create>CREATE SCHEMA HIBDB2TST</create>
|
||||
|
|
|
@ -65,6 +65,36 @@
|
|||
<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="TextHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="description" type="text" length="15000"/>
|
||||
<loader query-ref="textholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO TEXTHOLDER
|
||||
(DESCRIPTION, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE TEXTHOLDER SET DESCRIPTION=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM TEXTHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="ImageHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="photo" type="image" length="15000"/>
|
||||
<loader query-ref="imageholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO IMAGEHOLDER
|
||||
(PHOTO, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE IMAGEHOLDER SET PHOTO=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM IMAGEHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<resultset name="org-emp-regionCode">
|
||||
<return-scalar column="regionCode" type="string"/>
|
||||
<return alias="org" class="Organization"/>
|
||||
|
@ -180,7 +210,17 @@
|
|||
</return>
|
||||
{ call selectAllEmployments() }
|
||||
</sql-query>
|
||||
|
||||
|
||||
<sql-query name="textholder">
|
||||
<return alias="h" class="TextHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, DESCRIPTION AS {h.description} FROM TEXTHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="imageholder">
|
||||
<return alias="h" class="ImageHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, PHOTO AS {h.photo} FROM IMAGEHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<database-object>
|
||||
<create>
|
||||
CREATE PROCEDURE selectAllEmployments ()
|
||||
|
|
|
@ -65,6 +65,36 @@
|
|||
<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="TextHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="description" type="text" length="15000"/>
|
||||
<loader query-ref="textholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO TEXTHOLDER
|
||||
(DESCRIPTION, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE TEXTHOLDER SET DESCRIPTION=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM TEXTHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="ImageHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="photo" type="image" length="15000"/>
|
||||
<loader query-ref="imageholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO IMAGEHOLDER
|
||||
(PHOTO, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE IMAGEHOLDER SET PHOTO=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM IMAGEHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<resultset name="org-emp-regionCode">
|
||||
<return-scalar column="regionCode" type="string"/>
|
||||
<return alias="org" class="Organization"/>
|
||||
|
@ -139,6 +169,16 @@
|
|||
ORDER BY STARTDATE ASC
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="textholder">
|
||||
<return alias="h" class="TextHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, DESCRIPTION AS {h.description} FROM TEXTHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="imageholder">
|
||||
<return alias="h" class="ImageHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, PHOTO AS {h.photo} FROM IMAGEHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<database-object>
|
||||
<create>
|
||||
CREATE OR REPLACE FUNCTION testParamHandling (j number, i number)
|
||||
|
@ -202,7 +242,7 @@
|
|||
END;
|
||||
</create>
|
||||
<drop>
|
||||
DROP PROCEDURE createPerson;
|
||||
DROP PROCEDURE createPerson
|
||||
</drop>
|
||||
</database-object>
|
||||
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
This mapping demonstrates the use of Hibernate with all-handwritten SQL!
|
||||
|
||||
NOTE: this version is for SQLServer
|
||||
-->
|
||||
<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
|
||||
|
||||
<class name="Organization" table="ORGANIZATION">
|
||||
<id name="id" unsaved-value="0" column="ORGID">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" column="NAME"/>
|
||||
<set name="employments"
|
||||
inverse="true"
|
||||
order-by="DUMMY">
|
||||
<key column="EMPLOYER"/> <!-- only needed for DDL generation -->
|
||||
<one-to-many class="Employment"/>
|
||||
<loader query-ref="organizationEmployments"/>
|
||||
</set>
|
||||
<!-- query-list name="currentEmployments"
|
||||
query-ref="organizationCurrentEmployments"-->
|
||||
<loader query-ref="organization"/>
|
||||
<sql-insert>INSERT INTO ORGANIZATION (NAME, ORGID) VALUES ( UPPER(?), ? )</sql-insert>
|
||||
<sql-update>UPDATE ORGANIZATION SET NAME=UPPER(?) WHERE ORGID=?</sql-update>
|
||||
<sql-delete>DELETE FROM ORGANIZATION WHERE ORGID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="Person" table="PERSON">
|
||||
<id name="id" unsaved-value="0" column="PERID">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" column="NAME"/>
|
||||
<loader query-ref="person"/>
|
||||
<sql-insert>INSERT INTO PERSON (NAME, PERID) VALUES ( UPPER(?), ? )</sql-insert>
|
||||
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update>
|
||||
<sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="Employment" table="EMPLOYMENT">
|
||||
<id name="employmentId" unsaved-value="0" column="EMPID">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<many-to-one name="employee" column="EMPLOYEE" not-null="true" update="false"/>
|
||||
<many-to-one name="employer" column="EMPLOYER" not-null="true" update="false"/>
|
||||
<property name="startDate" column="STARTDATE" not-null="true" update="false" insert="false"/>
|
||||
<property name="endDate" column="ENDDATE" insert="false"/>
|
||||
<property name="regionCode" column="REGIONCODE" update="false"/>
|
||||
<property name="salary" type="org.hibernate.test.sql.hand.MonetaryAmountUserType">
|
||||
<column name="VALUE" sql-type="float"/>
|
||||
<column name="CURRENCY"/>
|
||||
</property>
|
||||
<loader query-ref="employment"/>
|
||||
<sql-insert>
|
||||
INSERT INTO EMPLOYMENT
|
||||
(EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, VALUE, CURRENCY, EMPID)
|
||||
VALUES (?, ?, getdate(), UPPER(?), ?, ?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE EMPLOYMENT SET ENDDATE=?, VALUE=?, CURRENCY=? WHERE EMPID=?</sql-update>
|
||||
<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="TextHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="description" type="text" length="15000"/>
|
||||
<loader query-ref="textholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO TEXTHOLDER
|
||||
(DESCRIPTION, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE TEXTHOLDER SET DESCRIPTION=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM TEXTHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="ImageHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="photo" type="image" length="15000"/>
|
||||
<loader query-ref="imageholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO IMAGEHOLDER
|
||||
(PHOTO, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE IMAGEHOLDER SET PHOTO=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM IMAGEHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<resultset name="org-emp-regionCode">
|
||||
<return-scalar column="regionCode" type="string"/>
|
||||
<return alias="org" class="Organization"/>
|
||||
<return-join alias="emp" property="org.employments"/>
|
||||
</resultset>
|
||||
|
||||
<resultset name="org-emp-person">
|
||||
<return alias="org" class="Organization"/>
|
||||
<return-join alias="emp" property="org.employments"/>
|
||||
<return-join alias="pers" property="emp.employee"/>
|
||||
</resultset>
|
||||
|
||||
<sql-query name="person">
|
||||
<return alias="p" class="Person" lock-mode="upgrade"/>
|
||||
SELECT NAME AS {p.name}, PERID AS {p.id} FROM PERSON WHERE PERID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="organization">
|
||||
<return alias="org" class="Organization"/>
|
||||
<return-join alias="emp" property="org.employments"/>
|
||||
SELECT {org.*}, {emp.*}
|
||||
FROM ORGANIZATION org
|
||||
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
|
||||
WHERE org.ORGID=?
|
||||
</sql-query>
|
||||
|
||||
|
||||
<!--sql-query name="organization">
|
||||
<return alias="org" class="Organization"/>
|
||||
SELECT NAME AS {org.name}, ORGID AS {org.id} FROM ORGANIZATION
|
||||
WHERE ORGID=?
|
||||
</sql-query-->
|
||||
|
||||
<sql-query name="allOrganizationsWithEmployees" flush-mode="never">
|
||||
<return alias="org" class="Organization"/>
|
||||
SELECT DISTINCT org.NAME AS {org.name}, org.ORGID AS {org.id}
|
||||
FROM ORGANIZATION org
|
||||
INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ORGID
|
||||
</sql-query>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<sql-query name="employment">
|
||||
<return alias="emp" class="Employment"/>
|
||||
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
||||
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
||||
REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}
|
||||
FROM EMPLOYMENT
|
||||
WHERE EMPID = ?
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="organizationEmployments">
|
||||
<load-collection alias="empcol" role="Organization.employments"/>
|
||||
SELECT {empcol.*}
|
||||
FROM EMPLOYMENT empcol
|
||||
WHERE EMPLOYER = :id
|
||||
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
||||
</sql-query>
|
||||
|
||||
|
||||
<sql-query name="organizationCurrentEmployments">
|
||||
<return alias="emp" class="Employment">
|
||||
<return-property name="salary">
|
||||
<!-- as multi column properties are not supported via the
|
||||
{}-syntax, we need to provide an explicit column list for salary via <return-property> -->
|
||||
<return-column name="VALUE"/>
|
||||
<return-column name="CURRENCY"/>
|
||||
</return-property>
|
||||
<!-- Here we are remapping endDate. Notice that we can still use {emp.endDate} in the SQL. -->
|
||||
<return-property name="endDate" column="myEndDate"/>
|
||||
</return>
|
||||
<synchronize table="EMPLOYMENT"/>
|
||||
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
||||
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
||||
REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}, VALUE, CURRENCY
|
||||
FROM EMPLOYMENT
|
||||
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
||||
ORDER BY STARTDATE ASC
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="simpleScalar" callable="true">
|
||||
<return-scalar column="name" type="string"/>
|
||||
<return-scalar column="value" type="long"/>
|
||||
{ call simpleScalar(:number) }
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="paramhandling" callable="true">
|
||||
<return-scalar column="value" type="long"/>
|
||||
<return-scalar column="value2" type="long"/>
|
||||
{ call paramHandling(?,?) }
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="paramhandling_mixed" callable="true">
|
||||
<return-scalar column="value" type="long" />
|
||||
<return-scalar column="value2" type="long" />
|
||||
{ call paramHandling(?,:second) }
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="selectAllEmployments" callable="true">
|
||||
<return alias="" class="Employment">
|
||||
<return-property name="employee" column="EMPLOYEE"/>
|
||||
<return-property name="employer" column="EMPLOYER"/>
|
||||
<return-property name="startDate" column="STARTDATE"/>
|
||||
<return-property name="endDate" column="ENDDATE"/>
|
||||
<return-property name="regionCode" column="REGIONCODE"/>
|
||||
<return-property name="id" column="EMPID"/>
|
||||
<return-property name="salary">
|
||||
<!-- as multi column properties are not supported via the
|
||||
{}-syntax, we need to provide an explicit column list for salary via <return-property> -->
|
||||
<return-column name="VALUE"/>
|
||||
<return-column name="CURRENCY"/>
|
||||
</return-property>
|
||||
</return>
|
||||
{ call selectAllEmployments() }
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="textholder">
|
||||
<return alias="h" class="TextHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, DESCRIPTION AS {h.description} FROM TEXTHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="imageholder">
|
||||
<return alias="h" class="ImageHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, PHOTO AS {h.photo} FROM IMAGEHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<database-object>
|
||||
<create>
|
||||
CREATE PROCEDURE selectAllEmployments AS
|
||||
SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE,
|
||||
REGIONCODE, EMPID, VALUE, CURRENCY
|
||||
FROM EMPLOYMENT
|
||||
</create>
|
||||
<drop>
|
||||
DROP PROCEDURE selectAllEmployments
|
||||
</drop>
|
||||
</database-object>
|
||||
|
||||
<!-- The following is a workaround for HHH-3685 so that SchemaExport -->
|
||||
<!-- changes the transaction mode of selectAllEmployments to "chained" -->
|
||||
<database-object>
|
||||
<create>
|
||||
sp_procxmode selectAllEmployments, 'chained'
|
||||
</create>
|
||||
<!-- no drop command corresponding to "sp_procxmode ..." -->
|
||||
<drop/>
|
||||
</database-object>
|
||||
|
||||
<database-object>
|
||||
<create>
|
||||
CREATE PROCEDURE paramHandling @j int, @i int AS
|
||||
SELECT @j as value, @i as value2
|
||||
</create>
|
||||
<drop>
|
||||
DROP PROCEDURE paramHandling
|
||||
</drop>
|
||||
</database-object>
|
||||
|
||||
<!-- The following is a workaround for HHH-3685 so that SchemaExport -->
|
||||
<!-- changes the transaction mode of paramHandling to "chained" -->
|
||||
<database-object>
|
||||
<create>
|
||||
sp_procxmode paramHandling, 'chained'
|
||||
</create>
|
||||
<!-- no drop command corresponding to "sp_procxmode ..." -->
|
||||
<drop/>
|
||||
</database-object>
|
||||
|
||||
<database-object>
|
||||
<create>
|
||||
CREATE PROCEDURE simpleScalar @number int AS
|
||||
SELECT @number as value, 'getAll' as name
|
||||
</create>
|
||||
<drop>
|
||||
DROP PROCEDURE simpleScalar
|
||||
</drop>
|
||||
</database-object>
|
||||
|
||||
<!-- The following is a workaround for HHH-3685 so that SchemaExport -->
|
||||
<!-- changes the transaction mode of simpleScalar to "chained" -->
|
||||
<database-object>
|
||||
<create>
|
||||
sp_procxmode simpleScalar, 'chained'
|
||||
</create>
|
||||
<!-- no drop command corresponding to "sp_procxmode ..." -->
|
||||
<drop/>
|
||||
</database-object>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.sql.hand.custom.sqlserver;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
|
||||
|
||||
/**
|
||||
* Custom SQL tests for SQLServer
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class SQLServerCustomSQLTest extends CustomStoredProcTestSupport {
|
||||
|
||||
public SQLServerCustomSQLTest(String str) {
|
||||
super( str );
|
||||
}
|
||||
|
||||
public String[] getMappings() {
|
||||
return new String[] { "sql/hand/custom/sqlserver/Mappings.hbm.xml" };
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new FunctionalTestClassTestSuite( SQLServerCustomSQLTest.class );
|
||||
}
|
||||
|
||||
public boolean appliesTo(Dialect dialect) {
|
||||
return ( dialect instanceof SQLServerDialect );
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<!--
|
||||
This mapping demonstrates the use of Hibernate with all-handwritten SQL!
|
||||
|
||||
NOTE: this version is for Sybase/SQLServer
|
||||
NOTE: this version is for Sybase
|
||||
-->
|
||||
<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
|
||||
|
||||
|
@ -64,6 +64,36 @@
|
|||
<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="TextHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="description" type="text" length="15000"/>
|
||||
<loader query-ref="textholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO TEXTHOLDER
|
||||
(DESCRIPTION, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE TEXTHOLDER SET DESCRIPTION=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM TEXTHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<class name="ImageHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="photo" type="image" length="15000"/>
|
||||
<loader query-ref="imageholder"/>
|
||||
<sql-insert>
|
||||
INSERT INTO IMAGEHOLDER
|
||||
(PHOTO, ID)
|
||||
VALUES (?, ?)
|
||||
</sql-insert>
|
||||
<sql-update>UPDATE IMAGEHOLDER SET PHOTO=? WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM IMAGEHOLDER WHERE ID=?</sql-delete>
|
||||
</class>
|
||||
|
||||
<resultset name="org-emp-regionCode">
|
||||
<return-scalar column="regionCode" type="string"/>
|
||||
<return alias="org" class="Organization"/>
|
||||
|
@ -181,7 +211,17 @@
|
|||
</return>
|
||||
{ call selectAllEmployments() }
|
||||
</sql-query>
|
||||
|
||||
|
||||
<sql-query name="textholder">
|
||||
<return alias="h" class="TextHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, DESCRIPTION AS {h.description} FROM TEXTHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<sql-query name="imageholder">
|
||||
<return alias="h" class="ImageHolder" lock-mode="upgrade"/>
|
||||
SELECT ID AS {h.id}, PHOTO AS {h.photo} FROM IMAGEHOLDER WHERE ID=? /*FOR UPDATE*/
|
||||
</sql-query>
|
||||
|
||||
<database-object>
|
||||
<create>
|
||||
CREATE PROCEDURE selectAllEmployments AS
|
||||
|
|
|
@ -5,11 +5,14 @@ import junit.framework.Test;
|
|||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||
import org.hibernate.dialect.Sybase11Dialect;
|
||||
import org.hibernate.dialect.SybaseAnywhereDialect;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
|
||||
|
||||
/**
|
||||
* Custom SQL tests for Sybase/SQLServer (Transact-SQL)
|
||||
* Custom SQL tests for Sybase dialects
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
|
@ -28,7 +31,10 @@ public class SybaseCustomSQLTest extends CustomStoredProcTestSupport {
|
|||
}
|
||||
|
||||
public boolean appliesTo(Dialect dialect) {
|
||||
return ( dialect instanceof SybaseDialect );
|
||||
return ( dialect instanceof SybaseDialect ||
|
||||
dialect instanceof SybaseASE15Dialect ||
|
||||
dialect instanceof Sybase11Dialect ||
|
||||
dialect instanceof SybaseAnywhereDialect );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,20 @@
|
|||
<property name="length" column="flength"/>
|
||||
</class>
|
||||
|
||||
<class name="TextHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="description" type="text" length="15000"/>
|
||||
</class>
|
||||
|
||||
<class name="ImageHolder">
|
||||
<id name="id" column="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="photo" type="image" length="15000"/>
|
||||
</class>
|
||||
|
||||
<resultset name="org-emp-regionCode">
|
||||
<return-scalar column="regionCode" type="string"/>
|
||||
<return alias="org" class="Organization"/>
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.util.ArrayHelper;
|
||||
import org.hibernate.test.sql.hand.Organization;
|
||||
import org.hibernate.test.sql.hand.Person;
|
||||
import org.hibernate.test.sql.hand.Employment;
|
||||
|
@ -24,6 +25,8 @@ import org.hibernate.test.sql.hand.Dimension;
|
|||
import org.hibernate.test.sql.hand.SpaceShip;
|
||||
import org.hibernate.test.sql.hand.Speech;
|
||||
import org.hibernate.test.sql.hand.Group;
|
||||
import org.hibernate.test.sql.hand.TextHolder;
|
||||
import org.hibernate.test.sql.hand.ImageHolder;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
|
@ -96,6 +99,14 @@ public class NativeSQLQueriesTest extends FunctionalTestCase {
|
|||
" join PERSON pers on pers.PERID = emp.EMPLOYEE ";
|
||||
}
|
||||
|
||||
protected String getDescriptionsSQL() {
|
||||
return "select DESCRIPTION from TEXTHOLDER";
|
||||
}
|
||||
|
||||
protected String getPhotosSQL() {
|
||||
return "select PHOTO from IMAGEHOLDER";
|
||||
}
|
||||
|
||||
public void testFailOnNoAddEntityOrScalar() {
|
||||
// Note: this passes, but for the wrong reason.
|
||||
// there is actually an exception thrown, but it is the database
|
||||
|
@ -668,6 +679,66 @@ public class NativeSQLQueriesTest extends FunctionalTestCase {
|
|||
s.close();
|
||||
}
|
||||
|
||||
public void testTextTypeInSQLQuery() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
String description = buildLongString( 15000, 'a' );
|
||||
TextHolder holder = new TextHolder( description );
|
||||
s.persist( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
String descriptionRead = ( String ) s.createSQLQuery( getDescriptionsSQL() )
|
||||
.uniqueResult();
|
||||
assertEquals( description, descriptionRead );
|
||||
s.delete( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testImageTypeInSQLQuery() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
byte[] photo = buildLongByteArray( 15000, true );
|
||||
ImageHolder holder = new ImageHolder( photo );
|
||||
s.persist( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
byte[] photoRead = ( byte[] ) s.createSQLQuery( getPhotosSQL() )
|
||||
.uniqueResult();
|
||||
assertTrue( ArrayHelper.isEquals( photo, photoRead ) );
|
||||
s.delete( holder );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
private String buildLongString(int size, char baseChar) {
|
||||
StringBuffer buff = new StringBuffer();
|
||||
for( int i = 0; i < size; i++ ) {
|
||||
buff.append( baseChar );
|
||||
}
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
private byte[] buildLongByteArray(int size, boolean on) {
|
||||
byte[] data = new byte[size];
|
||||
data[0] = mask( on );
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
data[i] = mask( on );
|
||||
on = !on;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private byte mask(boolean on) {
|
||||
return on ? ( byte ) 1 : ( byte ) 0;
|
||||
}
|
||||
|
||||
private static class UpperCasedAliasToEntityMapResultTransformer extends BasicTransformerAdapter implements Serializable {
|
||||
public Object transformTuple(Object[] tuple, String[] aliases) {
|
||||
Map result = new HashMap( tuple.length );
|
||||
|
|
Loading…
Reference in New Issue