1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.dialect;
26
27 import java.sql.CallableStatement;
28 import java.sql.ResultSet;
29 import java.sql.SQLException;
30 import java.sql.Types;
31 import java.util.Map;
32 import java.util.Iterator;
33
34 import org.hibernate.Hibernate;
35 import org.hibernate.LockMode;
36 import org.hibernate.cfg.Environment;
37 import org.hibernate.dialect.function.CharIndexFunction;
38 import org.hibernate.dialect.function.NoArgSQLFunction;
39 import org.hibernate.dialect.function.SQLFunctionTemplate;
40 import org.hibernate.dialect.function.StandardSQLFunction;
41 import org.hibernate.dialect.function.VarArgsSQLFunction;
42
43 /**
44 * An SQL dialect compatible with Sybase and MS SQL Server.
45 * @author Gavin King
46 */
47
48 public class SybaseDialect extends Dialect {
49 public SybaseDialect() {
50 super();
51 registerColumnType( Types.BIT, "tinyint" ); //Sybase BIT type does not support null values
52 registerColumnType( Types.BIGINT, "numeric(19,0)" );
53 registerColumnType( Types.SMALLINT, "smallint" );
54 registerColumnType( Types.TINYINT, "tinyint" );
55 registerColumnType( Types.INTEGER, "int" );
56 registerColumnType( Types.CHAR, "char(1)" );
57 registerColumnType( Types.VARCHAR, "varchar($l)" );
58 registerColumnType( Types.FLOAT, "float" );
59 registerColumnType( Types.DOUBLE, "double precision" );
60 registerColumnType( Types.DATE, "datetime" );
61 registerColumnType( Types.TIME, "datetime" );
62 registerColumnType( Types.TIMESTAMP, "datetime" );
63 registerColumnType( Types.VARBINARY, "varbinary($l)" );
64 registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
65 registerColumnType( Types.BLOB, "image" );
66 registerColumnType( Types.CLOB, "text" );
67
68 registerFunction( "ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER) );
69 registerFunction( "char", new StandardSQLFunction("char", Hibernate.CHARACTER) );
70 registerFunction( "len", new StandardSQLFunction("len", Hibernate.LONG) );
71 registerFunction( "lower", new StandardSQLFunction("lower") );
72 registerFunction( "upper", new StandardSQLFunction("upper") );
73 registerFunction( "str", new StandardSQLFunction("str", Hibernate.STRING) );
74 registerFunction( "ltrim", new StandardSQLFunction("ltrim") );
75 registerFunction( "rtrim", new StandardSQLFunction("rtrim") );
76 registerFunction( "reverse", new StandardSQLFunction("reverse") );
77 registerFunction( "space", new StandardSQLFunction("space", Hibernate.STRING) );
78
79 registerFunction( "user", new NoArgSQLFunction("user", Hibernate.STRING) );
80
81 registerFunction( "current_timestamp", new NoArgSQLFunction("getdate", Hibernate.TIMESTAMP) );
82 registerFunction( "current_time", new NoArgSQLFunction("getdate", Hibernate.TIME) );
83 registerFunction( "current_date", new NoArgSQLFunction("getdate", Hibernate.DATE) );
84
85 registerFunction( "getdate", new NoArgSQLFunction("getdate", Hibernate.TIMESTAMP) );
86 registerFunction( "getutcdate", new NoArgSQLFunction("getutcdate", Hibernate.TIMESTAMP) );
87 registerFunction( "day", new StandardSQLFunction("day", Hibernate.INTEGER) );
88 registerFunction( "month", new StandardSQLFunction("month", Hibernate.INTEGER) );
89 registerFunction( "year", new StandardSQLFunction("year", Hibernate.INTEGER) );
90 registerFunction( "datename", new StandardSQLFunction("datename", Hibernate.STRING) );
91
92 registerFunction( "abs", new StandardSQLFunction("abs") );
93 registerFunction( "sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
94
95 registerFunction( "acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
96 registerFunction( "asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
97 registerFunction( "atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
98 registerFunction( "cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
99 registerFunction( "cot", new StandardSQLFunction("cot", Hibernate.DOUBLE) );
100 registerFunction( "exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
101 registerFunction( "log", new StandardSQLFunction( "log", Hibernate.DOUBLE) );
102 registerFunction( "log10", new StandardSQLFunction("log10", Hibernate.DOUBLE) );
103 registerFunction( "sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
104 registerFunction( "sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
105 registerFunction( "tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
106 registerFunction( "pi", new NoArgSQLFunction("pi", Hibernate.DOUBLE) );
107 registerFunction( "square", new StandardSQLFunction("square") );
108 registerFunction( "rand", new StandardSQLFunction("rand", Hibernate.FLOAT) );
109
110 registerFunction("radians", new StandardSQLFunction("radians", Hibernate.DOUBLE) );
111 registerFunction("degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE) );
112
113 registerFunction( "round", new StandardSQLFunction("round") );
114 registerFunction( "ceiling", new StandardSQLFunction("ceiling") );
115 registerFunction( "floor", new StandardSQLFunction("floor") );
116
117 registerFunction( "isnull", new StandardSQLFunction("isnull") );
118
119 registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(","+",")" ) );
120
121 registerFunction( "length", new StandardSQLFunction( "len", Hibernate.INTEGER ) );
122 registerFunction( "trim", new SQLFunctionTemplate( Hibernate.STRING, "ltrim(rtrim(?1))") );
123 registerFunction( "locate", new CharIndexFunction() );
124
125 getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
126 }
127
128 public String getAddColumnString() {
129 return "add";
130 }
131 public String getNullColumnString() {
132 return " null";
133 }
134 public boolean qualifyIndexName() {
135 return false;
136 }
137
138 public String getForUpdateString() {
139 return "";
140 }
141
142 public boolean supportsIdentityColumns() {
143 return true;
144 }
145 public String getIdentitySelectString() {
146 return "select @@identity";
147 }
148 public String getIdentityColumnString() {
149 return "identity not null"; //starts with 1, implicitly
150 }
151
152 public boolean supportsInsertSelectIdentity() {
153 return true;
154 }
155
156 public String appendIdentitySelectToInsert(String insertSQL) {
157 return insertSQL + "\nselect @@identity";
158 }
159
160 public String appendLockHint(LockMode mode, String tableName) {
161 if ( mode.greaterThan( LockMode.READ ) ) {
162 return tableName + " holdlock";
163 }
164 else {
165 return tableName;
166 }
167 }
168
169 public String applyLocksToSql(String sql, Map aliasedLockModes, Map keyColumnNames) {
170 Iterator itr = aliasedLockModes.entrySet().iterator();
171 StringBuffer buffer = new StringBuffer( sql );
172 int correction = 0;
173 while ( itr.hasNext() ) {
174 final Map.Entry entry = ( Map.Entry ) itr.next();
175 final LockMode lockMode = ( LockMode ) entry.getValue();
176 if ( lockMode.greaterThan( LockMode.READ ) ) {
177 final String alias = ( String ) entry.getKey();
178 int start = -1, end = -1;
179 if ( sql.endsWith( " " + alias ) ) {
180 start = ( sql.length() - alias.length() ) + correction;
181 end = start + alias.length();
182 }
183 else {
184 int position = sql.indexOf( " " + alias + " " );
185 if ( position <= -1 ) {
186 position = sql.indexOf( " " + alias + "," );
187 }
188 if ( position > -1 ) {
189 start = position + correction + 1;
190 end = start + alias.length();
191 }
192 }
193
194 if ( start > -1 ) {
195 final String lockHint = appendLockHint( lockMode, alias );
196 buffer.replace( start, end, lockHint );
197 correction += ( lockHint.length() - alias.length() );
198 }
199 }
200 }
201 return buffer.toString();
202 }
203
204 public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
205 return col; // sql server just returns automatically
206 }
207
208 public ResultSet getResultSet(CallableStatement ps) throws SQLException {
209 boolean isResultSet = ps.execute();
210 // This assumes you will want to ignore any update counts
211 while ( !isResultSet && ps.getUpdateCount() != -1 ) {
212 isResultSet = ps.getMoreResults();
213 }
214 // You may still have other ResultSets or update counts left to process here
215 // but you can't do it now or the ResultSet you just got will be closed
216 return ps.getResultSet();
217 }
218
219 public boolean supportsCurrentTimestampSelection() {
220 return true;
221 }
222
223 public boolean isCurrentTimestampSelectStringCallable() {
224 return false;
225 }
226
227 public String getCurrentTimestampSelectString() {
228 return "select getdate()";
229 }
230
231 public boolean supportsTemporaryTables() {
232 return true;
233 }
234
235 public String generateTemporaryTableName(String baseTableName) {
236 return "#" + baseTableName;
237 }
238
239 public boolean dropTemporaryTableAfterUse() {
240 return true; // sql-server, at least needed this dropped after use; strange!
241 }
242
243
244 // Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
245
246 public boolean supportsEmptyInList() {
247 return false;
248 }
249
250 public boolean supportsExistsInSelect() {
251 return false;
252 }
253
254 public boolean doesReadCommittedCauseWritersToBlockReaders() {
255 return true;
256 }
257
258 public boolean doesRepeatableReadCauseReadersToBlockWriters() {
259 return true;
260 }
261 }