diff --git a/grammar-to-java/pom.xml b/grammar-to-java/pom.xml
index 7e4bbfb..1cab65f 100644
--- a/grammar-to-java/pom.xml
+++ b/grammar-to-java/pom.xml
@@ -5,7 +5,7 @@
com.splendiddata
pg_sqlparser
- 18.1
+ 18.2
com.splendiddata.pg_sqlparser
grammar-to-java
diff --git a/parser-enums/pom.xml b/parser-enums/pom.xml
index 49ad9dc..3f734be 100644
--- a/parser-enums/pom.xml
+++ b/parser-enums/pom.xml
@@ -5,7 +5,7 @@
com.splendiddata
pg_sqlparser
- 18.1
+ 18.2
com.splendiddata.pg_sqlparser
parser-enums
diff --git a/parser-test-gui/pom.xml b/parser-test-gui/pom.xml
index 8b49a7e..107a4a8 100644
--- a/parser-test-gui/pom.xml
+++ b/parser-test-gui/pom.xml
@@ -5,7 +5,7 @@
com.splendiddata
pg_sqlparser
- 18.1
+ 18.2
parser-test-gui
com.splendiddata.pg_sqlparser
diff --git a/parser/pom.xml b/parser/pom.xml
index d5b3b9e..eeb3b96 100644
--- a/parser/pom.xml
+++ b/parser/pom.xml
@@ -5,7 +5,7 @@
com.splendiddata
pg_sqlparser
- 18.1
+ 18.2
com.splendiddata.pg_sqlparser
parser
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/CollateClause.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/CollateClause.java
index 9695db6..efe2861 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/CollateClause.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/CollateClause.java
@@ -30,7 +30,7 @@
* @since 0.0.1
*/
@XmlRootElement(namespace = "parser")
-public class CollateClause extends Node {
+public class CollateClause extends Expr {
/** input expression */
@XmlElement
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/DefineStmt.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/DefineStmt.java
index 724d5c7..88c6cb8 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/DefineStmt.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/DefineStmt.java
@@ -231,6 +231,9 @@ public String toString() {
result.append(" = ").append(def.arg);
}
break;
+ case "category":
+ result.append(separator).append(def.defname.toLowerCase()).append(" = '").append(def.arg).append("'");
+ break;
default:
result.append(separator).append('"').append(def.defname.toLowerCase()).append('"');
if (def.arg != null) {
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonAggConstructor.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonAggConstructor.java
index 7997fcd..c199cd4 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonAggConstructor.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonAggConstructor.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArgument.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArgument.java
index 9ea5f9b..0b3f81c 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArgument.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArgument.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2020 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayAgg.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayAgg.java
index c08f777..057c9c0 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayAgg.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayAgg.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayConstructor.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayConstructor.java
index 49cc1bd..8482f4e 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayConstructor.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayConstructor.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayQueryConstructor.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayQueryConstructor.java
index 37f8544..c6d6088 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayQueryConstructor.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonArrayQueryConstructor.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonFormat.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonFormat.java
index 2d09fcb..b6d5a94 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonFormat.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonFormat.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2020 - 2023
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonIsPredicate.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonIsPredicate.java
index 432d7ab..9d7e554 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonIsPredicate.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonIsPredicate.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonKeyValue.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonKeyValue.java
index 8ef8b5b..9171c4a 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonKeyValue.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonKeyValue.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectAgg.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectAgg.java
index c4c8464..b041560 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectAgg.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectAgg.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectConstructor.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectConstructor.java
index f2bfa02..f31a683 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectConstructor.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonObjectConstructor.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonOutput.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonOutput.java
index db58fcc..c95d252 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonOutput.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonOutput.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonParseExpr.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonParseExpr.java
index 595aa3f..82ef5ad 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonParseExpr.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonParseExpr.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2020 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonReturning.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonReturning.java
index c086c32..617f72b 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonReturning.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonReturning.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonScalarExpr.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonScalarExpr.java
index cb5097e..36557cb 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonScalarExpr.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonScalarExpr.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2020 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonTablePathSpec.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonTablePathSpec.java
index b081c31..b72d3e1 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonTablePathSpec.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonTablePathSpec.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonValueExpr.java b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonValueExpr.java
index 3551f44..e8d2e6b 100644
--- a/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonValueExpr.java
+++ b/parser/src/main/java/com/splendiddata/sqlparser/structure/JsonValueExpr.java
@@ -1,9 +1,15 @@
/*
- * Copyright (c) Splendid Data Product Development B.V. 2023 - 2024
+ * Copyright (c) Splendid Data Product Development B.V. 2020 - 2026
*
- * This unpublished material is proprietary to Splendid Data Product Development B.V. All rights reserved. The methods
- * and techniques described herein are considered trade secrets and/or confidential. Reproduction or distribution, in
- * whole or in part, is forbidden except by express written permission of Splendid Data Product Development B.V.
+ * This program is free software: You may redistribute and/or modify under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at Client's option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, Client should
+ * obtain one via www.gnu.org/licenses/.
*/
package com.splendiddata.sqlparser.structure;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/aggregates.sql b/parser/src/test/resources/postgres/test/regress/sql/aggregates.sql
index 97ade14..8decdda 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/aggregates.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/aggregates.sql
@@ -548,6 +548,23 @@ alter table t2 alter column z drop not null;
create unique index t2_z_uidx on t2(z) nulls not distinct;
explain (costs off) select y,z from t2 group by y,z;
+-- A unique index proves uniqueness only under its own opfamily. When the
+-- GROUP BY's eqop comes from a different opfamily with looser equality,
+-- rows the index regards as distinct can collapse into one GROUP BY group,
+-- so the index is not usable for removing redundant columns.
+create type t_rec as (x numeric);
+create temp table t_opf (a t_rec not null, b text);
+create unique index on t_opf (a record_image_ops);
+-- (1.0) and (1.00) are bytewise distinct but logically equal as records;
+-- the index admits both, but GROUP BY a (default record_ops) would merge
+-- them, so b must be retained as a grouping key.
+insert into t_opf values (row(1.0)::t_rec, 'X'), (row(1.00)::t_rec, 'Y');
+explain (costs off)
+select a, b from t_opf group by a, b order by b;
+select a, b from t_opf group by a, b order by b;
+drop table t_opf;
+drop type t_rec;
+
drop table t1 cascade;
drop table t2;
drop table t3;
@@ -576,6 +593,12 @@ select f2, count(*) from
t1 x(x0,x1) left join (t1 left join t2 using(f2)) on (x0 = 0)
group by f2;
+-- check that we preserve join alias in GROUP BY expressions
+create temp view v1 as
+select f1::int from t1 left join t2 using (f1) group by f1;
+select pg_get_viewdef('v1'::regclass);
+
+drop view v1;
drop table t1, t2;
--
diff --git a/parser/src/test/resources/postgres/test/regress/sql/alter_table.sql b/parser/src/test/resources/postgres/test/regress/sql/alter_table.sql
index 05a5635..de8fc22 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/alter_table.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/alter_table.sql
@@ -2338,6 +2338,14 @@ ALTER TABLE test_add_column
\d test_add_column
ALTER TABLE test_add_column
ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10);
+ALTER TABLE test_add_column
+ ADD c6 integer; -- omit COLUMN
+ALTER TABLE test_add_column
+ ADD IF NOT EXISTS c6 integer;
+ALTER TABLE test_add_column
+ DROP c6; -- omit COLUMN
+ALTER TABLE test_add_column
+ DROP IF EXISTS c6;
\d test_add_column*
DROP TABLE test_add_column;
\d test_add_column*
@@ -2841,6 +2849,15 @@ ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY;
\d part_rp100
DROP TABLE range_parted2;
+-- Test that hash partitions continue to work after they're concurrently
+-- detached (bugs #18371, #19070)
+CREATE TABLE hash_parted2 (a int) PARTITION BY HASH(a);
+CREATE TABLE part_hp PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 2, REMAINDER 0);
+ALTER TABLE hash_parted2 DETACH PARTITION part_hp CONCURRENTLY;
+DROP TABLE hash_parted2;
+INSERT INTO part_hp VALUES (1);
+DROP TABLE part_hp;
+
-- Check ALTER TABLE commands for partitioned tables and partitions
-- cannot add/drop column to/from *only* the parent
diff --git a/parser/src/test/resources/postgres/test/regress/sql/arrays.sql b/parser/src/test/resources/postgres/test/regress/sql/arrays.sql
index 47d62c1..ddd496e 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/arrays.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/arrays.sql
@@ -528,6 +528,10 @@ select '[2147483646:2147483646]={1}'::int[];
select '[-2147483648:-2147483647]={1,2}'::int[];
-- all of the above should be accepted
+-- some day we might allow these cases, but for now they're errors:
+select array[]::oidvector;
+select array[]::int2vector;
+
-- tests for array aggregates
CREATE TEMP TABLE arraggtest ( f1 INT[], f2 TEXT[][], f3 FLOAT[]);
diff --git a/parser/src/test/resources/postgres/test/regress/sql/collate.icu.utf8.sql b/parser/src/test/resources/postgres/test/regress/sql/collate.icu.utf8.sql
index 6f06bcf..80b36db 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/collate.icu.utf8.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/collate.icu.utf8.sql
@@ -576,6 +576,9 @@ SELECT 'abc' <= 'ABC' COLLATE case_insensitive, 'abc' >= 'ABC' COLLATE case_inse
SELECT array_sort('{a,B}'::text[] COLLATE case_insensitive);
SELECT array_sort('{a,B}'::text[] COLLATE "C");
+-- test replace() at the end of the string (bug #19341)
+SELECT replace('testX' COLLATE case_insensitive, 'x' COLLATE case_insensitive, 'er');
+
-- test language tags
CREATE COLLATION lt_insensitive (provider = icu, locale = 'en-u-ks-level1', deterministic = false);
SELECT 'aBcD' COLLATE lt_insensitive = 'AbCd' COLLATE lt_insensitive;
@@ -613,6 +616,109 @@ CREATE UNIQUE INDEX ON test3cs (x); -- ok
SELECT string_to_array('ABC,DEF,GHI' COLLATE case_sensitive, ',', 'abc');
SELECT string_to_array('ABCDEFGHI' COLLATE case_sensitive, NULL, 'b');
+--
+-- A unique index under one collation does not prove uniqueness under
+-- another, so the planner must not use such a proof for any optimization.
+--
+
+-- Ensure that we do not use inner-unique join execution
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM test1cs t1, test3cs t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+SELECT * FROM test1cs t1, test3cs t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+-- Ensure that left-join is not removed
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM test3cs t1
+ LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1;
+
+SELECT t1.* FROM test3cs t1
+ LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1;
+
+-- Ensure that self-join is not removed
+EXPLAIN (COSTS OFF)
+SELECT * FROM test3cs t1, test3cs t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+SELECT * FROM test3cs t1, test3cs t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+-- Ensure that semijoin is not reduced to innerjoin
+EXPLAIN (COSTS OFF)
+SELECT * FROM test3cs t1
+ WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive)
+ORDER BY 1;
+
+SELECT * FROM test3cs t1
+ WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive)
+ORDER BY 1;
+
+--
+-- A DISTINCT / GROUP BY / set-op on a subquery does not prove uniqueness
+-- under a different collation, so the planner must not use such a proof for
+-- any optimization.
+--
+
+-- Ensure that we do not use inner-unique join execution
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+-- Same with GROUP BY
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+-- Same with set-op
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2
+WHERE t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1, 2;
+
+-- Ensure that left-join is not removed
+EXPLAIN (COSTS OFF)
+SELECT t1.* FROM test3cs t1
+ LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1;
+
+SELECT t1.* FROM test3cs t1
+ LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive
+ORDER BY 1;
+
+-- Ensure that semijoin is not reduced to innerjoin
+EXPLAIN (COSTS OFF)
+SELECT * FROM test3cs t1
+ WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2
+ WHERE t1.x = t2.x COLLATE case_insensitive)
+ORDER BY 1;
+
+SELECT * FROM test3cs t1
+ WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2
+ WHERE t1.x = t2.x COLLATE case_insensitive)
+ORDER BY 1;
+
CREATE TABLE test1ci (x text COLLATE case_insensitive);
CREATE TABLE test2ci (x text COLLATE case_insensitive);
CREATE TABLE test3ci (x text COLLATE case_insensitive);
@@ -643,6 +749,87 @@ CREATE UNIQUE INDEX ON test3ci (x); -- error
SELECT string_to_array('ABC,DEF,GHI' COLLATE case_insensitive, ',', 'abc');
SELECT string_to_array('ABCDEFGHI' COLLATE case_insensitive, NULL, 'b');
+-- Test HAVING-to-WHERE pushdown with nondeterministic collations.
+-- When a HAVING clause uses a different collation than the GROUP BY's
+-- nondeterministic collation, it must not be pushed to WHERE, otherwise
+-- aggregate results can change because the stricter filter eliminates rows
+-- before grouping.
+
+-- Negative: collation conflict, HAVING must not be pushed to WHERE
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive;
+
+-- Positive: same collation, safe to push HAVING to WHERE
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive;
+
+-- Negative: function applied to grouped column with conflicting collation
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive;
+
+-- Positive: function with same collation as GROUP BY
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive;
+
+-- Negative: inner function has conflicting collation, even though outer
+-- operator's collation matches GROUP BY due to a COLLATE override
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC';
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC';
+
+-- Mixed AND: conflicting clause stays in HAVING, safe clause pushed to WHERE
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1;
+
+-- Positive: AND of two safe clauses, both can be pushed
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1;
+
+-- Negative: OR with a conflicting clause: must stay in HAVING
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1;
+
+-- Negative: collation conflict inside a RowCompareExpr
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1;
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1;
+
+-- Negative: simple-CASE form with conflicting WHEN comparison collation
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END);
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END);
+
+-- Positive: simple-CASE form with matching collation, safe to push
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END);
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END);
+
+-- Negative: nested CASE with collation conflict
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END);
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END);
+
+-- Positive: conflicting collation but no grouping expression reference
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3ci GROUP BY x HAVING current_setting('server_version') = 'abc' COLLATE case_sensitive;
+
+-- Positive: deterministic collation in GROUP BY: always safe to push, even if
+-- HAVING uses a nondeterministic collation
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive;
+SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive;
+
+EXPLAIN (COSTS OFF)
+SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1;
+SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1;
+
-- bpchar
CREATE TABLE test1bpci (x char(3) COLLATE case_insensitive);
CREATE TABLE test2bpci (x char(3) COLLATE case_insensitive);
@@ -991,6 +1178,26 @@ RESET enable_partitionwise_aggregate;
RESET max_parallel_workers_per_gather;
RESET enable_incremental_sort;
+--
+-- A unique index can prove functional dependency for GROUP BY column
+-- removal only if its per-column collation agrees on equality with
+-- the GROUP BY column's collation. An index built under a different
+-- (deterministic) collation would otherwise let remove_useless_groupby_columns
+-- drop other columns whose values still differ within a nondeterministic
+-- group.
+--
+CREATE TABLE groupby_collation_t (a text COLLATE case_insensitive NOT NULL, b text);
+INSERT INTO groupby_collation_t VALUES ('foo', 'X'), ('FOO', 'Y');
+CREATE UNIQUE INDEX ON groupby_collation_t (a COLLATE "C");
+
+-- Column b must NOT be dropped: under case_insensitive on a, 'foo' and
+-- 'FOO' would merge, but they have distinct b values.
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b;
+SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b;
+
+DROP TABLE groupby_collation_t;
+
-- virtual generated columns
CREATE TABLE t5 (
a int,
@@ -1005,6 +1212,19 @@ INSERT INTO t5 (a, b) values (1, 'D1'), (2, 'D2'), (3, 'd1');
-- rewriting.)
SELECT * FROM t5 ORDER BY c ASC, a ASC;
+-- Check that DEFAULT expressions in SQL/JSON functions use the same collation
+-- as the RETURNING type. Mismatched collations should raise an error.
+CREATE DOMAIN d1 AS text COLLATE case_insensitive;
+CREATE DOMAIN d2 AS text COLLATE "C";
+SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT ('C' COLLATE "C") COLLATE case_insensitive ON EMPTY) = 'a'; -- true
+SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT 'C' ON EMPTY) = 'a'; -- true
+SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT 'C'::d2 ON EMPTY) = 'a'; -- error
+SELECT JSON_VALUE('{"a": "A"}', '$.a' RETURNING d1 DEFAULT 'C' COLLATE "C" ON EMPTY) = 'a'; -- error
+SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A' ON EMPTY) = 'a'; -- true
+SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A' COLLATE case_insensitive ON EMPTY) = 'a'; -- true
+SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A'::d2 ON EMPTY) = 'a'; -- error
+SELECT JSON_VALUE('{"a": "A"}', '$.c' RETURNING d1 DEFAULT 'A' COLLATE "C" ON EMPTY) = 'a'; -- error
+DROP DOMAIN d1, d2;
-- cleanup
RESET search_path;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/compression_pglz.sql b/parser/src/test/resources/postgres/test/regress/sql/compression_pglz.sql
new file mode 100644
index 0000000..dbd37f7
--- /dev/null
+++ b/parser/src/test/resources/postgres/test/regress/sql/compression_pglz.sql
@@ -0,0 +1,63 @@
+--
+-- Tests for PGLZ compression
+--
+
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+
+\set regresslib :libdir '/regress' :dlsuffix
+
+CREATE FUNCTION test_pglz_compress(bytea)
+ RETURNS bytea
+ AS :'regresslib' LANGUAGE C STRICT;
+CREATE FUNCTION test_pglz_decompress(bytea, int4, bool)
+ RETURNS bytea
+ AS :'regresslib' LANGUAGE C STRICT;
+
+-- Round-trip with pglz: compress then decompress.
+SELECT test_pglz_decompress(test_pglz_compress(
+ decode(repeat('abcd', 100), 'escape')), 400, false) =
+ decode(repeat('abcd', 100), 'escape') AS roundtrip_ok;
+SELECT test_pglz_decompress(test_pglz_compress(
+ decode(repeat('abcd', 100), 'escape')), 400, true) =
+ decode(repeat('abcd', 100), 'escape') AS roundtrip_ok;
+
+-- Decompression with rawsize too large, fails to fill the destination
+-- buffer.
+SELECT test_pglz_decompress(test_pglz_compress(
+ decode(repeat('abcd', 100), 'escape')), 500, true);
+
+-- Decompression with rawsize too small, fails with source not fully
+-- consumed.
+SELECT test_pglz_decompress(test_pglz_compress(
+ decode(repeat('abcd', 100), 'escape')), 100, true);
+
+-- Corrupted compressed data. Set control bit with read of a match tag,
+-- no data follows.
+SELECT length(test_pglz_decompress('\x01'::bytea, 1024, false)) AS ctrl_only_len;
+SELECT test_pglz_decompress('\x01'::bytea, 1024, true);
+
+-- Corrupted compressed data. Set control bit with read of a match tag,
+-- 1 byte follows.
+SELECT test_pglz_decompress('\x01ff'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true);
+
+-- Corrupted compressed data. Set control bit with match tag where length
+-- nibble is 3 bytes (extended length), no data follows.
+SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true);
+
+-- Corrupted compressed data. Set control bit with a valid 2-byte match
+-- tag where offset exceeds output written.
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, true);
+
+-- Corrupted compressed data. Set control bit with a valid 2-byte match
+-- tag where offset is 0.
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, true);
+
+-- Clean up
+DROP FUNCTION test_pglz_compress;
+DROP FUNCTION test_pglz_decompress;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/constraints.sql b/parser/src/test/resources/postgres/test/regress/sql/constraints.sql
index 68e48b6..b684f80 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/constraints.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/constraints.sql
@@ -631,7 +631,9 @@ DROP TABLE deferred_excl;
-- verify constraints created for NOT NULL clauses
CREATE TABLE notnull_tbl1 (a INTEGER NOT NULL NOT NULL);
\d+ notnull_tbl1
--- no-op
+-- specifying an existing constraint is a no-op
+ALTER TABLE notnull_tbl1 ADD CONSTRAINT notnull_tbl1_a_not_null NOT NULL a;
+-- but using a different constraint name is not allowed
ALTER TABLE notnull_tbl1 ADD CONSTRAINT nn NOT NULL a;
\d+ notnull_tbl1
-- duplicate name
@@ -708,6 +710,9 @@ DROP TABLE ATACC1, ATACC2, ATACC3;
-- NOT NULL NO INHERIT is not possible on partitioned tables
CREATE TABLE ATACC1 (a int NOT NULL NO INHERIT) PARTITION BY LIST (a);
CREATE TABLE ATACC1 (a int, NOT NULL a NO INHERIT) PARTITION BY LIST (a);
+CREATE TABLE ATACC1 (a int, CONSTRAINT a_is_not_null NOT NULL a) PARTITION BY LIST (a);
+ALTER TABLE ATACC1 ALTER CONSTRAINT a_is_not_null NO INHERIT;
+DROP TABLE ATACC1;
-- it's not possible to override a no-inherit constraint with an inheritable one
CREATE TABLE ATACC2 (a int, CONSTRAINT a_is_not_null NOT NULL a NO INHERIT);
@@ -840,6 +845,9 @@ ALTER TABLE notnull_tbl1 ADD CONSTRAINT nn NOT NULL a;
-- cannot add primary key on a column with an invalid not-null
ALTER TABLE notnull_tbl1 ADD PRIMARY KEY (a);
+-- cannot set column as generated-as-identity if it has an invalid not-null
+ALTER TABLE notnull_tbl1 ALTER COLUMN a ADD GENERATED ALWAYS AS IDENTITY;
+
-- ALTER column SET NOT NULL validates an invalid constraint (but this fails
-- because of rows with null values)
ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
@@ -1057,3 +1065,8 @@ CREATE DOMAIN constraint_comments_dom AS int;
ALTER DOMAIN constraint_comments_dom ADD CONSTRAINT inv_ck CHECK (value > 0) NOT VALID;
COMMENT ON CONSTRAINT inv_ck ON DOMAIN constraint_comments_dom IS 'comment on invalid constraint';
+
+-- Create a table that exercises pg_upgrade
+CREATE TABLE regress_notnull1 (a integer);
+CREATE TABLE regress_notnull2 () INHERITS (regress_notnull1);
+ALTER TABLE ONLY regress_notnull2 ALTER COLUMN a SET NOT NULL;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/create_index.sql b/parser/src/test/resources/postgres/test/regress/sql/create_index.sql
index 0f04298..13f4a39 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/create_index.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/create_index.sql
@@ -53,6 +53,10 @@ CREATE INDEX six ON shighway USING btree (name text_ops);
COMMENT ON INDEX six_wrong IS 'bad index';
COMMENT ON INDEX six IS 'good index';
COMMENT ON INDEX six IS NULL;
+SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null;
+COMMENT ON INDEX six IS 'add the comment back';
+COMMENT ON INDEX six IS ''; -- empty string removes the comment, same as NULL
+SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null;
--
-- BTREE partial indices
diff --git a/parser/src/test/resources/postgres/test/regress/sql/create_role.sql b/parser/src/test/resources/postgres/test/regress/sql/create_role.sql
index 4491a28..b22f9c6 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/create_role.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/create_role.sql
@@ -92,6 +92,13 @@ CREATE ROLE regress_hasprivs CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5;
-- ok, we should be able to modify a role we created
COMMENT ON ROLE regress_hasprivs IS 'some comment';
+SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment;
+COMMENT ON ROLE regress_hasprivs IS NULL;
+SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment;
+COMMENT ON ROLE regress_hasprivs IS 'add the comment back';
+SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment;
+COMMENT ON ROLE regress_hasprivs IS ''; -- empty string removes the comment, same as NULL
+SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment;
ALTER ROLE regress_hasprivs RENAME TO regress_tenant;
ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/create_table.sql b/parser/src/test/resources/postgres/test/regress/sql/create_table.sql
index f35f03f..801f9d6 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/create_table.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/create_table.sql
@@ -113,6 +113,13 @@ SAVEPOINT q; DROP TABLE remember_node_subid; ROLLBACK TO q;
COMMIT;
DROP TABLE remember_node_subid;
+-- generated NOT NULL constraint names must not collide with explicitly named constraints
+CREATE TABLE two_not_null_constraints (
+ col integer NOT NULL,
+ CONSTRAINT two_not_null_constraints_col_not_null CHECK (col IS NOT NULL)
+);
+DROP TABLE two_not_null_constraints;
+
--
-- Partitioned tables
--
diff --git a/parser/src/test/resources/postgres/test/regress/sql/create_table_like.sql b/parser/src/test/resources/postgres/test/regress/sql/create_table_like.sql
index 93389b5..d52a93e 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/create_table_like.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/create_table_like.sql
@@ -276,6 +276,32 @@ CREATE FOREIGN TABLE ctl_foreign_table2(LIKE ctl_table INCLUDING ALL) SERVER ctl
SELECT attname, attcompression FROM pg_attribute
WHERE attrelid = 'ctl_foreign_table2'::regclass and attnum > 0 ORDER BY attnum;
+-- LIKE ... INCLUDING STATISTICS with dropped columns in the parent,
+-- so stxkeys attnums are not contiguous.
+CREATE TABLE ctl_stats3_parent (a int, b int, c int);
+ALTER TABLE ctl_stats3_parent DROP COLUMN b;
+CREATE STATISTICS ctl_stats3_stat ON a, c FROM ctl_stats3_parent;
+CREATE TABLE ctl_stats3_child (LIKE ctl_stats3_parent INCLUDING STATISTICS);
+CREATE TABLE ctl_stats4_parent (a int, b int, c int, d int);
+ALTER TABLE ctl_stats4_parent DROP COLUMN b;
+CREATE STATISTICS ctl_stats4_stat ON a, c FROM ctl_stats4_parent;
+CREATE TABLE ctl_stats4_child (LIKE ctl_stats4_parent INCLUDING STATISTICS);
+SELECT s.stxrelid::regclass AS relation,
+ array_agg(a.attname ORDER BY u.ord) AS stats_columns
+FROM pg_statistic_ext s
+CROSS JOIN LATERAL
+ unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord)
+JOIN pg_attribute a
+ ON a.attrelid = s.stxrelid AND a.attnum = u.attnum
+WHERE s.stxrelid IN ('ctl_stats3_child'::regclass,
+ 'ctl_stats4_child'::regclass)
+GROUP BY s.stxrelid
+ORDER BY s.stxrelid::regclass::text;
+DROP TABLE ctl_stats3_parent;
+DROP TABLE ctl_stats3_child;
+DROP TABLE ctl_stats4_parent;
+DROP TABLE ctl_stats4_child;
+
DROP TABLE ctl_table;
DROP FOREIGN TABLE ctl_foreign_table1;
DROP FOREIGN TABLE ctl_foreign_table2;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/encoding.sql b/parser/src/test/resources/postgres/test/regress/sql/encoding.sql
new file mode 100644
index 0000000..d591818
--- /dev/null
+++ b/parser/src/test/resources/postgres/test/regress/sql/encoding.sql
@@ -0,0 +1,247 @@
+/* skip test if not UTF8 server encoding */
+SELECT getdatabaseencoding() <> 'UTF8' AS skip_test \gset
+\if :skip_test
+\quit
+\endif
+
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+
+\set regresslib :libdir '/regress' :dlsuffix
+
+CREATE FUNCTION test_bytea_to_text(bytea) RETURNS text
+ AS :'regresslib' LANGUAGE C STRICT;
+CREATE FUNCTION test_text_to_bytea(text) RETURNS bytea
+ AS :'regresslib' LANGUAGE C STRICT;
+CREATE FUNCTION test_mblen_func(text, text, text, int) RETURNS int
+ AS :'regresslib' LANGUAGE C STRICT;
+CREATE FUNCTION test_text_to_wchars(text, text) RETURNS int[]
+ AS :'regresslib' LANGUAGE C STRICT;
+CREATE FUNCTION test_wchars_to_text(text, int[]) RETURNS text
+ AS :'regresslib' LANGUAGE C STRICT;
+CREATE FUNCTION test_valid_server_encoding(text) RETURNS boolean
+ AS :'regresslib' LANGUAGE C STRICT;
+
+
+CREATE TABLE regress_encoding(good text, truncated text, with_nul text, truncated_with_nul text);
+INSERT INTO regress_encoding
+VALUES ('café',
+ 'caf' || test_bytea_to_text('\xc3'),
+ 'café' || test_bytea_to_text('\x00') || 'dcba',
+ 'caf' || test_bytea_to_text('\xc300') || 'dcba');
+
+SELECT good, truncated, with_nul FROM regress_encoding;
+
+SELECT length(good) FROM regress_encoding;
+SELECT substring(good, 3, 1) FROM regress_encoding;
+SELECT substring(good, 4, 1) FROM regress_encoding;
+SELECT regexp_replace(good, '^caf(.)$', '\1') FROM regress_encoding;
+SELECT reverse(good) FROM regress_encoding;
+
+-- invalid short mb character = error
+SELECT length(truncated) FROM regress_encoding;
+SELECT substring(truncated, 1, 3) FROM regress_encoding;
+SELECT substring(truncated, 1, 4) FROM regress_encoding;
+SELECT reverse(truncated) FROM regress_encoding;
+-- invalid short mb character = silently dropped
+SELECT regexp_replace(truncated, '^caf(.)$', '\1') FROM regress_encoding;
+
+-- PostgreSQL doesn't allow strings to contain NUL. If a corrupted string
+-- contains NUL at a character boundary position, some functions treat it as a
+-- character while others treat it as a terminator, as implementation details.
+
+-- NUL = terminator
+SELECT length(with_nul) FROM regress_encoding;
+SELECT substring(with_nul, 3, 1) FROM regress_encoding;
+SELECT substring(with_nul, 4, 1) FROM regress_encoding;
+SELECT substring(with_nul, 5, 1) FROM regress_encoding;
+SELECT convert_to(substring(with_nul, 5, 1), 'UTF8') FROM regress_encoding;
+SELECT regexp_replace(with_nul, '^caf(.)$', '\1') FROM regress_encoding;
+-- NUL = character
+SELECT with_nul, reverse(with_nul), reverse(reverse(with_nul)) FROM regress_encoding;
+
+-- If a corrupted string contains NUL in the tail bytes of a multibyte
+-- character (invalid in all encodings), it is considered part of the
+-- character for length purposes. An error will only be raised in code paths
+-- that convert or verify encodings.
+
+SELECT length(truncated_with_nul) FROM regress_encoding;
+SELECT substring(truncated_with_nul, 3, 1) FROM regress_encoding;
+SELECT substring(truncated_with_nul, 4, 1) FROM regress_encoding;
+SELECT convert_to(substring(truncated_with_nul, 4, 1), 'UTF8') FROM regress_encoding;
+SELECT substring(truncated_with_nul, 5, 1) FROM regress_encoding;
+SELECT regexp_replace(truncated_with_nul, '^caf(.)dcba$', '\1') = test_bytea_to_text('\xc300') FROM regress_encoding;
+SELECT reverse(truncated_with_nul) FROM regress_encoding;
+
+-- unbounded: sequence would overrun the string!
+SELECT test_mblen_func('pg_mblen_unbounded', 'UTF8', truncated, 3)
+FROM regress_encoding;
+
+-- condition detected when using the length/range variants
+SELECT test_mblen_func('pg_mblen_with_len', 'UTF8', truncated, 3)
+FROM regress_encoding;
+SELECT test_mblen_func('pg_mblen_range', 'UTF8', truncated, 3)
+FROM regress_encoding;
+
+-- unbounded: sequence would overrun the string, if the terminator were really
+-- the end of it
+SELECT test_mblen_func('pg_mblen_unbounded', 'UTF8', truncated_with_nul, 3)
+FROM regress_encoding;
+SELECT test_mblen_func('pg_encoding_mblen', 'GB18030', truncated_with_nul, 3)
+FROM regress_encoding;
+
+-- condition detected when using the cstr variants
+SELECT test_mblen_func('pg_mblen_cstr', 'UTF8', truncated_with_nul, 3)
+FROM regress_encoding;
+
+DROP TABLE regress_encoding;
+
+-- mb<->wchar conversions
+CREATE FUNCTION test_encoding(encoding text, description text, input bytea)
+RETURNS VOID LANGUAGE plpgsql AS
+$$
+DECLARE
+ prefix text;
+ len int;
+ wchars int[];
+ round_trip bytea;
+ result text;
+BEGIN
+ prefix := rpad(encoding || ' ' || description || ':', 28);
+
+ -- XXX could also test validation, length functions and include client
+ -- only encodings with these test cases
+
+ IF test_valid_server_encoding(encoding) THEN
+ wchars := test_text_to_wchars(encoding, test_bytea_to_text(input));
+ round_trip = test_text_to_bytea(test_wchars_to_text(encoding, wchars));
+ if input = round_trip then
+ result := 'OK';
+ elsif length(input) > length(round_trip) and round_trip = substr(input, 1, length(round_trip)) then
+ result := 'truncated';
+ else
+ result := 'failed';
+ end if;
+ RAISE NOTICE '% % -> % -> % = %', prefix, input, wchars, round_trip, result;
+ END IF;
+END;
+$$;
+-- No validation is done on the encoding itself, just the length to avoid
+-- overruns, so some of the byte sequences below are bogus. They cover
+-- all code branches, server encodings only for now.
+CREATE TABLE encoding_tests (encoding text, description text, input bytea);
+INSERT INTO encoding_tests VALUES
+ -- LATIN1, other single-byte encodings
+ ('LATIN1', 'ASCII', 'a'),
+ ('LATIN1', 'extended', '\xe9'),
+ -- EUC_JP, EUC_JIS_2004, EUR_KR (for the purposes of wchar conversion):
+ -- 2 8e (CS2, not used by EUR_KR but arbitrarily considered to have EUC_JP length)
+ -- 3 8f (CS3, not used by EUR_KR but arbitrarily considered to have EUC_JP length)
+ -- 2 80..ff (CS1)
+ ('EUC_JP', 'ASCII', 'a'),
+ ('EUC_JP', 'CS1, short', '\x80'),
+ ('EUC_JP', 'CS1', '\x8002'),
+ ('EUC_JP', 'CS2, short', '\x8e'),
+ ('EUC_JP', 'CS2', '\x8e02'),
+ ('EUC_JP', 'CS3, short', '\x8f'),
+ ('EUC_JP', 'CS3, short', '\x8f02'),
+ ('EUC_JP', 'CS3', '\x8f0203'),
+ -- EUC_CN
+ -- 3 8e (CS2, not used but arbitrarily considered to have length 3)
+ -- 3 8f (CS3, not used but arbitrarily considered to have length 3)
+ -- 2 80..ff (CS1)
+ ('EUC_CN', 'ASCII', 'a'),
+ ('EUC_CN', 'CS1, short', '\x80'),
+ ('EUC_CN', 'CS1', '\x8002'),
+ ('EUC_CN', 'CS2, short', '\x8e'),
+ ('EUC_CN', 'CS2, short', '\x8e02'),
+ ('EUC_CN', 'CS2', '\x8e0203'),
+ ('EUC_CN', 'CS3, short', '\x8f'),
+ ('EUC_CN', 'CS3, short', '\x8f02'),
+ ('EUC_CN', 'CS3', '\x8f0203'),
+ -- EUC_TW:
+ -- 4 8e (CS2)
+ -- 3 8f (CS3, not used but arbitrarily considered to have length 3)
+ -- 2 80..ff (CS1)
+ ('EUC_TW', 'ASCII', 'a'),
+ ('EUC_TW', 'CS1, short', '\x80'),
+ ('EUC_TW', 'CS1', '\x8002'),
+ ('EUC_TW', 'CS2, short', '\x8e'),
+ ('EUC_TW', 'CS2, short', '\x8e02'),
+ ('EUC_TW', 'CS2, short', '\x8e0203'),
+ ('EUC_TW', 'CS2', '\x8e020304'),
+ ('EUC_TW', 'CS3, short', '\x8f'),
+ ('EUC_TW', 'CS3, short', '\x8f02'),
+ ('EUC_TW', 'CS3', '\x8f0203'),
+ -- UTF8
+ -- 2 c0..df
+ -- 3 e0..ef
+ -- 4 f0..f7 (but maximum real codepoint U+10ffff has f4)
+ -- 5 f8..fb (not supported)
+ -- 6 fc..fd (not supported)
+ ('UTF8', 'ASCII', 'a'),
+ ('UTF8', '2 byte, short', '\xdf'),
+ ('UTF8', '2 byte', '\xdf82'),
+ ('UTF8', '3 byte, short', '\xef'),
+ ('UTF8', '3 byte, short', '\xef82'),
+ ('UTF8', '3 byte', '\xef8283'),
+ ('UTF8', '4 byte, short', '\xf7'),
+ ('UTF8', '4 byte, short', '\xf782'),
+ ('UTF8', '4 byte, short', '\xf78283'),
+ ('UTF8', '4 byte', '\xf7828384'),
+ ('UTF8', '5 byte, unsupported', '\xfb'),
+ ('UTF8', '5 byte, unsupported', '\xfb82'),
+ ('UTF8', '5 byte, unsupported', '\xfb8283'),
+ ('UTF8', '5 byte, unsupported', '\xfb828384'),
+ ('UTF8', '5 byte, unsupported', '\xfb82838485'),
+ ('UTF8', '6 byte, unsupported', '\xfd'),
+ ('UTF8', '6 byte, unsupported', '\xfd82'),
+ ('UTF8', '6 byte, unsupported', '\xfd8283'),
+ ('UTF8', '6 byte, unsupported', '\xfd828384'),
+ ('UTF8', '6 byte, unsupported', '\xfd82838485'),
+ ('UTF8', '6 byte, unsupported', '\xfd8283848586'),
+ -- MULE_INTERNAL
+ -- 2 81..8d LC1
+ -- 3 90..99 LC2
+ ('MULE_INTERNAL', 'ASCII', 'a'),
+ ('MULE_INTERNAL', 'LC1, short', '\x81'),
+ ('MULE_INTERNAL', 'LC1', '\x8182'),
+ ('MULE_INTERNAL', 'LC2, short', '\x90'),
+ ('MULE_INTERNAL', 'LC2, short', '\x9082'),
+ ('MULE_INTERNAL', 'LC2', '\x908283');
+
+SELECT COUNT(test_encoding(encoding, description, input)) > 0
+FROM encoding_tests;
+
+-- substring fetches a slice of a toasted value; unused tail of that slice is
+-- an incomplete char (bug #19406)
+CREATE TABLE toast_3b_utf8 (c text);
+INSERT INTO toast_3b_utf8 VALUES (repeat(U&'\2026', 4000));
+SELECT SUBSTRING(c FROM 1 FOR 1) FROM toast_3b_utf8;
+SELECT SUBSTRING(c FROM 4001 FOR 1) FROM toast_3b_utf8;
+-- diagnose incomplete char iff within the substring
+UPDATE toast_3b_utf8 SET c = c || test_bytea_to_text('\xe280');
+SELECT SUBSTRING(c FROM 4000 FOR 1) FROM toast_3b_utf8;
+SELECT SUBSTRING(c FROM 4001 FOR 1) FROM toast_3b_utf8;
+-- substring needing last byte of its slice_size
+ALTER TABLE toast_3b_utf8 RENAME TO toast_4b_utf8;
+UPDATE toast_4b_utf8 SET c = repeat(U&'\+01F680', 3000);
+SELECT SUBSTRING(c FROM 3000 FOR 1) FROM toast_4b_utf8;
+
+DROP TABLE encoding_tests;
+DROP TABLE toast_4b_utf8;
+DROP FUNCTION test_encoding;
+DROP FUNCTION test_wchars_to_text;
+DROP FUNCTION test_text_to_wchars;
+DROP FUNCTION test_valid_server_encoding;
+DROP FUNCTION test_mblen_func;
+DROP FUNCTION test_bytea_to_text;
+DROP FUNCTION test_text_to_bytea;
+
+
+-- substring slow path: multi-byte escape char vs. multi-byte pattern char.
+SELECT SUBSTRING('a' SIMILAR U&'\00AC' ESCAPE U&'\00A7');
+-- Levenshtein distance metric: exercise character length cache.
+SELECT U&"real\00A7_name" FROM (select 1) AS x(real_name);
+-- JSON errcontext: truncate long data.
+SELECT repeat(U&'\00A7', 30)::json;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/euc_kr.sql b/parser/src/test/resources/postgres/test/regress/sql/euc_kr.sql
new file mode 100644
index 0000000..1851b2a
--- /dev/null
+++ b/parser/src/test/resources/postgres/test/regress/sql/euc_kr.sql
@@ -0,0 +1,12 @@
+-- This test is about EUC_KR encoding, chosen as perhaps the most prevalent
+-- non-UTF8, multibyte encoding as of 2026-01. Since UTF8 can represent all
+-- of EUC_KR, also run the test in UTF8.
+SELECT getdatabaseencoding() NOT IN ('EUC_KR', 'UTF8') AS skip_test \gset
+\if :skip_test
+\quit
+\endif
+
+-- Exercise is_multibyte_char_in_char (non-UTF8) slow path.
+SELECT POSITION(
+ convert_from('\xbcf6c7d0', 'EUC_KR') IN
+ convert_from('\xb0fac7d02c20bcf6c7d02c20b1e2bcfa2c20bbee', 'EUC_KR'));
diff --git a/parser/src/test/resources/postgres/test/regress/sql/expressions.sql b/parser/src/test/resources/postgres/test/regress/sql/expressions.sql
index e02c21f..3b3048f 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/expressions.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/expressions.sql
@@ -196,16 +196,108 @@ default for type myint using hash as
function 1 myinthash(myint);
create table inttest (a myint);
-insert into inttest values(1::myint),(null);
-
--- try an array with enough elements to cause hashing
-select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null);
-select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null);
-select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null);
--- ensure the result matched with the non-hashed version. We simply remove
--- some array elements so that we don't reach the hashing threshold.
-select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint, null);
-select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint, null);
-select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint, null);
+insert into inttest values (null), (0::myint), (1::myint);
+
+-- Test EEOP_HASHED_SCALARARRAYOP against EEOP_SCALARARRAYOP. Ensure the
+-- result of non-hashed vs hashed is the same.
+select
+ a,
+ a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed,
+ a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed
+from inttest;
+
+select
+ a,
+ a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed,
+ a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed
+ from inttest;
+
+select
+ a,
+ a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed,
+ a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed
+from inttest;
+
+select
+ a,
+ a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed,
+ a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed
+from inttest;
+
+-- Now make the equal function return false when given two NULLs
+create or replace function myinteq(myint, myint) returns bool as $$
+begin
+ if $1 is null and $2 is null then
+ return false;
+ else
+ return $1::int = $2::int;
+ end if;
+end;
+$$ language plpgsql immutable;
+
+-- And try the same again to ensure EEOP_HASHED_SCALARARRAYOP does the same
+-- thing as EEOP_SCALARARRAYOP.
+select
+ a,
+ a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed,
+ a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed
+from inttest;
+
+select
+ a,
+ a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed,
+ a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed
+ from inttest;
+
+select
+ a,
+ a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed,
+ a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed
+from inttest;
+
+select
+ a,
+ a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed,
+ a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed
+from inttest;
+
+-- Try again with an equality function that treats NULLs as equal to 0.
+create or replace function myinteq(myint, myint) returns bool as $$
+begin
+ if $1 is null and $2 is null then
+ return false;
+ else
+ return coalesce($1::int,0) = coalesce($2::int, 0);
+ end if;
+end;
+$$ language plpgsql immutable;
+
+select
+ a,
+ a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed,
+ a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed,
+ a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero,
+ a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero
+from inttest;
+
+select
+ a,
+ a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed,
+ a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed
+ from inttest;
+
+select
+ a,
+ a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed,
+ a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed,
+ a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero,
+ a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero
+from inttest;
+
+select
+ a,
+ a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed,
+ a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed
+from inttest;
rollback;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/foreign_data.sql b/parser/src/test/resources/postgres/test/regress/sql/foreign_data.sql
index 92de65c..8e65c81 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/foreign_data.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/foreign_data.sql
@@ -75,6 +75,11 @@ CREATE FUNCTION invalid_fdw_handler() RETURNS int LANGUAGE SQL AS 'SELECT 1;';
CREATE FOREIGN DATA WRAPPER test_fdw HANDLER invalid_fdw_handler; -- ERROR
CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER invalid_fdw_handler; -- ERROR
CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler;
+
+-- should preserve dependency on test_fdw_handler
+ALTER FOREIGN DATA WRAPPER test_fdw VALIDATOR postgresql_fdw_validator;
+DROP FUNCTION test_fdw_handler(); -- ERROR
+
DROP FOREIGN DATA WRAPPER test_fdw;
-- ALTER FOREIGN DATA WRAPPER
@@ -391,10 +396,12 @@ COMMENT ON COLUMN ft1.c1 IS NULL;
ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0;
ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer;
+ALTER FOREIGN TABLE ft1 ADD COLUMN IF NOT EXISTS c6 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL;
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer;
ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer;
--- Deactivated for SplendidDataTest: ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
+ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
+ALTER FOREIGN TABLE ft1 ADD c11 integer;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT;
@@ -427,6 +434,7 @@ ALTER FOREIGN TABLE ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@');
ALTER FOREIGN TABLE ft1 DROP COLUMN no_column; -- ERROR
ALTER FOREIGN TABLE ft1 DROP COLUMN IF EXISTS no_column;
ALTER FOREIGN TABLE ft1 DROP COLUMN c9;
+ALTER FOREIGN TABLE ft1 DROP c11;
ALTER FOREIGN TABLE ft1 ADD COLUMN c11 serial;
ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema;
ALTER FOREIGN TABLE ft1 SET TABLESPACE ts; -- ERROR
@@ -438,10 +446,12 @@ ALTER FOREIGN TABLE foreign_schema.ft1 RENAME TO foreign_table_1;
-- alter noexisting table
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c4 integer;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c6 integer;
+ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN IF NOT EXISTS c6 integer;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c7 integer NOT NULL;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c8 integer;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c9 integer;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1');
+ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD c11 integer;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c6 SET NOT NULL;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c7 DROP NOT NULL;
@@ -455,8 +465,10 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP CONSTRAINT IF EXISTS no_cons
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP CONSTRAINT ft1_c1_check;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OWNER TO regress_test_role;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@');
+ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN no_column;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN IF EXISTS no_column;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN c9;
+ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP c11;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 SET SCHEMA foreign_schema;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME c1 TO foreign_column_1;
ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME TO foreign_table_1;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/foreign_key.sql b/parser/src/test/resources/postgres/test/regress/sql/foreign_key.sql
index 09f8df8..d2058df 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/foreign_key.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/foreign_key.sql
@@ -792,6 +792,43 @@ INSERT INTO fktable VALUES (500, 1000);
COMMIT;
+-- Check that the existing FK trigger is both deferrable and initially deferred
+SELECT conname, tgrelid::regclass as tgrel,
+ regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype,
+ tgdeferrable, tginitdeferred
+FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid)
+WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey'
+ORDER BY tgrelid, tgtype;
+
+-- Changing the constraint to NOT ENFORCED drops the associated FK triggers
+ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey NOT ENFORCED;
+SELECT conname, tgrelid::regclass as tgrel,
+ regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype,
+ tgdeferrable, tginitdeferred
+FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid)
+WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey'
+ORDER BY tgrelid, tgtype;
+
+-- Changing it back to ENFORCED will recreate the necessary FK triggers
+-- that are deferrable and initially deferred
+ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey ENFORCED;
+SELECT conname, tgrelid::regclass as tgrel,
+ regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype,
+ tgdeferrable, tginitdeferred
+FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid)
+WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey'
+ORDER BY tgrelid, tgtype;
+
+-- Verify that a deferrable, initially deferred foreign key still works
+-- as expected after being set to NOT ENFORCED and then re-enabled
+BEGIN;
+
+-- doesn't match PK, but no error yet
+INSERT INTO fktable VALUES (2, 20);
+
+-- should catch error from INSERT at commit
+COMMIT;
+
DROP TABLE fktable, pktable;
-- tricky behavior: according to SQL99, if a deferred constraint is set
@@ -2394,3 +2431,51 @@ SET client_min_messages TO warning;
DROP SCHEMA fkpart12 CASCADE;
RESET client_min_messages;
RESET search_path;
+
+-- Exercise the column mapping code with foreign keys. In this test we'll
+-- create a partitioned table which has a partition with a dropped column and
+-- check to ensure that an UPDATE cascades the changes correctly to the
+-- partitioned table.
+CREATE SCHEMA fkpart13;
+SET search_path TO fkpart13;
+
+CREATE TABLE fkpart13_t1 (a int PRIMARY KEY);
+
+CREATE TABLE fkpart13_t2 (
+ part_id int PRIMARY KEY,
+ column_to_drop int,
+ FOREIGN KEY (part_id) REFERENCES fkpart13_t1 ON UPDATE CASCADE ON DELETE CASCADE
+) PARTITION BY LIST (part_id);
+
+CREATE TABLE fkpart13_t2_p1 PARTITION OF fkpart13_t2 FOR VALUES IN (1);
+
+-- drop the column
+ALTER TABLE fkpart13_t2 DROP COLUMN column_to_drop;
+
+-- create a new partition without the dropped column
+CREATE TABLE fkpart13_t2_p2 PARTITION OF fkpart13_t2 FOR VALUES IN (2);
+
+CREATE TABLE fkpart13_t3 (
+ a int NOT NULL,
+ FOREIGN KEY (a)
+ REFERENCES fkpart13_t2
+ ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+INSERT INTO fkpart13_t1 (a) VALUES (1);
+INSERT INTO fkpart13_t2 (part_id) VALUES (1);
+INSERT INTO fkpart13_t3 (a) VALUES (1);
+
+-- Test a cascading update works correctly with with the dropped column
+UPDATE fkpart13_t1 SET a = 2 WHERE a = 1;
+SELECT tableoid::regclass,* FROM fkpart13_t2;
+SELECT tableoid::regclass,* FROM fkpart13_t3;
+
+-- Exercise code in ExecGetTriggerResultRel() as there's been previous issues
+-- with ResultRelInfos being returned with the incorrect ri_RootResultRelInfo
+WITH cte AS (
+ UPDATE fkpart13_t2_p1 SET part_id = part_id
+) UPDATE fkpart13_t1 SET a = 2 WHERE a = 1;
+
+DROP SCHEMA fkpart13 CASCADE;
+RESET search_path;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/generated_stored.sql b/parser/src/test/resources/postgres/test/regress/sql/generated_stored.sql
index 2a5fcdf..4ccf55d 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/generated_stored.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/generated_stored.sql
@@ -225,6 +225,10 @@ COPY gtest1 FROM stdin;
COPY gtest1 (a, b) FROM stdin;
+COPY gtest1 FROM stdin WHERE b <> 10;
+
+COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
+
SELECT * FROM gtest1 ORDER BY a;
TRUNCATE gtest3;
@@ -508,7 +512,10 @@ SELECT tableoid::regclass, * FROM gtest_parent ORDER BY 1, 2, 3;
-- generated columns in partition key (not allowed)
CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE (f3);
+CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((f3));
CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((f3 * 3));
+CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((gtest_part_key));
+CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) STORED) PARTITION BY RANGE ((gtest_part_key is not null));
-- ALTER TABLE ... ADD COLUMN
CREATE TABLE gtest25 (a int PRIMARY KEY);
@@ -752,6 +759,29 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED);
\d gtest28*
+-- rule actions referring to generated columns:
+-- NEW.b in a rule action should reflect the generated column's new value
+CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) STORED);
+CREATE TABLE gtest_rule_log (op text, old_b int, new_b int);
+CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule
+ DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b);
+CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule
+ DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b);
+INSERT INTO gtest_rule (a) VALUES (1);
+UPDATE gtest_rule SET a = 10;
+UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule);
+SELECT * FROM gtest_rule_log;
+DROP RULE gtest_rule_upd ON gtest_rule;
+DROP RULE gtest_rule_ins ON gtest_rule;
+DROP TABLE gtest_rule_log;
+
+-- rule quals referring to generated columns:
+-- NEW.b in the rule qual should reflect the generated column's new value
+CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100
+ DO INSTEAD NOTHING;
+UPDATE gtest_rule SET a = 100;
+SELECT * FROM gtest_rule;
+DROP TABLE gtest_rule;
-- sanity check of system catalog
SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v');
diff --git a/parser/src/test/resources/postgres/test/regress/sql/generated_virtual.sql b/parser/src/test/resources/postgres/test/regress/sql/generated_virtual.sql
index a5e0b57..7579212 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/generated_virtual.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/generated_virtual.sql
@@ -225,6 +225,10 @@ COPY gtest1 FROM stdin;
COPY gtest1 (a, b) FROM stdin;
+COPY gtest1 FROM stdin WHERE b <> 10;
+
+COPY gtest1 FROM stdin WHERE gtest1 IS NULL;
+
SELECT * FROM gtest1 ORDER BY a;
TRUNCATE gtest3;
@@ -370,6 +374,27 @@ INSERT INTO gtest21b (a) VALUES (NULL); -- error
ALTER TABLE gtest21b ALTER COLUMN b DROP NOT NULL;
INSERT INTO gtest21b (a) VALUES (0); -- ok now
+-- virtual generated columns are not physically stored, even when not null
+CREATE TABLE gtest21c (a int NOT NULL, b int GENERATED ALWAYS AS (a * 2) VIRTUAL NOT NULL, c int NOT NULL);
+INSERT INTO gtest21c (a, c) VALUES (10, 42);
+SELECT a, b, c FROM gtest21c;
+DROP TABLE gtest21c;
+
+-- try adding a virtual generated column to an existing table with tuples,
+-- then try adding an atthasmissing column before adding a normal nullable
+-- column.
+CREATE TABLE gtest21d (a int NOT NULL);
+INSERT INTO gtest21d (a) VALUES(10);
+ALTER TABLE gtest21d ADD COLUMN b INT GENERATED ALWAYS AS (a * 10) VIRTUAL NOT NULL;
+SELECT * FROM gtest21d ORDER BY a;
+INSERT INTO gtest21d (a) VALUES(20);
+ALTER TABLE gtest21d ADD COLUMN c INT NOT NULL DEFAULT 1234;
+SELECT * FROM gtest21d ORDER BY a;
+ALTER TABLE gtest21d ADD COLUMN d INT;
+INSERT INTO gtest21d (a, c, d) VALUES(30, 12345, 100);
+SELECT * FROM gtest21d ORDER BY a;
+DROP TABLE gtest21d;
+
-- not-null constraint with partitioned table
CREATE TABLE gtestnn_parent (
f1 int,
@@ -551,7 +576,10 @@ SELECT tableoid::regclass, * FROM gtest_parent ORDER BY 1, 2, 3;
-- generated columns in partition key (not allowed)
CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE (f3);
+CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((f3));
CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((f3 * 3));
+CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((gtest_part_key));
+CREATE TABLE gtest_part_key (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((gtest_part_key is not null));
-- ALTER TABLE ... ADD COLUMN
CREATE TABLE gtest25 (a int PRIMARY KEY);
@@ -803,6 +831,29 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED);
\d gtest28*
+-- rule actions referring to generated columns:
+-- NEW.b in a rule action should reflect the generated column's new value
+CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL);
+CREATE TABLE gtest_rule_log (op text, old_b int, new_b int);
+CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule
+ DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b);
+CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule
+ DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b);
+INSERT INTO gtest_rule (a) VALUES (1);
+UPDATE gtest_rule SET a = 10;
+UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule);
+SELECT * FROM gtest_rule_log;
+DROP RULE gtest_rule_upd ON gtest_rule;
+DROP RULE gtest_rule_ins ON gtest_rule;
+DROP TABLE gtest_rule_log;
+
+-- rule quals referring to generated columns:
+-- NEW.b in the rule qual should reflect the generated column's new value
+CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100
+ DO INSTEAD NOTHING;
+UPDATE gtest_rule SET a = 100;
+SELECT * FROM gtest_rule;
+DROP TABLE gtest_rule;
-- sanity check of system catalog
SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v');
@@ -882,3 +933,43 @@ select * from gtest33 where b is null;
reset constraint_exclusion;
drop table gtest33;
+
+-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT
+-- DO UPDATE is expanded to the generation expression, both for plain and
+-- partitioned target relations.
+create table gtest34 (id int primary key, a int,
+ c int generated always as (a * 10) virtual);
+insert into gtest34 values (1, 5);
+insert into gtest34 values (1, 7)
+ on conflict (id) do update set a = excluded.c returning *;
+insert into gtest34 values (1, 2)
+ on conflict (id) do update set a = gtest34.c + excluded.c returning *;
+insert into gtest34 values (1, 3)
+ on conflict (id) do update set a = 999 where excluded.c > 20 returning *;
+drop table gtest34;
+
+create table gtest34p (id int primary key, a int,
+ c int generated always as (a * 10) virtual)
+ partition by range (id);
+create table gtest34p_1 partition of gtest34p for values from (1) to (100);
+insert into gtest34p values (1, 5);
+insert into gtest34p values (1, 7)
+ on conflict (id) do update set a = excluded.c returning *;
+insert into gtest34p values (1, 2)
+ on conflict (id) do update set a = gtest34p.c + excluded.c returning *;
+drop table gtest34p;
+
+-- Ensure that virtual generated columns work with WHERE CURRENT OF
+create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual);
+insert into gtest_cursor values (1, 10), (2, 20), (3, 30);
+
+begin;
+declare curs cursor for select * from gtest_cursor order by id for update;
+fetch 1 from curs;
+update gtest_cursor set a = 99 where current of curs;
+select * from gtest_cursor order by id;
+delete from gtest_cursor where current of curs;
+select * from gtest_cursor order by id;
+commit;
+
+drop table gtest_cursor;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/groupingsets.sql b/parser/src/test/resources/postgres/test/regress/sql/groupingsets.sql
index 4fbc158..92cc5a1 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/groupingsets.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/groupingsets.sql
@@ -191,6 +191,52 @@ select x, y || 'y'
group by grouping sets (x, y)
order by 1, 2;
+-- check that operands wrapped in PlaceHolderVars are capable of index matching
+begin;
+
+set local enable_bitmapscan = off;
+
+explain (costs off)
+select x, y
+ from (select unique1 as x, unique2 as y from tenk1) as t
+ where x = 1
+ group by grouping sets (x, y)
+ order by 1, 2;
+
+select x, y
+ from (select unique1 as x, unique2 as y from tenk1) as t
+ where x = 1
+ group by grouping sets (x, y)
+ order by 1, 2;
+
+explain (costs off)
+select x, y
+ from (select unique1::oid as x, unique2 as y from tenk1) as t
+ where x::integer = 1
+ group by grouping sets (x, y)
+ order by 1, 2;
+
+select x, y
+ from (select unique1::oid as x, unique2 as y from tenk1) as t
+ where x::integer = 1
+ group by grouping sets (x, y)
+ order by 1, 2;
+
+explain (costs off)
+select x, y
+ from (select t1.unique1 as x, t1.unique2 as y from tenk1 t1, tenk1 t2) as t
+ where x = 1
+ group by grouping sets (x, y)
+ order by 1, 2;
+
+select x, y
+ from (select t1.unique1 as x, t1.unique2 as y from tenk1 t1, tenk1 t2) as t
+ where x = 1
+ group by grouping sets (x, y)
+ order by 1, 2;
+
+rollback;
+
-- check qual push-down rules for a subquery with grouping sets
explain (verbose, costs off)
select * from (
@@ -298,11 +344,29 @@ explain (costs off)
select v.c, (select count(*) from gstest2 group by () having v.c)
from (values (false),(true)) v(c) order by v.c;
--- test pushdown of HAVING clause that does not reference any columns that are nullable by grouping sets
+-- test pushdown of non-degenerate HAVING clause that does not reference any
+-- columns that are nullable by grouping sets
explain (costs off)
select a, b, count(*) from gstest2 group by grouping sets ((a, b), (a)) having a > 1 and b > 1;
select a, b, count(*) from gstest2 group by grouping sets ((a, b), (a)) having a > 1 and b > 1;
+explain (costs off)
+select a, b, count(*) from gstest2 group by rollup(a), b having b > 1;
+select a, b, count(*) from gstest2 group by rollup(a), b having b > 1;
+
+-- test pushdown of degenerate HAVING clause
+explain (costs off)
+select count(*) from gstest2 group by grouping sets (()) having false;
+select count(*) from gstest2 group by grouping sets (()) having false;
+
+explain (costs off)
+select a, count(*) from gstest2 group by grouping sets ((a), ()) having false;
+select a, count(*) from gstest2 group by grouping sets ((a), ()) having false;
+
+explain (costs off)
+select a, b, count(*) from gstest2 group by grouping sets ((a), (b)) having false;
+select a, b, count(*) from gstest2 group by grouping sets ((a), (b)) having false;
+
-- HAVING with GROUPING queries
select ten, grouping(ten) from onek
group by grouping sets(ten) having grouping(ten) >= 0
@@ -711,4 +775,27 @@ select a, b, row_number() over (order by a, b nulls first)
from (values (1, 1), (2, 2)) as t (a, b) where a = b
group by grouping sets((a, b), (a));
+-- test handling of SRFs with grouping sets
+explain (verbose, costs off)
+select generate_series(1, a) as g
+from (values (1, 1), (2, 2)) as t (a, b)
+group by rollup(g)
+order by 1;
+
+select generate_series(1, a) as g
+from (values (1, 1), (2, 2)) as t (a, b)
+group by rollup(g)
+order by 1;
+
+explain (verbose, costs off)
+select generate_series(1, a) as g, a+b as ab
+from (values (1, 1), (2, 2)) as t (a, b)
+group by rollup(a, ab)
+order by 1, 2;
+
+select generate_series(1, a) as g, a+b as ab
+from (values (1, 1), (2, 2)) as t (a, b)
+group by rollup(a, ab)
+order by 1, 2;
+
-- end
diff --git a/parser/src/test/resources/postgres/test/regress/sql/hash_index.sql b/parser/src/test/resources/postgres/test/regress/sql/hash_index.sql
index 219da82..60571f6 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/hash_index.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/hash_index.sql
@@ -53,6 +53,9 @@ CREATE INDEX hash_txt_index ON hash_txt_heap USING hash (random text_ops);
CREATE INDEX hash_f8_index ON hash_f8_heap USING hash (random float8_ops)
WITH (fillfactor=60);
+CREATE INDEX hash_i4_partial_index ON hash_i4_heap USING hash (seqno)
+ WHERE seqno = 9999;
+
--
-- Also try building functional, expressional, and partial indexes on
-- tables that already contain data.
@@ -117,6 +120,16 @@ SELECT * FROM hash_f8_heap
SELECT * FROM hash_f8_heap
WHERE hash_f8_heap.random = '88888888'::float8;
+--
+-- partial hash index
+--
+EXPLAIN (COSTS OFF)
+SELECT * FROM hash_i4_heap
+ WHERE seqno = 9999;
+
+SELECT * FROM hash_i4_heap
+ WHERE seqno = 9999;
+
--
-- hash index
-- grep '^90[^0-9]' hashovfl.data
diff --git a/parser/src/test/resources/postgres/test/regress/sql/indexing.sql b/parser/src/test/resources/postgres/test/regress/sql/indexing.sql
index b5cb01c..706a6ec 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/indexing.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/indexing.sql
@@ -246,6 +246,65 @@ select relname, indisvalid from pg_class join pg_index on indexrelid = oid
where relname like 'idxpart%' order by relname;
drop table idxpart;
+-- Verify that re-attaching an already-attached partition index can
+-- validate the parent index if it was still invalid, including
+-- indirect ancestors in subpartitions.
+create table idxpart (a int, b int) partition by range (a);
+create table idxpart1 partition of idxpart for values from (0) to (1000) partition by range (a);
+create table idxpart11 partition of idxpart1 for values from (0) to (500);
+-- Partitioned table with no partitions
+create table idxpart2 partition of idxpart for values from (1000) to (2000) partition by range (a);
+-- create parent indexes
+create index on only idxpart ((a/b));
+create index on only idxpart1 ((a/b));
+create index on only idxpart2 ((a/b));
+-- fail, leaves behind an invalid index on the leaf partition
+insert into idxpart11 values (1, 0);
+create index concurrently on idxpart11 ((a/b));
+select relname, indisvalid from pg_class join pg_index on indexrelid = oid
+ where relname like 'idxpart%' order by relname;
+-- attach the indexes; parents stay invalid
+alter index idxpart1_expr_idx attach partition idxpart11_expr_idx;
+alter index idxpart_expr_idx attach partition idxpart1_expr_idx;
+alter index idxpart_expr_idx attach partition idxpart2_expr_idx;
+select relname, indisvalid from pg_class join pg_index on indexrelid = oid
+ where relname like 'idxpart%' order by relname;
+-- fix the index on the leaf partition
+delete from idxpart11 where b = 0;
+reindex index concurrently idxpart11_expr_idx;
+-- reattach the leaf partition index; parents should now be valid
+alter index idxpart1_expr_idx attach partition idxpart11_expr_idx;
+select relname, indisvalid from pg_class join pg_index on indexrelid = oid
+ where relname like 'idxpart%' order by relname;
+drop table idxpart;
+
+-- Verify that re-attaching does not validate the parent when another
+-- child index is still invalid.
+create table idxpart (a int, b int) partition by range (a);
+create table idxpart1 partition of idxpart for values from (0) to (500);
+create table idxpart2 partition of idxpart for values from (500) to (1000);
+create index on only idxpart ((a/b));
+-- create invalid indexes on both children
+insert into idxpart1 values (1, 0);
+insert into idxpart2 values (501, 0);
+create index concurrently on idxpart1 ((a/b));
+create index concurrently on idxpart2 ((a/b));
+select relname, indisvalid from pg_class join pg_index on indexrelid = oid
+ where relname like 'idxpart%' order by relname;
+-- attach both; parent stays invalid
+alter index idxpart_expr_idx attach partition idxpart1_expr_idx;
+alter index idxpart_expr_idx attach partition idxpart2_expr_idx;
+select relname, indisvalid from pg_class join pg_index on indexrelid = oid
+ where relname like 'idxpart%' order by relname;
+-- fix only idxpart1's index, leave idxpart2's still invalid
+delete from idxpart1 where b = 0;
+reindex index concurrently idxpart1_expr_idx;
+-- re-attach the fixed child; parent should stay invalid
+alter index idxpart_expr_idx attach partition idxpart1_expr_idx;
+select relname, indisvalid from pg_class join pg_index on indexrelid = oid
+ where relname like 'idxpart%' order by relname;
+drop table idxpart;
+
-- verify dependency handling during ALTER TABLE DETACH PARTITION
create table idxpart (a int) partition by range (a);
create table idxpart1 (like idxpart);
diff --git a/parser/src/test/resources/postgres/test/regress/sql/join.sql b/parser/src/test/resources/postgres/test/regress/sql/join.sql
index 3533fd3..d0f36be 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/join.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/join.sql
@@ -759,6 +759,26 @@ select * from tbl_rs t1 join
(select t1.a+t3.a from tbl_rs t3) and t2.a < 5)
on true;
+--
+-- regression test for bug with parallel-hash-right-semi join
+--
+
+begin;
+
+-- encourage use of parallel plans
+set local parallel_setup_cost=0;
+set local parallel_tuple_cost=0;
+set local min_parallel_table_scan_size=0;
+set local max_parallel_workers_per_gather=4;
+
+-- ensure we don't get parallel hash right semi join
+explain (costs off)
+select * from tenk1 t1
+where exists (select 1 from tenk1 t2 where fivethous = t1.fivethous)
+and t1.fivethous < 5;
+
+rollback;
+
--
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
--
@@ -1461,6 +1481,30 @@ select * from int4_tbl left join (
) ss(x) on true
where ss.x is null;
+-- Test computation of varnullingrels when translating appendrel Var
+begin;
+
+create temp table t_append (a int not null, b int);
+insert into t_append values (1, 1);
+insert into t_append values (2, 3);
+
+explain (verbose, costs off)
+select t1.a, s.a from t_append t1
+ left join t_append t2 on t1.a = t2.b
+ join lateral (
+ select t1.a as a union all select t2.a as a
+ ) s on true
+where s.a is not null;
+
+select t1.a, s.a from t_append t1
+ left join t_append t2 on t1.a = t2.b
+ join lateral (
+ select t1.a as a union all select t2.a as a
+ ) s on true
+where s.a is not null;
+
+rollback;
+
--
-- test inlining of immutable functions
--
@@ -2181,6 +2225,29 @@ from int8_tbl t1
left join onek t4
on t2.q2 < t3.unique2;
+-- bug #19460: we need to clean up RestrictInfos more than we had been doing
+explain (costs off)
+select * from
+ (select 1::int as id) as lhs
+full join
+ (select dummy_source.id
+ from (select null::int as id) as dummy_source
+ left join (select a.id from a where a.id = 42) as sub
+ on sub.id = dummy_source.id
+ ) as rhs
+on lhs.id = rhs.id;
+
+explain (costs off)
+select * from
+ (select 1::int as id) as lhs
+full join
+ (select dummy_source.id
+ from (select 2::int as id) as dummy_source
+ left join (select a.id from a) as sub
+ on sub.id = dummy_source.id
+ ) as rhs
+on lhs.id = rhs.id;
+
-- More tests of correct placement of pseudoconstant quals
-- simple constant-false condition
@@ -2275,6 +2342,18 @@ CREATE TEMP TABLE parted_b1 partition of parted_b for values from (0) to (10);
explain (costs off)
select a.* from a left join parted_b pb on a.b_id = pb.id;
+-- test that clauses that still embed PHVs are not referencing the removed
+-- relation when rebuilt for a partition of the kept relation
+explain (costs off)
+select 1 from (select t1.id from parted_b t1 left join parted_b t2 on t1.id = t2.id) s
+where s.id = 1 group by ();
+
+explain (costs off)
+select 1 from parted_b t1
+ join (select t2.id from parted_b t2 left join parted_b t3 on t2.id = t3.id) s
+ on t1.id = s.id
+group by ();
+
rollback;
create temp table parent (k int primary key, pd int);
@@ -3034,6 +3113,12 @@ SELECT * FROM
(SELECT n2.a FROM sj n1, sj n2 WHERE n1.a <> n2.a) q0, sl
WHERE q0.a = 1;
+-- Do not forget to replace relid in bare Var join clause (bug #19435)
+ALTER TABLE sl ADD COLUMN bool_col boolean;
+EXPLAIN (COSTS OFF)
+SELECT 1 AS c1 FROM sl sl1 LEFT JOIN (sl AS sl2 NATURAL JOIN sl AS sl3)
+ ON sl2.bool_col LEFT JOIN sl AS sl4 ON sl2.bool_col;
+
-- Check optimization disabling if it will violate special join conditions.
-- Two identical joined relations satisfies self join removal conditions but
-- stay in different special join infos.
@@ -3712,6 +3797,16 @@ GROUP BY s.c1, s.c2;
DROP TABLE group_tbl;
+-- Test that we ignore PlaceHolderVars when looking up statistics
+EXPLAIN (COSTS OFF)
+SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
+ (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
+WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
+
+SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
+ (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
+WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
+
--
-- Test for a nested loop join involving index scan, transforming OR-clauses
-- to SAOP.
diff --git a/parser/src/test/resources/postgres/test/regress/sql/jsonb.sql b/parser/src/test/resources/postgres/test/regress/sql/jsonb.sql
index 57c11ac..07295b4 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/jsonb.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/jsonb.sql
@@ -851,6 +851,7 @@ SELECT count(*) FROM testjsonb WHERE j @? '$';
SELECT count(*) FROM testjsonb WHERE j @? '$.public';
SELECT count(*) FROM testjsonb WHERE j @? '$.bar';
+ALTER TABLE testjsonb SET (parallel_workers = 2);
CREATE INDEX jidx ON testjsonb USING gin (j);
SET enable_seqscan = off;
@@ -939,7 +940,7 @@ SELECT count(*) FROM testjsonb WHERE j = '{"pos":98, "line":371, "node":"CBA", "
--gin path opclass
DROP INDEX jidx;
-CREATE INDEX jidx ON testjsonb USING gin (j jsonb_path_ops);
+CREATE INDEX CONCURRENTLY jidx ON testjsonb USING gin (j jsonb_path_ops);
SET enable_seqscan = off;
SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
diff --git a/parser/src/test/resources/postgres/test/regress/sql/multirangetypes.sql b/parser/src/test/resources/postgres/test/regress/sql/multirangetypes.sql
index 41d5524..c7953aa 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/multirangetypes.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/multirangetypes.sql
@@ -721,6 +721,22 @@ drop type textrange1;
reset role;
drop role regress_multirange_owner;
+--
+-- CREATE TYPE checks for CREATE on multirange schema
+--
+create role regress_mr;
+create schema mr_sch;
+set role regress_mr;
+create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type);
+reset role;
+grant create on schema mr_sch to regress_mr;
+set role regress_mr;
+create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type);
+reset role;
+drop type mytype;
+drop schema mr_sch;
+drop role regress_mr;
+
--
-- Test polymorphic type system
--
@@ -815,6 +831,9 @@ select *, row_to_json(upper(t)) as u from
(values (two_ints_multirange(two_ints_range(row(1,2), row(3,4)))),
(two_ints_multirange(two_ints_range(row(5,6), row(7,8))))) v(t);
+-- this must be rejected to avoid self-inclusion issues:
+alter type two_ints add attribute c two_ints_multirange;
+
drop type two_ints cascade;
--
diff --git a/parser/src/test/resources/postgres/test/regress/sql/partition_aggregate.sql b/parser/src/test/resources/postgres/test/regress/sql/partition_aggregate.sql
index ab070fe..f2f23d5 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/partition_aggregate.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/partition_aggregate.sql
@@ -74,6 +74,11 @@ EXPLAIN (COSTS OFF)
SELECT a FROM pagg_tab WHERE a < 3 GROUP BY a ORDER BY 1;
SELECT a FROM pagg_tab WHERE a < 3 GROUP BY a ORDER BY 1;
+-- Test partitionwise aggregation with ordered append path built from fractional paths
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM pagg_tab GROUP BY c ORDER BY c LIMIT 1;
+SELECT count(*) FROM pagg_tab GROUP BY c ORDER BY c LIMIT 1;
+
RESET enable_hashagg;
-- ROLLUP, partitionwise aggregation does not apply
diff --git a/parser/src/test/resources/postgres/test/regress/sql/partition_prune.sql b/parser/src/test/resources/postgres/test/regress/sql/partition_prune.sql
index d93c0c0..359a920 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/partition_prune.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/partition_prune.sql
@@ -1447,3 +1447,74 @@ select min(a) over (partition by a order by a) from part_abc where a >= stable_o
drop view part_abc_view;
drop table part_abc;
+
+--
+-- Check that operands wrapped in PlaceHolderVars are matched to partition
+-- keys, allowing partition pruning to occur. PlaceHolderVars can be
+-- introduced when a subquery's output is used with grouping sets.
+--
+create table phv_part (a int, b text) partition by list (a);
+create table phv_part_1 partition of phv_part for values in (1);
+create table phv_part_2 partition of phv_part for values in (2);
+create table phv_part_null partition of phv_part for values in (null);
+insert into phv_part values (1, 'one'), (2, 'two'), (null, 'null');
+
+-- OpExpr: PHV-wrapped operand matched via equal()
+explain (costs off)
+select * from (select a, b from phv_part) t
+ where a = 1
+ group by grouping sets (a, b);
+
+select * from (select a, b from phv_part) t
+ where a = 1
+ group by grouping sets (a, b);
+
+-- OpExpr with RelabelType: PHV wrapped around a casted column
+explain (costs off)
+select * from (select a::oid as x, b from phv_part) t
+ where x::int = 1
+ group by grouping sets (x, b);
+
+select * from (select a::oid as x, b from phv_part) t
+ where x::int = 1
+ group by grouping sets (x, b);
+
+-- ScalarArrayOpExpr: IN clause with PHV-wrapped operand
+explain (costs off)
+select * from (select a, b from phv_part) t
+ where a in (1, null)
+ group by grouping sets (a, b);
+
+select * from (select a, b from phv_part) t
+ where a in (1, null)
+ group by grouping sets (a, b);
+
+-- NullTest: IS NULL with PHV-wrapped operand
+explain (costs off)
+select * from (select a, b from phv_part) t
+ where a is null
+ group by grouping sets (a, b);
+
+select * from (select a, b from phv_part) t
+ where a is null
+ group by grouping sets (a, b);
+
+drop table phv_part;
+
+-- BooleanTest: IS TRUE with PHV-wrapped boolean partition key
+create table phv_boolpart (a bool, b text) partition by list (a);
+create table phv_boolpart_t partition of phv_boolpart for values in (true);
+create table phv_boolpart_f partition of phv_boolpart for values in (false);
+create table phv_boolpart_null partition of phv_boolpart default;
+insert into phv_boolpart values (true, 'yes'), (false, 'no'), (null, 'unknown');
+
+explain (costs off)
+select * from (select a, b from phv_boolpart) t
+ where a is true
+ group by grouping sets (a, b);
+
+select * from (select a, b from phv_boolpart) t
+ where a is true
+ group by grouping sets (a, b);
+
+drop table phv_boolpart;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/portals.sql b/parser/src/test/resources/postgres/test/regress/sql/portals.sql
index fc4cccb..196b862 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/portals.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/portals.sql
@@ -508,6 +508,11 @@ DECLARE c1 CURSOR FOR SELECT * FROM ucview;
FETCH FROM c1;
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
ROLLBACK;
+BEGIN;
+DECLARE c1 CURSOR FOR SELECT * FROM ucview;
+FETCH FROM c1;
+UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported
+ROLLBACK;
-- Check WHERE CURRENT OF with an index-only scan
BEGIN;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/prepared_xacts.sql b/parser/src/test/resources/postgres/test/regress/sql/prepared_xacts.sql
index ade3a26..b0712b1 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/prepared_xacts.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/prepared_xacts.sql
@@ -1,3 +1,8 @@
+SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset
+\if :skip_test
+\quit
+\endif
+
--
-- PREPARED TRANSACTIONS (two-phase commit)
--
@@ -158,7 +163,32 @@ SELECT * FROM pxtest3;
-- There should be no prepared transactions
SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid;
+
+-- Test row-level locks held by prepared transactions
+CREATE TABLE pxtest_rowlock (id int PRIMARY KEY, data text);
+INSERT INTO pxtest_rowlock VALUES (1, 'test data');
+
+BEGIN;
+SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE;
+PREPARE TRANSACTION 'regress_p1';
+
+-- Should fail because the row is locked
+SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT;
+
+-- Test prepared transactions that participate in multixacts. For
+-- that, lock the same row again, creating a multixid.
+BEGIN;
+SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE;
+PREPARE TRANSACTION 'regress_p2';
+
+-- Should fail because the row is locked
+SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT;
+
+ROLLBACK PREPARED 'regress_p1';
+ROLLBACK PREPARED 'regress_p2';
+
-- Clean up
DROP TABLE pxtest2;
-DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
+-- pxtest3 was already dropped
DROP TABLE pxtest4;
+DROP TABLE pxtest_rowlock;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/psql.sql b/parser/src/test/resources/postgres/test/regress/sql/psql.sql
index b6428c0..f247627 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/psql.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/psql.sql
@@ -1,12 +1,9 @@
/*
- * This file has been altered by SplendidData.
- * It is only used for happy flow syntax checking, so erroneous statements are commented out here.
- * The deactivated lines are marked by: -- Deactivated for SplendidDataTest:
- */
+ * This file is completely commented out as it is there to test psql.
+ * It hardly has added value for testing sql.
+ *
+ *
-
-
-
--
-- Tests for psql features that aren't closely connected to any
-- specific server features
@@ -32,48 +29,78 @@
-- \g and \gx
--- Deactivated for SplendidDataTest: SELECT 1 as one, 2 as two \g
--- Deactivated for SplendidDataTest: \gx
--- Deactivated for SplendidDataTest: SELECT 3 as three, 4 as four \gx
--- Deactivated for SplendidDataTest: \g
+SELECT 1 as one, 2 as two \g
+\gx
+SELECT 3 as three, 4 as four \gx
+\g
-- \gx should work in FETCH_COUNT mode too
\set FETCH_COUNT 1
--- Deactivated for SplendidDataTest: SELECT 1 as one, 2 as two \g
--- Deactivated for SplendidDataTest: \gx
--- Deactivated for SplendidDataTest: SELECT 3 as three, 4 as four \gx
--- Deactivated for SplendidDataTest: \g
+SELECT 1 as one, 2 as two \g
+\gx
+SELECT 3 as three, 4 as four \gx
+\g
\unset FETCH_COUNT
-- \g/\gx with pset options
--- Deactivated for SplendidDataTest: SELECT 1 as one, 2 as two \g (format=csv csv_fieldsep='\t')
--- Deactivated for SplendidDataTest: \g
--- Deactivated for SplendidDataTest: SELECT 1 as one, 2 as two \gx (title='foo bar')
--- Deactivated for SplendidDataTest: \g
+SELECT 1 as one, 2 as two \g (format=csv csv_fieldsep='\t')
+\g
+SELECT 1 as one, 2 as two \gx (title='foo bar')
+\g
+
+-- \parse (extended query protocol)
+\parse
+SELECT 1 \parse ''
+SELECT 2 \parse stmt1
+SELECT $1 \parse stmt2
+SELECT $1, $2 \parse stmt3
+
+-- \bind_named (extended query protocol)
+\bind_named
+\bind_named '' \g
+\bind_named stmt1 \g
+\bind_named stmt2 'foo' \g
+\bind_named stmt3 'foo' 'bar' \g
+-- Repeated calls. The second call generates an error, cleaning up the
+-- statement name set by the first call.
+\bind_named stmt4
+\bind_named
+\g
+-- Last \bind_named wins
+\bind_named stmt2 'foo' \bind_named stmt3 'foo2' 'bar2' \g
+-- Multiple \g calls mean multiple executions
+\bind_named stmt2 'foo3' \g \bind_named stmt3 'foo4' 'bar4' \g
+
+-- \close_prepared (extended query protocol)
+\close_prepared
+\close_prepared ''
+\close_prepared stmt2
+\close_prepared stmt2
+SELECT name, statement FROM pg_prepared_statements ORDER BY name;
-- \bind (extended query protocol)
--- Deactivated for SplendidDataTest: SELECT 1 \bind \g
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'foo' \g
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'foo' 'bar' \g
+SELECT 1 \bind \g
+SELECT $1 \bind 'foo' \g
+SELECT $1, $2 \bind 'foo' 'bar' \g
-- last \bind wins
--- Deactivated for SplendidDataTest: select $1::int as col \bind 'foo' \bind 2 \g
+select $1::int as col \bind 'foo' \bind 2 \g
-- Multiple \g calls mean multiple executions
--- Deactivated for SplendidDataTest: select $1::int as col \bind 1 \g \bind 2 \g
+select $1::int as col \bind 1 \g \bind 2 \g
-- errors
-- parse error
--- Deactivated for SplendidDataTest: SELECT foo \bind \g
+SELECT foo \bind \g
-- tcop error
--- Deactivated for SplendidDataTest: SELECT 1 \; SELECT 2 \bind \g
+SELECT 1 \; SELECT 2 \bind \g
-- bind error
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'foo' \g
+SELECT $1, $2 \bind 'foo' \g
-- bind_named error
--- Deactivated for SplendidDataTest: \bind_named stmt2 'baz' \g
--- Deactivated for SplendidDataTest: \bind_named stmt3 'baz' \g
+\bind_named stmt2 'baz' \g
+\bind_named stmt3 'baz' \g
-- \gset
@@ -92,7 +119,7 @@ select 97 as "EOF", 'ok' as _foo \gset IGNORE
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y
select 5 as x, 6 as y \gset pref01_ \\ \g \echo :pref01_x :pref01_y
--- Deactivated for SplendidDataTest: select 7 as x, 8 as y \g \gset pref01_ \echo :pref01_x :pref01_y
+select 7 as x, 8 as y \g \gset pref01_ \echo :pref01_x :pref01_y
-- NULL should unset the variable
\set var2 xyz
@@ -104,7 +131,7 @@ select 10 as test01, 20 as test02 from generate_series(1,3) \gset
select 10 as test01, 20 as test02 from generate_series(1,0) \gset
-- \gset returns no tuples
--- Deactivated for SplendidDataTest: select a from generate_series(1, 10) as a where a = 11 \gset
+select a from generate_series(1, 10) as a where a = 11 \gset
\echo :ROW_COUNT
-- \gset should work in FETCH_COUNT mode too
@@ -119,44 +146,44 @@ select 10 as test01, 20 as test02 from generate_series(1,0) \gset
-- \gdesc
--- Deactivated for SplendidDataTest: SELECT
--- Deactivated for SplendidDataTest: NULL AS zero,
--- Deactivated for SplendidDataTest: 1 AS one,
--- Deactivated for SplendidDataTest: 2.0 AS two,
--- Deactivated for SplendidDataTest: 'three' AS three,
--- Deactivated for SplendidDataTest: $1 AS four,
--- Deactivated for SplendidDataTest: sin($2) as five,
--- Deactivated for SplendidDataTest: 'foo'::varchar(4) as six,
--- Deactivated for SplendidDataTest: CURRENT_DATE AS now
+SELECT
+ NULL AS zero,
+ 1 AS one,
+ 2.0 AS two,
+ 'three' AS three,
+ $1 AS four,
+ sin($2) as five,
+ 'foo'::varchar(4) as six,
+ CURRENT_DATE AS now
\gdesc
-- should work with tuple-returning utilities, such as EXECUTE
--- Deactivated for SplendidDataTest: PREPARE test AS SELECT 1 AS first, 2 AS second;
--- Deactivated for SplendidDataTest: EXECUTE test \gdesc
--- Deactivated for SplendidDataTest: EXPLAIN EXECUTE test \gdesc
+PREPARE test AS SELECT 1 AS first, 2 AS second;
+EXECUTE test \gdesc
+EXPLAIN EXECUTE test \gdesc
-- should fail cleanly - syntax error
--- Deactivated for SplendidDataTest: SELECT 1 + \gdesc
+SELECT 1 + \gdesc
-- check behavior with empty results
--- Deactivated for SplendidDataTest: SELECT \gdesc
--- Deactivated for SplendidDataTest: CREATE TABLE bububu(a int) \gdesc
+SELECT \gdesc
+CREATE TABLE bububu(a int) \gdesc
-- subject command should not have executed
--- Deactivated for SplendidDataTest: TABLE bububu; -- fail
+TABLE bububu; -- fail
-- query buffer should remain unchanged
--- Deactivated for SplendidDataTest: SELECT 1 AS x, 'Hello', 2 AS y, true AS "dirty\name"
+SELECT 1 AS x, 'Hello', 2 AS y, true AS "dirty\name"
\gdesc
\g
-- all on one line
--- Deactivated for SplendidDataTest: SELECT 3 AS x, 'Hello', 4 AS y, true AS "dirty\name" \gdesc \g
+SELECT 3 AS x, 'Hello', 4 AS y, true AS "dirty\name" \gdesc \g
-- test for server bug #17983 with empty statement in aborted transaction
set search_path = default;
begin;
--- Deactivated for SplendidDataTest: bogus;
+bogus;
;
\gdesc
rollback;
@@ -164,22 +191,22 @@ rollback;
-- \gexec
create temporary table gexec_test(a int, b text, c date, d float);
--- Deactivated for SplendidDataTest: select format('create index on gexec_test(%I)', attname)
--- Deactivated for SplendidDataTest: from pg_attribute
--- Deactivated for SplendidDataTest: where attrelid = 'gexec_test'::regclass and attnum > 0
--- Deactivated for SplendidDataTest: rder by attnum
+select format('create index on gexec_test(%I)', attname)
+from pg_attribute
+where attrelid = 'gexec_test'::regclass and attnum > 0
+order by attnum
\gexec
-- \gexec should work in FETCH_COUNT mode too
-- (though the fetch limit applies to the executed queries not the meta query)
\set FETCH_COUNT 1
--- Deactivated for SplendidDataTest: select 'select 1 as ones', 'select x.y, x.y*2 as double from generate_series(1,4) as x(y)'
--- Deactivated for SplendidDataTest: union all
--- Deactivated for SplendidDataTest: select 'drop table gexec_test', NULL
--- Deactivated for SplendidDataTest: union all
--- Deactivated for SplendidDataTest: select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over'
--- Deactivated for SplendidDataTest: \gexec
+select 'select 1 as ones', 'select x.y, x.y*2 as double from generate_series(1,4) as x(y)'
+union all
+select 'drop table gexec_test', NULL
+union all
+select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over'
+\gexec
\unset FETCH_COUNT
@@ -200,10 +227,10 @@ create temporary table gexec_test(a int, b text, c date, d float);
-- test multi-line headers, wrapping, and newline indicators
-- in aligned, unaligned, and wrapped formats
--- Deactivated for SplendidDataTest: prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab
+prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab
--- Deactivated for SplendidDataTest: c", array_to_string(array_agg(repeat('y',20-2*n)),E'\n') as "a
--- Deactivated for SplendidDataTest: bc" from generate_series(1,10) as n(n) group by n>1 order by n>1;
+c", array_to_string(array_agg(repeat('y',20-2*n)),E'\n') as "a
+bc" from generate_series(1,10) as n(n) group by n>1 order by n>1;
\pset linestyle ascii
@@ -212,54 +239,54 @@ create temporary table gexec_test(a int, b text, c date, d float);
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset columns 20
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset linestyle old-ascii
@@ -268,54 +295,54 @@ create temporary table gexec_test(a int, b text, c date, d float);
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset columns 20
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
deallocate q;
@@ -329,81 +356,81 @@ prepare q as select repeat('x',2*n) as "0123456789abcdef", repeat('y',20-2*n) as
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset columns 30
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset columns 20
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset linestyle old-ascii
@@ -412,56 +439,67 @@ prepare q as select repeat('x',2*n) as "0123456789abcdef", repeat('y',20-2*n) as
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset border 0
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
\pset format unaligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format aligned
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset format wrapped
--- Deactivated for SplendidDataTest: execute q;
+execute q;
deallocate q;
+-- expanded output with short-width columns
+\pset border 2
+\pset expanded on
+create table psql_short_tab(a int, b int);
+insert into psql_short_tab values(10,20),(30,40);
+\pset format aligned
+select * from psql_short_tab;
+\pset format wrapped
+select * from psql_short_tab;
+drop table psql_short_tab;
+
\pset linestyle ascii
\pset border 1
@@ -582,23 +620,23 @@ prepare q as
\pset expanded off
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
deallocate q;
@@ -624,10 +662,10 @@ prepare q as
from generate_series(1,2) as n;
\pset expanded off
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
--- Deactivated for SplendidDataTest: execute q;
+execute q;
deallocate q;
@@ -673,24 +711,24 @@ prepare q as
\pset expanded off
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr foobar
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr
\pset expanded on
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr foobar
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr
deallocate q;
@@ -718,29 +756,29 @@ prepare q as
\pset expanded off
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 3
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 3
--- Deactivated for SplendidDataTest: execute q;
+execute q;
deallocate q;
@@ -767,36 +805,36 @@ prepare q as
\pset expanded off
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 3
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr lr
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr
\pset expanded on
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 3
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr lr
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset tableattr
deallocate q;
@@ -824,25 +862,25 @@ prepare q as
\pset expanded off
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset expanded on
\pset border 0
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 1
--- Deactivated for SplendidDataTest: execute q;
+execute q;
\pset border 2
--- Deactivated for SplendidDataTest: execute q;
+execute q;
--- Deactivated for SplendidDataTest: deallocate q;
+deallocate q;
-- check ambiguous format requests
@@ -879,8 +917,8 @@ drop table psql_serial_tab;
select 'okay';
select 'still okay';
\else
--- Deactivated for SplendidDataTest: not okay;
--- Deactivated for SplendidDataTest: still not okay
+ not okay;
+ still not okay
\endif
-- at this point query buffer should still have last valid line
@@ -888,80 +926,80 @@ drop table psql_serial_tab;
-- \if should work okay on part of a query
select
--- Deactivated for SplendidDataTest: \if true
--- Deactivated for SplendidDataTest: 42
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: (bogus
--- Deactivated for SplendidDataTest: \endif
+ \if true
+ 42
+ \else
+ (bogus
+ \endif
forty_two;
--- Deactivated for SplendidDataTest: select \if false \\ (bogus \else \\ 42 \endif \\ forty_two;
+select \if false \\ (bogus \else \\ 42 \endif \\ forty_two;
-- test a large nested if using a variety of true-equivalents
--- Deactivated for SplendidDataTest: \if true
--- Deactivated for SplendidDataTest: \if 1
--- Deactivated for SplendidDataTest: \if yes
--- Deactivated for SplendidDataTest: \if on
--- Deactivated for SplendidDataTest: \echo 'all true'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #1-1'
--- Deactivated for SplendidDataTest: \endif
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #1-2'
--- Deactivated for SplendidDataTest: \endif
--- Deactivated for SplendidDataTest: -- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #1-3'
--- Deactivated for SplendidDataTest: \endif
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #1-4'
--- Deactivated for SplendidDataTest: \endif
+\if true
+ \if 1
+ \if yes
+ \if on
+ \echo 'all true'
+ \else
+ \echo 'should not print #1-1'
+ \endif
+ \else
+ \echo 'should not print #1-2'
+ \endif
+ \else
+ \echo 'should not print #1-3'
+ \endif
+\else
+ \echo 'should not print #1-4'
+\endif
-- test a variety of false-equivalents in an if/elif/else structure
--- Deactivated for SplendidDataTest: \if false
--- Deactivated for SplendidDataTest: \echo 'should not print #2-1'
--- Deactivated for SplendidDataTest: \elif 0
--- Deactivated for SplendidDataTest: \echo 'should not print #2-2'
--- Deactivated for SplendidDataTest: \elif no
--- Deactivated for SplendidDataTest: \echo 'should not print #2-3'
--- Deactivated for SplendidDataTest: \elif off
--- Deactivated for SplendidDataTest: \echo 'should not print #2-4'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'all false'
--- Deactivated for SplendidDataTest: \endif
+\if false
+ \echo 'should not print #2-1'
+\elif 0
+ \echo 'should not print #2-2'
+\elif no
+ \echo 'should not print #2-3'
+\elif off
+ \echo 'should not print #2-4'
+\else
+ \echo 'all false'
+\endif
-- test true-false elif after initial true branch
--- Deactivated for SplendidDataTest: \if true
--- Deactivated for SplendidDataTest: \echo 'should print #2-5'
--- Deactivated for SplendidDataTest: \elif true
--- Deactivated for SplendidDataTest: \echo 'should not print #2-6'
--- Deactivated for SplendidDataTest: \elif false
--- Deactivated for SplendidDataTest: \echo 'should not print #2-7'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #2-8'
--- Deactivated for SplendidDataTest: \endif
+\if true
+ \echo 'should print #2-5'
+\elif true
+ \echo 'should not print #2-6'
+\elif false
+ \echo 'should not print #2-7'
+\else
+ \echo 'should not print #2-8'
+\endif
-- test simple true-then-else
--- Deactivated for SplendidDataTest: \if true
--- Deactivated for SplendidDataTest: \echo 'first thing true'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #3-1'
--- Deactivated for SplendidDataTest: \endif
+\if true
+ \echo 'first thing true'
+\else
+ \echo 'should not print #3-1'
+\endif
-- test simple false-true-else
--- Deactivated for SplendidDataTest: \if false
--- Deactivated for SplendidDataTest: \echo 'should not print #4-1'
--- Deactivated for SplendidDataTest: \elif true
--- Deactivated for SplendidDataTest: \echo 'second thing true'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #5-1'
--- Deactivated for SplendidDataTest: \endif
+\if false
+ \echo 'should not print #4-1'
+\elif true
+ \echo 'second thing true'
+\else
+ \echo 'should not print #5-1'
+\endif
-- invalid boolean expressions are false
--- Deactivated for SplendidDataTest: \if invalid boolean expression
--- Deactivated for SplendidDataTest: \echo 'will not print #6-1'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'will print anyway #6-2'
--- Deactivated for SplendidDataTest: \endif
+\if invalid boolean expression
+ \echo 'will not print #6-1'
+\else
+ \echo 'will print anyway #6-2'
+\endif
-- test un-matched endif
\endif
@@ -984,17 +1022,17 @@ select
\elif
\endif
--- Deactivated for SplendidDataTest: -- test if-endif matching in a false branch
--- Deactivated for SplendidDataTest: \if false
--- Deactivated for SplendidDataTest: \if false
--- Deactivated for SplendidDataTest: \echo 'should not print #7-1'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #7-2'
--- Deactivated for SplendidDataTest: \endif
--- Deactivated for SplendidDataTest: \echo 'should not print #7-3'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should print #7-4'
--- Deactivated for SplendidDataTest: \endif
+-- test if-endif matching in a false branch
+\if false
+ \if false
+ \echo 'should not print #7-1'
+ \else
+ \echo 'should not print #7-2'
+ \endif
+ \echo 'should not print #7-3'
+\else
+ \echo 'should print #7-4'
+\endif
-- show that vars and backticks are not expanded when ignoring extra args
\set foo bar
@@ -1003,85 +1041,98 @@ select
-- show that vars and backticks are not expanded and commands are ignored
-- when in a false if-branch
--- Deactivated for SplendidDataTest: \set try_to_quit '\\q'
--- Deactivated for SplendidDataTest: \if false
--- Deactivated for SplendidDataTest: :try_to_quit
--- Deactivated for SplendidDataTest: \echo `nosuchcommand` :foo :'foo' :"foo"
--- Deactivated for SplendidDataTest: \pset fieldsep | `nosuchcommand` :foo :'foo' :"foo"
--- Deactivated for SplendidDataTest: \a
--- Deactivated for SplendidDataTest: \C arg1
--- Deactivated for SplendidDataTest: \c arg1 arg2 arg3 arg4
--- Deactivated for SplendidDataTest: \cd arg1
--- Deactivated for SplendidDataTest: \conninfo
--- Deactivated for SplendidDataTest: \copy arg1 arg2 arg3 arg4 arg5 arg6
--- Deactivated for SplendidDataTest: \copyright
--- Deactivated for SplendidDataTest: SELECT 1 as one, 2, 3 \crosstabview
--- Deactivated for SplendidDataTest: \dt arg1
--- Deactivated for SplendidDataTest: \e arg1 arg2
--- Deactivated for SplendidDataTest: \ef whole_line
--- Deactivated for SplendidDataTest: \ev whole_line
--- Deactivated for SplendidDataTest: \echo arg1 arg2 arg3 arg4 arg5
--- Deactivated for SplendidDataTest: \echo arg1
--- Deactivated for SplendidDataTest: \encoding arg1
--- Deactivated for SplendidDataTest: \errverbose
--- Deactivated for SplendidDataTest: \f arg1
--- Deactivated for SplendidDataTest: \g arg1
--- Deactivated for SplendidDataTest: \gx arg1
--- Deactivated for SplendidDataTest: \gexec
--- Deactivated for SplendidDataTest: SELECT 1 AS one \gset
--- Deactivated for SplendidDataTest: \h
--- Deactivated for SplendidDataTest: \?
--- Deactivated for SplendidDataTest: \html
--- Deactivated for SplendidDataTest: \i arg1
--- Deactivated for SplendidDataTest: \ir arg1
--- Deactivated for SplendidDataTest: \l arg1
--- Deactivated for SplendidDataTest: \lo arg1 arg2
--- Deactivated for SplendidDataTest: \lo_list
--- Deactivated for SplendidDataTest: \o arg1
--- Deactivated for SplendidDataTest: \p
--- Deactivated for SplendidDataTest: \password arg1
--- Deactivated for SplendidDataTest: \prompt arg1 arg2
--- Deactivated for SplendidDataTest: \pset arg1 arg2
--- Deactivated for SplendidDataTest: \q
--- Deactivated for SplendidDataTest: \reset
--- Deactivated for SplendidDataTest: \s arg1
--- Deactivated for SplendidDataTest: \set arg1 arg2 arg3 arg4 arg5 arg6 arg7
--- Deactivated for SplendidDataTest: \setenv arg1 arg2
--- Deactivated for SplendidDataTest: \sf whole_line
--- Deactivated for SplendidDataTest: \sv whole_line
--- Deactivated for SplendidDataTest: \t arg1
--- Deactivated for SplendidDataTest: \T arg1
--- Deactivated for SplendidDataTest: \timing arg1
--- Deactivated for SplendidDataTest: \unset arg1
--- Deactivated for SplendidDataTest: \w arg1
--- Deactivated for SplendidDataTest: \watch arg1 arg2
--- Deactivated for SplendidDataTest: \x arg1
--- Deactivated for SplendidDataTest: -- \else here is eaten as part of OT_FILEPIPE argument
--- Deactivated for SplendidDataTest: \w |/no/such/file \else
--- Deactivated for SplendidDataTest: -- \endif here is eaten as part of whole-line argument
--- Deactivated for SplendidDataTest: \! whole_line \endif
--- Deactivated for SplendidDataTest: \z
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should print #8-1'
--- Deactivated for SplendidDataTest: \endif
+\set try_to_quit '\\q'
+\if false
+ :try_to_quit
+ \echo `nosuchcommand` :foo :'foo' :"foo"
+ \pset fieldsep | `nosuchcommand` :foo :'foo' :"foo"
+ \a
+ SELECT $1 \bind 1 \g
+ \bind_named stmt1 1 2 \g
+ \C arg1
+ \c arg1 arg2 arg3 arg4
+ \cd arg1
+ \close_prepared stmt1
+ \conninfo
+ \copy arg1 arg2 arg3 arg4 arg5 arg6
+ \copyright
+ SELECT 1 as one, 2, 3 \crosstabview
+ \dt arg1
+ \e arg1 arg2
+ \ef whole_line
+ \ev whole_line
+ \echo arg1 arg2 arg3 arg4 arg5
+ \echo arg1
+ \encoding arg1
+ \endpipeline
+ \errverbose
+ \f arg1
+ \flush
+ \flushrequest
+ \g arg1
+ \gx arg1
+ \gexec
+ \getresults
+ SELECT 1 AS one \gset
+ \h
+ \?
+ \html
+ \i arg1
+ \ir arg1
+ \l arg1
+ \lo arg1 arg2
+ \lo_list
+ \o arg1
+ \p
+ SELECT 1 \parse
+ \password arg1
+ \prompt arg1 arg2
+ \pset arg1 arg2
+ \q
+ \reset
+ \restrict test
+ \s arg1
+ \sendpipeline
+ \set arg1 arg2 arg3 arg4 arg5 arg6 arg7
+ \setenv arg1 arg2
+ \sf whole_line
+ \sv whole_line
+ \startpipeline
+ \syncpipeline
+ \t arg1
+ \T arg1
+ \timing arg1
+ \unrestrict not_valid
+ \unset arg1
+ \w arg1
+ \watch arg1 arg2
+ \x arg1
+ -- \else here is eaten as part of OT_FILEPIPE argument
+ \w |/no/such/file \else
+ -- \endif here is eaten as part of whole-line argument
+ \! whole_line \endif
+ \z
+\else
+ \echo 'should print #8-1'
+\endif
-- :{?...} defined variable test
--- Deactivated for SplendidDataTest: \set i 1
--- Deactivated for SplendidDataTest: \if :{?i}
--- Deactivated for SplendidDataTest: \echo '#9-1 ok, variable i is defined'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo 'should not print #9-2'
--- Deactivated for SplendidDataTest: \endif
+\set i 1
+\if :{?i}
+ \echo '#9-1 ok, variable i is defined'
+\else
+ \echo 'should not print #9-2'
+\endif
--- Deactivated for SplendidDataTest: \if :{?no_such_variable}
--- Deactivated for SplendidDataTest: \echo 'should not print #10-1'
--- Deactivated for SplendidDataTest: \else
--- Deactivated for SplendidDataTest: \echo '#10-2 ok, variable no_such_variable is not defined'
--- Deactivated for SplendidDataTest: \endif
+\if :{?no_such_variable}
+ \echo 'should not print #10-1'
+\else
+ \echo '#10-2 ok, variable no_such_variable is not defined'
+\endif
--- Deactivated for SplendidDataTest: SELECT :{?i} AS i_is_defined;
+SELECT :{?i} AS i_is_defined;
--- Deactivated for SplendidDataTest: SELECT NOT :{?no_such_var} AS no_such_var_is_not_defined;
+SELECT NOT :{?no_such_var} AS no_such_var_is_not_defined;
-- SHOW_CONTEXT
@@ -1109,12 +1160,12 @@ end $$;
-- test printing and clearing the query buffer
SELECT 1;
\p
--- Deactivated for SplendidDataTest: SELECT 2 \r
+SELECT 2 \r
\p
--- Deactivated for SplendidDataTest: SELECT 3 \p
--- Deactivated for SplendidDataTest: UNION SELECT 4 \p
--- Deactivated for SplendidDataTest: UNION SELECT 5
--- Deactivated for SplendidDataTest: ORDER BY 1;
+SELECT 3 \p
+UNION SELECT 4 \p
+UNION SELECT 5
+ORDER BY 1;
\r
\p
@@ -1127,7 +1178,7 @@ SELECT 1 AS stuff UNION SELECT 2;
\echo 'number of rows:' :ROW_COUNT
-- syntax error
--- Deactivated for SplendidDataTest: SELECT 1 UNION;
+SELECT 1 UNION;
\echo 'error:' :ERROR
\echo 'error code:' :SQLSTATE
\echo 'number of rows:' :ROW_COUNT
@@ -1153,7 +1204,7 @@ DROP TABLE this_table_does_not_exist;
-- nondefault verbosity error settings (except verbose, which is too unstable)
\set VERBOSITY terse
--- Deactivated for SplendidDataTest: SELECT 1 UNION;
+SELECT 1 UNION;
\echo 'error:' :ERROR
\echo 'error code:' :SQLSTATE
\echo 'last error message:' :LAST_ERROR_MESSAGE
@@ -1167,20 +1218,20 @@ SELECT 1/0;
\set VERBOSITY default
-- working \gdesc
--- Deactivated for SplendidDataTest: SELECT 3 AS three, 4 AS four \gdesc
+SELECT 3 AS three, 4 AS four \gdesc
\echo 'error:' :ERROR
\echo 'error code:' :SQLSTATE
\echo 'number of rows:' :ROW_COUNT
-- \gdesc with an error
--- Deactivated for SplendidDataTest: SELECT 4 AS \gdesc
+SELECT 4 AS \gdesc
\echo 'error:' :ERROR
\echo 'error code:' :SQLSTATE
\echo 'number of rows:' :ROW_COUNT
\echo 'last error message:' :LAST_ERROR_MESSAGE
\echo 'last error code:' :LAST_ERROR_SQLSTATE
--- check row count for a cursor-fetched query
+-- check row count for a query with chunked results
\set FETCH_COUNT 10
select unique2 from tenk1 order by unique2 limit 19;
\echo 'error:' :ERROR
@@ -1419,7 +1470,7 @@ SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
SELECT 3 AS three \; SELECT warn('3.5') \; SELECT 4 AS four \gset
\echo :three :four
-- syntax error stops all processing
--- Deactivated for SplendidDataTest: SELECT 5 \; SELECT 6 + \; SELECT warn('6.5') \; SELECT 7 ;
+SELECT 5 \; SELECT 6 + \; SELECT warn('6.5') \; SELECT 7 ;
-- with aborted transaction, stop on first error
BEGIN \; SELECT 8 AS eight \; SELECT 9/0 AS nine \; ROLLBACK \; SELECT 10 AS ten ;
-- close previously aborted transaction
@@ -1437,9 +1488,9 @@ COPY psql_comics TO STDOUT \;
TRUNCATE psql_comics \;
DROP TABLE psql_comics \;
SELECT 'ok' AS "done" ;
--- Deactivated for SplendidDataTest: Moe
--- Deactivated for SplendidDataTest: Susie
--- Deactivated for SplendidDataTest: \.
+Moe
+Susie
+\.
\set SHOW_ALL_RESULTS off
SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
@@ -1458,11 +1509,11 @@ CREATE TEMPORARY TABLE reload_output(
line text
);
--- Deactivated for SplendidDataTest: SELECT 1 AS a \g :g_out_file
+SELECT 1 AS a \g :g_out_file
COPY reload_output(line) FROM :'g_out_file';
--- Deactivated for SplendidDataTest: SELECT 2 AS b\; SELECT 3 AS c\; SELECT 4 AS d \g :g_out_file
+SELECT 2 AS b\; SELECT 3 AS c\; SELECT 4 AS d \g :g_out_file
COPY reload_output(line) FROM :'g_out_file';
--- Deactivated for SplendidDataTest: COPY (SELECT 'foo') TO STDOUT \; COPY (SELECT 'bar') TO STDOUT \g :g_out_file
+COPY (SELECT 'foo') TO STDOUT \; COPY (SELECT 'bar') TO STDOUT \g :g_out_file
COPY reload_output(line) FROM :'g_out_file';
SELECT line FROM reload_output ORDER BY lineno;
@@ -1499,7 +1550,7 @@ TRUNCATE TABLE reload_output;
-- The data goes to :o_out_file with no status generated.
COPY (SELECT 'foo1') TO STDOUT \; COPY (SELECT 'bar1') TO STDOUT;
-- Combination of \o and \g file with multiple COPY queries.
--- Deactivated for SplendidDataTest: COPY (SELECT 'foo2') TO STDOUT \; COPY (SELECT 'bar2') TO STDOUT \g :g_out_file
+COPY (SELECT 'foo2') TO STDOUT \; COPY (SELECT 'bar2') TO STDOUT \g :g_out_file
\o
-- Check the contents of the files generated.
@@ -1910,3 +1961,7 @@ CREATE TABLE defprivs (a int);
\zx defprivs
\pset null ''
DROP TABLE defprivs;
+
+*
+*/
+select 1;
\ No newline at end of file
diff --git a/parser/src/test/resources/postgres/test/regress/sql/psql_pipeline.sql b/parser/src/test/resources/postgres/test/regress/sql/psql_pipeline.sql
index 854dbcd..c9e2563 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/psql_pipeline.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/psql_pipeline.sql
@@ -1,10 +1,9 @@
/*
- * This file has been altered by SplendidData.
- * It is only used for happy flow syntax checking, so erroneous statements are commented out here.
- * The deactivated lines are marked by: -- Deactivated for SplendidDataTest:
- */
-
-
+ * This file is completely commented out as it is there to test psql pipelines.
+ * It hardly has added value for testing sql.
+ *
+ *
+
--
-- Tests using psql pipelining
--
@@ -13,7 +12,7 @@ CREATE TABLE psql_pipeline(a INTEGER PRIMARY KEY, s TEXT);
-- Single query
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'val1' \sendpipeline
+SELECT $1 \bind 'val1' \sendpipeline
\endpipeline
\startpipeline
SELECT 'val1';
@@ -21,9 +20,9 @@ SELECT 'val1';
-- Multiple queries
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'val1' \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
+SELECT $1 \bind 'val1' \sendpipeline
+SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
+SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
SELECT 'val4';
SELECT 'val5', 'val6';
\endpipeline
@@ -38,10 +37,10 @@ SELECT 1; SELECT 2; SELECT 3
-- Test \flush
\startpipeline
\flush
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'val1' \sendpipeline
+SELECT $1 \bind 'val1' \sendpipeline
\flush
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
+SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
+SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
\flush
SELECT 'val4';
SELECT 'val5', 'val6';
@@ -52,12 +51,12 @@ SELECT 'val5', 'val6';
\echo :PIPELINE_COMMAND_COUNT
\echo :PIPELINE_SYNC_COUNT
\echo :PIPELINE_RESULT_COUNT
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'val1' \sendpipeline
+SELECT $1 \bind 'val1' \sendpipeline
\syncpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
+SELECT $1, $2 \bind 'val2' 'val3' \sendpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: SELECT $1, $2 \bind 'val4' 'val5' \sendpipeline
+SELECT $1, $2 \bind 'val4' 'val5' \sendpipeline
\echo :PIPELINE_COMMAND_COUNT
\echo :PIPELINE_SYNC_COUNT
\echo :PIPELINE_RESULT_COUNT
@@ -75,7 +74,7 @@ SELECT 'val9';
-- Query terminated with a semicolon replaces an unnamed prepared
-- statement.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \parse ''
+SELECT $1 \parse ''
SELECT 1;
\bind_named ''
\endpipeline
@@ -83,7 +82,7 @@ SELECT 1;
-- Extended query is appended to pipeline by a semicolon after a
-- newline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1
+SELECT $1 \bind 1
;
SELECT 2;
\endpipeline
@@ -91,48 +90,48 @@ SELECT 2;
-- \startpipeline should not have any effect if already in a pipeline.
\startpipeline
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'val1' \sendpipeline
+SELECT $1 \bind 'val1' \sendpipeline
\endpipeline
-- Convert an implicit transaction block to an explicit transaction block.
\startpipeline
--- Deactivated for SplendidDataTest: INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: BEGIN \bind \sendpipeline
--- Deactivated for SplendidDataTest: INSERT INTO psql_pipeline VALUES ($1) \bind 2 \sendpipeline
--- Deactivated for SplendidDataTest: ROLLBACK \bind \sendpipeline
+INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
+BEGIN \bind \sendpipeline
+INSERT INTO psql_pipeline VALUES ($1) \bind 2 \sendpipeline
+ROLLBACK \bind \sendpipeline
\endpipeline
-- Multiple explicit transactions
\startpipeline
--- Deactivated for SplendidDataTest: BEGIN \bind \sendpipeline
--- Deactivated for SplendidDataTest: INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: ROLLBACK \bind \sendpipeline
--- Deactivated for SplendidDataTest: BEGIN \bind \sendpipeline
--- Deactivated for SplendidDataTest: INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: COMMIT \bind \sendpipeline
+BEGIN \bind \sendpipeline
+INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
+ROLLBACK \bind \sendpipeline
+BEGIN \bind \sendpipeline
+INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
+COMMIT \bind \sendpipeline
\endpipeline
-- Use \parse and \bind_named
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \parse ''
--- Deactivated for SplendidDataTest: SELECT $1, $2 \parse ''
--- Deactivated for SplendidDataTest: SELECT $2 \parse pipeline_1
--- Deactivated for SplendidDataTest: \bind_named '' 1 2 \sendpipeline
--- Deactivated for SplendidDataTest: \bind_named pipeline_1 2 \sendpipeline
+SELECT $1 \parse ''
+SELECT $1, $2 \parse ''
+SELECT $2 \parse pipeline_1
+\bind_named '' 1 2 \sendpipeline
+\bind_named pipeline_1 2 \sendpipeline
\endpipeline
-- \getresults displays all results preceding a \flushrequest.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\flushrequest
\getresults
\endpipeline
-- \getresults displays all results preceding a \syncpipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\syncpipeline
\getresults
\endpipeline
@@ -140,7 +139,7 @@ SELECT 2;
-- \getresults immediately returns if there is no result to fetch.
\startpipeline
\getresults
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\getresults
\flushrequest
\endpipeline
@@ -148,42 +147,42 @@ SELECT 2;
-- \getresults only fetches results preceding a \flushrequest.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\flushrequest
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\getresults
\endpipeline
-- \getresults only fetches results preceding a \syncpipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\getresults
\endpipeline
-- Use pipeline with chunked results for both \getresults and \endpipeline.
\startpipeline
\set FETCH_COUNT 10
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\flushrequest
\getresults
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\endpipeline
\unset FETCH_COUNT
-- \getresults with specific number of requested results.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 3 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 3 \sendpipeline
\echo :PIPELINE_SYNC_COUNT
\syncpipeline
\echo :PIPELINE_SYNC_COUNT
\echo :PIPELINE_RESULT_COUNT
\getresults 1
\echo :PIPELINE_RESULT_COUNT
--- Deactivated for SplendidDataTest: SELECT $1 \bind 4 \sendpipeline
+SELECT $1 \bind 4 \sendpipeline
\getresults 3
\echo :PIPELINE_RESULT_COUNT
\endpipeline
@@ -192,7 +191,7 @@ SELECT 2;
\startpipeline
\syncpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
\flushrequest
\getresults 2
\getresults 1
@@ -200,9 +199,9 @@ SELECT 2;
-- \getresults 0 should get all the results.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 3 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 3 \sendpipeline
\syncpipeline
\getresults 0
\endpipeline
@@ -217,16 +216,16 @@ SELECT 2;
-- After an aborted pipeline, commands after a \syncpipeline should be
-- displayed.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind \sendpipeline
+SELECT $1 \bind \sendpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
\endpipeline
-- For an incorrect number of parameters, the pipeline is aborted and
-- the following queries will not be executed.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT \bind 'val1' \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 'val1' \sendpipeline
+SELECT \bind 'val1' \sendpipeline
+SELECT $1 \bind 'val1' \sendpipeline
\endpipeline
-- Using a semicolon with a parameter triggers an error and aborts
@@ -239,29 +238,29 @@ SELECT 1;
-- An explicit transaction with an error needs to be rollbacked after
-- the pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: BEGIN \bind \sendpipeline
--- Deactivated for SplendidDataTest: INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: ROLLBACK \bind \sendpipeline
+BEGIN \bind \sendpipeline
+INSERT INTO psql_pipeline VALUES ($1) \bind 1 \sendpipeline
+ROLLBACK \bind \sendpipeline
\endpipeline
ROLLBACK;
-- \watch is not allowed in a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT \bind \sendpipeline
+SELECT \bind \sendpipeline
\watch 1
\endpipeline
-- \gdesc should fail as synchronous commands are not allowed in a pipeline,
-- and the pipeline should still be usable.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \gdesc
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 1 \gdesc
+SELECT $1 \bind 1 \sendpipeline
\endpipeline
-- \gset is not allowed in a pipeline, pipeline should still be usable.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 as i, $2 as j \parse ''
--- Deactivated for SplendidDataTest: SELECT $1 as k, $2 as l \parse 'second'
+SELECT $1 as i, $2 as j \parse ''
+SELECT $1 as k, $2 as l \parse 'second'
\bind_named '' 1 2 \gset
\bind_named second 1 2 \gset pref02_ \echo :pref02_i :pref02_j
\bind_named '' 1 2 \sendpipeline
@@ -269,63 +268,63 @@ ROLLBACK;
-- \g and \gx are not allowed, pipeline should still be usable.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \g
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \g (format=unaligned tuples_only=on)
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \gx
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \gx (format=unaligned tuples_only=on)
+SELECT $1 \bind 1 \g
+SELECT $1 \bind 1 \g (format=unaligned tuples_only=on)
+SELECT $1 \bind 1 \gx
+SELECT $1 \bind 1 \gx (format=unaligned tuples_only=on)
\reset
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
\endpipeline
-- \g and \gx warnings should be emitted in an aborted pipeline, with
-- pipeline still usable.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind \sendpipeline
+SELECT $1 \bind \sendpipeline
\flushrequest
\getresults
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \g
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \gx
+SELECT $1 \bind 1 \g
+SELECT $1 \bind 1 \gx
\endpipeline
-- \sendpipeline is not allowed outside of a pipeline
\sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
\reset
-- \sendpipeline is not allowed if not preceded by \bind or \bind_named
\startpipeline
\sendpipeline
--- Deactivated for SplendidDataTest: SELECT 1 \sendpipeline
+SELECT 1 \sendpipeline
\endpipeline
-- \gexec is not allowed, pipeline should still be usable.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT 'INSERT INTO psql_pipeline(a) SELECT generate_series(1, 10)' \parse 'insert_stmt'
+SELECT 'INSERT INTO psql_pipeline(a) SELECT generate_series(1, 10)' \parse 'insert_stmt'
\bind_named insert_stmt \gexec
\bind_named insert_stmt \sendpipeline
--- Deactivated for SplendidDataTest: SELECT COUNT(*) FROM psql_pipeline \bind \sendpipeline
+SELECT COUNT(*) FROM psql_pipeline \bind \sendpipeline
\endpipeline
-- After an error, pipeline is aborted and requires \syncpipeline to be
-- reusable.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \parse a
+SELECT $1 \bind \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \parse a
\bind_named a 1 \sendpipeline
\close_prepared a
\flushrequest
\getresults
-- Pipeline is aborted.
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \parse a
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \parse a
\bind_named a 1 \sendpipeline
\close_prepared a
-- Sync allows pipeline to recover.
\syncpipeline
\getresults
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \parse a
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \parse a
\bind_named a 1 \sendpipeline
\close_prepared a
\flushrequest
@@ -334,9 +333,9 @@ ROLLBACK;
-- In an aborted pipeline, \getresults 1 aborts commands one at a time.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \parse a
+SELECT $1 \bind \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+SELECT $1 \parse a
\bind_named a 1 \sendpipeline
\syncpipeline
\getresults 1
@@ -349,10 +348,10 @@ ROLLBACK;
-- Test chunked results with an aborted pipeline.
\startpipeline
\set FETCH_COUNT 10
--- Deactivated for SplendidDataTest: SELECT $1 \bind \sendpipeline
+SELECT $1 \bind \sendpipeline
\flushrequest
\getresults
--- Deactivated for SplendidDataTest: SELECT $1 \bind \sendpipeline
+SELECT $1 \bind \sendpipeline
\endpipeline
\unset FETCH_COUNT
@@ -368,7 +367,7 @@ select 1;
-- Error messages accumulate and are repeated.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT 1 \bind \sendpipeline
+SELECT 1 \bind \sendpipeline
\gdesc
\gdesc
\endpipeline
@@ -383,67 +382,134 @@ select 1;
-- commit the implicit transaction block. The first command after a
-- sync will not be seen as belonging to a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SET LOCAL statement_timeout='1h' \bind \sendpipeline
--- Deactivated for SplendidDataTest: SHOW statement_timeout \bind \sendpipeline
+SET LOCAL statement_timeout='1h' \bind \sendpipeline
+SHOW statement_timeout \bind \sendpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: SHOW statement_timeout \bind \sendpipeline
--- Deactivated for SplendidDataTest: SET LOCAL statement_timeout='2h' \bind \sendpipeline
--- Deactivated for SplendidDataTest: SHOW statement_timeout \bind \sendpipeline
+SHOW statement_timeout \bind \sendpipeline
+SET LOCAL statement_timeout='2h' \bind \sendpipeline
+SHOW statement_timeout \bind \sendpipeline
\endpipeline
-- REINDEX CONCURRENTLY fails if not the first command in a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\endpipeline
-- REINDEX CONCURRENTLY works if it is the first command in a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+REINDEX TABLE CONCURRENTLY psql_pipeline \bind \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\endpipeline
-- Subtransactions are not allowed in a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SAVEPOINT a \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: ROLLBACK TO SAVEPOINT a \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SAVEPOINT a \bind \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+ROLLBACK TO SAVEPOINT a \bind \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\endpipeline
-- LOCK fails as the first command in a pipeline, as not seen in an
-- implicit transaction block.
\startpipeline
--- Deactivated for SplendidDataTest: LOCK psql_pipeline \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+LOCK psql_pipeline \bind \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\endpipeline
-- LOCK succeeds as it is not the first command in a pipeline,
-- seen in an implicit transaction block.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 1 \sendpipeline
--- Deactivated for SplendidDataTest: LOCK psql_pipeline \bind \sendpipeline
--- Deactivated for SplendidDataTest: SELECT $1 \bind 2 \sendpipeline
+SELECT $1 \bind 1 \sendpipeline
+LOCK psql_pipeline \bind \sendpipeline
+SELECT $1 \bind 2 \sendpipeline
\endpipeline
-- VACUUM works as the first command in a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: VACUUM psql_pipeline \bind \sendpipeline
+VACUUM psql_pipeline \bind \sendpipeline
\endpipeline
-- VACUUM fails when not the first command in a pipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT 1 \bind \sendpipeline
--- Deactivated for SplendidDataTest: VACUUM psql_pipeline \bind \sendpipeline
+SELECT 1 \bind \sendpipeline
+VACUUM psql_pipeline \bind \sendpipeline
\endpipeline
-- VACUUM works after a \syncpipeline.
\startpipeline
--- Deactivated for SplendidDataTest: SELECT 1 \bind \sendpipeline
+SELECT 1 \bind \sendpipeline
+\syncpipeline
+VACUUM psql_pipeline \bind \sendpipeline
+\endpipeline
+
+-- Deferred constraint violation at commit time in a pipeline.
+CREATE TABLE psql_pipeline_defer (a INTEGER PRIMARY KEY DEFERRABLE INITIALLY DEFERRED);
+\startpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) RETURNING * \bind 1 \sendpipeline
+\endpipeline
+
+-- Same with \syncpipeline and commands after the failing sync.
+\startpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
\syncpipeline
--- Deactivated for SplendidDataTest: VACUUM psql_pipeline \bind \sendpipeline
+SELECT $1 \bind 'after_sync_1' \sendpipeline
\endpipeline
+-- More patterns with more \syncpipeline, more commands and \getresults
+\startpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+\syncpipeline
+SELECT $1 \bind 'after_sync_1' \sendpipeline
+\getresults
+SELECT $1 \bind 'after_sync_2' \sendpipeline
+\endpipeline
+\startpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+\syncpipeline
+\getresults
+SELECT $1 \bind 'after_sync_1' \sendpipeline
+\getresults
+SELECT $1 \bind 'after_sync_2' \sendpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+SELECT $1 \bind 'after_sync_3' \sendpipeline
+SELECT $1 \bind 'after_sync_4' \sendpipeline
+SELECT $1 \bind 'after_sync_5' \sendpipeline
+\endpipeline
+
+-- Deferred error combined with a regular command error after the sync.
+\startpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+\syncpipeline
+SELECT $1 \bind \sendpipeline
+SELECT $1 \bind 'after_error' \sendpipeline
+\endpipeline
+
+-- Empty sync segment followed by a deferred error.
+\startpipeline
+\syncpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+\endpipeline
+
+-- Deferred error with \getresults reading results one at a time.
+\startpipeline
+INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline
+SELECT $1 \bind 'partial' \sendpipeline
+\syncpipeline
+\getresults 1
+\getresults 1
+\getresults
+\endpipeline
+
+DROP TABLE psql_pipeline_defer;
+
-- Clean up
DROP TABLE psql_pipeline;
+
+*
+*/
+select 1;
\ No newline at end of file
diff --git a/parser/src/test/resources/postgres/test/regress/sql/returning.sql b/parser/src/test/resources/postgres/test/regress/sql/returning.sql
index b60c5b2..9ddaad6 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/returning.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/returning.sql
@@ -250,6 +250,17 @@ DELETE FROM foo WHERE f1 = 5
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
+-- Parenthesized OLD and NEW
+INSERT INTO foo VALUES (6, 'paren-test', 60, 600)
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+UPDATE foo SET f4 = 700 WHERE f1 = 6
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+DELETE FROM foo WHERE f1 = 6
+ RETURNING old, (old).f4, (old).*,
+ new, (new).f4, (new).*;
+
-- RETURNING OLD and NEW from subquery
EXPLAIN (verbose, costs off)
INSERT INTO foo VALUES (5, 'subquery test')
diff --git a/parser/src/test/resources/postgres/test/regress/sql/sqljson.sql b/parser/src/test/resources/postgres/test/regress/sql/sqljson.sql
index 2cd327e..0ed94ae 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/sqljson.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/sqljson.sql
@@ -403,6 +403,28 @@ SELECT NULL::text IS JSON;
SELECT NULL::bytea IS JSON;
SELECT NULL::int IS JSON;
+-- A user-defined string-category type with no implicit cast to text must
+-- produce a clean error rather than crash for IS JSON / JSON() input
+-- (per bug #19491).
+CREATE FUNCTION sqljson_mystr_in(cstring) RETURNS sqljson_mystr
+ AS 'textin' LANGUAGE internal IMMUTABLE STRICT;
+CREATE FUNCTION sqljson_mystr_out(sqljson_mystr) RETURNS cstring
+ AS 'textout' LANGUAGE internal IMMUTABLE STRICT;
+CREATE TYPE sqljson_mystr (
+ INPUT = sqljson_mystr_in,
+ OUTPUT = sqljson_mystr_out,
+ LIKE = text,
+ CATEGORY = 'S'
+);
+SELECT '{"a":1}'::sqljson_mystr IS JSON; -- error
+SELECT JSON('{"a":1}'::sqljson_mystr WITH UNIQUE KEYS); -- error
+-- An implicit cast to text lets the same query work normally.
+CREATE CAST (sqljson_mystr AS text) WITHOUT FUNCTION AS IMPLICIT;
+SELECT '{"a":1}'::sqljson_mystr IS JSON;
+\set VERBOSITY terse
+DROP TYPE sqljson_mystr CASCADE;
+\set VERBOSITY default
+
SELECT '' IS JSON;
SELECT bytea '\x00' IS JSON;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/sqljson_queryfuncs.sql b/parser/src/test/resources/postgres/test/regress/sql/sqljson_queryfuncs.sql
index 8d7b225..a5d5e25 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/sqljson_queryfuncs.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/sqljson_queryfuncs.sql
@@ -450,6 +450,7 @@ SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'a');
SELECT JSON_VALUE(jsonb '{"a": 123}', '$' || '.' || 'b' DEFAULT 'foo' ON EMPTY);
SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a');
SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
+SELECT JSON_QUERY(jsonb '{"a": 123}', ('$' || '.' || 'a' || NULL)::date WITH WRAPPER);
-- Should fail (invalid path)
SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
@@ -460,6 +461,7 @@ SELECT JSON_QUERY(NULL FORMAT JSON, '$');
-- Test non-const jsonpath
CREATE TEMP TABLE jsonpaths (path) AS SELECT '$';
SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
+SELECT json_value('"aaa"', jsonpaths RETURNING json) FROM jsonpaths;
-- Test PASSING argument parsing
SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
diff --git a/parser/src/test/resources/postgres/test/regress/sql/stats.sql b/parser/src/test/resources/postgres/test/regress/sql/stats.sql
index b42d89c..3ee14db 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/stats.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/stats.sql
@@ -410,9 +410,17 @@ COMMIT;
-- check that the stats are reset.
SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables
WHERE relid = 'pg_shdescription'::regclass;
+-- stats_reset may not be set for datid=0 and shared objects in
+-- pg_stat_database, so reset once.
SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass);
SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables
WHERE relid = 'pg_shdescription'::regclass;
+SELECT stats_reset AS shared_db_reset_before
+ FROM pg_stat_database WHERE datid = 0 \gset
+-- Second reset for comparison.
+SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass);
+SELECT stats_reset > :'shared_db_reset_before'::timestamptz AS has_updated
+ FROM pg_stat_database WHERE datid = 0;
-- set back comment
\if :{?description_before}
diff --git a/parser/src/test/resources/postgres/test/regress/sql/stats_ext.sql b/parser/src/test/resources/postgres/test/regress/sql/stats_ext.sql
index 6b98b75..9dc1903 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/stats_ext.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/stats_ext.sql
@@ -91,6 +91,14 @@ DROP STATISTICS ab1_a_b_stats;
ALTER STATISTICS ab1_a_b_stats RENAME TO ab1_a_b_stats_new;
RESET SESSION AUTHORIZATION;
DROP ROLE regress_stats_ext;
+CREATE STATISTICS pg_temp.stats_ext_temp ON a, b FROM ab1;
+SELECT regexp_replace(pg_describe_object(tableoid, oid, 0),
+ 'pg_temp_[0-9]*', 'pg_temp_REDACTED') AS descr,
+ pg_statistics_obj_is_visible(oid) AS visible
+ FROM pg_statistic_ext
+ WHERE stxname = 'stats_ext_temp';
+DROP STATISTICS stats_ext_temp; -- shall fail
+DROP STATISTICS pg_temp.stats_ext_temp;
CREATE STATISTICS IF NOT EXISTS ab1_a_b_stats ON a, b FROM ab1;
DROP STATISTICS ab1_a_b_stats;
@@ -1759,6 +1767,39 @@ SELECT statistics_name, most_common_vals FROM pg_stats_ext x
SELECT statistics_name, most_common_vals FROM pg_stats_ext_exprs x
WHERE tablename = 'stats_ext_tbl' ORDER BY ROW(x.*);
+-- CREATE STATISTICS checks for CREATE on the schema
+RESET SESSION AUTHORIZATION;
+CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT, c INT GENERATED ALWAYS AS (b * 2) STORED);
+CREATE SCHEMA sts_sch2;
+GRANT USAGE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1;
+ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1;
+SET SESSION AUTHORIZATION regress_stats_user1;
+CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
+CREATE STATISTICS sts_sch2.fail ON a, b, c FROM sts_sch1.tbl;
+RESET SESSION AUTHORIZATION;
+GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1;
+SET SESSION AUTHORIZATION regress_stats_user1;
+CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
+CREATE STATISTICS sts_sch2.fail ON a, b, c FROM sts_sch1.tbl;
+RESET SESSION AUTHORIZATION;
+REVOKE CREATE ON SCHEMA sts_sch1 FROM regress_stats_user1;
+GRANT CREATE ON SCHEMA sts_sch2 TO regress_stats_user1;
+SET SESSION AUTHORIZATION regress_stats_user1;
+CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
+CREATE STATISTICS sts_sch2.pass1 ON a, b, c FROM sts_sch1.tbl;
+RESET SESSION AUTHORIZATION;
+GRANT CREATE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1;
+SET SESSION AUTHORIZATION regress_stats_user1;
+CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
+CREATE STATISTICS sts_sch2.pass2 ON a, b, c FROM sts_sch1.tbl;
+
+-- re-creating statistics via ALTER TABLE bypasses checks for CREATE on schema
+RESET SESSION AUTHORIZATION;
+REVOKE CREATE ON SCHEMA sts_sch1, sts_sch2 FROM regress_stats_user1;
+SET SESSION AUTHORIZATION regress_stats_user1;
+ALTER TABLE sts_sch1.tbl ALTER COLUMN a TYPE SMALLINT;
+ALTER TABLE sts_sch1.tbl ALTER COLUMN c SET EXPRESSION AS (a * 3);
+
-- Tidy up
DROP OPERATOR <<< (int, int);
DROP FUNCTION op_leak(int, int);
@@ -1767,6 +1808,7 @@ DROP FUNCTION op_leak(record, record);
RESET SESSION AUTHORIZATION;
DROP TABLE stats_ext_tbl;
DROP SCHEMA tststats CASCADE;
+DROP SCHEMA sts_sch1, sts_sch2 CASCADE;
DROP USER regress_stats_user1;
CREATE TABLE grouping_unique (x integer);
diff --git a/parser/src/test/resources/postgres/test/regress/sql/stats_import.sql b/parser/src/test/resources/postgres/test/regress/sql/stats_import.sql
index d140733..ee97fa6 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/stats_import.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/stats_import.sql
@@ -457,6 +457,60 @@ AND tablename = 'test'
AND inherited = false
AND attname = 'id';
+-- warn: mcv / mcf array length mismatch (more vals), mcv-pair fails, rest get set
+SELECT pg_catalog.pg_restore_attribute_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'attname', 'id',
+ 'inherited', false::boolean,
+ 'null_frac', 0.24::real,
+ 'most_common_vals', '{2,1,3}'::text,
+ 'most_common_freqs', '{0.3,0.25}'::real[]
+ );
+
+SELECT *
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND inherited = false
+AND attname = 'id';
+
+-- warn: mcv / mcf array length mismatch (more freqs), mcv-pair fails, rest get set
+SELECT pg_catalog.pg_restore_attribute_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'attname', 'id',
+ 'inherited', false::boolean,
+ 'null_frac', 0.25::real,
+ 'most_common_vals', '{2,1}'::text,
+ 'most_common_freqs', '{0.3,0.25,0.05}'::real[]
+ );
+
+SELECT *
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND inherited = false
+AND attname = 'id';
+
+-- warn: most_common_vals is multi-dimensional, mcv-pair fails, rest get set
+SELECT pg_catalog.pg_restore_attribute_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'attname', 'id',
+ 'inherited', false::boolean,
+ 'null_frac', 0.26::real,
+ 'most_common_vals', '{{2,1},{3,4}}'::text,
+ 'most_common_freqs', '{0.3,0.25,0.05,0.04}'::real[]
+ );
+
+SELECT *
+FROM pg_stats
+WHERE schemaname = 'stats_import'
+AND tablename = 'test'
+AND inherited = false
+AND attname = 'id';
+
-- ok: mcv+mcf
SELECT pg_catalog.pg_restore_attribute_stats(
'schemaname', 'stats_import',
diff --git a/parser/src/test/resources/postgres/test/regress/sql/subselect.sql b/parser/src/test/resources/postgres/test/regress/sql/subselect.sql
index cbb3485..42e4221 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/subselect.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/subselect.sql
@@ -347,6 +347,17 @@ select * from (
where not exists (select 1 from tenk1 as b where b.unique2 = 10000)
) ss;
+
+--
+-- Test cases for interactions between PARAM_EXEC, subplans and array
+-- subscripts
+--
+
+-- check that array subscription doesn't conflict with PARAM_EXEC (see #19370)
+SELECT (array[1,2])[(SELECT g.i)] FROM generate_series(1, 1) g(i);
+SELECT (array[1,2])[(SELECT g.i):(SELECT g.i + 1)] FROM generate_series(1, 1) g(i);
+
+
--
-- Test that an IN implemented using a UniquePath does unique-ification
-- with the right semantics, as per bug #4113. (Unfortunately we have
@@ -879,6 +890,46 @@ select * from
(select 9 as x, unnest(array[1,2,3,11,12,13]) as u) ss
where tattle(x, u);
+--
+-- check that an upper-level qual is not pushed down if it references a grouped
+-- Var whose underlying expression contains SRFs
+--
+explain (verbose, costs off)
+select * from
+ (select generate_series(1, ten) as g, count(*) from tenk1 group by 1) ss
+ where ss.g = 1;
+
+select * from
+ (select generate_series(1, ten) as g, count(*) from tenk1 group by 1) ss
+ where ss.g = 1;
+
+--
+-- check that an upper-level qual is not pushed down if it references a grouped
+-- Var whose underlying expression contains volatile functions
+--
+alter function tattle(x int, y int) volatile;
+
+explain (verbose, costs off)
+select * from
+ (select tattle(3, ten) as v, count(*) from tenk1 where unique1 < 3 group by 1) ss
+ where ss.v;
+
+select * from
+ (select tattle(3, ten) as v, count(*) from tenk1 where unique1 < 3 group by 1) ss
+ where ss.v;
+
+-- if we pretend it's stable, we get different results:
+alter function tattle(x int, y int) stable;
+
+explain (verbose, costs off)
+select * from
+ (select tattle(3, ten) as v, count(*) from tenk1 where unique1 < 3 group by 1) ss
+ where ss.v;
+
+select * from
+ (select tattle(3, ten) as v, count(*) from tenk1 where unique1 < 3 group by 1) ss
+ where ss.v;
+
drop function tattle(x int, y int);
--
diff --git a/parser/src/test/resources/postgres/test/regress/sql/triggers.sql b/parser/src/test/resources/postgres/test/regress/sql/triggers.sql
index 1e58bc3..c8f7ba8 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/triggers.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/triggers.sql
@@ -2223,6 +2223,10 @@ with wcte as (insert into table1 values (42))
with wcte as (insert into table1 values (43))
insert into table1 values (44);
+with wcte as (insert into table1 values (45))
+ merge into table1 using (values (46)) as v(a) on table1.a = v.a
+ when not matched then insert values (v.a);
+
select * from table1;
select * from table2;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/tsearch.sql b/parser/src/test/resources/postgres/test/regress/sql/tsearch.sql
index 8f03cc6..d570557 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/tsearch.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/tsearch.sql
@@ -230,6 +230,7 @@ RESET enable_bitmapscan;
DROP INDEX wowidx;
+ALTER TABLE test_tsvector SET (parallel_workers = 2);
CREATE INDEX wowidx ON test_tsvector USING gin (a);
SET enable_seqscan=OFF;
@@ -654,6 +655,14 @@ SELECT ts_headline('english',
SELECT ts_headline('english',
'foo bar', to_tsquery('english', ''));
+-- Test for large values of StartSel, StopSel and FragmentDelimiter
+SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'),
+ 'StartSel=' || repeat('x', 32768));
+SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'),
+ 'StopSel=' || repeat('x', 32768));
+SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'),
+ 'FragmentDelimiter=' || repeat('x', 32768));
+
--Rewrite sub system
CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT);
diff --git a/parser/src/test/resources/postgres/test/regress/sql/unicode.sql b/parser/src/test/resources/postgres/test/regress/sql/unicode.sql
index 5fc0386..19135ea 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/unicode.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/unicode.sql
@@ -44,3 +44,23 @@ FROM
ORDER BY num;
SELECT is_normalized('abc', 'def'); -- run-time error
+
+-- Hangul NFC recomposition tests
+-- L+V -> LV composition (first and last)
+SELECT normalize(U&'\1100\1161', NFC) = U&'\AC00' COLLATE "C" AS hangul_lv_first;
+SELECT normalize(U&'\1112\1175', NFC) = U&'\D788' COLLATE "C" AS hangul_lv_last;
+-- LV+T -> LVT composition
+SELECT normalize(U&'\AC00\11A8', NFC) = U&'\AC01' COLLATE "C" AS hangul_lvt_first_t;
+SELECT normalize(U&'\AC00\11C2', NFC) = U&'\AC1B' COLLATE "C" AS hangul_lvt_last_t;
+SELECT normalize(U&'\D788\11A8', NFC) = U&'\D789' COLLATE "C" AS hangul_lvt_last_lv;
+-- L+V+T -> LVT composition
+SELECT normalize(U&'\1100\1161\11A8', NFC) = U&'\AC01' COLLATE "C" AS hangul_full_lvt;
+SELECT normalize(U&'\1112\1175\11C2', NFC) = U&'\D7A3' COLLATE "C" AS hangul_full_lvt;
+-- TBASE invalid T syllable
+SELECT normalize(U&'\AC00\11A7', NFC) = U&'\AC00\11A7' COLLATE "C" AS hangul_tbase_not_combined;
+SELECT normalize(U&'\1100\1161\11A7', NFC) = U&'\AC00\11A7' COLLATE "C" AS hangul_lv_tbase_separate;
+
+-- Hangul NFD decomposition tests
+SELECT normalize(U&'\AC00', NFD) = U&'\1100\1161' COLLATE "C" AS hangul_nfd_lv;
+SELECT normalize(U&'\AC01', NFD) = U&'\1100\1161\11A8' COLLATE "C" AS hangul_nfd_lvt;
+SELECT normalize(U&'\D7A3', NFD) = U&'\1112\1175\11C2' COLLATE "C" AS hangul_nfd_last;
diff --git a/parser/src/test/resources/postgres/test/regress/sql/union.sql b/parser/src/test/resources/postgres/test/regress/sql/union.sql
index 13700a6..bc50bc4 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/union.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/union.sql
@@ -592,3 +592,7 @@ select * from tenk1 t1
left join lateral
(select t1.tenthous from tenk2 t2 union all (values(1)))
on true limit 1;
+
+-- Test handling of Vars with varno 0 in estimate_array_length
+explain (verbose, costs off)
+select null::int[] union all select null::int[] union all select null::bigint[];
diff --git a/parser/src/test/resources/postgres/test/regress/sql/window.sql b/parser/src/test/resources/postgres/test/regress/sql/window.sql
index 62df09d..cafec98 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/window.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/window.sql
@@ -338,6 +338,32 @@ CREATE TEMP VIEW v_window AS
SELECT pg_get_viewdef('v_window');
+-- test overflow frame specifications
+SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+-- These test GROUPS mode with an offset large enough to cause overflow when
+-- added to currentgroup. Although the overflow doesn't produce visibly wrong
+-- results (due to the incremental nature of group pointer advancement), we
+-- still need to protect against it as signed integer overflow is undefined
+-- behavior in C.
+SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
+SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following),
+ unique1, four
+FROM tenk1 WHERE unique1 < 10;
+
-- RANGE offset PRECEDING/FOLLOWING tests
SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding),
diff --git a/parser/src/test/resources/postgres/test/regress/sql/with.sql b/parser/src/test/resources/postgres/test/regress/sql/with.sql
index 26079e7..b1521f6 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/with.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/with.sql
@@ -1108,16 +1108,26 @@ from int4_tbl;
--
-- test for bug #19055: interaction of WITH with aggregates
--
--- The reference to cte1 must determine the aggregate's level,
--- even though it contains no Vars referencing cte1
-explain (verbose, costs off)
+-- For now, we just throw an error if there's a use of a CTE below the
+-- semantic level that the SQL standard assigns to the aggregate.
+-- It's not entirely clear what we could do instead that doesn't risk
+-- breaking more things than it fixes.
select f1, (with cte1(x,y) as (select 1,2)
select count((select i4.f1 from cte1))) as ss
from int4_tbl i4;
-select f1, (with cte1(x,y) as (select 1,2)
- select count((select i4.f1 from cte1))) as ss
-from int4_tbl i4;
+--
+-- test for bug #19106: interaction of WITH with aggregates
+--
+-- the initial fix for #19055 was too aggressive and broke this case
+explain (verbose, costs off)
+with a as ( select id from (values (1), (2)) as v(id) ),
+ b as ( select max((select sum(id) from a)) as agg )
+select agg from b;
+
+with a as ( select id from (values (1), (2)) as v(id) ),
+ b as ( select max((select sum(id) from a)) as agg )
+select agg from b;
--
-- test for nested-recursive-WITH bug
@@ -1358,6 +1368,29 @@ COMMIT;
SELECT * FROM bug6051_3;
+-- check that recursive CTE processing doesn't rewrite a CTE more than once
+-- (must not try to expand GENERATED ALWAYS IDENTITY columns more than once)
+CREATE TEMP TABLE id_alw1 (i int GENERATED ALWAYS AS IDENTITY);
+
+CREATE TEMP TABLE id_alw2 (i int GENERATED ALWAYS AS IDENTITY);
+CREATE TEMP VIEW id_alw2_view AS SELECT * FROM id_alw2;
+
+CREATE TEMP TABLE id_alw3 (i int GENERATED ALWAYS AS IDENTITY);
+CREATE RULE id_alw3_ins AS ON INSERT TO id_alw3 DO INSTEAD
+ WITH t1 AS (INSERT INTO id_alw1 DEFAULT VALUES RETURNING i)
+ INSERT INTO id_alw2_view DEFAULT VALUES RETURNING i;
+CREATE TEMP VIEW id_alw3_view AS SELECT * FROM id_alw3;
+
+CREATE TEMP TABLE id_alw4 (i int GENERATED ALWAYS AS IDENTITY);
+
+WITH t4 AS (INSERT INTO id_alw4 DEFAULT VALUES RETURNING i)
+ INSERT INTO id_alw3_view DEFAULT VALUES RETURNING i;
+
+SELECT * from id_alw1;
+SELECT * from id_alw2;
+SELECT * from id_alw3;
+SELECT * from id_alw4;
+
-- check case where CTE reference is removed due to optimization
EXPLAIN (VERBOSE, COSTS OFF)
SELECT q1 FROM
diff --git a/parser/src/test/resources/postgres/test/regress/sql/without_overlaps.sql b/parser/src/test/resources/postgres/test/regress/sql/without_overlaps.sql
index 4aaca24..430f5bf 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/without_overlaps.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/without_overlaps.sql
@@ -180,6 +180,37 @@ ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_uq;
DROP TABLE temporal_rng3;
DROP TYPE textrange2;
+--
+-- test PRIMARY KEY and UNIQUE constraints' interaction with domains
+--
+
+-- range over domain:
+CREATE DOMAIN int4_d as integer check (value <> 10);
+CREATE TYPE int4_d_range as range (subtype = int4_d);
+CREATE TABLE temporal_rng4 (
+ id int4range,
+ valid_at int4_d_range,
+ CONSTRAINT temporal_rng4_pk PRIMARY KEY(id, valid_at WITHOUT OVERLAPS)
+);
+INSERT INTO temporal_rng4 VALUES ('[1,11)', '[9,10)'); -- start bound violates domain
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); -- end bound violates domain
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[2,5)'); -- overlaps
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[20,23)'); -- okay
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[30,)'); -- null bound is okay
+DROP TABLE temporal_rng4;
+
+-- domain over range:
+CREATE DOMAIN int4range_d AS int4range CHECK (VALUE <> '[10,11)');
+CREATE TABLE temporal_rng4 (
+ id int4range,
+ valid_at int4range_d,
+ CONSTRAINT temporal_rng4_pk UNIQUE (id, valid_at WITHOUT OVERLAPS)
+);
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); -- violates domain
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[2,13)'); -- overlaps
+INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[20,23)'); -- okay
+DROP TABLE temporal_rng4;
+
--
-- test ALTER TABLE ADD CONSTRAINT
--
diff --git a/parser/src/test/resources/postgres/test/regress/sql/xml.sql b/parser/src/test/resources/postgres/test/regress/sql/xml.sql
index 931ec78..f8cdaf3 100644
--- a/parser/src/test/resources/postgres/test/regress/sql/xml.sql
+++ b/parser/src/test/resources/postgres/test/regress/sql/xml.sql
@@ -13,7 +13,14 @@ CREATE TABLE xmltest (
INSERT INTO xmltest VALUES (1, 'one');
INSERT INTO xmltest VALUES (2, 'two');
-INSERT INTO xmltest VALUES (3, 'three ');
+
+-- If no XML data could be inserted, skip the tests as the server has been
+-- compiled without libxml support.
+SELECT count(*) = 0 AS skip_test FROM xmltest \gset
+\if :skip_test
+\quit
+\endif
SELECT * FROM xmltest;
@@ -38,7 +45,7 @@ SELECT xmlconcat(xmlcomment('hello'),
SELECT xmlconcat('hello', 'you');
SELECT xmlconcat(1, 2);
-SELECT xmlconcat('bad', ' ');
SELECT xmlconcat('', NULL, '');
SELECT xmlconcat('', NULL, '');
SELECT xmlconcat(NULL);
@@ -83,17 +90,17 @@ SELECT xmlparse(content '&');
SELECT xmlparse(content '&idontexist;');
SELECT xmlparse(content '');
SELECT xmlparse(content '');
-SELECT xmlparse(content '&idontexist;');
+SELECT xmlparse(content '&idontexist; ');
SELECT xmlparse(content '');
-SELECT xmlparse(document ' ');
+SELECT xmlparse(document '!');
SELECT xmlparse(document 'abc');
SELECT xmlparse(document 'x');
-SELECT xmlparse(document '&');
-SELECT xmlparse(document '&idontexist;');
+SELECT xmlparse(document '& ');
+SELECT xmlparse(document '&idontexist; ');
SELECT xmlparse(document '');
SELECT xmlparse(document '');
-SELECT xmlparse(document '&idontexist;');
+SELECT xmlparse(document '&idontexist; ');
SELECT xmlparse(document '');
@@ -252,6 +259,7 @@ SELECT xpath('count(//*)=3', '');
SELECT xpath('name(/*)', '');
SELECT xpath('/nosuchtag', '');
SELECT xpath('root', '');
+SELECT xpath('//namespace::foo', '');
-- Round-trip non-ASCII data through xpath().
DO $$
diff --git a/pom.xml b/pom.xml
index 28e874a..5f8c556 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.splendiddata
pg_sqlparser
- 18.1
+ 18.2
pom
pg_sqlparser
Java implementation of the Postgres sql parser. This version of
@@ -42,9 +42,9 @@
${java.version}
UTF-8
file:**/generated-sources/**
- 2.25.2
- 21.0.8
- 5.13.4
+ 2.26.0
+ 21.0.11
+ 6.1.0
3.9.1
2.8
@@ -95,40 +95,40 @@
org.apache.maven
maven-plugin-api
- 3.9.11
+ 3.9.16
org.apache.maven.plugin-tools
maven-plugin-annotations
- 3.15.1
+ 3.15.2
provided
org.apache.maven.plugin-tools
maven-plugin-tools-api
- 3.15.1
+ 3.15.2
org.apache.maven
maven-core
- 3.9.11
+ 3.9.16
com.github.javaparser
javaparser-core
- 3.27.0
+ 3.28.2
jakarta.xml.bind
jakarta.xml.bind-api
- 4.0.4
+ 4.0.5
org.glassfish.jaxb
jaxb-runtime
- 4.0.6
+ 4.0.9
@@ -159,18 +159,18 @@
org.checkerframework
checker-qual
- 3.51.0
+ 4.2.0
org.apache.maven
maven-model
- 3.9.11
+ 3.9.16
provided
org.apache.maven
maven-artifact
- 3.9.11
+ 3.9.16
provided
@@ -187,7 +187,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.14.1
+ 3.15.0
${java.version}
@@ -198,12 +198,12 @@
org.apache.maven.plugins
maven-antrun-plugin
- 3.1.0
+ 3.2.0
org.codehaus.mojo
exec-maven-plugin
- 3.5.1
+ 3.6.3
org.codehaus.mojo
@@ -218,12 +218,12 @@
org.apache.maven.plugins
maven-dependency-plugin
- 3.8.1
+ 3.11.0
org.apache.maven.plugins
maven-jar-plugin
- 3.4.2
+ 3.5.0
org.openjfx
@@ -233,17 +233,17 @@
org.jacoco
jacoco-maven-plugin
- 0.8.13
+ 0.8.15
org.apache.maven.plugins
maven-plugin-plugin
- 3.15.1
+ 3.15.2
org.apache.maven.plugins
maven-site-plugin
- 3.21.0
+ 3.22.0
org.apache.maven.plugins
@@ -253,7 +253,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.5.4
+ 3.5.6
org.apache.maven.plugins
@@ -276,12 +276,12 @@
org.apache.maven.plugins
maven-resources-plugin
- 3.3.1
+ 3.5.0
org.apache.maven.plugins
maven-enforcer-plugin
- 3.6.1
+ 3.6.3
@@ -339,7 +339,7 @@
org.apache.maven.plugins
maven-source-plugin
- 3.3.1
+ 3.4.0
attach-sources
@@ -393,7 +393,7 @@
org.apache.maven.plugins
maven-surefire-report-plugin
- 3.5.4
+ 3.5.6