~ubuntu-branches/ubuntu/raring/apgdiff/raring

« back to all changes in this revision

Viewing changes to src/main/java/cz/startnet/utils/pgdiff/PgDiffTables.java

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Berg
  • Date: 2008-09-09 15:42:54 UTC
  • Revision ID: james.westby@ubuntu.com-20080909154254-458sv7ew1rczdal1
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: PgDiffTables.java 80 2007-09-01 20:25:45Z fordfrog $
 
3
 */
 
4
package cz.startnet.utils.pgdiff;
 
5
 
 
6
import cz.startnet.utils.pgdiff.schema.PgColumn;
 
7
import cz.startnet.utils.pgdiff.schema.PgColumnUtils;
 
8
import cz.startnet.utils.pgdiff.schema.PgSchema;
 
9
import cz.startnet.utils.pgdiff.schema.PgTable;
 
10
 
 
11
import java.io.PrintWriter;
 
12
 
 
13
import java.util.ArrayList;
 
14
import java.util.HashMap;
 
15
import java.util.List;
 
16
import java.util.Map;
 
17
 
 
18
 
 
19
/**
 
20
 * Diffs tables.
 
21
 *
 
22
 * @author fordfrog
 
23
 * @version $Id: PgDiffTables.java 80 2007-09-01 20:25:45Z fordfrog $
 
24
 */
 
