Hi Ahmet,

On 11/4/21 14:35, Ahmet Gedemenli wrote:
Hey,

I've noticed that the current documentation doesn't mention IF EXISTS clause for ALTER STATISTICS in the synopsis section, where PG supports it. https://www.postgresql.org/docs/14/sql-alterstatistics.html <https://www.postgresql.org/docs/14/sql-alterstatistics.html> (Only for the last item, that is ALTER STATISTICS .. SET STATISTICS; for the others, PG just throws a syntax error.)

I'm from the Citus team and noticed this while bug fixing, and I wonder if it is intentional or not. If it's intentionally supported while the other ALTER STATISTICS statement types are not supported, it would be good to mention that in the documentation.


Well, it's intentional in the sense that support for IF EXISTS in ALTER commands is rather spotty. For OWNER TO it's not supported at all, and for the other (RENAME & SET SCHEMA) it's supported only for some object types. So we added the minimum grammar and never got around to add it.

So you're right we should update the docs for the SET STATISTICS case to show it's supported in 14. I'll do that shortly.

For 15+ we could improve this to allow IF EXISTS in the other cases. For RENAME and SET SCHEMA it's fairly easy (see attached fix), for OWNER TO it's going to be more work because the AlterOwnerStmt does not have the missing_ok flag.

regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 40044070cf..801f6eddb6 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -374,6 +374,49 @@ ExecRenameStmt(RenameStmt *stmt)
 		case OBJECT_TYPE:
 			return RenameType(stmt);
 
+		case OBJECT_STATISTIC_EXT:
+			{
+				ObjectAddress address;
+				Relation	catalog;
+				Relation	relation = NULL;
+
+				address = get_object_address(stmt->renameType,
+											 stmt->object,
+											 &relation,
+											 AccessExclusiveLock,
+											 stmt->missing_ok);
+				Assert(relation == NULL);
+
+				if (OidIsValid(address.objectId))
+				{
+					catalog = table_open(address.classId, RowExclusiveLock);
+					AlterObjectRename_internal(catalog,
+											   address.objectId,
+											   stmt->newname);
+					table_close(catalog, RowExclusiveLock);
+				}
+				else
+				{
+					char	   *schemaname;
+					char	   *statname;
+
+					Assert(stmt->missing_ok);
+
+					DeconstructQualifiedName(castNode(List, stmt->object), &schemaname, &statname);
+
+					if (schemaname)
+						ereport(NOTICE,
+								(errmsg("statistics object \"%s.%s\" does not exist, skipping",
+										schemaname, statname)));
+					else
+						ereport(NOTICE,
+								(errmsg("statistics object \"%s\" does not exist, skipping",
+										statname)));
+				}
+
+				return address;
+			}
+
 		case OBJECT_AGGREGATE:
 		case OBJECT_COLLATION:
 		case OBJECT_CONVERSION:
@@ -386,7 +429,6 @@ ExecRenameStmt(RenameStmt *stmt)
 		case OBJECT_LANGUAGE:
 		case OBJECT_PROCEDURE:
 		case OBJECT_ROUTINE:
-		case OBJECT_STATISTIC_EXT:
 		case OBJECT_TSCONFIGURATION:
 		case OBJECT_TSDICTIONARY:
 		case OBJECT_TSPARSER:
@@ -521,6 +563,51 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
 										 oldSchemaAddr ? &oldNspOid : NULL);
 			break;
 
+		case OBJECT_STATISTIC_EXT:
+			{
+				Relation	catalog;
+				Relation	relation;
+				Oid			classId;
+				Oid			nspOid;
+
+				address = get_object_address(stmt->objectType,
+											 stmt->object,
+											 &relation,
+											 AccessExclusiveLock,
+											 stmt->missing_ok);
+
+				if (OidIsValid(address.objectId))
+				{
+					Assert(relation == NULL);
+					classId = address.classId;
+					catalog = table_open(classId, RowExclusiveLock);
+					nspOid = LookupCreationNamespace(stmt->newschema);
+
+					oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
+															  nspOid);
+					table_close(catalog, RowExclusiveLock);
+				}
+				else
+				{
+					char	   *schemaname;
+					char	   *statname;
+
+					Assert(stmt->missing_ok);
+
+					DeconstructQualifiedName(castNode(List, stmt->object), &schemaname, &statname);
+
+					if (schemaname)
+						ereport(NOTICE,
+								(errmsg("statistics object \"%s.%s\" does not exist, skipping",
+										schemaname, statname)));
+					else
+						ereport(NOTICE,
+								(errmsg("statistics object \"%s\" does not exist, skipping",
+										statname)));
+				}
+			}
+			break;
+
 			/* generic code path */
 		case OBJECT_AGGREGATE:
 		case OBJECT_COLLATION:
@@ -531,7 +618,6 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
 		case OBJECT_OPFAMILY:
 		case OBJECT_PROCEDURE:
 		case OBJECT_ROUTINE:
-		case OBJECT_STATISTIC_EXT:
 		case OBJECT_TSCONFIGURATION:
 		case OBJECT_TSDICTIONARY:
 		case OBJECT_TSPARSER:
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d0eb80e69c..878e9152f6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -8955,6 +8955,15 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER STATISTICS IF_P EXISTS any_name RENAME TO name
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_STATISTIC_EXT;
+					n->object = (Node *) $5;
+					n->newname = $8;
+					n->missing_ok = true;
+					$$ = (Node *)n;
+				}
 			| ALTER TEXT_P SEARCH PARSER any_name RENAME TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
@@ -9223,6 +9232,15 @@ AlterObjectSchemaStmt:
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER STATISTICS IF_P EXISTS any_name SET SCHEMA name
+				{
+					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+					n->objectType = OBJECT_STATISTIC_EXT;
+					n->object = (Node *) $5;
+					n->newschema = $8;
+					n->missing_ok = true;
+					$$ = (Node *)n;
+				}
 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
 				{
 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);

Reply via email to