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
@@ -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:
+
@@ -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));