001: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the Hypersonic SQL Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: *
030: * This software consists of voluntary contributions made by many individuals
031: * on behalf of the Hypersonic SQL Group.
032: *
033: *
034: * For work added by the HSQL Development Group:
035: *
036: * Copyright (c) 2001-2005, The HSQL Development Group
037: * All rights reserved.
038: *
039: * Redistribution and use in source and binary forms, with or without
040: * modification, are permitted provided that the following conditions are met:
041: *
042: * Redistributions of source code must retain the above copyright notice, this
043: * list of conditions and the following disclaimer.
044: *
045: * Redistributions in binary form must reproduce the above copyright notice,
046: * this list of conditions and the following disclaimer in the documentation
047: * and/or other materials provided with the distribution.
048: *
049: * Neither the name of the HSQL Development Group nor the names of its
050: * contributors may be used to endorse or promote products derived from this
051: * software without specific prior written permission.
052: *
053: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
054: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
055: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
056: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
057: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
058: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
059: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
060: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
061: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
062: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
063: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
064: */
065:
066: package org.hsqldb;
067:
068: import org.hsqldb.HsqlNameManager.HsqlName;
069: import org.hsqldb.lib.HashMap;
070: import org.hsqldb.lib.HashMappedList;
071: import org.hsqldb.lib.HsqlArrayList;
072: import org.hsqldb.lib.IntValueHashMap;
073: import org.hsqldb.lib.Iterator;
074: import org.hsqldb.lib.StringConverter;
075:
076: /**
077: * Script generation.
078: *
079: * The core functionality of this class was inherited from Hypersonic and
080: * extensively rewritten and extended in successive versions of HSQLDB.<p>
081: *
082: * @author Thomas Mueller (Hypersonic SQL Group)
083: * @author fredt@users
084: * @version 1.8.0
085: * @since 1.7.0
086: */
087: public class DatabaseScript {
088:
089: /**
090: * Returns the DDL and all other statements for the database excluding
091: * INSERT and SET <tablename> READONLY statements.
092: * cachedData == true indicates that SET <tablename> INDEX statements should
093: * also be included.
094: *
095: * This class should not have any dependencies on metadata reporting.
096: */
097: public static Result getScript(Database database, boolean indexRoots) {
098:
099: Iterator it;
100: Result r = Result.newSingleColumnResult("COMMAND",
101: Types.VARCHAR);
102:
103: r.metaData.tableNames[0] = "SYSTEM_SCRIPT";
104:
105: // collation for database
106: if (database.collation.name != null) {
107: String name = StringConverter.toQuotedString(
108: database.collation.name, '"', true);
109:
110: addRow(r, "SET DATABASE COLLATION " + name);
111: }
112:
113: // Role definitions
114: it = database.getGranteeManager().getRoleNames().iterator();
115:
116: String role;
117:
118: while (it.hasNext()) {
119: role = (String) it.next();
120:
121: // ADMIN_ROLE_NAME is not persisted
122: if (!GranteeManager.DBA_ADMIN_ROLE_NAME.equals(role)) {
123: addRow(r, "CREATE ROLE " + role);
124: }
125: }
126:
127: // aliases
128: HashMap h = database.getAliasMap();
129: HashMap builtin = Library.getAliasMap();
130:
131: it = h.keySet().iterator();
132:
133: while (it.hasNext()) {
134: String alias = (String) it.next();
135: String java = (String) h.get(alias);
136: String biJava = (String) builtin.get(alias);
137:
138: if (biJava != null && biJava.equals(java)) {
139: continue;
140: }
141:
142: StringBuffer buffer = new StringBuffer(64);
143:
144: buffer.append(Token.T_CREATE).append(' ').append(
145: Token.T_ALIAS).append(' ');
146: buffer.append(alias);
147: buffer.append(" FOR \"");
148: buffer.append(java);
149: buffer.append('"');
150: addRow(r, buffer.toString());
151: }
152:
153: addSchemaStatements(database, r, indexRoots);
154:
155: // rights for classes, tables and views
156: addRightsStatements(database, r);
157:
158: if (database.logger.hasLog()) {
159: int delay = database.logger.getWriteDelay();
160: boolean millis = delay < 1000;
161:
162: if (millis) {
163: if (delay != 0 && delay < 20) {
164: delay = 20;
165: }
166: } else {
167: delay /= 1000;
168: }
169:
170: String statement = "SET WRITE_DELAY " + delay
171: + (millis ? " MILLIS" : "");
172:
173: addRow(r, statement);
174: }
175:
176: return r;
177: }
178:
179: static void addSchemaStatements(Database database, Result r,
180: boolean indexRoots) {
181:
182: Iterator schemas = database.schemaManager
183: .userSchemaNameIterator();
184:
185: while (schemas.hasNext()) {
186: String schemaKey = (String) schemas.next();
187: HsqlName schema = database.schemaManager
188: .toSchemaHsqlName(schemaKey);
189: HashMappedList tTable = database.schemaManager
190: .getTables(schema.name);
191: HsqlArrayList forwardFK = new HsqlArrayList();
192:
193: // schema creation
194: {
195: String ddl = getSchemaCreateDDL(database, schema);
196:
197: addRow(r, ddl);
198: }
199:
200: // sequences
201: /*
202: CREATE SEQUENCE <name>
203: [AS {INTEGER | BIGINT}]
204: [START WITH <value>]
205: [INCREMENT BY <value>]
206: */
207: Iterator it = database.schemaManager
208: .sequenceIterator(schema.name);
209:
210: while (it.hasNext()) {
211: NumberSequence seq = (NumberSequence) it.next();
212: StringBuffer a = new StringBuffer(128);
213:
214: a.append(Token.T_CREATE).append(' ');
215: a.append(Token.T_SEQUENCE).append(' ');
216: a.append(seq.getName().statementName).append(' ');
217: a.append(Token.T_AS).append(' ');
218: a.append(Types.getTypeString(seq.getType()))
219: .append(' ');
220: a.append(Token.T_START).append(' ');
221: a.append(Token.T_WITH).append(' ');
222: a.append(seq.peek()).append(' ');
223:
224: if (seq.getIncrement() != 1) {
225: a.append(Token.T_INCREMENT).append(' ');
226: a.append(Token.T_BY).append(' ');
227: a.append(seq.getIncrement()).append(' ');
228: }
229:
230: addRow(r, a.toString());
231: }
232:
233: // tables
234: for (int i = 0, tSize = tTable.size(); i < tSize; i++) {
235: Table t = (Table) tTable.get(i);
236:
237: if (t.isView()) {
238: continue;
239: }
240:
241: StringBuffer a = new StringBuffer(128);
242:
243: getTableDDL(database, t, i, forwardFK, false, a);
244: addRow(r, a.toString());
245:
246: // indexes for table
247: for (int j = 1; j < t.getIndexCount(); j++) {
248: Index index = t.getIndex(j);
249:
250: if (HsqlName.isReservedName(index.getName().name)) {
251:
252: // the following are autocreated with the table
253: // indexes for primary keys
254: // indexes for unique constraints
255: // own table indexes for foreign keys
256: continue;
257: }
258:
259: a = new StringBuffer(64);
260:
261: a.append(Token.T_CREATE).append(' ');
262:
263: if (index.isUnique()) {
264: a.append(Token.T_UNIQUE).append(' ');
265: }
266:
267: a.append(Token.T_INDEX).append(' ');
268: a.append(index.getName().statementName);
269: a.append(' ').append(Token.T_ON).append(' ');
270: a.append(t.getName().statementName);
271:
272: int[] col = index.getColumns();
273: int len = index.getVisibleColumns();
274:
275: getColumnList(t, col, len, a);
276: addRow(r, a.toString());
277: }
278:
279: // readonly for TEXT tables only
280: if (t.isText() && t.isConnected() && t.isDataReadOnly()) {
281: a = new StringBuffer(64);
282:
283: a.append(Token.T_SET).append(' ').append(
284: Token.T_TABLE).append(' ');
285: a.append(t.getName().statementName);
286: a.append(' ').append(Token.T_READONLY).append(' ')
287: .append(Token.T_TRUE);
288: addRow(r, a.toString());
289: }
290:
291: // data source
292: String dataSource = getDataSource(t);
293:
294: if (dataSource != null) {
295: addRow(r, dataSource);
296: }
297:
298: // header
299: String header = getDataSourceHeader(t);
300:
301: if (!indexRoots && header != null) {
302: addRow(r, header);
303: }
304:
305: // triggers
306: int numTrigs = TriggerDef.NUM_TRIGS;
307:
308: for (int tv = 0; tv < numTrigs; tv++) {
309: HsqlArrayList trigVec = t.triggerLists[tv];
310:
311: if (trigVec == null) {
312: continue;
313: }
314:
315: int trCount = trigVec.size();
316:
317: for (int k = 0; k < trCount; k++) {
318: a = ((TriggerDef) trigVec.get(k)).getDDL();
319:
320: addRow(r, a.toString());
321: }
322: }
323: }
324:
325: // forward referencing foreign keys
326: for (int i = 0, tSize = forwardFK.size(); i < tSize; i++) {
327: Constraint c = (Constraint) forwardFK.get(i);
328: StringBuffer a = new StringBuffer(128);
329:
330: a.append(Token.T_ALTER).append(' ').append(
331: Token.T_TABLE).append(' ');
332: a.append(c.getRef().getName().statementName);
333: a.append(' ').append(Token.T_ADD).append(' ');
334: getFKStatement(c, a);
335: addRow(r, a.toString());
336: }
337:
338: // SET <tablename> INDEX statements
339: Session sysSession = database.sessionManager
340: .getSysSession();
341:
342: for (int i = 0, tSize = tTable.size(); i < tSize; i++) {
343: Table t = (Table) tTable.get(i);
344:
345: if (indexRoots && t.isIndexCached()
346: && !t.isEmpty(sysSession)) {
347: addRow(r, getIndexRootsDDL((Table) tTable.get(i)));
348: }
349: }
350:
351: // RESTART WITH <value> statements
352: for (int i = 0, tSize = tTable.size(); i < tSize; i++) {
353: Table t = (Table) tTable.get(i);
354:
355: if (!t.isTemp()) {
356: String ddl = getIdentityUpdateDDL(t);
357:
358: addRow(r, ddl);
359: }
360: }
361:
362: // views
363: for (int i = 0, tSize = tTable.size(); i < tSize; i++) {
364: Table t = (Table) tTable.get(i);
365:
366: if (t.isView()) {
367: View v = (View) tTable.get(i);
368: StringBuffer a = new StringBuffer(128);
369:
370: a.append(Token.T_CREATE).append(' ').append(
371: Token.T_VIEW).append(' ');
372: a.append(v.getName().statementName).append(' ')
373: .append('(');
374:
375: int count = v.getColumnCount();
376:
377: for (int j = 0; j < count; j++) {
378: a
379: .append(v.getColumn(j).columnName.statementName);
380:
381: if (j < count - 1) {
382: a.append(',');
383: }
384: }
385:
386: a.append(')').append(' ').append(Token.T_AS)
387: .append(' ');
388: a.append(v.getStatement());
389: addRow(r, a.toString());
390: }
391: }
392: }
393: }
394:
395: static String getIdentityUpdateDDL(Table t) {
396:
397: if (t.identityColumn == -1) {
398: return "";
399: } else {
400: String tablename = t.getName().statementName;
401: String colname = t.getColumn(t.identityColumn).columnName.statementName;
402: long idval = t.identitySequence.peek();
403: StringBuffer a = new StringBuffer(128);
404:
405: a.append(Token.T_ALTER).append(' ').append(Token.T_TABLE)
406: .append(' ').append(tablename).append(' ').append(
407: Token.T_ALTER).append(' ').append(
408: Token.T_COLUMN).append(' ').append(colname)
409: .append(' ').append(Token.T_RESTART).append(' ')
410: .append(Token.T_WITH).append(' ').append(idval);
411:
412: return a.toString();
413: }
414: }
415:
416: static String getIndexRootsDDL(Table t) {
417:
418: StringBuffer a = new StringBuffer(128);
419:
420: a.append(Token.T_SET).append(' ').append(Token.T_TABLE).append(
421: ' ');
422: a.append(t.getName().statementName);
423: a.append(' ').append(Token.T_INDEX).append('\'');
424: a.append(t.getIndexRoots());
425: a.append('\'');
426:
427: return a.toString();
428: }
429:
430: static String getSchemaCreateDDL(Database database,
431: HsqlName schemaName) {
432:
433: StringBuffer ab = new StringBuffer(128);
434:
435: ab.append(Token.T_CREATE).append(' ');
436: ab.append(Token.T_SCHEMA).append(' ');
437: ab.append(schemaName.statementName).append(' ');
438: ab.append(Token.T_AUTHORIZATION).append(' ');
439: ab.append(GranteeManager.DBA_ADMIN_ROLE_NAME);
440:
441: return ab.toString();
442: }
443:
444: static void getTableDDL(Database database, Table t, int i,
445: HsqlArrayList forwardFK, boolean useSchema, StringBuffer a) {
446:
447: a.append(Token.T_CREATE).append(' ');
448:
449: if (t.isTemp) {
450: a.append(Token.T_GLOBAL).append(' ');
451: a.append(Token.T_TEMPORARY).append(' ');
452: }
453:
454: if (t.isText()) {
455: a.append(Token.T_TEXT).append(' ');
456: } else if (t.isCached()) {
457: a.append(Token.T_CACHED).append(' ');
458: } else {
459: a.append(Token.T_MEMORY).append(' ');
460: }
461:
462: a.append(Token.T_TABLE).append(' ');
463:
464: if (useSchema) {
465: a.append(t.getName().schema.statementName).append('.');
466: }
467:
468: a.append(t.getName().statementName);
469: a.append('(');
470:
471: int columns = t.getColumnCount();
472: int[] pk = t.getPrimaryKey();
473: HsqlName pkName = null;
474: Constraint pkConst = t.getPrimaryConstraint();
475:
476: if (pkConst != null && !pkConst.getName().isReservedName()) {
477: pkName = pkConst.getName();
478: }
479:
480: for (int j = 0; j < columns; j++) {
481: Column column = t.getColumn(j);
482: String colname = column.columnName.statementName;
483:
484: a.append(colname);
485: a.append(' ');
486:
487: String sType = Types.getTypeString(column.getType());
488:
489: a.append(sType);
490:
491: // append the size and scale if > 0
492: boolean hasSize = false;
493:
494: if (column.getType() == Types.TIMESTAMP) {
495: if (column.getSize() != 6) {
496: hasSize = true;
497: }
498: } else {
499: hasSize = column.getSize() > 0;
500: }
501:
502: if (hasSize) {
503: a.append('(');
504: a.append(column.getSize());
505:
506: if (column.getScale() > 0) {
507: a.append(',');
508: a.append(column.getScale());
509: }
510:
511: a.append(')');
512: }
513:
514: String defaultString = column.getDefaultDDL();
515:
516: if (defaultString != null) {
517: a.append(' ').append(Token.T_DEFAULT).append(' ');
518: a.append(defaultString);
519: }
520:
521: if (j == t.getIdentityColumn()) {
522: a
523: .append(" GENERATED BY DEFAULT AS IDENTITY(START WITH ");
524: a.append(column.identityStart);
525:
526: if (column.identityIncrement != 1) {
527: a.append(Token.T_COMMA).append(Token.T_INCREMENT)
528: .append(' ').append(Token.T_BY).append(' ');
529: a.append(column.identityIncrement);
530: }
531:
532: a.append(")");
533: }
534:
535: if (!column.isNullable()) {
536: a.append(' ').append(Token.T_NOT).append(' ').append(
537: Token.T_NULL);
538: }
539:
540: if ((pk.length == 1) && (j == pk[0]) && pkName == null) {
541: a.append(' ').append(Token.T_PRIMARY).append(' ')
542: .append(Token.T_KEY);
543: }
544:
545: if (j < columns - 1) {
546: a.append(',');
547: }
548: }
549:
550: if (pk.length > 1 || (pk.length == 1 && pkName != null)) {
551: a.append(',');
552:
553: if (pkName != null) {
554: a.append(Token.T_CONSTRAINT).append(' ');
555: a.append(pkName.statementName).append(' ');
556: }
557:
558: a.append(Token.T_PRIMARY).append(' ').append(Token.T_KEY);
559: getColumnList(t, pk, pk.length, a);
560: }
561:
562: Constraint[] v = t.getConstraints();
563:
564: for (int j = 0, vSize = v.length; j < vSize; j++) {
565: Constraint c = v[j];
566:
567: switch (c.getType()) {
568:
569: case Constraint.UNIQUE:
570: a.append(',').append(Token.T_CONSTRAINT).append(' ');
571: a.append(c.getName().statementName);
572: a.append(' ').append(Token.T_UNIQUE);
573:
574: int[] col = c.getMainColumns();
575:
576: getColumnList(c.getMain(), col, col.length, a);
577: break;
578:
579: case Constraint.FOREIGN_KEY:
580:
581: // forward referencing FK
582: Table maintable = c.getMain();
583: int maintableindex = database.schemaManager
584: .getTableIndex(maintable);
585:
586: if (maintableindex > i) {
587: forwardFK.add(c);
588: } else {
589: a.append(',');
590: getFKStatement(c, a);
591: }
592: break;
593:
594: case Constraint.CHECK:
595: try {
596: a.append(',').append(Token.T_CONSTRAINT)
597: .append(' ');
598: a.append(c.getName().statementName);
599: a.append(' ').append(Token.T_CHECK).append('(');
600: a.append(c.core.check.getDDL());
601: a.append(')');
602: } catch (HsqlException e) {
603:
604: // should not throw as it is already tested OK
605: }
606: break;
607: }
608: }
609:
610: a.append(')');
611:
612: if (t.onCommitPreserve) {
613: a.append(' ').append(Token.T_ON).append(' ');
614: a.append(Token.T_COMMIT).append(' ').append(
615: Token.T_PRESERVE);
616: a.append(' ').append(Token.T_ROWS);
617: }
618: }
619:
620: /**
621: * Generates the SET TABLE <tablename> SOURCE <string> statement for a
622: * text table;
623: */
624: static String getDataSource(Table t) {
625:
626: String dataSource = t.getDataSource();
627:
628: if (dataSource == null) {
629: return null;
630: }
631:
632: boolean isDesc = t.isDescDataSource();
633: StringBuffer a = new StringBuffer(128);
634:
635: a.append(Token.T_SET).append(' ').append(Token.T_TABLE).append(
636: ' ');
637: a.append(t.getName().statementName);
638: a.append(' ').append(Token.T_SOURCE).append(' ').append('"');
639: a.append(dataSource);
640: a.append('"');
641:
642: if (isDesc) {
643: a.append(' ').append(Token.T_DESC);
644: }
645:
646: return a.toString();
647: }
648:
649: /**
650: * Generates the SET TABLE <tablename> SOURCE HEADER <string> statement for a
651: * text table;
652: */
653: static String getDataSourceHeader(Table t) {
654:
655: String header = t.getHeader();
656:
657: if (header == null) {
658: return null;
659: }
660:
661: StringBuffer a = new StringBuffer(128);
662:
663: a.append(Token.T_SET).append(' ').append(Token.T_TABLE).append(
664: ' ');
665: a.append(t.getName().statementName);
666: a.append(' ').append(Token.T_SOURCE).append(' ');
667: a.append(Token.T_HEADER).append(' ');
668: a.append(header);
669:
670: return a.toString();
671: }
672:
673: /**
674: * Generates the column definitions for a table.
675: */
676: private static void getColumnList(Table t, int[] col, int len,
677: StringBuffer a) {
678:
679: a.append('(');
680:
681: for (int i = 0; i < len; i++) {
682: a.append(t.getColumn(col[i]).columnName.statementName);
683:
684: if (i < len - 1) {
685: a.append(',');
686: }
687: }
688:
689: a.append(')');
690: }
691:
692: /**
693: * Generates the foreign key declaration for a given Constraint object.
694: */
695: private static void getFKStatement(Constraint c, StringBuffer a) {
696:
697: a.append(Token.T_CONSTRAINT).append(' ');
698: a.append(c.getName().statementName);
699: a.append(' ').append(Token.T_FOREIGN).append(' ').append(
700: Token.T_KEY);
701:
702: int[] col = c.getRefColumns();
703:
704: getColumnList(c.getRef(), col, col.length, a);
705: a.append(' ').append(Token.T_REFERENCES).append(' ');
706: a.append(c.getMain().getName().statementName);
707:
708: col = c.getMainColumns();
709:
710: getColumnList(c.getMain(), col, col.length, a);
711:
712: if (c.getDeleteAction() != Constraint.NO_ACTION) {
713: a.append(' ').append(Token.T_ON).append(' ').append(
714: Token.T_DELETE).append(' ');
715: a.append(getFKAction(c.getDeleteAction()));
716: }
717:
718: if (c.getUpdateAction() != Constraint.NO_ACTION) {
719: a.append(' ').append(Token.T_ON).append(' ').append(
720: Token.T_UPDATE).append(' ');
721: a.append(getFKAction(c.getUpdateAction()));
722: }
723: }
724:
725: /**
726: * Returns the foreign key action rule.
727: */
728: private static String getFKAction(int action) {
729:
730: switch (action) {
731:
732: case Constraint.CASCADE:
733: return Token.T_CASCADE;
734:
735: case Constraint.SET_DEFAULT:
736: return Token.T_SET + ' ' + Token.T_DEFAULT;
737:
738: case Constraint.SET_NULL:
739: return Token.T_SET + ' ' + Token.T_NULL;
740:
741: default:
742: return Token.T_NO + ' ' + Token.T_ACTION;
743: }
744: }
745:
746: /**
747: * Adds a script line to the result.
748: */
749: private static void addRow(Result r, String sql) {
750:
751: if (sql == null || sql.length() == 0) {
752: return;
753: }
754:
755: String[] s = new String[1];
756:
757: s[0] = sql;
758:
759: r.add(s);
760: }
761:
762: /**
763: * Generates the GRANT statements for grantees.
764: *
765: * When views is true, generates rights for views only. Otherwise generates
766: * rights for tables and classes.
767: *
768: * Does not generate script for:
769: *
770: * grant on builtin classes to public
771: * grant select on system tables
772: *
773: */
774: private static void addRightsStatements(Database dDatabase, Result r) {
775:
776: StringBuffer a;
777: HashMappedList userlist = dDatabase.getUserManager().getUsers();
778: Iterator users = userlist.values().iterator();
779: GranteeManager gm = dDatabase.getGranteeManager();
780: Iterator grantees = gm.getGrantees().iterator();
781:
782: for (; users.hasNext();) {
783: User u = (User) users.next();
784: String name = u.getName();
785:
786: // PUBLIC user is not persisted. (However, his
787: // grants/revokes are). _SYSTEM user not in user list.
788: if (!name.equals(Token.T_PUBLIC)) {
789: addRow(r, u.getCreateUserDDL());
790: }
791: }
792:
793: // grantees has ALL Users and Roles, incl. hidden and reserved ones.
794: // Therefore, we filter out the non-persisting ones.
795: for (; grantees.hasNext();) {
796: Grantee g = (Grantee) grantees.next();
797: String name = g.getName();
798:
799: // _SYSTEM user, DBA Role grants/revokes not persisted
800: if (name.equals("_SYSTEM") || name.equals("DBA")) {
801: continue;
802: }
803:
804: String roleString = g.allRolesString();
805:
806: if (roleString != null) {
807: addRow(r, "GRANT " + roleString + " TO " + name);
808: }
809:
810: IntValueHashMap rightsmap = g.getRights();
811:
812: if (rightsmap == null) {
813: continue;
814: }
815:
816: Iterator dbobjects = rightsmap.keySet().iterator();
817:
818: while (dbobjects.hasNext()) {
819: Object nameobject = dbobjects.next();
820: int right = rightsmap.get(nameobject, 0);
821:
822: a = new StringBuffer(64);
823:
824: a.append(Token.T_GRANT).append(' ');
825: a.append(GranteeManager.getRightsList(right));
826: a.append(' ').append(Token.T_ON).append(' ');
827:
828: if (nameobject instanceof String) {
829: if (nameobject.equals("java.lang.Math")
830: || nameobject.equals("org.hsqldb.Library")) {
831: continue;
832: }
833:
834: a.append("CLASS \"");
835: a.append((String) nameobject);
836: a.append('\"');
837: } else {
838: HsqlName hsqlname = (HsqlName) nameobject;
839:
840: // assumes all non String objects are table names
841: Table table = dDatabase.schemaManager
842: .findUserTable(null, hsqlname.name,
843: hsqlname.schema.name);
844:
845: // either table != null or is system table
846: if (table != null) {
847: a.append(hsqlname.schema.statementName).append(
848: '.').append(hsqlname.statementName);
849: } else {
850: continue;
851: }
852: }
853:
854: a.append(' ').append(Token.T_TO).append(' ');
855: a.append(g.getName());
856: addRow(r, a.toString());
857: }
858: }
859: }
860: }
|