File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\command\dml\ScriptCommand.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.command.dml;
8
9 import java.io.BufferedInputStream;
10 import java.io.BufferedReader;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.Reader;
14 import java.sql.Connection;
15 import java.sql.PreparedStatement;
16 import java.sql.ResultSet;
17 import java.sql.SQLException;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.Set;
23 import org.h2.command.CommandInterface;
24 import org.h2.command.Parser;
25 import org.h2.constant.ErrorCode;
26 import org.h2.constant.SysProperties;
27 import org.h2.constraint.Constraint;
28 import org.h2.engine.Comment;
29 import org.h2.engine.Constants;
30 import org.h2.engine.Database;
31 import org.h2.engine.DbObject;
32 import org.h2.engine.Right;
33 import org.h2.engine.Role;
34 import org.h2.engine.Session;
35 import org.h2.engine.Setting;
36 import org.h2.engine.User;
37 import org.h2.engine.UserAggregate;
38 import org.h2.engine.UserDataType;
39 import org.h2.expression.Expression;
40 import org.h2.expression.ExpressionColumn;
41 import org.h2.index.Cursor;
42 import org.h2.index.Index;
43 import org.h2.message.DbException;
44 import org.h2.result.LocalResult;
45 import org.h2.result.ResultInterface;
46 import org.h2.result.Row;
47 import org.h2.schema.Constant;
48 import org.h2.schema.Schema;
49 import org.h2.schema.SchemaObject;
50 import org.h2.schema.Sequence;
51 import org.h2.schema.TriggerObject;
52 import org.h2.table.Column;
53 import org.h2.table.PlanItem;
54 import org.h2.table.Table;
55 import org.h2.util.IOUtils;
56 import org.h2.util.MathUtils;
57 import org.h2.util.StatementBuilder;
58 import org.h2.util.StringUtils;
59 import org.h2.util.Utils;
60 import org.h2.value.Value;
61 import org.h2.value.ValueString;
62
63 /**
64 * This class represents the statement
65 * SCRIPT
66 */
67 public class ScriptCommand extends ScriptBase {
68
69 private String charset = Constants.UTF8;
70 private Set<String> schemaNames;
71 private Collection<Table> tables;
72 private boolean passwords;
73 /** true if we're generating the INSERT..VALUES statements for row values */
74 private boolean data;
75 private boolean settings;
76 /** true if we're generating the DROP statements */
77 private boolean drop;
78 private boolean simple;
79 private LocalResult result;
80 private byte[] lineSeparator;
81 private byte[] buffer;
82 private boolean tempLobTableCreated;
83 private int nextLobId;
84 private int lobBlockSize = Constants.IO_BUFFER_SIZE;
85
86 public ScriptCommand(Session session) {
87 super(session);
88 }
89
90 public boolean isQuery() {
91 return true;
92 }
93
94 // TODO lock all tables for 'script' command
95
96 public void setSchemaNames(Set<String> schemaNames) {
97 this.schemaNames = schemaNames;
98 }
99
100 public void setTables(Collection<Table> tables) {
101 this.tables = tables;
102 }
103
104 public void setData(boolean data) {
105 this.data = data;
106 }
107
108 public void setPasswords(boolean passwords) {
109 this.passwords = passwords;
110 }
111
112 public void setSettings(boolean settings) {
113 this.settings = settings;
114 }
115
116 public void setLobBlockSize(long blockSize) {
117 this.lobBlockSize = MathUtils.convertLongToInt(blockSize);
118 }
119
120 public void setDrop(boolean drop) {
121 this.drop = drop;
122 }
123
124 public ResultInterface queryMeta() {
125 LocalResult r = createResult();
126 r.done();
127 return r;
128 }
129
130 private LocalResult createResult() {
131 Expression[] expressions = { new ExpressionColumn(session.getDatabase(), new Column("SCRIPT",
132 Value.STRING)) };
133 return new LocalResult(session, expressions, 1);
134 }
135
136 public ResultInterface query(int maxrows) {
137 session.getUser().checkAdmin();
138 reset();
139 Database db = session.getDatabase();
140 if (schemaNames != null) {
141 for (String schemaName : schemaNames) {
142 Schema schema = db.findSchema(schemaName);
143 if (schema == null) {
144 throw DbException.get(ErrorCode.SCHEMA_NOT_FOUND_1, schemaName);
145 }
146 }
147 }
148 try {
149 result = createResult();
150 deleteStore();
151 openOutput();
152 if (out != null) {
153 buffer = new byte[Constants.IO_BUFFER_SIZE];
154 }
155 if (settings) {
156 for (Setting setting : db.getAllSettings()) {
157 if (setting.getName().equals(SetTypes.getTypeName(SetTypes.CREATE_BUILD))) {
158 // don't add CREATE_BUILD to the script
159 // (it is only set when creating the database)
160 continue;
161 }
162 add(setting.getCreateSQL(), false);
163 }
164 }
165 if (out != null) {
166 add("", true);
167 }
168 for (User user : db.getAllUsers()) {
169 add(user.getCreateSQL(passwords), false);
170 }
171 for (Role role : db.getAllRoles()) {
172 add(role.getCreateSQL(true), false);
173 }
174 for (Schema schema : db.getAllSchemas()) {
175 if (excludeSchema(schema)) {
176 continue;
177 }
178 add(schema.getCreateSQL(), false);
179 }
180 for (UserDataType datatype : db.getAllUserDataTypes()) {
181 if (drop) {
182 add(datatype.getDropSQL(), false);
183 }
184 add(datatype.getCreateSQL(), false);
185 }
186 for (SchemaObject obj : db.getAllSchemaObjects(DbObject.CONSTANT)) {
187 if (excludeSchema(obj.getSchema())) {
188 continue;
189 }
190 Constant constant = (Constant) obj;
191 add(constant.getCreateSQL(), false);
192 }
193
194 final ArrayList<Table> tables = db.getAllTablesAndViews(false);
195 // sort by id, so that views are after tables and views on views
196 // after the base views
197 Collections.sort(tables, new Comparator<Table>() {
198 public int compare(Table t1, Table t2) {
199 return t1.getId() - t2.getId();
200 }
201 });
202
203 // Generate the DROP XXX ... IF EXISTS
204 for (Table table : tables) {
205 if (excludeSchema(table.getSchema())) {
206 continue;
207 }
208 if (excludeTable(table)) {
209 continue;
210 }
211 if (table.isHidden()) {
212 continue;
213 }
214 table.lock(session, false, false);
215 String sql = table.getCreateSQL();
216 if (sql == null) {
217 // null for metadata tables
218 continue;
219 }
220 if (drop) {
221 add(table.getDropSQL(), false);
222 }
223 }
224 for (SchemaObject obj : db.getAllSchemaObjects(DbObject.FUNCTION_ALIAS)) {
225 if (excludeSchema(obj.getSchema())) {
226 continue;
227 }
228 if (drop) {
229 add(obj.getDropSQL(), false);
230 }
231 add(obj.getCreateSQL(), false);
232 }
233 for (UserAggregate agg : db.getAllAggregates()) {
234 if (drop) {
235 add(agg.getDropSQL(), false);
236 }
237 add(agg.getCreateSQL(), false);
238 }
239 for (SchemaObject obj : db.getAllSchemaObjects(DbObject.SEQUENCE)) {
240 if (excludeSchema(obj.getSchema())) {
241 continue;
242 }
243 Sequence sequence = (Sequence) obj;
244 if (drop) {
245 add(sequence.getDropSQL(), false);
246 }
247 add(sequence.getCreateSQL(), false);
248 }
249
250 // Generate CREATE TABLE and INSERT...VALUES
251 int count = 0;
252 for (Table table : tables) {
253 if (excludeSchema(table.getSchema())) {
254 continue;
255 }
256 if (excludeTable(table)) {
257 continue;
258 }
259 if (table.isHidden()) {
260 continue;
261 }
262 table.lock(session, false, false);
263 String createTableSql = table.getCreateSQL();
264 if (createTableSql == null) {
265 // null for metadata tables
266 continue;
267 }
268 final String tableType = table.getTableType();
269 add(createTableSql, false);
270 final ArrayList<Constraint> constraints = table.getConstraints();
271 if (constraints != null) {
272 for (Constraint constraint : constraints) {
273 if (Constraint.PRIMARY_KEY.equals(constraint.getConstraintType())) {
274 add(constraint.getCreateSQLWithoutIndexes(), false);
275 }
276 }
277 }
278 if (Table.TABLE.equals(tableType)) {
279 if (table.canGetRowCount()) {
280 String rowcount = "-- " + table.getRowCountApproximation() + " +/- SELECT COUNT(*) FROM "
281 + table.getSQL();
282 add(rowcount, false);
283 }
284 if (data) {
285 count = generateInsertValues(count, table);
286 }
287 }
288 final ArrayList<Index> indexes = table.getIndexes();
289 for (int j = 0; indexes != null && j < indexes.size(); j++) {
290 Index index = indexes.get(j);
291 if (!index.getIndexType().getBelongsToConstraint()) {
292 add(index.getCreateSQL(), false);
293 }
294 }
295 }
296 if (tempLobTableCreated) {
297 add("DROP TABLE IF EXISTS SYSTEM_LOB_STREAM", true);
298 add("CALL SYSTEM_COMBINE_BLOB(-1)", true);
299 add("DROP ALIAS IF EXISTS SYSTEM_COMBINE_CLOB", true);
300 add("DROP ALIAS IF EXISTS SYSTEM_COMBINE_BLOB", true);
301 tempLobTableCreated = false;
302 }
303 // Generate CREATE CONSTRAINT ...
304 final ArrayList<SchemaObject> constraints = db.getAllSchemaObjects(DbObject.CONSTRAINT);
305 Collections.sort(constraints, new Comparator<SchemaObject>() {
306 public int compare(SchemaObject c1, SchemaObject c2) {
307 return ((Constraint) c1).compareTo((Constraint) c2);
308 }
309 });
310 for (SchemaObject obj : constraints) {
311 if (excludeSchema(obj.getSchema())) {
312 continue;
313 }
314 Constraint constraint = (Constraint) obj;
315 if (excludeTable(constraint.getTable())) {
316 continue;
317 }
318 if (constraint.getTable().isHidden()) {
319 continue;
320 }
321 if (!Constraint.PRIMARY_KEY.equals(constraint.getConstraintType())) {
322 add(constraint.getCreateSQLWithoutIndexes(), false);
323 }
324 }
325 // Generate CREATE TRIGGER ...
326 for (SchemaObject obj : db.getAllSchemaObjects(DbObject.TRIGGER)) {
327 if (excludeSchema(obj.getSchema())) {
328 continue;
329 }
330 TriggerObject trigger = (TriggerObject) obj;
331 if (excludeTable(trigger.getTable())) {
332 continue;
333 }
334 add(trigger.getCreateSQL(), false);
335 }
336 // Generate GRANT ...
337 for (Right right : db.getAllRights()) {
338 Table table = right.getGrantedTable();
339 if (table != null) {
340 if (excludeSchema(table.getSchema())) {
341 continue;
342 }
343 if (excludeTable(table)) {
344 continue;
345 }
346 }
347 add(right.getCreateSQL(), false);
348 }
349 // Generate COMMENT ON ...
350 for (Comment comment : db.getAllComments()) {
351 add(comment.getCreateSQL(), false);
352 }
353 if (out != null) {
354 out.close();
355 }
356 } catch (IOException e) {
357 throw DbException.convertIOException(e, getFileName());
358 } finally {
359 closeIO();
360 }
361 result.done();
362 LocalResult r = result;
363 reset();
364 return r;
365 }
366
367 private int generateInsertValues(int count, Table table) throws IOException {
368 PlanItem plan = table.getBestPlanItem(session, null);
369 Index index = plan.getIndex();
370 Cursor cursor = index.find(session, null, null);
371 Column[] columns = table.getColumns();
372 StatementBuilder buff = new StatementBuilder("INSERT INTO ");
373 buff.append(table.getSQL()).append('(');
374 for (Column col : columns) {
375 buff.appendExceptFirst(", ");
376 buff.append(Parser.quoteIdentifier(col.getName()));
377 }
378 buff.append(") VALUES");
379 if (!simple) {
380 buff.append('\n');
381 }
382 buff.append('(');
383 String ins = buff.toString();
384 buff = null;
385 while (cursor.next()) {
386 Row row = cursor.get();
387 if (buff == null) {
388 buff = new StatementBuilder(ins);
389 } else {
390 buff.append(",\n(");
391 }
392 for (int j = 0; j < row.getColumnCount(); j++) {
393 if (j > 0) {
394 buff.append(", ");
395 }
396 Value v = row.getValue(j);
397 if (v.getPrecision() > lobBlockSize) {
398 int id;
399 if (v.getType() == Value.CLOB) {
400 id = writeLobStream(v);
401 buff.append("SYSTEM_COMBINE_CLOB(" + id + ")");
402 } else if (v.getType() == Value.BLOB) {
403 id = writeLobStream(v);
404 buff.append("SYSTEM_COMBINE_BLOB(" + id + ")");
405 } else {
406 buff.append(v.getSQL());
407 }
408 } else {
409 buff.append(v.getSQL());
410 }
411 }
412 buff.append(')');
413 count++;
414 if ((count & 127) == 0) {
415 checkCanceled();
416 }
417 if (simple || buff.length() > Constants.IO_BUFFER_SIZE) {
418 add(buff.toString(), true);
419 buff = null;
420 }
421 }
422 if (buff != null) {
423 add(buff.toString(), true);
424 }
425 return count;
426 }
427
428 private int writeLobStream(Value v) throws IOException {
429 if (!tempLobTableCreated) {
430 add("CREATE TABLE IF NOT EXISTS SYSTEM_LOB_STREAM" +
431 "(ID INT NOT NULL, PART INT NOT NULL, CDATA VARCHAR, BDATA BINARY)", true);
432 add("CREATE PRIMARY KEY SYSTEM_LOB_STREAM_PRIMARY_KEY " +
433 "ON SYSTEM_LOB_STREAM(ID, PART)", true);
434 add("CREATE ALIAS IF NOT EXISTS " +
435 "SYSTEM_COMBINE_CLOB FOR \"" + this.getClass().getName() + ".combineClob\"", true);
436 add("CREATE ALIAS IF NOT EXISTS " +
437 "SYSTEM_COMBINE_BLOB FOR \"" + this.getClass().getName() + ".combineBlob\"", true);
438 tempLobTableCreated = true;
439 }
440 int id = nextLobId++;
441 switch (v.getType()) {
442 case Value.BLOB: {
443 byte[] bytes = new byte[lobBlockSize];
444 InputStream input = v.getInputStream();
445 try {
446 for (int i = 0;; i++) {
447 StringBuilder buff = new StringBuilder(lobBlockSize * 2);
448 buff.append("INSERT INTO SYSTEM_LOB_STREAM VALUES(" + id + ", " + i + ", NULL, '");
449 int len = IOUtils.readFully(input, bytes, 0, lobBlockSize);
450 if (len <= 0) {
451 break;
452 }
453 buff.append(StringUtils.convertBytesToHex(bytes, len)).append("')");
454 String sql = buff.toString();
455 add(sql, true);
456 }
457 } finally {
458 IOUtils.closeSilently(input);
459 }
460 break;
461 }
462 case Value.CLOB: {
463 char[] chars = new char[lobBlockSize];
464 Reader reader = v.getReader();
465 try {
466 for (int i = 0;; i++) {
467 StringBuilder buff = new StringBuilder(lobBlockSize * 2);
468 buff.append("INSERT INTO SYSTEM_LOB_STREAM VALUES(" + id + ", " + i + ", ");
469 int len = IOUtils.readFully(reader, chars, lobBlockSize);
470 if (len < 0) {
471 break;
472 }
473 buff.append(StringUtils.quoteStringSQL(new String(chars, 0, len))).
474 append(", NULL)");
475 String sql = buff.toString();
476 add(sql, true);
477 }
478 } finally {
479 IOUtils.closeSilently(reader);
480 }
481 break;
482 }
483 default:
484 DbException.throwInternalError("type:" + v.getType());
485 }
486 return id;
487 }
488
489 /**
490 * Combine a BLOB.
491 * This method is called from the script.
492 * When calling with id -1, the file is deleted.
493 *
494 * @param conn a connection
495 * @param id the lob id
496 * @return a stream for the combined data
497 */
498 public static InputStream combineBlob(Connection conn, int id) throws SQLException {
499 if (id < 0) {
500 return null;
501 }
502 final ResultSet rs = getLobStream(conn, "BDATA", id);
503 return new InputStream() {
504 private InputStream current;
505 private boolean closed;
506 public int read() throws IOException {
507 while (true) {
508 try {
509 if (current == null) {
510 if (closed) {
511 return -1;
512 }
513 if (!rs.next()) {
514 close();
515 return -1;
516 }
517 current = rs.getBinaryStream(1);
518 current = new BufferedInputStream(current);
519 }
520 int x = current.read();
521 if (x >= 0) {
522 return x;
523 }
524 current = null;
525 } catch (SQLException e) {
526 throw DbException.convertToIOException(e);
527 }
528 }
529 }
530 public void close() throws IOException {
531 if (closed) {
532 return;
533 }
534 closed = true;
535 try {
536 rs.close();
537 } catch (SQLException e) {
538 throw DbException.convertToIOException(e);
539 }
540 }
541 };
542 }
543
544 /**
545 * Combine a CLOB.
546 * This method is called from the script.
547 *
548 * @param conn a connection
549 * @param id the lob id
550 * @return a reader for the combined data
551 */
552 public static Reader combineClob(Connection conn, int id) throws SQLException {
553 if (id < 0) {
554 return null;
555 }
556 final ResultSet rs = getLobStream(conn, "CDATA", id);
557 return new Reader() {
558 private Reader current;
559 private boolean closed;
560 public int read() throws IOException {
561 while (true) {
562 try {
563 if (current == null) {
564 if (closed) {
565 return -1;
566 }
567 if (!rs.next()) {
568 close();
569 return -1;
570 }
571 current = rs.getCharacterStream(1);
572 current = new BufferedReader(current);
573 }
574 int x = current.read();
575 if (x >= 0) {
576 return x;
577 }
578 current = null;
579 } catch (SQLException e) {
580 throw DbException.convertToIOException(e);
581 }
582 }
583 }
584 public void close() throws IOException {
585 if (closed) {
586 return;
587 }
588 closed = true;
589 try {
590 rs.close();
591 } catch (SQLException e) {
592 throw DbException.convertToIOException(e);
593 }
594 }
595 public int read(char[] buffer, int off, int len) throws IOException {
596 if (len == 0) {
597 return 0;
598 }
599 int c = read();
600 if (c == -1) {
601 return -1;
602 }
603 buffer[off] = (char) c;
604 int i = 1;
605 for (; i < len; i++) {
606 c = read();
607 if (c == -1) {
608 break;
609 }
610 buffer[off + i] = (char) c;
611 }
612 return i;
613 }
614 };
615 }
616
617 private static ResultSet getLobStream(Connection conn, String column, int id) throws SQLException {
618 PreparedStatement prep = conn.prepareStatement(
619 "SELECT " + column + " FROM SYSTEM_LOB_STREAM WHERE ID=? ORDER BY PART");
620 prep.setInt(1, id);
621 return prep.executeQuery();
622 }
623
624 private void reset() {
625 result = null;
626 buffer = null;
627 try {
628 lineSeparator = SysProperties.LINE_SEPARATOR.getBytes(charset);
629 } catch (IOException e) {
630 throw DbException.convertIOException(e, null);
631 }
632 }
633
634 private boolean excludeSchema(Schema schema) {
635 if (schemaNames != null && !schemaNames.contains(schema.getName())) {
636 return true;
637 }
638 if (tables != null) {
639 // if filtering on specific tables, only include those schemas
640 for (Table table : schema.getAllTablesAndViews()) {
641 if (tables.contains(table)) {
642 return false;
643 }
644 }
645 return true;
646 }
647 return false;
648 }
649
650 private boolean excludeTable(Table table) {
651 return tables != null && !tables.contains(table);
652 }
653
654 private void add(String s, boolean insert) throws IOException {
655 if (s == null) {
656 return;
657 }
658 s += ";";
659 if (out != null) {
660 byte[] buff = s.getBytes(charset);
661 int len = MathUtils.roundUpInt(buff.length + lineSeparator.length, Constants.FILE_BLOCK_SIZE);
662 buffer = Utils.copy(buff, buffer);
663
664 if (len > buffer.length) {
665 buffer = new byte[len];
666 }
667 System.arraycopy(buff, 0, buffer, 0, buff.length);
668 for (int i = buff.length; i < len - lineSeparator.length; i++) {
669 buffer[i] = ' ';
670 }
671 for (int j = 0, i = len - lineSeparator.length; i < len; i++, j++) {
672 buffer[i] = lineSeparator[j];
673 }
674 out.write(buffer, 0, len);
675 if (!insert) {
676 Value[] row = { ValueString.get(s) };
677 result.addRow(row);
678 }
679 } else {
680 Value[] row = { ValueString.get(s) };
681 result.addRow(row);
682 }
683 }
684
685 public void setSimple(boolean simple) {
686 this.simple = simple;
687 }
688
689 public void setCharset(String charset) {
690 this.charset = charset;
691 }
692
693 public int getType() {
694 return CommandInterface.SCRIPT;
695 }
696
697 }
698