25
public class PgDiffTables {
 
26
    /**
 
27
     * Creates a new instance of PgDiffTables.
 
28
     */
 
29
    private PgDiffTables() {
 
30
        super();
 
31
    }
 
32
 
 
33
    /**
 
34
     * Generates and outputs CLUSTER specific DDL if appropriate.
 
35
     *
 
36
     * @param writer writer the output should be written to
 
37
     * @param arguments object containing arguments settings
 
38
     * @param oldSchema original schema
 
39
     * @param newSchema new schema
 
40
     */
 
41
    public static void diffClusters(
 
42
        final PrintWriter writer,
 
43
        final PgDiffArguments arguments,
 
44
        final PgSchema oldSchema,
 
45
        final PgSchema newSchema) {
 
46
        for (PgTable newTable : newSchema.getTables()) {
 
47
            final PgTable oldTable;
 
48
 
 
49
            if (oldSchema == null) {
 
50
                oldTable = null;
 
51
            } else {
 
52
                oldTable = oldSchema.getTable(newTable.getName());
 
53
            }
 
54
 
 
55
            final String oldCluster;
 
56
 
 
57
            if (oldTable == null) {
 
58
                oldCluster = null;
 
59
            } else {
 
60
                oldCluster = oldTable.getClusterIndexName();
 
61
            }
 
62
 
 
63
            final String newCluster = newTable.getClusterIndexName();
 
64
 
 
65
            if (
 
66
                ((oldCluster == null) && (newCluster != null))
 
67
                    || ((oldCluster != null) && (newCluster != null)
 
68
                    && (newCluster.compareTo(oldCluster) != 0))) {
 
69
                writer.println();
 
70
                writer.print("ALTER TABLE ");
 
71
                writer.print(
 
72
                        PgDiffUtils.getQuotedName(
 
73
                                newTable.getName(),
 
74
                                arguments.isQuoteNames()));
 
75
                writer.print(" CLUSTER ON ");
 
76
                writer.print(
 
77
                        PgDiffUtils.getQuotedName(
 
78
                                newCluster,
 
79
                                arguments.isQuoteNames()));
 
80
                writer.println(';');
 
81
            } else if (
 
82
                (oldCluster != null)
 
83
                    && (newCluster == null)
 
84
                    && newTable.containsIndex(oldCluster)) {
 
85
                writer.println();
 
86
                writer.print("ALTER TABLE ");
 
87
                writer.print(
 
88
                        PgDiffUtils.getQuotedName(
 
89
                                newTable.getName(),
 
90
                                arguments.isQuoteNames()));
 
91
                writer.println(" SET WITHOUT CLUSTER;");
 
92
            }
 
93
        }
 
94
    }
 
95
 
 
96
    /**
 
97
     * Creates diff of tables.
 
98
     *
 
99
     * @param writer writer the output should be written to
 
100
     * @param arguments object containing arguments settings
 
101
     * @param oldSchema original schema
 
102
     * @param newSchema new schema
 
103
     */
 
104
    public static void diffTables(
 
105
        final PrintWriter writer,
 
106
        final PgDiffArguments arguments,
 
107
        final PgSchema oldSchema,
 
108
        final PgSchema newSchema) {
 
109
        dropTables(writer, arguments, oldSchema, newSchema);
 
110
        createTables(writer, arguments, oldSchema, newSchema);
 
111
 
 
112
        for (PgTable newTable : newSchema.getTables()) {
 
113
            if (
 
114
                (oldSchema == null)
 
115
                    || !oldSchema.containsTable(newTable.getName())) {
 
116
                continue;
 
117
            }
 
118
 
 
119
            final PgTable oldTable = oldSchema.getTable(newTable.getName());
 
120
            updateTableColumns(writer, arguments, oldTable, newTable);
 
121
            checkWithOIDS(writer, arguments, oldTable, newTable);
 
122
            checkInherits(writer, arguments, oldTable, newTable);
 
123
            addAlterStatistics(writer, arguments, oldTable, newTable);
 
124
        }
 
125
    }
 
126
 
 
127
    /**
 
128
     * Generate the needed alter table xxx set statistics when needed.
 
129
     *
 
130
     * @param writer writer the output should be written to
 
131
     * @param arguments object containing arguments settings
 
132
     * @param oldTable original table
 
133
     * @param newTable new table
 
134
     */
 
135
    private static void addAlterStatistics(
 
136
        final PrintWriter writer,
 
137
        final PgDiffArguments arguments,
 
138
        final PgTable oldTable,
 
139
        final PgTable newTable) {
 
140
        final Map<String, Integer> stats = new HashMap<String, Integer>();
 
141
 
 
142
        for (PgColumn newColumn : newTable.getColumns()) {
 
143
            final PgColumn oldColumn = oldTable.getColumn(newColumn.getName());
 
144
 
 
145
            if (oldColumn != null) {
 
146
                final Integer oldStat = oldColumn.getStatistics();
 
147
                final Integer newStat = newColumn.getStatistics();
 
148
                Integer newStatValue = null;
 
149
 
 
150
                if (
 
151
                    (newStat != null)
 
152
                        && ((oldStat == null) || !newStat.equals(oldStat))) {
 
153
                    newStatValue = newStat;
 
154
                } else if ((oldStat != null) && (newStat == null)) {
 
155
                    newStatValue = Integer.valueOf(-1);
 
156
                }
 
157
 
 
158
                if (newStatValue != null) {
 
159
                    stats.put(newColumn.getName(), newStatValue);
 
160
                }
 
161
            }
 
162
        }
 
163
 
 
164
        for (Map.Entry<String, Integer> entry : stats.entrySet()) {
 
165
            writer.println();
 
166
            writer.print("ALTER TABLE ONLY ");
 
167
            writer.print(
 
168
                    PgDiffUtils.getQuotedName(
 
169
                            newTable.getName(),
 
170
                            arguments.isQuoteNames()));
 
171
            writer.print(" ALTER COLUMN ");
 
172
            writer.print(
 
173
                    PgDiffUtils.getQuotedName(
 
174
                            entry.getKey(),
 
175
                            arguments.isQuoteNames()));
 
176
            writer.print(" SET STATISTICS ");
 
177
            writer.print(entry.getValue());
 
178
            writer.println(';');
 
179
        }
 
180
    }
 
181
 
 
182
    /**
 
183
     * Adds commands for creation of new columns to the list of
 
184
     * commands.
 
185
     *
 
186
     * @param commands list of commands
 
187
     * @param arguments object containing arguments settings
 
188
     * @param oldTable original table
 
189
     * @param newTable new table
 
190
     * @param dropDefaultsColumns list for storing columns for which default
 
191
     *        value should be dropped
 
192
     */
 
193
    private static void addCreateTableColumns(
 
194
        final List<String> commands,
 
195
        final PgDiffArguments arguments,
 
196
        final PgTable oldTable,
 
197
        final PgTable newTable,
 
198
        final List<PgColumn> dropDefaultsColumns) {
 
199
        for (PgColumn column : newTable.getColumns()) {
 
200
            if (!oldTable.containsColumn(column.getName())) {
 
201
                commands.add(
 
202
                        "\tADD COLUMN "
 
203
                        + column.getFullDefinition(
 
204
                                arguments.isQuoteNames(),
 
205
                                arguments.isAddDefaults()));
 
206
 
 
207
                if (arguments.isAddDefaults() && !column.getNullValue()) {
 
208
                    dropDefaultsColumns.add(column);
 
209
                }
 
210
            }
 
211
        }
 
212
    }
 
213
 
 
214
    /**
 
215
     * Adds commands for removal of columns to the list of commands.
 
216
     *
 
217
     * @param commands list of commands
 
218
     * @param arguments object containing arguments settings
 
219
     * @param oldTable original table
 
220
     * @param newTable new table
 
221
     */
 
222
    private static void addDropTableColumns(
 
223
        final List<String> commands,
 
224
        final PgDiffArguments arguments,
 
225
        final PgTable oldTable,
 
226
        final PgTable newTable) {
 
227
        for (PgColumn column : oldTable.getColumns()) {
 
228
            if (!newTable.containsColumn(column.getName())) {
 
229
                commands.add(
 
230
                        "\tDROP COLUMN "
 
231
                        + PgDiffUtils.getQuotedName(
 
232
                                column.getName(),
 
233
                                arguments.isQuoteNames()));
 
234
            }
 
235
        }
 
236
    }
 
237
 
 
238
    /**
 
239
     * Adds commands for modification of columns to the list of
 
240
     * commands.
 
241
     *
 
242
     * @param commands list of commands
 
243
     * @param arguments object containing arguments settings
 
244
     * @param oldTable original table
 
245
     * @param newTable new table
 
246
     * @param dropDefaultsColumns list for storing columns for which default
 
247
     *        value should be dropped
 
248
     */
 
249
    private static void addModifyTableColumns(
 
250
        final List<String> commands,
 
251
        final PgDiffArguments arguments,
 
252
        final PgTable oldTable,
 
253
        final PgTable newTable,
 
254
        final List<PgColumn> dropDefaultsColumns) {
 
255
        for (PgColumn newColumn : newTable.getColumns()) {
 
256
            if (!oldTable.containsColumn(newColumn.getName())) {
 
257
                continue;
 
258
            }
 
259
 
 
260
            final PgColumn oldColumn = oldTable.getColumn(newColumn.getName());
 
261
            final String newColumnName =
 
262
                PgDiffUtils.getQuotedName(
 
263
                        newColumn.getName(),
 
264
                        arguments.isQuoteNames());
 
265
 
 
266
            if (!oldColumn.getType().equals(newColumn.getType())) {
 
267
                commands.add(
 
268
                        "\tALTER COLUMN " + newColumnName + " TYPE "
 
269
                        + newColumn.getType());
 
270
            }
 
271
 
 
272
            final String oldDefault =
 
273
                (oldColumn.getDefaultValue() == null) ? ""
 
274
                                                      : oldColumn
 
275
                .getDefaultValue();
 
276
            final String newDefault =
 
277
                (newColumn.getDefaultValue() == null) ? ""
 
278
                                                      : newColumn
 
279
                .getDefaultValue();
 
280
 
 
281
            if (!oldDefault.equals(newDefault)) {
 
282
                if (newDefault.length() == 0) {
 
283
                    commands.add(
 
284
                            "\tALTER COLUMN " + newColumnName + " DROP DEFAULT");
 
285
                } else {
 
286
                    commands.add(
 
287
                            "\tALTER COLUMN " + newColumnName + " SET DEFAULT "
 
288
                            + newDefault);
 
289
                }
 
290
            }
 
291
 
 
292
            if (oldColumn.getNullValue() != newColumn.getNullValue()) {
 
293
                if (newColumn.getNullValue()) {
 
294
                    commands.add(
 
295
                            "\tALTER COLUMN " + newColumnName
 
296
                            + " DROP NOT NULL");
 
297
                } else {
 
298
                    if (arguments.isAddDefaults()) {
 
299
                        final String defaultValue =
 
300
                            PgColumnUtils.getDefaultValue(newColumn.getType());
 
301
 
 
302
                        if (defaultValue != null) {
 
303
                            commands.add(
 
304
                                    "\tALTER COLUMN " + newColumnName
 
305
                                    + " SET DEFAULT " + defaultValue);
 
306
                            dropDefaultsColumns.add(newColumn);
 
307
                        }
 
308
                    }
 
309
 
 
310
                    commands.add(
 
311
                            "\tALTER COLUMN " + newColumnName + " SET NOT NULL");
 
312
                }
 
313
            }
 
314
        }
 
315
    }
 
316
 
 
317
    /**
 
318
     * Checks whether there is a discrepancy in INHERITS for original
 
319
     * and new table.
 
320
     *
 
321
     * @param writer writer the output should be written to
 
322
     * @param arguments object containing arguments settings
 
323
     * @param oldTable original table
 
324
     * @param newTable new table
 
325
     */
 
326
    private static void checkInherits(
 
327
        final PrintWriter writer,
 
328
        final PgDiffArguments arguments,
 
329
        final PgTable oldTable,
 
330
        final PgTable newTable) {
 
331
        final String oldInherits = oldTable.getInherits();
 
332
        final String newInherits = newTable.getInherits();
 
333
 
 
334
        if ((oldInherits == null) && (newInherits != null)) {
 
335
            writer.println();
 
336
            writer.println(
 
337
                    "Modified INHERITS on TABLE "
 
338
                    + PgDiffUtils.getQuotedName(
 
339
                            newTable.getName(),
 
340
                            arguments.isQuoteNames())
 
341
                    + ": original table doesn't use INHERITS but new table "
 
342
                    + "uses INHERITS " + newTable.getInherits());
 
343
        } else if ((oldInherits != null) && (newInherits == null)) {
 
344
            writer.println();
 
345
            writer.println(
 
346
                    "Modified INHERITS on TABLE "
 
347
                    + PgDiffUtils.getQuotedName(
 
348
                            newTable.getName(),
 
349
                            arguments.isQuoteNames())
 
350
                    + ": original table uses INHERITS "
 
351
                    + oldTable.getInherits()
 
352
                    + " but new table doesn't use INHERITS");
 
353
        } else if (
 
354
            (oldInherits != null)
 
355
                && (newInherits != null)
 
356
                && !oldInherits.equals(newInherits)) {
 
357
            writer.println();
 
358
            writer.println(
 
359
                    "Modified INHERITS on TABLE "
 
360
                    + PgDiffUtils.getQuotedName(
 
361
                            newTable.getName(),
 
362
                            arguments.isQuoteNames())
 
363
                    + ": original table uses INHERITS "
 
364
                    + oldTable.getInherits() + " but new table uses INHERITS "
 
365
                    + newTable.getInherits());
 
366
        }
 
367
    }
 
368
 
 
369
    /**
 
370
     * Checks whether OIDS are dropped from the new table. There is no
 
371
     * way to add OIDS to existing table so we do not create SQL command for
 
372
     * addition of OIDS but we issue warning.
 
373
     *
 
374
     * @param writer writer the output should be written to
 
375
     * @param arguments object containing arguments settings
 
376
     * @param oldTable original table
 
377
     * @param newTable new table
 
378
     */
 
379
    private static void checkWithOIDS(
 
380
        final PrintWriter writer,
 
381
        final PgDiffArguments arguments,
 
382
        final PgTable oldTable,
 
383
        final PgTable newTable) {
 
384
        if (oldTable.isWithOIDS() && !newTable.isWithOIDS()) {
 
385
            writer.println();
 
386
            writer.println(
 
387
                    "ALTER TABLE "
 
388
                    + PgDiffUtils.getQuotedName(
 
389
                            newTable.getName(),
 
390
                            arguments.isQuoteNames()));
 
391
            writer.println("\tSET WITHOUT OIDS;");
 
392
        } else if (!oldTable.isWithOIDS() && newTable.isWithOIDS()) {
 
393
            writer.println();
 
394
            writer.println(
 
395
                    "WARNING: Table "
 
396
                    + PgDiffUtils.getQuotedName(
 
397
                            newTable.getName(),
 
398
                            arguments.isQuoteNames())
 
399
                    + " adds WITH OIDS but there is no equivalent command "
 
400
                    + "for adding of OIDS in PostgreSQL");
 
401
        }
 
402
    }
 
403
 
 
404
    /**
 
405
     * Outputs commands for creation of new tables.
 
406
     *
 
407
     * @param writer writer the output should be written to
 
408
     * @param arguments object containing arguments settings
 
409
     * @param oldSchema original schema
 
410
     * @param newSchema new schema
 
411
     */
 
412
    private static void createTables(
 
413
        final PrintWriter writer,
 
414
        final PgDiffArguments arguments,
 
415
        final PgSchema oldSchema,
 
416
        final PgSchema newSchema) {
 
417
        for (PgTable table : newSchema.getTables()) {
 
418
            if (
 
419
                (oldSchema == null)
 
420
                    || !oldSchema.containsTable(table.getName())) {
 
421
                writer.println();
 
422
                writer.println(table.getCreationSQL(arguments.isQuoteNames()));
 
423
            }
 
424
        }
 
425
    }
 
426
 
 
427
    /**
 
428
     * Outputs commands for dropping tables.
 
429
     *
 
430
     * @param writer writer the output should be written to
 
431
     * @param arguments object containing arguments settings
 
432
     * @param oldSchema original schema
 
433
     * @param newSchema new schema
 
434
     */
 
435
    private static void dropTables(
 
436
        final PrintWriter writer,
 
437
        final PgDiffArguments arguments,
 
438
        final PgSchema oldSchema,
 
439
        final PgSchema newSchema) {
 
440
        if (oldSchema != null) {
 
441
            for (PgTable table : oldSchema.getTables()) {
 
442
                if (!newSchema.containsTable(table.getName())) {
 
443
                    writer.println();
 
444
                    writer.println(table.getDropSQL(arguments.isQuoteNames()));
 
445
                }
 
446
            }
 
447
        }
 
448
    }
 
449
 
 
450
    /**
 
451
     * Outputs commands for addition, removal and modifications of
 
452
     * table columns.
 
453
     *
 
454
     * @param writer writer the output should be written to
 
455
     * @param arguments object containing arguments settings
 
456
     * @param oldTable original table
 
457
     * @param newTable new table
 
458
     */
 
459
    private static void updateTableColumns(
 
460
        final PrintWriter writer,
 
461
        final PgDiffArguments arguments,
 
462
        final PgTable oldTable,
 
463
        final PgTable newTable) {
 
464
        final List<String> commands = new ArrayList<String>();
 
465
        final List<PgColumn> dropDefaultsColumns = new ArrayList<PgColumn>();
 
466
        addDropTableColumns(commands, arguments, oldTable, newTable);
 
467
        addCreateTableColumns(
 
468
                commands,
 
469
                arguments,
 
470
                oldTable,
 
471
                newTable,
 
472
                dropDefaultsColumns);
 
473
        addModifyTableColumns(
 
474
                commands,
 
475
                arguments,
 
476
                oldTable,
 
477
                newTable,
 
478
                dropDefaultsColumns);
 
479
 
 
480
        if (commands.size() > 0) {
 
481
            final String quotedTableName =
 
482
                PgDiffUtils.getQuotedName(
 
483
                        newTable.getName(),
 
484
                        arguments.isQuoteNames());
 
485
            writer.println();
 
486
            writer.println("ALTER TABLE " + quotedTableName);
 
487
 
 
488
            for (int i = 0; i < commands.size(); i++) {
 
489
                writer.print(commands.get(i));
 
490
                writer.println(((i + 1) < commands.size()) ? "," : ";");
 
491
            }
 
492
 
 
493
            if (!dropDefaultsColumns.isEmpty()) {
 
494
                writer.println();
 
495
                writer.println("ALTER TABLE " + quotedTableName);
 
496
 
 
497
                for (int i = 0; i < dropDefaultsColumns.size(); i++) {
 
498
                    writer.print("\tALTER COLUMN ");
 
499
                    writer.print(
 
500
                            PgDiffUtils.getQuotedName(
 
501
                                    dropDefaultsColumns.get(i).getName(),
 
502
                                    arguments.isQuoteNames()));
 
503
                    writer.print(" DROP DEFAULT");
 
504
                    writer.println(
 
505
                            ((i + 1) < dropDefaultsColumns.size()) ? "," : ";");
 
506
                }
 
507
            }
 
508
        }
 
509
    }
 
510
}