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);