diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterForeignDataWrapper.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterForeignDataWrapper.java index 2da15e6ac..6a327e93c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterForeignDataWrapper.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterForeignDataWrapper.java @@ -16,12 +16,8 @@ import net.sf.jsqlparser.statement.create.fdw.ForeignDataWrapperFunctions; public class AlterForeignDataWrapper extends ForeignDataStatement { - public enum Action { - OPTIONS, OWNER, RENAME - } - private String name; - private Action action = Action.OPTIONS; + private ForeignObjectAlterAction action = ForeignObjectAlterAction.OPTIONS; private String newName; private String owner; private ForeignDataWrapperFunctions functions = new ForeignDataWrapperFunctions(); @@ -34,11 +30,11 @@ public void setName(String value) { name = value; } - public Action getAction() { + public ForeignObjectAlterAction getAction() { return action; } - public void setAction(Action value) { + public void setAction(ForeignObjectAlterAction value) { action = value; } @@ -93,7 +89,7 @@ public StringBuilder appendTo(StringBuilder sql, Consumer printer) { @Override public void visitExpressions(Consumer visitor) { - if (action == Action.OPTIONS) { + if (action == ForeignObjectAlterAction.OPTIONS) { super.visitExpressions(visitor); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterServer.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterServer.java index 55b5f0411..509496790 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterServer.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterServer.java @@ -15,12 +15,8 @@ import net.sf.jsqlparser.statement.foreign.ForeignDataStatement; public class AlterServer extends ForeignDataStatement { - public enum Action { - OPTIONS, OWNER, RENAME - } - private String name; - private Action action = Action.OPTIONS; + private ForeignObjectAlterAction action = ForeignObjectAlterAction.OPTIONS; private String newName; private String owner; private Expression version; @@ -33,11 +29,11 @@ public void setName(String value) { name = value; } - public Action getAction() { + public ForeignObjectAlterAction getAction() { return action; } - public void setAction(Action value) { + public void setAction(ForeignObjectAlterAction value) { action = value; } @@ -95,7 +91,7 @@ public StringBuilder appendTo(StringBuilder sql, Consumer printer) { @Override public void visitExpressions(Consumer visitor) { - if (action != Action.OPTIONS) { + if (action != ForeignObjectAlterAction.OPTIONS) { return; } super.visitExpressions(visitor); diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/ForeignObjectAlterAction.java b/src/main/java/net/sf/jsqlparser/statement/alter/ForeignObjectAlterAction.java new file mode 100644 index 000000000..64a8b023b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/ForeignObjectAlterAction.java @@ -0,0 +1,16 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +/** Shared operations for ALTER SERVER and ALTER FOREIGN DATA WRAPPER. */ +public enum ForeignObjectAlterAction { + /** Changes options and the object's server version or wrapper functions, when supplied. */ + OPTIONS, OWNER, RENAME +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/RelationAlterAction.java b/src/main/java/net/sf/jsqlparser/statement/alter/RelationAlterAction.java index d00479dc0..b8bb0f3a9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/RelationAlterAction.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/RelationAlterAction.java @@ -62,10 +62,6 @@ public enum EnableState { ENABLE, DISABLE, ENABLE_ALWAYS, ENABLE_REPLICA } - /** Compatibility names for existing trigger clients. */ - public enum TriggerState { - ENABLE, DISABLE, ENABLE_ALWAYS, ENABLE_REPLICA - } public enum TriggerTarget { NAME, ALL, USER } @@ -79,14 +75,6 @@ public void setEnableState(EnableState state) { enableState = state; } - public TriggerState getTriggerState() { - return enableState == null ? null : TriggerState.valueOf(enableState.name()); - } - - public void setTriggerState(TriggerState state) { - enableState = state == null ? null : EnableState.valueOf(state.name()); - } - public TriggerTarget getTriggerTarget() { return triggerTarget; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index c94af8730..117952c33 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -21293,9 +21293,9 @@ AlterForeignDataWrapper AlterForeignDataWrapper(): ContextualKeyword("WRAPPER") name=RelObjectName() { statement.setName(name); } ( name=RelObjectName() - { statement.setAction(AlterForeignDataWrapper.Action.RENAME); statement.setNewName(name); } + { statement.setAction(ForeignObjectAlterAction.RENAME); statement.setNewName(name); } | LOOKAHEAD({ isKeywordAhead("OWNER") }) ContextualKeyword("OWNER") name=RelObjectName() - { statement.setAction(AlterForeignDataWrapper.Action.OWNER); statement.setOwner(name); } + { statement.setAction(ForeignObjectAlterAction.OWNER); statement.setOwner(name); } | functions=ForeignDataWrapperFunctions() { statement.setFunctions(functions); } [ LOOKAHEAD({ isKeywordAhead("OPTIONS") }) options=ForeignDataOptions(true) { statement.setOptions(options); } ] { requireDdlSyntax(functions.isHandlerSpecified() || functions.isValidatorSpecified() @@ -21365,9 +21365,9 @@ AlterServer AlterServer(): ContextualKeyword("SERVER") name=RelObjectName() { statement.setName(name); } ( name=RelObjectName() - { statement.setAction(AlterServer.Action.RENAME); statement.setNewName(name); } + { statement.setAction(ForeignObjectAlterAction.RENAME); statement.setNewName(name); } | LOOKAHEAD({ isKeywordAhead("OWNER") }) ContextualKeyword("OWNER") name=RelObjectName() - { statement.setAction(AlterServer.Action.OWNER); statement.setOwner(name); } + { statement.setAction(ForeignObjectAlterAction.OWNER); statement.setOwner(name); } | [ version=ForeignServerVersion() { statement.setVersion(version); } ] [ LOOKAHEAD({ isKeywordAhead("OPTIONS") }) options=ForeignDataOptions(true) { statement.setOptions(options); } ] { requireDdlSyntax(statement.getVersion() != null || statement.getOptions() != null, diff --git a/src/site/sphinx/usage.rst b/src/site/sphinx/usage.rst index a4a8a304f..873e0a636 100644 --- a/src/site/sphinx/usage.rst +++ b/src/site/sphinx/usage.rst @@ -1269,6 +1269,51 @@ References: `CREATE ROLE `_, `CREATE TRIGGER `_. +Migrating shared ALTER enums +---------------------------- + +``AlterServer.Action`` and ``AlterForeignDataWrapper.Action`` have been replaced +by ``ForeignObjectAlterAction`` in ``net.sf.jsqlparser.statement.alter``. Both +statements' ``getAction()`` and ``setAction()`` now use this enum, with the same +``OPTIONS``, ``OWNER`` and ``RENAME`` constants. Update imports and recompile code +using these APIs; the removed nested enums are not compatibility aliases. + +.. code-block:: java + + AlterServer server = (AlterServer) CCJSqlParserUtil.parse( + "ALTER SERVER s VERSION NULL"); + server.setAction(ForeignObjectAlterAction.OWNER); + server.setOwner("CURRENT_USER"); + // ALTER SERVER s OWNER TO CURRENT_USER + + AlterForeignDataWrapper wrapper = (AlterForeignDataWrapper) CCJSqlParserUtil.parse( + "ALTER FOREIGN DATA WRAPPER w NO HANDLER"); + wrapper.setAction(ForeignObjectAlterAction.OWNER); + wrapper.setOwner("CURRENT_USER"); + // ALTER FOREIGN DATA WRAPPER w OWNER TO CURRENT_USER + +``OPTIONS`` remains the initial action. It includes server ``VERSION`` changes +and wrapper handler/validator changes as well as foreign-data options. These +payloads remain on their respective statement classes. Switching to ``OWNER`` or +``RENAME`` leaves the inactive payload available for switching back to ``OPTIONS``. + +``RelationAlterAction.TriggerState``, ``getTriggerState()`` and +``setTriggerState()`` have been removed. Use the existing +``RelationAlterAction.EnableState``, ``getEnableState()`` and ``setEnableState()`` +for both trigger and rewrite-rule actions: + +.. code-block:: java + + Alter alter = (Alter) CCJSqlParserUtil.parse( + "ALTER TABLE t ENABLE REPLICA TRIGGER trg", + parser -> parser.withDialect(Dialect.POSTGRESQL)); + RelationAlterAction trigger = (RelationAlterAction) alter.getAlterExpressions().get(0); + trigger.setEnableState(RelationAlterAction.EnableState.DISABLE); + // ALTER TABLE t DISABLE TRIGGER trg + +The action's ``Kind`` still distinguishes ``TRIGGER_STATE`` from ``RULE_STATE``. +Trigger targets also retain their ``NAME``, ``ALL`` and ``USER`` distinctions. + Oracle anonymous blocks ----------------------- diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRelationAlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRelationAlterTest.java index 06bd472d9..bc3f6ecb6 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRelationAlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRelationAlterTest.java @@ -193,8 +193,8 @@ void objectBoundariesAreEnforced(String sql) { void triggerTargetsAndTypeNamesAreMutableWithoutInventingTables() throws JSQLParserException { Alter statement = (Alter) parse("ALTER TABLE t ENABLE REPLICA TRIGGER trg"); RelationAlterAction action = (RelationAlterAction) statement.getAlterExpressions().get(0); - assertEquals(RelationAlterAction.TriggerState.ENABLE_REPLICA, action.getTriggerState()); - action.setTriggerState(RelationAlterAction.TriggerState.DISABLE); + assertEquals(RelationAlterAction.EnableState.ENABLE_REPLICA, action.getEnableState()); + action.setEnableState(RelationAlterAction.EnableState.DISABLE); action.setTriggerTarget(RelationAlterAction.TriggerTarget.USER); assertEquals("ALTER TABLE t DISABLE TRIGGER USER", statement.toString()); assertRoundTrip(statement); diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRuleStateTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRuleStateTest.java index 1a4ed148a..475a5e523 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRuleStateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/PostgreSqlRuleStateTest.java @@ -43,9 +43,20 @@ void ruleAndTriggerActionsShareStates(String state) throws JSQLParserException { p -> p.withDialect(Dialect.POSTGRESQL)); RelationAlterAction triggerAction = (RelationAlterAction) trigger.getAlterExpressions().get(0); - assertEquals(state.replace(' ', '_'), triggerAction.getTriggerState().name()); - triggerAction.setTriggerState(RelationAlterAction.TriggerState.ENABLE_ALWAYS); + assertEquals(state.replace(' ', '_'), triggerAction.getEnableState().name()); + triggerAction.setEnableState(null); + assertNull(triggerAction.getEnableState()); + assertEquals(RelationAlterAction.Kind.TRIGGER_STATE, triggerAction.getKind()); + assertEquals(RelationAlterAction.TriggerTarget.NAME, triggerAction.getTriggerTarget()); + assertEquals("trg", triggerAction.getValue()); + triggerAction.setEnableState(RelationAlterAction.EnableState.ENABLE_ALWAYS); assertEquals(RelationAlterAction.EnableState.ENABLE_ALWAYS, triggerAction.getEnableState()); + StringBuilder triggerSql = new StringBuilder(); + trigger.accept(new StatementDeParser(triggerSql)); + assertEquals("ALTER TABLE t ENABLE ALWAYS TRIGGER trg", triggerSql.toString()); + assertEquals(trigger.toString(), triggerSql.toString()); + assertEquals(triggerSql.toString(), CCJSqlParserUtil.parse(triggerSql.toString(), + p -> p.withDialect(Dialect.POSTGRESQL)).toString()); assertEquals(2, CCJSqlParserUtil.parseStatements(rule + "; SELECT 1").size()); } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/PostgreSqlForeignDataObjectsTest.java b/src/test/java/net/sf/jsqlparser/statement/create/PostgreSqlForeignDataObjectsTest.java index 772ff17da..83f2f07de 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/PostgreSqlForeignDataObjectsTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/PostgreSqlForeignDataObjectsTest.java @@ -22,6 +22,7 @@ import net.sf.jsqlparser.statement.alter.AlterForeignDataWrapper; import net.sf.jsqlparser.statement.alter.AlterServer; import net.sf.jsqlparser.statement.alter.AlterUserMapping; +import net.sf.jsqlparser.statement.alter.ForeignObjectAlterAction; import net.sf.jsqlparser.statement.create.fdw.CreateForeignDataWrapper; import net.sf.jsqlparser.statement.create.server.CreateServer; import net.sf.jsqlparser.statement.create.table.ForeignDataOption; @@ -102,7 +103,7 @@ void serverLiteralsAndOptionsAreVisitedAndMutable() throws JSQLParserException { roundTrip(create); AlterServer alter = (AlterServer) CCJSqlParserUtil.parse("ALTER SERVER s VERSION NULL"); assertInstanceOf(NullValue.class, alter.getVersion()); - alter.setAction(AlterServer.Action.RENAME); + alter.setAction(ForeignObjectAlterAction.RENAME); alter.setNewName("new_server"); visited.clear(); alter.visitExpressions(visited::add); @@ -110,6 +111,71 @@ void serverLiteralsAndOptionsAreVisitedAndMutable() throws JSQLParserException { assertEquals("ALTER SERVER s RENAME TO new_server", alter.toString()); } + @Test + void sharedActionsKeepObjectSpecificOptionsInactiveAndRestorable() throws JSQLParserException { + AlterServer server = (AlterServer) CCJSqlParserUtil.parse( + "ALTER SERVER s VERSION NULL OPTIONS(SET host 'remote')"); + AlterForeignDataWrapper wrapper = (AlterForeignDataWrapper) CCJSqlParserUtil.parse( + "ALTER FOREIGN DATA WRAPPER w NO HANDLER VALIDATOR public.validator " + + "OPTIONS(SET x 'y')"); + assertEquals(ForeignObjectAlterAction.OPTIONS, server.getAction()); + assertSame(server.getAction(), wrapper.getAction()); + String serverOptions = server.toString(); + String wrapperOptions = wrapper.toString(); + + server.setOwner("CURRENT_ROLE"); + wrapper.setOwner("CURRENT_USER"); + server.setAction(ForeignObjectAlterAction.OWNER); + wrapper.setAction(ForeignObjectAlterAction.OWNER); + assertEquals("ALTER SERVER s OWNER TO CURRENT_ROLE", server.toString()); + assertEquals("ALTER FOREIGN DATA WRAPPER w OWNER TO CURRENT_USER", wrapper.toString()); + roundTrip(server); + roundTrip(wrapper); + + server.setNewName("\"new server\""); + wrapper.setNewName("\"new wrapper\""); + server.setAction(ForeignObjectAlterAction.RENAME); + wrapper.setAction(ForeignObjectAlterAction.RENAME); + assertEquals("ALTER SERVER s RENAME TO \"new server\"", server.toString()); + assertEquals("ALTER FOREIGN DATA WRAPPER w RENAME TO \"new wrapper\"", wrapper.toString()); + roundTrip(server); + roundTrip(wrapper); + + List visited = new ArrayList<>(); + server.visitExpressions(visited::add); + wrapper.visitExpressions(visited::add); + assertTrue(visited.isEmpty()); + server.setAction(null); + wrapper.setAction(null); + assertNull(server.getAction()); + assertNull(wrapper.getAction()); + server.visitExpressions(visited::add); + wrapper.visitExpressions(visited::add); + assertTrue(visited.isEmpty()); + + server.setAction(ForeignObjectAlterAction.OPTIONS); + wrapper.setAction(ForeignObjectAlterAction.OPTIONS); + assertEquals(serverOptions, server.toString()); + assertEquals(wrapperOptions, wrapper.toString()); + server.visitExpressions(visited::add); + wrapper.visitExpressions(visited::add); + assertEquals(List.of(server.getOptions().get(0).getValue(), server.getVersion(), + wrapper.getOptions().get(0).getValue()), visited); + assertInstanceOf(NullValue.class, server.getVersion()); + assertTrue(wrapper.getFunctions().isHandlerSpecified()); + assertNull(wrapper.getFunctions().getHandler()); + roundTrip(server); + roundTrip(wrapper); + + server.setVersion(null); + wrapper.getFunctions().clearHandler(); + assertEquals("ALTER SERVER s OPTIONS (SET host 'remote')", server.toString()); + assertEquals("ALTER FOREIGN DATA WRAPPER w VALIDATOR public.validator OPTIONS (SET x 'y')", + wrapper.toString()); + roundTrip(server); + roundTrip(wrapper); + } + @Test void userMappingOptionsUseExistingForeignDataNodes() throws JSQLParserException { CreateUserMapping create = (CreateUserMapping) CCJSqlParserUtil.parse(