diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index a2831484..438bffa6 --- a/README.md +++ b/README.md @@ -11,6 +11,21 @@ This repo is mainly unmaintained. But if you found a bug and create a pull reque ## Changelog +### Version 2.7.0 + +#### New Features +* Initial Support to PARTITION BY on Create Table jalissonmello +* Initial suport to identity column. #277 jalissonmello +* Support Postgresql 12 -Add support for FUNCTION in CREATE TRIGGER #273 alexander-smyslov +* Add supports for CREATE SEQUENCE IF NOT EXISTS and CREATE INDEX IF NOT EXISTS. UltramanJack +#### Fixes +* Fix incorrect disable trigger parsing of quoted identifiers. Bugfixes #271 marcus-kempe +* fix for null pointer exception #270 marco44 +* Fix issue where rule parsing was throwing # 269-marcus-kempe +* fixed some crashes #257 d1maxa +* Error on disable/enable trigger on trigger that dont exists on old schema. +* Drop and Add constraint if table exists, issue #252 + ### Version 2.6 #### New Features diff --git a/pom.xml b/pom.xml index 3a990cf3..853d7f0b 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ cz.startnet apgdiff Another PostgreSQL Diff Tool - 2.6.0-SNAPSHOT + 2.7.0 Simple PostgreSQL diff tool that is useful for schema upgrades. The tool compares two schema dump files and creates output file that is (after some hand-made modifications) suitable for upgrade of old schema. http://www.apgdiff.com/ @@ -113,7 +113,7 @@ maven-compiler-plugin - 3.7.0 + 3.8.1 1.8 1.8 @@ -125,15 +125,15 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + 2.22.2 maven-surefire-report-plugin - 2.21.0 + 2.22.2 maven-jar-plugin - 3.0.2 + 3.2.0 @@ -147,7 +147,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.2.1 attach-sources @@ -161,7 +161,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.1.0 + 3.2.0 attach-javadoc @@ -183,6 +183,7 @@ To do something: + 8 @@ -198,7 +199,7 @@ org.apache.maven.plugins maven-resources-plugin - 2.7 + 3.1.0 ${project.build.sourceEncoding} @@ -206,7 +207,7 @@ org.apache.maven.plugins maven-clean-plugin - 3.0.0 + 3.1.0 ${project.build.sourceEncoding} @@ -218,21 +219,21 @@ org.apache.maven.plugins maven-resources-plugin - 3.0.2 + 3.1.0 maven-plugin org.apache.maven.plugins maven-compiler-plugin - 3.7.0 + 3.8.1 maven-plugin org.apache.maven.plugins maven-clean-plugin - 3.0.0 + 3.1.0 maven-plugin @@ -254,11 +255,11 @@ maven-project-info-reports-plugin - 2.9 + 3.0.0 maven-javadoc-plugin - 3.1.0 + 3.2.0 128m 512 @@ -280,10 +281,10 @@ maven-pmd-plugin - 3.9.0 + 3.13.0 utf-8 - 1.6 + 1.8 @@ -293,7 +294,7 @@ maven-jxr-plugin - 2.5 + 3.0.0 UTF-8 UTF-8 diff --git a/releases/apgdiff-2.7.0.jar b/releases/apgdiff-2.7.0.jar new file mode 100644 index 00000000..3a075352 Binary files /dev/null and b/releases/apgdiff-2.7.0.jar differ diff --git a/src/main/java/cz/startnet/utils/pgdiff/Pair.java b/src/main/java/cz/startnet/utils/pgdiff/Pair.java old mode 100644 new mode 100755 diff --git a/src/main/java/cz/startnet/utils/pgdiff/PgDiff.java b/src/main/java/cz/startnet/utils/pgdiff/PgDiff.java index 2c883d56..23ce7a58 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/PgDiff.java +++ b/src/main/java/cz/startnet/utils/pgdiff/PgDiff.java @@ -277,6 +277,8 @@ private static void updateSchemas(final PrintWriter writer, writer, oldSchema, newSchema, searchPathHelper); PgDiffFunctions.dropFunctions( writer, arguments, oldSchema, newSchema, searchPathHelper); + PgDiffProcedures.dropPocedures( + writer, arguments, oldSchema, newSchema, searchPathHelper); PgDiffViews.dropViews( writer, oldSchema, newSchema, searchPathHelper); PgDiffConstraints.dropConstraints( @@ -308,6 +310,8 @@ private static void updateSchemas(final PrintWriter writer, writer, oldSchema, newSchema, searchPathHelper); PgDiffFunctions.createFunctions( writer, arguments, oldSchema, newSchema, searchPathHelper); + PgDiffProcedures.createProducedures( + writer, arguments, oldSchema, newSchema, searchPathHelper); PgDiffConstraints.createConstraints( writer, oldSchema, newSchema, true, searchPathHelper); PgDiffConstraints.createConstraints( @@ -331,6 +335,8 @@ private static void updateSchemas(final PrintWriter writer, writer, oldSchema, newSchema, searchPathHelper); PgDiffFunctions.alterComments( writer, oldSchema, newSchema, searchPathHelper); + PgDiffProcedures.alterComments( + writer, oldSchema, newSchema, searchPathHelper); PgDiffConstraints.alterComments( writer, oldSchema, newSchema, searchPathHelper); PgDiffIndexes.alterComments( diff --git a/src/main/java/cz/startnet/utils/pgdiff/PgDiffProcedures.java b/src/main/java/cz/startnet/utils/pgdiff/PgDiffProcedures.java new file mode 100644 index 00000000..bacf3c91 --- /dev/null +++ b/src/main/java/cz/startnet/utils/pgdiff/PgDiffProcedures.java @@ -0,0 +1,158 @@ +/** + * Copyright 2006 StartNet s.r.o. + * + * Distributed under MIT license + */ +package cz.startnet.utils.pgdiff; + +import cz.startnet.utils.pgdiff.schema.PgProcedure; +import cz.startnet.utils.pgdiff.schema.PgSchema; +import java.io.PrintWriter; + +/** + * Diffs procedures. + * + * @author jalissonmello + */ +public class PgDiffProcedures { + + /** + * Outputs statements for new or modified procedures. + * + * @param writer writer the output should be written to + * @param arguments object containing arguments settings + * @param oldSchema original schema + * @param newSchema new schema + * @param searchPathHelper search path helper + */ + public static void createProducedures(final PrintWriter writer, + final PgDiffArguments arguments, final PgSchema oldSchema, + final PgSchema newSchema, final SearchPathHelper searchPathHelper) { + // Add new procedures and replace modified procedures + for (final PgProcedure newProcedure : newSchema.getProcedures()) { + final PgProcedure oldProcedure; + + if (oldSchema == null) { + oldProcedure = null; + } else { + oldProcedure = oldSchema.getProcedure(newProcedure.getSignature()); + } + + if ((oldProcedure == null) || !newProcedure.equals( + oldProcedure, arguments.isIgnoreFunctionWhitespace())) { + searchPathHelper.outputSearchPath(writer); + writer.println(); + writer.println(newProcedure.getCreationSQL()); + } + } + } + + /** + * Outputs statements for dropping of procedures that exist no more. + * + * @param writer writer the output should be written to + * @param arguments object containing arguments settings + * @param oldSchema original schema + * @param newSchema new schema + * @param searchPathHelper search path helper + */ + public static void dropPocedures(final PrintWriter writer, + final PgDiffArguments arguments, final PgSchema oldSchema, + final PgSchema newSchema, final SearchPathHelper searchPathHelper) { + if (oldSchema == null) { + return; + } + + // Drop procedures that exist no more + for (final PgProcedure oldProcedure : oldSchema.getProcedures()) { + if (!newSchema.containsProcedure(oldProcedure.getSignature())) { + searchPathHelper.outputSearchPath(writer); + writer.println(); + writer.println(oldProcedure.getDropSQL()); + } + } + } + + /** + * Outputs statements for procedure comments that have changed. + * + * @param writer writer + * @param oldSchema old schema + * @param newSchema new schema + * @param searchPathHelper search path helper + */ + public static void alterComments(final PrintWriter writer, + final PgSchema oldSchema, final PgSchema newSchema, + final SearchPathHelper searchPathHelper) { + if (oldSchema == null) { + return; + } + + for (final PgProcedure oldprocedure : oldSchema.getProcedures()) { + final PgProcedure newProcedure = + newSchema.getProcedure(oldprocedure.getSignature()); + + if (newProcedure == null) { + continue; + } + + if (oldprocedure.getComment() == null + && newProcedure.getComment() != null + || oldprocedure.getComment() != null + && newProcedure.getComment() != null + && !oldprocedure.getComment().equals( + newProcedure.getComment())) { + searchPathHelper.outputSearchPath(writer); + writer.println(); + writer.print("COMMENT ON PROCEDURE "); + writer.print(PgDiffUtils.getQuotedName(newProcedure.getName())); + writer.print('('); + + boolean addComma = false; + + for (final PgProcedure.Argument argument : + newProcedure.getArguments()) { + if (addComma) { + writer.print(", "); + } else { + addComma = true; + } + + writer.print(argument.getDeclaration(false)); + } + + writer.print(") IS "); + writer.print(newProcedure.getComment()); + writer.println(';'); + } else if (oldprocedure.getComment() != null + && newProcedure.getComment() == null) { + searchPathHelper.outputSearchPath(writer); + writer.println(); + writer.print("COMMENT ON PROCEDURE "); + writer.print(PgDiffUtils.getQuotedName(newProcedure.getName())); + writer.print('('); + + boolean addComma = false; + + for (final PgProcedure.Argument argument : + newProcedure.getArguments()) { + if (addComma) { + writer.print(", "); + } else { + addComma = true; + } + + writer.print(argument.getDeclaration(false)); + } + + writer.println(") IS NULL;"); + } + } + } + + /** + * Creates a new instance of PgDiffProcedures. + */ + private PgDiffProcedures() { + } +} diff --git a/src/main/java/cz/startnet/utils/pgdiff/PgDiffTables.java b/src/main/java/cz/startnet/utils/pgdiff/PgDiffTables.java index bca06eee..93ed7bce 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/PgDiffTables.java +++ b/src/main/java/cz/startnet/utils/pgdiff/PgDiffTables.java @@ -18,6 +18,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Diffs tables. @@ -250,20 +251,28 @@ private static void addAlterStorage(final PrintWriter writer, * @param newTable new table * @param dropDefaultsColumns list for storing columns for which default * value should be dropped + * @param generatedColumns list for storing generated columns */ private static void addCreateTableColumns(final List statements, final PgDiffArguments arguments, final PgTable oldTable, - final PgTable newTable, final List dropDefaultsColumns) { + final PgTable newTable, final List dropDefaultsColumns, + final List generatedColumns + ) { for (final PgColumn column : newTable.getColumns()) { if (!oldTable.containsColumn(column.getName())) { statements.add("\tADD COLUMN "+ PgDiffUtils.getCreateIfNotExists() + column.getFullDefinition(arguments.isAddDefaults())); - + if (arguments.isAddDefaults() && !column.getNullValue() && (column.getDefaultValue() == null || column.getDefaultValue().isEmpty())) { dropDefaultsColumns.add(column); } + + if (Objects.nonNull(column.getGenerated())){ + + generatedColumns.add(column); + } } } } @@ -315,7 +324,7 @@ private static void addModifyTableColumns(final List statements, newTable.getName(), oldColumn.getType(), newColumn.getType()) + " */"); } - + final String oldDefault = (oldColumn.getDefaultValue() == null) ? "" : oldColumn.getDefaultValue(); final String newDefault = (newColumn.getDefaultValue() == null) ? "" @@ -623,9 +632,10 @@ private static void updateTableColumns(final PrintWriter writer, final List statements = new ArrayList(); @SuppressWarnings("CollectionWithoutInitialCapacity") final List dropDefaultsColumns = new ArrayList(); + final List generatedColumns = new ArrayList(); addDropTableColumns(statements, oldTable, newTable); addCreateTableColumns( - statements, arguments, oldTable, newTable, dropDefaultsColumns); + statements, arguments, oldTable, newTable, dropDefaultsColumns,generatedColumns); addModifyTableColumns( statements, arguments, oldTable, newTable, dropDefaultsColumns); @@ -654,6 +664,15 @@ private static void updateTableColumns(final PrintWriter writer, (i + 1) < dropDefaultsColumns.size() ? "," : ";"); } } + + for (int i = 0; i < generatedColumns.size(); i++) { + writer.println(); + writer.print("ALTER TABLE "); + writer.println(newTable.getName()); + writer.println("\tALTER COLUMN " + PgDiffUtils.getQuotedName( + generatedColumns.get(i).getName()) + " " + generatedColumns.get(i).getGenerated() +";"); + + } } } diff --git a/src/main/java/cz/startnet/utils/pgdiff/PgDiffTriggers.java b/src/main/java/cz/startnet/utils/pgdiff/PgDiffTriggers.java index 95e397bd..8ab7eb49 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/PgDiffTriggers.java +++ b/src/main/java/cz/startnet/utils/pgdiff/PgDiffTriggers.java @@ -11,6 +11,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Diffs triggers. @@ -215,17 +216,19 @@ private static List getEnablerOrDisableTriggers(final PgRelation oldR @SuppressWarnings("CollectionWithoutInitialCapacity") final List list = new ArrayList(); - if (newRelation != null) { - - for (final PgTrigger newTrigger : newRelation.getTriggers()) { - - PgTrigger oldTrigger = oldRelation.getTrigger(newTrigger.getName()); - if ((newTrigger.isDisable() && oldTrigger==null) || - (oldTrigger!=null && oldTrigger.isDisable()!=newTrigger.isDisable())) { + if (newRelation != null) { + + for (final PgTrigger newTrigger : newRelation.getTriggers()) { + + if (Objects.nonNull(oldRelation)) { + PgTrigger oldTrigger = oldRelation.getTrigger(newTrigger.getName()); + if ((newTrigger.isDisable() && oldTrigger == null) + || (oldTrigger != null && oldTrigger.isDisable() != newTrigger.isDisable())) { list.add(newTrigger); } } - + } + } return list; diff --git a/src/main/java/cz/startnet/utils/pgdiff/PgDiffViews.java b/src/main/java/cz/startnet/utils/pgdiff/PgDiffViews.java index 26965827..0c0a0bbd 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/PgDiffViews.java +++ b/src/main/java/cz/startnet/utils/pgdiff/PgDiffViews.java @@ -13,6 +13,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Diffs views. @@ -33,7 +34,12 @@ public static void createViews(final PrintWriter writer, final PgSchema oldSchema, final PgSchema newSchema, final SearchPathHelper searchPathHelper) { for (final PgView newView : newSchema.getViews()) { - final PgView oldView = oldSchema.getView(newView.getName()); + PgView oldView = null; + + if (Objects.nonNull(oldSchema)) { + oldView = oldSchema.getView(newView.getName()); + } + if (oldSchema == null || !oldSchema.containsView(newView.getName()) || isViewModified(oldView, newView)) { diff --git a/src/main/java/cz/startnet/utils/pgdiff/loader/PgDumpLoader.java b/src/main/java/cz/startnet/utils/pgdiff/loader/PgDumpLoader.java old mode 100644 new mode 100755 index f8e16989..06169d0b --- a/src/main/java/cz/startnet/utils/pgdiff/loader/PgDumpLoader.java +++ b/src/main/java/cz/startnet/utils/pgdiff/loader/PgDumpLoader.java @@ -20,6 +20,7 @@ import cz.startnet.utils.pgdiff.parsers.CreateViewParser; import cz.startnet.utils.pgdiff.parsers.GrantRevokeParser; import cz.startnet.utils.pgdiff.parsers.CreatePolicyParser; +import cz.startnet.utils.pgdiff.parsers.CreateProcedureParser; import cz.startnet.utils.pgdiff.parsers.CreateRuleParser; import cz.startnet.utils.pgdiff.schema.PgDatabase; import java.io.BufferedReader; @@ -123,7 +124,15 @@ public class PgDumpLoader { //NOPMD */ private static final Pattern PATTERN_CREATE_FUNCTION = Pattern.compile( "^CREATE[\\s]+(?:OR[\\s]+REPLACE[\\s]+)?FUNCTION[\\s]+.*$", + Pattern.CASE_INSENSITIVE | Pattern.DOTALL); + /** + * Pattern for testing whether it is CREATE PROCEDURE or CREATE OR REPLACE + * PROCEDURE statement. + */ + private static final Pattern PATTERN_CREATE_PROCEDURE = Pattern.compile( + "^CREATE[\\s]+(?:OR[\\s]+REPLACE[\\s]+)?PROCEDURE[\\s]+.*$", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); + /** * Pattern for testing whether it is ALTER VIEW statement. */ @@ -175,7 +184,7 @@ public class PgDumpLoader { //NOPMD * Pattern for testing whether it is CREATE POLICY statement. */ private static final Pattern PATTERN_DISABLE_TRIGGER = Pattern.compile( - "ALTER\\s+TABLE+\\s+\\w+.+\\w+\\s+DISABLE+\\s+TRIGGER+\\s+\\w+.*$", + "ALTER\\s+TABLE+\\s+\"?\\w+\"?.+\"?\\w+\"?\\s+DISABLE+\\s+TRIGGER+\\s+\\w+.*$", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); /** * Pattern for testing whether it is CREATE RULE statement. @@ -254,6 +263,8 @@ public static PgDatabase loadDatabaseSchema(final InputStream inputStream, CreateTriggerParser.parseDisable(database, statement); } else if (PATTERN_CREATE_FUNCTION.matcher(statement).matches()) { CreateFunctionParser.parse(database, statement); + } else if (PATTERN_CREATE_PROCEDURE.matcher(statement).matches()) { + CreateProcedureParser.parse(database, statement); } else if (PATTERN_CREATE_TYPE.matcher(statement).matches()) { CreateTypeParser.parse(database, statement); } else if (PATTERN_COMMENT.matcher(statement).matches()) { diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/AlterRelationParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/AlterRelationParser.java old mode 100644 new mode 100755 index 94f37c9e..794d61fc --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/AlterRelationParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/AlterRelationParser.java @@ -339,6 +339,9 @@ private static void parseAlterColumn(final Parser parser, } else { parser.throwUnsupportedCommand(); } + } else if(parser.expectOptional("ADD GENERATED")){ + PgColumn column = rel.getColumn(columnName); + column.setGenerated("ADD GENERATED " +parser.getExpression()); } else { parser.throwUnsupportedCommand(); } diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CommentParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CommentParser.java old mode 100644 new mode 100755 index 98ce5967..27bf0a69 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/CommentParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CommentParser.java @@ -90,7 +90,7 @@ private static void parseConstraint(final Parser parser, final String tableName = parser.parseIdentifier(); final String objectName = ParserUtils.getObjectName(tableName); final String schemaName = - ParserUtils.getSchemaName(constraintName, database); + ParserUtils.getSchemaName(tableName, database); final PgConstraint constraint = database.getSchema(schemaName). getTable(objectName).getConstraint(constraintName); @@ -196,7 +196,7 @@ private static void parseTrigger(final Parser parser, final String tableName = parser.parseIdentifier(); final String objectName = ParserUtils.getObjectName(tableName); final String schemaName = - ParserUtils.getSchemaName(triggerName, database); + ParserUtils.getSchemaName(tableName, database); final PgTrigger trigger = database.getSchema(schemaName). getTable(objectName).getTrigger(triggerName); diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateIndexParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateIndexParser.java old mode 100644 new mode 100755 index 5c47e981..c3eb53d5 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateIndexParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateIndexParser.java @@ -32,7 +32,8 @@ public static void parse(final PgDatabase database, parser.expect("INDEX"); parser.expectOptional("CONCURRENTLY"); - + parser.expectOptional("IF", "NOT", "EXISTS"); + final String indexName = ParserUtils.getObjectName(parser.parseIdentifier()); diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateProcedureParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateProcedureParser.java new file mode 100644 index 00000000..afc5f7d1 --- /dev/null +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateProcedureParser.java @@ -0,0 +1,114 @@ +/** + * Copyright 2006 StartNet s.r.o. + * + * Distributed under MIT license + */ +package cz.startnet.utils.pgdiff.parsers; + +import cz.startnet.utils.pgdiff.Resources; +import cz.startnet.utils.pgdiff.schema.PgDatabase; +import cz.startnet.utils.pgdiff.schema.PgProcedure; +import cz.startnet.utils.pgdiff.schema.PgSchema; +import java.text.MessageFormat; + +/** + * Parses CREATE PROCEDURE and CREATE OR REPLACE PROCEDURE statements. + * + * @author jalissonmello + */ +public class CreateProcedureParser { + + /** + * Parses CREATE PROCEDURE and CREATE OR REPLACE PROCEDURE statement. + * + * @param database database + * @param statement CREATE PROCEDURE statement + */ + public static void parse(final PgDatabase database, + final String statement) { + final Parser parser = new Parser(statement); + parser.expect("CREATE"); + parser.expectOptional("OR", "REPLACE"); + parser.expect("PROCEDURE"); + + final String procedureName = parser.parseIdentifier(); + final String schemaName = + ParserUtils.getSchemaName(procedureName, database); + final PgSchema schema = database.getSchema(schemaName); + + if (schema == null) { + throw new RuntimeException(MessageFormat.format( + Resources.getString("CannotFindSchema"), schemaName, + statement)); + } + + final PgProcedure procedure = new PgProcedure(); + procedure.setName(ParserUtils.getObjectName(procedureName)); + schema.addProcedure(procedure); + + parser.expect("("); + + while (!parser.expectOptional(")")) { + final String mode; + + if (parser.expectOptional("IN")) { + mode = "IN"; + } else if (parser.expectOptional("OUT")) { + mode = "OUT"; + } else if (parser.expectOptional("INOUT")) { + mode = "INOUT"; + } else if (parser.expectOptional("VARIADIC")) { + mode = "VARIADIC"; + } else { + mode = null; + } + + final int position = parser.getPosition(); + String argumentName = null; + String dataType = parser.parseDataType(); + + final int position2 = parser.getPosition(); + + if (!parser.expectOptional(")") && !parser.expectOptional(",") + && !parser.expectOptional("=") + && !parser.expectOptional("DEFAULT")) { + parser.setPosition(position); + argumentName = + ParserUtils.getObjectName(parser.parseIdentifier()); + dataType = parser.parseDataType(); + } else { + parser.setPosition(position2); + } + + final String defaultExpression; + + if (parser.expectOptional("=") + || parser.expectOptional("DEFAULT")) { + defaultExpression = parser.getExpression(); + } else { + defaultExpression = null; + } + + final PgProcedure.Argument argument = new PgProcedure.Argument(); + argument.setDataType(dataType); + argument.setDefaultExpression(defaultExpression); + argument.setMode(mode); + argument.setName(argumentName); + procedure.addArgument(argument); + + if (parser.expectOptional(")")) { + break; + } else { + parser.expect(","); + } + } + + procedure.setBody(parser.getRest()); + } + + /** + * Creates a new instance of CreateProcedureParser. + */ + private CreateProcedureParser() { + } +} diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateRuleParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateRuleParser.java old mode 100644 new mode 100755 index 056b7f8f..7b0b5257 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateRuleParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateRuleParser.java @@ -60,7 +60,7 @@ public static void parse(final PgDatabase database, rule.setQuery(query); - final String schemaName = ParserUtils.getSchemaName(ruleName, database); + final String schemaName = ParserUtils.getSchemaName(relationName, database); final PgSchema schema = database.getSchema(schemaName); if (schema == null) { diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateSequenceParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateSequenceParser.java old mode 100644 new mode 100755 index a547262f..ce0df3d8 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateSequenceParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateSequenceParser.java @@ -28,7 +28,8 @@ public static void parse(final PgDatabase database, final String statement) { final Parser parser = new Parser(statement); parser.expect("CREATE", "SEQUENCE"); - + parser.expectOptional("IF", "NOT", "EXISTS"); + final String sequenceName = parser.parseIdentifier(); final PgSequence sequence = new PgSequence(ParserUtils.getObjectName(sequenceName)); diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTableParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTableParser.java index 3dc39e3d..92dbe2b6 100644 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTableParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTableParser.java @@ -82,7 +82,9 @@ public static void parse(final PgDatabase database, } while (!parser.expectOptional(";")) { - if (parser.expectOptional("INHERITS")) { + if (parser.expectOptional("PARTITION","BY")) { + table.setPartionBy("PARTITION BY "+parser.getExpression()); + } else if (parser.expectOptional("INHERITS")) { parseInherits(database, parser, table); } else if (parser.expectOptional("WITHOUT")) { table.setWith("OIDS=false"); diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTriggerParser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTriggerParser.java old mode 100644 new mode 100755 index f45bd514..13ef98a6 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTriggerParser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/CreateTriggerParser.java @@ -108,14 +108,12 @@ public static void parse(final PgDatabase database, } parser.expect("EXECUTE"); - - if (parser.expectOptional("PROCEDURE")) { - trigger.setFunction(parser.getRest()); - } else if (parser.expectOptional("FUNCTION")) { - trigger.setFunction(parser.getRest()); - } else { + if (!parser.expectOptional("PROCEDURE") && + !parser.expectOptional("FUNCTION")) { parser.throwUnsupportedCommand(); } + + trigger.setFunction(parser.getRest()); final boolean ignoreSlonyTrigger = ignoreSlonyTriggers && ("_slony_logtrigger".equals(trigger.getName()) diff --git a/src/main/java/cz/startnet/utils/pgdiff/parsers/Parser.java b/src/main/java/cz/startnet/utils/pgdiff/parsers/Parser.java index 97743895..4f77b34c 100644 --- a/src/main/java/cz/startnet/utils/pgdiff/parsers/Parser.java +++ b/src/main/java/cz/startnet/utils/pgdiff/parsers/Parser.java @@ -102,7 +102,8 @@ public boolean expect(final String word, final boolean optional) { * @return true if whole sequence was found, otherwise false */ public boolean expectOptional(final String... words) { - final boolean found = expect(words[0], true); + final int oldPosition = position; + boolean found = expect(words[0], true); if (!found) { return false; @@ -110,7 +111,11 @@ public boolean expectOptional(final String... words) { for (int i = 1; i < words.length; i++) { skipWhitespace(); - expect(words[i]); + found = expect(words[i], true); + if (!found) { + position = oldPosition; + return false; + } } return true; @@ -249,7 +254,7 @@ public int parseInteger() { * * @return parsed string, if quoted then including quotes */ - public String parseString() { + public String parseString() { final boolean quoted = string.charAt(position) == '\''; if (quoted) { @@ -274,6 +279,11 @@ public String parseString() { final String result; try { + if (endPos >= string.length()) + { + //try to fix StringIndexOutOfBoundsException + endPos = string.lastIndexOf('\''); + } result = string.substring(position, endPos + 1); } catch (final Throwable ex) { throw new RuntimeException("Failed to get substring: " + string diff --git a/src/main/java/cz/startnet/utils/pgdiff/schema/PgColumn.java b/src/main/java/cz/startnet/utils/pgdiff/schema/PgColumn.java old mode 100644 new mode 100755 index fcceb48c..a46bdf07 --- a/src/main/java/cz/startnet/utils/pgdiff/schema/PgColumn.java +++ b/src/main/java/cz/startnet/utils/pgdiff/schema/PgColumn.java @@ -67,6 +67,11 @@ public class PgColumn { */ @SuppressWarnings("CollectionWithoutInitialCapacity") private final List privileges = new ArrayList(); + + /** + * Generated. + */ + private String generated; /** * Creates a new PgColumn object. @@ -126,7 +131,7 @@ public String getFullDefinition(final boolean addDefaults) { sbDefinition.append(PgDiffUtils.getQuotedName(name)); sbDefinition.append(' '); sbDefinition.append(type); - + if (defaultValue != null && !defaultValue.isEmpty()) { sbDefinition.append(" DEFAULT "); sbDefinition.append(defaultValue); @@ -284,4 +289,22 @@ public void parseDefinition(final String definition) { setType(string); } + + /** + * Getter for {@link #generated}. + * + * @return {@link #generated} + */ + public String getGenerated() { + return generated; + } + + /** + * Setter for {@link #generated}. + * + * @param generated {@link #generated} + */ + public void setGenerated(final String generated) { + this.generated = generated; + } } diff --git a/src/main/java/cz/startnet/utils/pgdiff/schema/PgConstraint.java b/src/main/java/cz/startnet/utils/pgdiff/schema/PgConstraint.java index 6cefafa0..36fc5898 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/schema/PgConstraint.java +++ b/src/main/java/cz/startnet/utils/pgdiff/schema/PgConstraint.java @@ -53,6 +53,7 @@ public PgConstraint(String name) { public String getCreationSQL() { final StringBuilder sbSQL = new StringBuilder(100); sbSQL.append("ALTER TABLE "); + sbSQL.append(PgDiffUtils.getDropIfExists()); sbSQL.append(PgDiffUtils.getQuotedName(getTableName())); sbSQL.append(System.getProperty("line.separator")); sbSQL.append("\tADD CONSTRAINT "); @@ -120,6 +121,7 @@ public String getDefinition() { public String getDropSQL() { final StringBuilder sbSQL = new StringBuilder(100); sbSQL.append("ALTER TABLE "); + sbSQL.append(PgDiffUtils.getDropIfExists()); sbSQL.append(PgDiffUtils.getQuotedName(getTableName())); sbSQL.append(System.getProperty("line.separator")); sbSQL.append("\tDROP CONSTRAINT "); diff --git a/src/main/java/cz/startnet/utils/pgdiff/schema/PgDatabase.java b/src/main/java/cz/startnet/utils/pgdiff/schema/PgDatabase.java index 8231f3c3..0f58a075 100644 --- a/src/main/java/cz/startnet/utils/pgdiff/schema/PgDatabase.java +++ b/src/main/java/cz/startnet/utils/pgdiff/schema/PgDatabase.java @@ -5,9 +5,11 @@ */ package cz.startnet.utils.pgdiff.schema; +import cz.startnet.utils.pgdiff.parsers.ParserException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; /** * Stores database information. @@ -137,7 +139,12 @@ public List getSchemas() { * @param schema schema */ public void addSchema(final PgSchema schema) { - schemas.add(schema); + + if (schemas.isEmpty()) { + schemas.add(schema); + } else if (!schemas.stream().filter(o -> o.getName().equals(schema.getName())).findFirst().isPresent()) { + schemas.add(schema); + } } /** diff --git a/src/main/java/cz/startnet/utils/pgdiff/schema/PgProcedure.java b/src/main/java/cz/startnet/utils/pgdiff/schema/PgProcedure.java new file mode 100644 index 00000000..0e73ba2b --- /dev/null +++ b/src/main/java/cz/startnet/utils/pgdiff/schema/PgProcedure.java @@ -0,0 +1,480 @@ +/** + * Copyright 2006 StartNet s.r.o. + * + * Distributed under MIT license + */ +package cz.startnet.utils.pgdiff.schema; + + +import cz.startnet.utils.pgdiff.PgDiffUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +/** + * Stores procedure information. + * + * @author jalissonmello + */ +public class PgProcedure { + + /** + * Name of the procedure including argument types. + */ + private String name; + /** + * List of arguments. + */ + @SuppressWarnings("CollectionWithoutInitialCapacity") + private final List arguments = new ArrayList(); + /** + * Whole definition of the procedure from RETURNS keyword. + */ + private String body; + /** + * Comment. + */ + private String comment; + + /** + * Getter for {@link #comment}. + * + * @return {@link #comment} + */ + public String getComment() { + return comment; + } + + /** + * Setter for {@link #comment}. + * + * @param comment {@link #comment} + */ + public void setComment(final String comment) { + this.comment = comment; + } + + /** + * Returns creation SQL of the procedure. + * + * @return creation SQL + */ + public String getCreationSQL() { + final StringBuilder sbSQL = new StringBuilder(500); + sbSQL.append("CREATE OR REPLACE PROCEDURE "); + sbSQL.append(PgDiffUtils.getQuotedName(name)); + sbSQL.append('('); + + boolean addComma = false; + + for (final Argument argument : arguments) { + if (addComma) { + sbSQL.append(", "); + } + + sbSQL.append(argument.getDeclaration(true)); + + addComma = true; + } + + sbSQL.append(") "); + sbSQL.append(body); + sbSQL.append(';'); + + if (comment != null && !comment.isEmpty()) { + sbSQL.append(System.getProperty("line.separator")); + sbSQL.append(System.getProperty("line.separator")); + sbSQL.append("COMMENT ON PROCEDURE "); + sbSQL.append(PgDiffUtils.getQuotedName(name)); + sbSQL.append('('); + + addComma = false; + + for (final Argument argument : arguments) { + if (addComma) { + sbSQL.append(", "); + } + + sbSQL.append(argument.getDeclaration(false)); + + addComma = true; + } + + sbSQL.append(") IS "); + sbSQL.append(comment); + sbSQL.append(';'); + } + + return sbSQL.toString(); + } + + /** + * Setter for {@link #body}. + * + * @param body {@link #body} + */ + public void setBody(final String body) { + this.body = body; + } + + /** + * Getter for {@link #body}. + * + * @return {@link #body} + */ + public String getBody() { + return body; + } + + /** + * Creates and returns SQL for dropping the procedure. + * + * @return created SQL + */ + public String getDropSQL() { + final StringBuilder sbString = new StringBuilder(100); + sbString.append("DROP PROCEDURE "); + sbString.append(PgDiffUtils.getDropIfExists()); + sbString.append(name); + sbString.append('('); + + boolean addComma = false; + + for (final Argument argument : arguments) { + if ("OUT".equalsIgnoreCase(argument.getMode())) { + continue; + } + + if (addComma) { + sbString.append(", "); + } + + sbString.append(argument.getDeclaration(false)); + + addComma = true; + } + + sbString.append(");"); + + return sbString.toString(); + } + + /** + * Setter for {@link #name}. + * + * @param name {@link #name} + */ + public void setName(final String name) { + this.name = name; + } + + /** + * Getter for {@link #name}. + * + * @return {@link #name} + */ + public String getName() { + return name; + } + + /** + * Getter for {@link #arguments}. List cannot be modified. + * + * @return {@link #arguments} + */ + public List getArguments() { + return Collections.unmodifiableList(arguments); + } + + /** + * Adds argument to the list of arguments. + * + * @param argument argument + */ + public void addArgument(final Argument argument) { + arguments.add(argument); + } + + /** + * Returns procedure signature. It consists of unquoted name and argument + * data types. + * + * @return procedure signature + */ + public String getSignature() { + final StringBuilder sbString = new StringBuilder(100); + sbString.append(name); + sbString.append('('); + + boolean addComma = false; + + for (final Argument argument : arguments) { + if ("OUT".equalsIgnoreCase(argument.getMode())) { + continue; + } + + if (addComma) { + sbString.append(','); + } + + sbString.append(argument.getDataType().toLowerCase(Locale.ENGLISH)); + + addComma = true; + } + + sbString.append(')'); + + return sbString.toString(); + } + + @Override + public boolean equals(final Object object) { + if (!(object instanceof PgProcedure)) { + return false; + } else if (object == this) { + return true; + } + + return equals(object, false); + } + + /** + * Compares two objects whether they are equal. If both objects are of the + * same class but they equal just in whitespace in {@link #body}, they are + * considered being equal. + * + * @param object object to be compared + * @param ignoreProcedureWhitespace whether multiple whitespaces in procedure + * {@link #body} should be ignored + * + * @return true if {@code object} is pg procedure and the procedure code is + * the same when compared ignoring whitespace, otherwise returns + * false + */ + public boolean equals(final Object object, + final boolean ignoreProcedureWhitespace) { + boolean equals = false; + + if (this == object) { + equals = true; + } else if (object instanceof PgProcedure) { + final PgProcedure procedure = (PgProcedure) object; + + if (name == null && procedure.getName() != null + || name != null && !name.equals(procedure.getName())) { + return false; + } + + final String thisBody; + final String thatBody; + + if (ignoreProcedureWhitespace) { + thisBody = body.replaceAll("\\s+", " "); + thatBody = + procedure.getBody().replaceAll("\\s+", " "); + } else { + thisBody = body; + thatBody = procedure.getBody(); + } + + if (thisBody == null && thatBody != null + || thisBody != null && !thisBody.equals(thatBody)) { + return false; + } + + if (arguments.size() != procedure.getArguments().size()) { + return false; + } else { + for (int i = 0; i < arguments.size(); i++) { + if (!arguments.get(i).equals(procedure.getArguments().get(i))) { + return false; + } + } + } + + return true; + } + + return equals; + } + + @Override + public int hashCode() { + final StringBuilder sbString = new StringBuilder(500); + sbString.append(body); + sbString.append('|'); + sbString.append(name); + + for (final Argument argument : arguments) { + sbString.append('|'); + sbString.append(argument.getDeclaration(true)); + } + + return sbString.toString().hashCode(); + } + + /** + * Procedure argument information. + */ + @SuppressWarnings("PublicInnerClass") + public static class Argument { + + /** + * Argument mode. + */ + private String mode = "IN"; + /** + * Argument name. + */ + private String name; + /** + * Argument data type. + */ + private String dataType; + /** + * Argument default expression. + */ + private String defaultExpression; + + /** + * Getter for {@link #dataType}. + * + * @return {@link #dataType} + */ + public String getDataType() { + return dataType; + } + + /** + * Setter for {@link #dataType}. + * + * @param dataType {@link #dataType} + */ + public void setDataType(final String dataType) { + this.dataType = dataType; + } + + /** + * Getter for {@link #defaultExpression}. + * + * @return {@link #defaultExpression} + */ + public String getDefaultExpression() { + return defaultExpression; + } + + /** + * Setter for {@link #defaultExpression}. + * + * @param defaultExpression {@link #defaultExpression} + */ + public void setDefaultExpression(final String defaultExpression) { + this.defaultExpression = defaultExpression; + } + + /** + * Getter for {@link #mode}. + * + * @return {@link #mode} + */ + public String getMode() { + return mode; + } + + /** + * Setter for {@link #mode}. + * + * @param mode {@link #mode} + */ + public void setMode(final String mode) { + this.mode = mode == null || mode.isEmpty() ? "IN" : mode; + } + + /** + * Getter for {@link #name}. + * + * @return {@link #name} + */ + public String getName() { + return name; + } + + /** + * Setter for {@link #name}. + * + * @param name {@link #name} + */ + public void setName(final String name) { + this.name = name; + } + + /** + * Creates argument declaration. + * + * @param includeDefaultValue whether to include default value + * + * @return argument declaration + */ + public String getDeclaration(final boolean includeDefaultValue) { + final StringBuilder sbString = new StringBuilder(50); + + if (mode != null && !"IN".equalsIgnoreCase(mode)) { + sbString.append(mode); + sbString.append(' '); + } + + if (name != null && !name.isEmpty()) { + sbString.append(PgDiffUtils.getQuotedName(name)); + sbString.append(' '); + } + + sbString.append(dataType); + + if (includeDefaultValue && defaultExpression != null + && !defaultExpression.isEmpty()) { + sbString.append(" = "); + sbString.append(defaultExpression); + } + + return sbString.toString(); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Argument)) { + return false; + } else if (this == obj) { + return true; + } + + final Argument argument = (Argument) obj; + + return (dataType == null ? argument.getDataType() == null + : dataType.equalsIgnoreCase(argument.getDataType())) + && (defaultExpression == null + ? argument.getDefaultExpression() == null + : defaultExpression.equals(defaultExpression)) + && (mode == null ? argument.getMode() == null + : mode.equalsIgnoreCase(argument.getMode())) + && (name == null ? argument.getName() == null + : name.equals(argument.getName())); + } + + @Override + public int hashCode() { + final StringBuilder sbString = new StringBuilder(50); + sbString.append( + mode == null ? null : mode.toUpperCase(Locale.ENGLISH)); + sbString.append('|'); + sbString.append(name); + sbString.append('|'); + sbString.append(dataType == null ? null + : dataType.toUpperCase(Locale.ENGLISH)); + sbString.append('|'); + sbString.append(defaultExpression); + + return sbString.toString().hashCode(); + } + } +} diff --git a/src/main/java/cz/startnet/utils/pgdiff/schema/PgSchema.java b/src/main/java/cz/startnet/utils/pgdiff/schema/PgSchema.java index 127ff546..118e2804 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/schema/PgSchema.java +++ b/src/main/java/cz/startnet/utils/pgdiff/schema/PgSchema.java @@ -22,6 +22,11 @@ public class PgSchema { */ @SuppressWarnings("CollectionWithoutInitialCapacity") private final List functions = new ArrayList(); + /** + * List of procedures defined in the schema. + */ + @SuppressWarnings("CollectionWithoutInitialCapacity") + private final List procedures = new ArrayList(); /** * List of sequences defined in the schema. */ @@ -190,6 +195,32 @@ public PgFunction getFunction(final String signature) { public List getFunctions() { return Collections.unmodifiableList(functions); } + + /** + * Finds procedure according to specified procedure {@code signature}. + * + * @param signature signature of the procedure to be searched + * + * @return found procedure or null if no such procedure has been found + */ + public PgProcedure getProcedure(final String signature) { + for (PgProcedure procedure : procedures) { + if (procedure.getSignature().equals(signature)) { + return procedure; + } + } + + return null; + } + + /** + * Getter for {@link #procedures}. The list cannot be modified. + * + * @return {@link #procedures} + */ + public List getProcedures() { + return Collections.unmodifiableList(procedures); + } /** * Getter for {@link #name}. @@ -394,6 +425,15 @@ public void addPrimaryKey(final PgConstraint primaryKey) { public void addFunction(final PgFunction function) { functions.add(function); } + + /** + * Adds {@code procedure} to the list of procedures. + * + * @param procedure procedure + */ + public void addProcedure(final PgProcedure procedure) { + procedures.add(procedure); + } /** * Adds {@code sequence} to the list of sequences. @@ -522,6 +562,25 @@ public boolean containsFunction(final String signature) { return false; } + + /** + * Returns true if schema contains procedure with given {@code signature}, + * otherwise false. + * + * @param signature signature of the procedure + * + * @return true if schema contains procedure with given {@code signature}, + * otherwise false + */ + public boolean containsProcedure(final String signature) { + for (PgProcedure procedure : procedures) { + if (procedure.getSignature().equals(signature)) { + return true; + } + } + + return false; + } /** * Returns true if schema contains sequence with given {@code name}, diff --git a/src/main/java/cz/startnet/utils/pgdiff/schema/PgTable.java b/src/main/java/cz/startnet/utils/pgdiff/schema/PgTable.java index ee2069b8..e84686c9 100755 --- a/src/main/java/cz/startnet/utils/pgdiff/schema/PgTable.java +++ b/src/main/java/cz/startnet/utils/pgdiff/schema/PgTable.java @@ -72,6 +72,11 @@ public class PgTable extends PgRelation { * PgSchema */ private final PgSchema schema; + + /** + * Partion By + */ + private String partitionBy; /** * Creates a new PgTable object. @@ -163,6 +168,11 @@ public String getCreationSQL(final PgSchema schema) { sbSQL.append(System.getProperty("line.separator")); sbSQL.append(")"); } + + if(partitionBy!=null && !partitionBy.isEmpty()){ + sbSQL.append(" "); + sbSQL.append(partitionBy); + } if (inherits != null && !inherits.isEmpty()) { sbSQL.append(System.getProperty("line.separator")); @@ -497,4 +507,12 @@ public PgPolicy getPolicy(final String name) { public List getPolicies() { return Collections.unmodifiableList(policies); } + + public void setPartionBy(String partitionBy){ + this.partitionBy = partitionBy; + } + + public String getPartionBy(){ + return partitionBy; + } } diff --git a/src/test/java/cz/startnet/utils/pgdiff/PgDiffTest.java b/src/test/java/cz/startnet/utils/pgdiff/PgDiffTest.java old mode 100644 new mode 100755 index 9054852c..4b455a03 --- a/src/test/java/cz/startnet/utils/pgdiff/PgDiffTest.java +++ b/src/test/java/cz/startnet/utils/pgdiff/PgDiffTest.java @@ -177,6 +177,7 @@ public static Collection parameters() { {"drop_trigger", false, false, false, false}, // Tests scenario where TRIGGER is modified. {"modify_trigger", false, false, false, false}, + {"create_trigger_postgres12", false, false, false, false}, // Tests scenario where VIEW is added. {"add_view", false, false, false, false}, // Tests scenario where VIEW is dropped. @@ -229,6 +230,8 @@ public static Collection parameters() { {"view_colnames", false, false, false, false}, // Tests objects with the $ sign in the name {"add_table_bug102", false, false, false, false}, + // Tests objects with the PARTITION BY + {"add_table_partition_by", false, false, false, false}, // Tests scenario where new UNLOGGED TABLE is added. {"add_unlogged_table", false, false, false, false}, // Tests scenario where UNLOGGED TABLE is dropped. @@ -272,6 +275,8 @@ public static Collection parameters() { , {"alter_view_owner", false, false, false, false} , {"grant_on_table_cols_mixed", false, false, false, false} , {"grant_on_view_cols_mixed", false, false, false, false} + , {"create_schema_no_change_table", false, false, false, false} + , {"add_table_identity_sequence",false,false,false,false} // Test create trigger in PostgreSQL v12 , {"add_trigger_function_postgres12", false, false, false, false} // Test create trigger with referencing tables diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_constraint_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_constraint_diff.sql index cf526329..aa9b96d3 100644 --- a/src/test/resources/cz/startnet/utils/pgdiff/add_constraint_diff.sql +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_constraint_diff.sql @@ -1,3 +1,3 @@ -ALTER TABLE testtable +ALTER TABLE IF EXISTS testtable ADD CONSTRAINT IF NOT EXISTS field4check CHECK (((field4 > (-5.0)::double precision) AND (field4 < (5.0)::double precision))); diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_bug102_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_bug102_diff.sql index 43c2d3bb..78e272b7 100644 --- a/src/test/resources/cz/startnet/utils/pgdiff/add_table_bug102_diff.sql +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_bug102_diff.sql @@ -6,5 +6,5 @@ CREATE TABLE IF NOT EXISTS "procedureresult$Operation" ( ALTER TABLE "procedureresult$Operation" OWNER TO fordfrog; -ALTER TABLE "procedureresult$Operation" +ALTER TABLE IF EXISTS "procedureresult$Operation" ADD CONSTRAINT IF NOT EXISTS $1 FOREIGN KEY (result_id) REFERENCES testtable(field1) ON UPDATE RESTRICT ON DELETE RESTRICT; diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_diff.sql new file mode 100644 index 00000000..59686580 --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_diff.sql @@ -0,0 +1,12 @@ +ALTER TABLE teste + ADD COLUMN IF NOT EXISTS id integer NOT NULL; + +ALTER TABLE teste + ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME public.teste_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); \ No newline at end of file diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_new.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_new.sql new file mode 100644 index 00000000..6c592434 --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_new.sql @@ -0,0 +1,39 @@ +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: teste; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.teste ( + codigo integer NOT NULL, + id integer NOT NULL +); + + +ALTER TABLE public.teste OWNER TO postgres; + +-- +-- Name: teste_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +ALTER TABLE public.teste ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME public.teste_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); \ No newline at end of file diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_original.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_original.sql new file mode 100644 index 00000000..b58fa2d9 --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_identity_sequence_original.sql @@ -0,0 +1,36 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 13.3 +-- Dumped by pg_dump version 13.3 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: teste; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.teste ( + codigo integer NOT NULL +); + + +ALTER TABLE public.teste OWNER TO postgres; + +-- +-- PostgreSQL database dump complete +-- \ No newline at end of file diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_diff.sql new file mode 100644 index 00000000..e1d73662 --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_diff.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS "procedureresult$Operation" ( + id bigint NOT NULL, + name character varying(255), + result_id bigint +) PARTITION BY RANGE(result_id); + +ALTER TABLE "procedureresult$Operation" OWNER TO fordfrog; + +ALTER TABLE IF EXISTS "procedureresult$Operation" + ADD CONSTRAINT IF NOT EXISTS $1 FOREIGN KEY (result_id) REFERENCES testtable(field1) ON UPDATE RESTRICT ON DELETE RESTRICT; diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_new.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_new.sql new file mode 100644 index 00000000..6ec3e31f --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_new.sql @@ -0,0 +1,71 @@ +-- +-- PostgreSQL database dump +-- + +SET client_encoding = 'UTF8'; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres +-- + +COMMENT ON SCHEMA public IS 'Standard public schema'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: testtable; Type: TABLE; Schema: public; Owner: fordfrog; Tablespace: +-- + +CREATE TABLE testtable ( + field1 integer, + field2 integer, + field3 character varying(150) DEFAULT 'none'::character varying, + field4 double precision +); + + +ALTER TABLE public.testtable OWNER TO fordfrog; + +-- +-- Name: procedureresult$operation; Type: TABLE; Schema: public; Owner: fordfrog; Tablespace: +-- + +CREATE TABLE "procedureresult$Operation" ( + id bigint NOT NULL, + name character varying(255), + result_id bigint +) PARTITION BY RANGE(result_id); + +ALTER TABLE public."procedureresult$Operation" OWNER TO fordfrog; + +ALTER TABLE ONLY "procedureresult$Operation" +ADD CONSTRAINT "$1" FOREIGN KEY (result_id) REFERENCES testtable(field1) ON UPDATE RESTRICT ON DELETE RESTRICT; + +-- +-- Name: testindex; Type: INDEX; Schema: public; Owner: fordfrog; Tablespace: +-- + +CREATE INDEX testindex ON testtable USING btree (field3); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_original.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_original.sql new file mode 100644 index 00000000..c7349f2a --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_table_partition_by_original.sql @@ -0,0 +1,57 @@ + +-- +-- PostgreSQL database dump +-- + +SET client_encoding = 'UTF8'; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres +-- + +COMMENT ON SCHEMA public IS 'Standard public schema'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: testtable; Type: TABLE; Schema: public; Owner: fordfrog; Tablespace: +-- + +CREATE TABLE testtable ( + field1 integer, + field2 integer, + field3 character varying(150) DEFAULT 'none'::character varying, + field4 double precision +); + + +ALTER TABLE public.testtable OWNER TO fordfrog; + +-- +-- Name: testindex; Type: INDEX; Schema: public; Owner: fordfrog; Tablespace: +-- + +CREATE INDEX testindex ON testtable USING btree (field3); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/add_unique_constraint_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/add_unique_constraint_diff.sql index ce282b33..bd6df0ce 100644 --- a/src/test/resources/cz/startnet/utils/pgdiff/add_unique_constraint_diff.sql +++ b/src/test/resources/cz/startnet/utils/pgdiff/add_unique_constraint_diff.sql @@ -1,6 +1,6 @@ -ALTER TABLE inventoryitemsupplier +ALTER TABLE IF EXISTS inventoryitemsupplier ADD CONSTRAINT IF NOT EXISTS inventoryitemsupplier_pkey PRIMARY KEY (id); -ALTER TABLE inventoryitemsupplier +ALTER TABLE IF EXISTS inventoryitemsupplier ADD CONSTRAINT IF NOT EXISTS inventoryitemsupplier_5a808b9c_key UNIQUE (inventoryitemid, partneridentificationid); diff --git a/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_diff.sql new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_diff.sql @@ -0,0 +1,2 @@ + + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_new.sql b/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_new.sql new file mode 100644 index 00000000..e1f0dcaa --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_new.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA public; +CREATE TABLE public.node (instance_id text); + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_original.sql b/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_original.sql new file mode 100644 index 00000000..e1f0dcaa --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/create_schema_no_change_table_original.sql @@ -0,0 +1,3 @@ +CREATE SCHEMA public; +CREATE TABLE public.node (instance_id text); + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_diff.sql new file mode 100644 index 00000000..ba6db001 --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_diff.sql @@ -0,0 +1,14 @@ + +SET search_path = schema_1, pg_catalog; + +CREATE TABLE IF NOT EXISTS tb_teste3 ( + id integer, + description character varying +); + +ALTER TABLE tb_teste3 OWNER TO postgres; + +CREATE TRIGGER trg_testview_after_insert + AFTER INSERT ON tb_teste3 + FOR EACH ROW + EXECUTE PROCEDURE public.fn_trg_testview(); diff --git a/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_new.sql b/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_new.sql new file mode 100644 index 00000000..94f3c7dd --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_new.sql @@ -0,0 +1,78 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 12.2 +-- Dumped by pg_dump version 12.2 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: schema_1; Type: SCHEMA; Schema: -; Owner: postgres +-- + +CREATE SCHEMA schema_1; + + +ALTER SCHEMA schema_1 OWNER TO postgres; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: tb_teste1; Type: TABLE; Schema: schema_1; Owner: postgres +-- + +CREATE TABLE schema_1.tb_teste1 ( + id integer, + description character varying +); + + +ALTER TABLE schema_1.tb_teste1 OWNER TO postgres; + +-- +-- Name: tb_teste2; Type: TABLE; Schema: schema_1; Owner: postgres +-- + +CREATE TABLE schema_1.tb_teste2 ( + id integer, + description character varying +); + + +ALTER TABLE schema_1.tb_teste2 OWNER TO postgres; + +-- +-- Name: tb_teste3; Type: TABLE; Schema: schema_1; Owner: postgres +-- + +CREATE TABLE schema_1.tb_teste3 ( + id integer, + description character varying +); + + +ALTER TABLE schema_1.tb_teste3 OWNER TO postgres; + +-- +-- Name: tb_teste3 trg_testview_after_insert; Type: TRIGGER; Schema: schema_1; Owner: postgres +-- + +CREATE TRIGGER trg_testview_after_insert AFTER INSERT ON schema_1.tb_teste3 FOR EACH ROW EXECUTE FUNCTION public.fn_trg_testview(); + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_original.sql b/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_original.sql new file mode 100644 index 00000000..e491ef4a --- /dev/null +++ b/src/test/resources/cz/startnet/utils/pgdiff/create_trigger_postgres12_original.sql @@ -0,0 +1,59 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 12.2 +-- Dumped by pg_dump version 12.2 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: schema_1; Type: SCHEMA; Schema: -; Owner: postgres +-- + +CREATE SCHEMA schema_1; + + +ALTER SCHEMA schema_1 OWNER TO postgres; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: tb_teste1; Type: TABLE; Schema: schema_1; Owner: postgres +-- + +CREATE TABLE schema_1.tb_teste1 ( + id integer, + description character varying +); + + +ALTER TABLE schema_1.tb_teste1 OWNER TO postgres; + +-- +-- Name: tb_teste2; Type: TABLE; Schema: schema_1; Owner: postgres +-- + +CREATE TABLE schema_1.tb_teste2 ( + id integer, + description character varying +); + + +ALTER TABLE schema_1.tb_teste2 OWNER TO postgres; + +-- +-- PostgreSQL database dump complete +-- + diff --git a/src/test/resources/cz/startnet/utils/pgdiff/drop_constraint_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/drop_constraint_diff.sql index 6732feb8..11947d0a 100644 --- a/src/test/resources/cz/startnet/utils/pgdiff/drop_constraint_diff.sql +++ b/src/test/resources/cz/startnet/utils/pgdiff/drop_constraint_diff.sql @@ -1,3 +1,3 @@ -ALTER TABLE testtable +ALTER TABLE IF EXISTS testtable DROP CONSTRAINT IF EXISTS field4check; diff --git a/src/test/resources/cz/startnet/utils/pgdiff/modify_constraint_diff.sql b/src/test/resources/cz/startnet/utils/pgdiff/modify_constraint_diff.sql index a13f3633..e88603bb 100644 --- a/src/test/resources/cz/startnet/utils/pgdiff/modify_constraint_diff.sql +++ b/src/test/resources/cz/startnet/utils/pgdiff/modify_constraint_diff.sql @@ -1,6 +1,6 @@ -ALTER TABLE testtable +ALTER TABLE IF EXISTS testtable DROP CONSTRAINT IF EXISTS field4check; -ALTER TABLE testtable +ALTER TABLE IF EXISTS testtable ADD CONSTRAINT IF NOT EXISTS field4check CHECK ((field4 > (0.0)::double precision));