1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package org.riverock.dbrevision.db.impl;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.InputStream;
30 import java.sql.Blob;
31 import java.sql.Connection;
32 import java.sql.DatabaseMetaData;
33 import java.sql.PreparedStatement;
34 import java.sql.ResultSet;
35 import java.sql.SQLException;
36 import java.sql.Statement;
37 import java.sql.Types;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.List;
41
42 import org.apache.commons.lang.StringUtils;
43 import org.apache.log4j.Logger;
44
45 import org.hsqldb.Trace;
46
47 import org.riverock.dbrevision.annotation.schema.db.DbDataFieldData;
48 import org.riverock.dbrevision.annotation.schema.db.DbField;
49 import org.riverock.dbrevision.annotation.schema.db.DbForeignKey;
50 import org.riverock.dbrevision.annotation.schema.db.DbPrimaryKey;
51 import org.riverock.dbrevision.annotation.schema.db.DbPrimaryKeyColumn;
52 import org.riverock.dbrevision.annotation.schema.db.DbSequence;
53 import org.riverock.dbrevision.annotation.schema.db.DbTable;
54 import org.riverock.dbrevision.annotation.schema.db.DbView;
55 import org.riverock.dbrevision.db.Database;
56 import org.riverock.dbrevision.db.DatabaseManager;
57 import org.riverock.dbrevision.db.DbPkComparator;
58 import org.riverock.dbrevision.exception.DbRevisionException;
59 import org.riverock.dbrevision.utils.DbUtils;
60
61
62
63
64
65
66
67 @SuppressWarnings({"UnusedAssignment"})
68 public class SqlServerDatabase extends Database {
69 private static Logger log = Logger.getLogger(SqlServerDatabase.class);
70
71
72
73
74
75 public Family getFamily() {
76 return Family.SQLSERVER;
77 }
78
79 public void setBlobField(String tableName, String fieldName, byte[] bytes, String whereQuery, Object[] objects, int[] fieldTyped) {
80
81 }
82
83 public SqlServerDatabase(Connection conn) {
84 super(conn);
85 }
86
87 public int getMaxLengthStringField() {
88 return 4000;
89 }
90
91 public boolean isBatchUpdate() {
92 return false;
93 }
94
95 public boolean isNeedUpdateBracket() {
96 return false;
97 }
98
99 public boolean isByteArrayInUtf8() {
100 return false;
101 }
102
103 public boolean isSchemaSupports() {
104 return false;
105 }
106
107 public String getDefaultSchemaName(DatabaseMetaData databaseMetaData) {
108 return null;
109 }
110
111 public String getClobField(ResultSet rs, String nameField) {
112 return getClobField(rs, nameField, 20000);
113 }
114
115 public byte[] getBlobField(ResultSet rs, String nameField, int maxLength) {
116 try {
117 Blob blob = rs.getBlob(nameField);
118 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
119 int count;
120 byte buffer[] = new byte[1024];
121
122 InputStream inputStream = blob.getBinaryStream();
123 while ((count = inputStream.read(buffer)) >= 0) {
124 outputStream.write(buffer, 0, count);
125 outputStream.flush();
126 }
127 outputStream.close();
128 return outputStream.toByteArray();
129 }
130 catch (Exception e) {
131 throw new DbRevisionException(e);
132 }
133 }
134
135 public void createTable(DbTable table) {
136 if (table == null || table.getFields().isEmpty() ) {
137 return;
138 }
139
140 String sql = "create table \"" + table.getName() + "\"\n" +
141 "(";
142
143 boolean isFirst = true;
144
145 for (DbField field : table.getFields()) {
146 if (!isFirst)
147 sql += ",";
148 else
149 isFirst = !isFirst;
150
151 sql += "\n\"" + field.getName() + "\"";
152 int javaType = field.getJavaType();
153 switch (javaType) {
154
155 case Types.BIT:
156 sql += " DECIMAL(1,0)";
157 break;
158
159 case Types.TINYINT:
160 sql += " DECIMAL(4,0)";
161 break;
162
163 case Types.BIGINT:
164 sql += " DECIMAL(38,0)";
165 break;
166
167 case Types.NUMERIC:
168 case Types.DECIMAL:
169 Integer digit = field.getDecimalDigit();
170 if (digit==null) digit=0;
171 sql += " DECIMAL(" + (field.getSize()==null || field.getSize() > 38 ? 38 : field.getSize()) + ',' + digit + ")";
172 break;
173
174 case Types.INTEGER:
175 sql += " INTEGER";
176 break;
177
178 case Types.SMALLINT:
179 sql += " SMALLINT";
180 break;
181
182 case Types.DOUBLE:
183 sql += " DOUBLE";
184 break;
185
186 case Types.FLOAT:
187 sql += " FLOAT";
188 break;
189
190 case Types.CHAR:
191 sql += " VARCHAR(1)";
192 break;
193
194 case Types.VARCHAR:
195 sql += " VARCHAR(" + field.getSize() + ")";
196 break;
197
198 case Types.TIMESTAMP:
199 case Types.DATE:
200 sql += " DATETIME";
201 break;
202
203 case Types.BLOB:
204 sql += " IMAGE";
205
206 break;
207
208
209
210
211
212
213
214
215 default:
216 field.setJavaStringType("unknown field type field - " + field.getName() + " javaType - " + javaType);
217 System.out.println("unknown field type field - " + field.getName() + " javaType - " + javaType);
218 }
219
220 if (field.getDefaultValue() != null) {
221 String val = field.getDefaultValue().trim();
222
223 if (StringUtils.isNotBlank(val)) {
224 switch (javaType) {
225 case Types.CHAR:
226 case Types.VARCHAR:
227 val = "'" + val + "'";
228 break;
229 case Types.TIMESTAMP:
230 case Types.DATE:
231 if (DatabaseManager.checkDefaultTimestamp(val))
232 val = "CURRENT_TIMESTAMP";
233
234 break;
235 default:
236 }
237 sql += (" DEFAULT " + val);
238 }
239 }
240
241 if (field.getNullable() == DatabaseMetaData.columnNoNulls) {
242 sql += " NOT NULL ";
243 }
244 }
245 if (table.getPrimaryKey() != null && table.getPrimaryKey().getColumns().size() != 0) {
246 DbPrimaryKey pk = table.getPrimaryKey();
247
248 String namePk = pk.getPkName();
249
250
251
252
253
254
255 sql += ",\nCONSTRAINT " + namePk + " PRIMARY KEY (\n";
256
257 List<DbPrimaryKeyColumn> list = pk.getColumns();
258 Collections.sort(list, DbPkComparator.getInstance());
259
260 isFirst = true;
261 for (DbPrimaryKeyColumn column : list) {
262 if (!isFirst)
263 sql += ',';
264 else
265 isFirst = !isFirst;
266
267 sql += column.getColumnName();
268 }
269 sql += "\n)";
270 }
271 sql += "\n)";
272
273 Statement st = null;
274 try {
275 st = this.getConnection().createStatement();
276 st.execute(sql);
277 int count = st.getUpdateCount();
278 if (log.isDebugEnabled()) {
279 log.debug("count of processed records " + count);
280 }
281 }
282 catch (SQLException e) {
283 throw new DbRevisionException(e);
284 }
285 finally {
286 DbUtils.close(st);
287 st = null;
288 }
289
290 }
291
292 public void createForeignKey(DbTable view) {
293 }
294
295 public void dropTable(DbTable table) {
296 dropTable(table.getName());
297 }
298
299 public void dropTable(String nameTable) {
300 if (nameTable == null)
301 return;
302
303 String sql = "drop table " + nameTable;
304
305 Statement st = null;
306 try {
307 st = this.getConnection().createStatement();
308 st.execute(sql);
309 int count = st.getUpdateCount();
310 if (log.isDebugEnabled()) {
311 log.debug("count of deleted object " + count);
312 }
313 }
314 catch (SQLException e) {
315 log.error("Error drop table " + nameTable, e);
316 throw new DbRevisionException(e);
317 }
318 finally {
319 DbUtils.close(st);
320 st = null;
321 }
322 }
323
324 public void dropSequence(String nameSequence) {
325 }
326
327 public void dropConstraint(DbForeignKey impPk) {
328 if (impPk == null) {
329 return;
330 }
331
332 String sql = "ALTER TABLE " + impPk.getPkTableName() + " DROP CONSTRAINT " + impPk.getPkName();
333
334 PreparedStatement ps = null;
335 try {
336 ps = this.getConnection().prepareStatement(sql);
337 ps.executeUpdate();
338 }
339 catch (SQLException e) {
340 throw new DbRevisionException(e);
341 }
342 finally {
343 DbUtils.close(ps);
344 ps = null;
345 }
346 }
347
348 public void addColumn(DbTable table, DbField field) {
349 String sql = "alter table \"" + table.getName() + "\" add " + field.getName() + " ";
350
351 int fieldType = field.getJavaType();
352 switch (fieldType) {
353
354 case Types.BIT:
355 sql += " BIT";
356 break;
357
358 case Types.TINYINT:
359 sql += " TINYINT";
360 break;
361
362 case Types.BIGINT:
363 sql += " BIGINT";
364 break;
365
366
367
368 case Types.NUMERIC:
369 case Types.DECIMAL:
370 sql += " DECIMAL";
371 break;
372
373 case Types.INTEGER:
374 sql += " INTEGER";
375 break;
376
377 case Types.DOUBLE:
378 sql += " DOUBLE";
379 break;
380
381 case Types.CHAR:
382 sql += " VARCHAR(1)";
383 break;
384
385 case Types.VARCHAR:
386 sql += " VARCHAR(" + field.getSize() + ")";
387 break;
388
389 case Types.TIMESTAMP:
390 case Types.DATE:
391 sql += " DATETIME";
392 break;
393
394 case Types.LONGVARCHAR:
395 sql += " VARCHAR(10)";
396 break;
397
398 case Types.LONGVARBINARY:
399 sql += " LONGVARBINARY";
400 break;
401
402 default:
403 field.setJavaStringType("unknown field type field - " + field.getName() + " javaType - " + field.getJavaType());
404 System.out.println("unknown field type field - " + field.getName() + " javaType - " + field.getJavaType());
405 }
406
407 if (field.getDefaultValue() != null) {
408 String val = field.getDefaultValue().trim();
409
410 switch (fieldType) {
411 case Types.CHAR:
412 case Types.VARCHAR:
413 if (!val.equalsIgnoreCase("null")) {
414 val = "'" + val + "'";
415 }
416 break;
417 case Types.DATE:
418 case Types.TIMESTAMP:
419 if (DatabaseManager.checkDefaultTimestamp(val)) {
420 val = getDefaultTimestampValue();
421 }
422 break;
423 }
424 sql += (" DEFAULT " + val);
425 }
426
427 if (field.getNullable() == DatabaseMetaData.columnNoNulls) {
428 sql += " NOT NULL ";
429 }
430
431 if (log.isDebugEnabled()) {
432 log.debug("MSSQL addColumn sql - \n" + sql);
433 }
434
435 Statement ps = null;
436 try {
437 ps = this.getConnection().createStatement();
438 ps.executeUpdate(sql);
439 this.getConnection().commit();
440 }
441 catch (SQLException e) {
442 throw new DbRevisionException(e);
443 }
444 finally {
445 DbUtils.close(ps);
446 ps = null;
447 }
448 }
449
450 public String getOnDeleteSetNull() {
451 return "ON DELETE NO ACTION";
452 }
453
454 public String getDefaultTimestampValue() {
455 return "current_timestamp";
456 }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530 public List<DbView> getViewList(String schemaPattern, String tablePattern) {
531 return DatabaseManager.getViewList(getConnection(), schemaPattern, tablePattern);
532 }
533
534 public List<DbSequence> getSequnceList(String schemaPattern) {
535 return new ArrayList<DbSequence>();
536 }
537
538 public String getViewText(DbView view) {
539 return null;
540 }
541
542 public void createView(DbView view) {
543 if (view == null ||
544 view.getName() == null || view.getName().length() == 0 ||
545 view.getText() == null || view.getText().length() == 0
546 )
547 return;
548
549 String sql_ =
550 "CREATE VIEW " + view.getName() +
551 " AS " + StringUtils.replace(view.getText(), "||", "+");
552
553 Statement ps = null;
554 try {
555 ps = this.getConnection().createStatement();
556 ps.execute(sql_);
557 }
558 catch (SQLException e) {
559 String errorString = "Error create view. Error code " + e.getErrorCode() + "\n" + sql_;
560 log.error(errorString, e);
561 throw new DbRevisionException(errorString, e);
562 }
563 finally {
564 DbUtils.close(ps);
565 ps = null;
566 }
567 }
568
569 public void createSequence(DbSequence seq) {
570 }
571
572 public void setLongVarbinary(PreparedStatement ps, int index, DbDataFieldData fieldData) {
573 try {
574 ps.setNull(index, Types.VARCHAR);
575 }
576 catch (SQLException e) {
577 throw new DbRevisionException(e);
578 }
579 }
580
581 public void setLongVarchar(PreparedStatement ps, int index, DbDataFieldData fieldData) {
582 try {
583 ps.setString(index, "");
584 }
585 catch (SQLException e) {
586 throw new DbRevisionException(e);
587 }
588 }
589
590 public String getClobField(ResultSet rs, String nameField, int maxLength) {
591 return null;
592 }
593
594
595
596
597
598
599
600
601
602
603 public boolean testExceptionTableNotFound(Exception e) {
604 if (e instanceof SQLException) {
605
606 return ((SQLException) e).getErrorCode() == -(Trace.TABLE_NOT_FOUND);
607 }
608 return false;
609 }
610
611 public boolean testExceptionIndexUniqueKey(Exception e, String index) {
612 if (e instanceof SQLException) {
613 if (((SQLException) e).getErrorCode() == -(Trace.VIOLATION_OF_UNIQUE_INDEX))
614 return true;
615 }
616 return false;
617 }
618
619 public boolean testExceptionIndexUniqueKey(Exception e) {
620 return false;
621 }
622
623 public boolean testExceptionTableExists(Exception e) {
624 if (e instanceof SQLException) {
625 if (((SQLException) e).getErrorCode() == 2714)
626 return true;
627 }
628 return false;
629 }
630
631 public boolean testExceptionViewExists(Exception e) {
632 if (e instanceof SQLException) {
633 if (((SQLException) e).getErrorCode() == 2714)
634 return true;
635 }
636 return false;
637 }
638
639 public boolean testExceptionSequenceExists(Exception e) {
640 return false;
641 }
642
643 public boolean testExceptionConstraintExists(Exception e) {
644 if (e instanceof SQLException) {
645 if (((SQLException) e).getErrorCode() == -(org.hsqldb.Trace.CONSTRAINT_ALREADY_EXISTS))
646 return true;
647 }
648 return false;
649 }
650 }