Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ public enum Feature {
*
* @see CreateSequence
*/
createSequence,
createSequence, createAccessMethod, createAccessMethodTable,
/** Publication and subscription definitions. */
createForeignDataWrapper, alterForeignDataWrapper, createServer, alterServer, createUserMapping, alterUserMapping,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.statement;

import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;

import net.sf.jsqlparser.statement.oracle.OracleBlock;
import net.sf.jsqlparser.statement.oracle.OracleAssignment;
import net.sf.jsqlparser.statement.oracle.OracleNullStatement;
Expand Down Expand Up @@ -1142,4 +1144,9 @@ public <S> Void visit(OracleNullStatement statement, S context) {
return null;
}


@Override
public <S> Void visit(CreateAccessMethod statement, S context) {
return schemaOnly();
}
}
10 changes: 10 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.statement;

import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;

import net.sf.jsqlparser.statement.create.fdw.CreateForeignDataWrapper;
import net.sf.jsqlparser.statement.alter.AlterForeignDataWrapper;
import net.sf.jsqlparser.statement.create.server.CreateServer;
Expand Down Expand Up @@ -790,6 +792,14 @@ default void visit(AlterUserMapping statement) {
visit(statement, null);
}

default <S> T visit(CreateAccessMethod statement, S context) {
return null;
}

default void visit(CreateAccessMethod statement) {
visit(statement, null);
}

default <S> T visit(CreateCollation statement, S context) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.statement;

import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;

import net.sf.jsqlparser.statement.oracle.OracleBlock;
import net.sf.jsqlparser.statement.oracle.OracleAssignment;

Expand Down Expand Up @@ -887,4 +889,9 @@ public <S> T visit(OracleAssignment assignment, S context) {
return null;
}


@Override
public <S> T visit(CreateAccessMethod statement, S context) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*-
* #%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.create.accessmethod;

import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;

/** A PostgreSQL table or index access method, whose handler names a function, not a table. */
public class CreateAccessMethod implements Statement {
public enum Type {
TABLE, INDEX
}

private String name;
private Type type;
private String handler;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Type getType() {
return type;
}

public void setType(Type type) {
this.type = type;
}

public String getHandler() {
return handler;
}

public void setHandler(String handler) {
this.handler = handler;
}

@Override
public <T, S> T accept(StatementVisitor<T> visitor, S context) {
return visitor.visit(this, context);
}

public StringBuilder appendTo(StringBuilder builder) {
return builder.append("CREATE ACCESS METHOD ").append(name)
.append(" TYPE ").append(type).append(" HANDLER ").append(handler);
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
}
7 changes: 7 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.util;

import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;

import net.sf.jsqlparser.statement.create.fdw.CreateForeignDataWrapper;
import net.sf.jsqlparser.statement.alter.AlterForeignDataWrapper;
import net.sf.jsqlparser.statement.create.server.CreateServer;
Expand Down Expand Up @@ -3013,6 +3015,11 @@ public <S> Void visit(AlterUserMapping statement, S context) {
return null;
}

@Override
public <S> Void visit(CreateAccessMethod statement, S context) {
return null;
}

@Override
public <S> Void visit(CreateCollation statement, S context) {
statement.visitExpressions(expression -> expression.accept(this, context));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.util.deparser;

import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;

import net.sf.jsqlparser.statement.create.fdw.CreateForeignDataWrapper;
import net.sf.jsqlparser.statement.alter.AlterForeignDataWrapper;
import net.sf.jsqlparser.statement.create.server.CreateServer;
Expand Down Expand Up @@ -879,6 +881,11 @@ public <S> StringBuilder visit(AlterUserMapping statement, S context) {
expression -> expression.accept(expressionDeParser, context));
}

@Override
public <S> StringBuilder visit(CreateAccessMethod statement, S context) {
return statement.appendTo(builder);
}

@Override
public <S> StringBuilder visit(CreateCollation statement, S context) {
return statement.appendTo(builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS
Feature.createCollation,
Feature.createSchema, Feature.createSequence, Feature.createTable,
Feature.createForeignDataWrapper, Feature.createServer, Feature.createUserMapping,
Feature.createAccessMethod, Feature.createAccessMethodTable,
Feature.createTableUnlogged,
Feature.createTableCreateOptionStrings, Feature.createTableTableOptionStrings,
Feature.createTableIfNotExists, Feature.createTableRowMovement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public enum PostgresqlVersion implements Version {

// https://www.postgresql.org/docs/current/sql-createsequence.html
Feature.createSequence,
Feature.createAccessMethod,
Feature.createForeignDataWrapper, Feature.alterForeignDataWrapper,
Feature.createServer, Feature.alterServer, Feature.createUserMapping,
Feature.alterUserMapping,
Expand Down Expand Up @@ -155,7 +156,8 @@ public enum PostgresqlVersion implements Version {
Feature.set, Feature.setAssignmentTo, // https://www.postgresql.org/docs/current/sql-reset.html
Feature.reset, // https://www.postgresql.org/docs/current/sql-commit.html
Feature.commit)), V11("11", V10.copy().getFeatures()), V12("12",
V11.copy().getFeatures()), V13("13",
V11.copy().add(Feature.createAccessMethodTable).getFeatures()), V13(
"13",
V12.copy().getFeatures()), V14("14", V13.copy().getFeatures());

private Set<Feature> features;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.util.validation.validator;

import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;

import net.sf.jsqlparser.statement.create.fdw.CreateForeignDataWrapper;
import net.sf.jsqlparser.statement.alter.AlterForeignDataWrapper;
import net.sf.jsqlparser.statement.create.server.CreateServer;
Expand Down Expand Up @@ -1075,6 +1077,15 @@ public <S> Void visit(AlterUserMapping statement, S context) {
return null;
}

@Override
public <S> Void visit(CreateAccessMethod statement, S context) {
validateFeature(Feature.createAccessMethod);
if (statement.getType() == CreateAccessMethod.Type.TABLE) {
validateFeature(Feature.createAccessMethodTable);
}
return null;
}

@Override
public <S> Void visit(CreateCollation statement, S context) {
validateFeature(Feature.createCollation);
Expand Down
19 changes: 19 additions & 0 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import net.sf.jsqlparser.statement.analyze.*;
import net.sf.jsqlparser.statement.alter.*;
import net.sf.jsqlparser.statement.create.fdw.*;
import net.sf.jsqlparser.statement.create.server.CreateServer;
import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;
import net.sf.jsqlparser.statement.create.usermapping.CreateUserMapping;
import net.sf.jsqlparser.statement.create.collation.CreateCollation;
import net.sf.jsqlparser.statement.alter.schema.AlterSchema;
Expand Down Expand Up @@ -19830,6 +19831,10 @@ Statement Create():
{
<K_CREATE> [ <K_OR> <K_REPLACE> { isUsingOrReplace = true; } ]
(
LOOKAHEAD({ isKeywordAhead("ACCESS") && "METHOD".equalsIgnoreCase(getToken(2).image) })
{ requireDdlSyntax(!isUsingOrReplace, "CREATE ACCESS METHOD does not support OR REPLACE"); }
statement = CreateAccessMethod()
|
LOOKAHEAD(<K_FOREIGN> <K_DATA>) { requireDdlSyntax(!isUsingOrReplace, "OR REPLACE is not supported for foreign-data objects"); } statement = CreateForeignDataWrapper()
|
LOOKAHEAD({ isKeywordAhead("SERVER") }) { requireDdlSyntax(!isUsingOrReplace, "OR REPLACE is not supported for foreign-data objects"); } statement = CreateServer()
Expand Down Expand Up @@ -21263,6 +21268,20 @@ AlterUserMapping AlterUserMapping():
options=ForeignDataOptions(true) { statement.setOptions(options); return statement; }
}

CreateAccessMethod CreateAccessMethod():
{
CreateAccessMethod statement = new CreateAccessMethod();
String name;
}
{
ContextualKeyword("ACCESS") ContextualKeyword("METHOD") name=RelObjectName()
{ statement.setName(name); }
<K_TYPE> ( <K_TABLE> { statement.setType(CreateAccessMethod.Type.TABLE); }
| <K_INDEX> { statement.setType(CreateAccessMethod.Type.INDEX); } )
ContextualKeyword("HANDLER") name=AccessQualifiedName()
{ statement.setHandler(name); return statement; }
}

CreateCollation CreateCollation():
{
CreateCollation statement = new CreateCollation(); String name; List<Index.Option> options;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*-
* #%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.create;

import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.StatementVisitorAdapter;
import net.sf.jsqlparser.statement.create.accessmethod.CreateAccessMethod;
import net.sf.jsqlparser.util.TablesNamesFinder;
import net.sf.jsqlparser.util.deparser.StatementDeParser;
import net.sf.jsqlparser.util.validation.Validation;
import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed;
import net.sf.jsqlparser.util.validation.feature.PostgresqlVersion;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class PostgreSqlAccessMethodTest {
@ParameterizedTest
@ValueSource(strings = {"TABLE", "INDEX"})
void preservesAccessMethodKindAndDoesNotInventTableReferences(String type)
throws JSQLParserException {
String sql = "CREATE ACCESS METHOD am TYPE " + type + " HANDLER public.handlerfn";
CreateAccessMethod statement = assertInstanceOf(CreateAccessMethod.class,
CCJSqlParserUtil.parse(sql));
assertEquals("am", statement.getName());
assertEquals(CreateAccessMethod.Type.valueOf(type), statement.getType());
assertEquals("public.handlerfn", statement.getHandler());
assertEquals(sql, statement.toString());
assertTrue(new TablesNamesFinder().getTables(statement).isEmpty());
assertTrue(statement.getFeatures().modifiesSchema());
assertFalse(statement.getFeatures().returnsResultSet());
StringBuilder output = new StringBuilder();
statement.accept(new StatementDeParser(output));
assertEquals(sql, output.toString());
assertInstanceOf(CreateAccessMethod.class, CCJSqlParserUtil.parse(output.toString()));
assertEquals(2, CCJSqlParserUtil.parseStatements(sql + "; SELECT 1").size());
assertTrue(new Validation(List.of(FeaturesAllowed.DDL), sql).validate().isEmpty());
assertTrue(new Validation(List.of(PostgresqlVersion.V12), sql).validate().isEmpty());
assertFalse(new Validation(List.of(FeaturesAllowed.SELECT), sql).validate().isEmpty());
assertEquals(type.equals("INDEX"),
new Validation(List.of(PostgresqlVersion.V10), sql).validate().isEmpty());
}

@Test
void quotedNamesRemainMutableAndVisitorsReceiveContext() throws JSQLParserException {
CreateAccessMethod statement = assertInstanceOf(CreateAccessMethod.class,
CCJSqlParserUtil.parse(
"CREATE ACCESS METHOD \"my method\" TYPE TABLE HANDLER \"my schema\".\"my handler\""));
assertEquals("\"my method\"", statement.getName());
assertEquals("\"my schema\".\"my handler\"", statement.getHandler());
String actual = statement.accept(new StatementVisitorAdapter<String>() {
@Override
public <S> String visit(CreateAccessMethod method, S context) {
return context + ":" + method.getName();
}
}, "visited");
assertEquals("visited:\"my method\"", actual);
statement.setName("other_method");
statement.setType(CreateAccessMethod.Type.INDEX);
statement.setHandler("other_schema.handler");
StringBuilder output = new StringBuilder();
statement.accept(new StatementDeParser(output));
assertEquals("CREATE ACCESS METHOD other_method TYPE INDEX HANDLER other_schema.handler",
output.toString());
}

@ParameterizedTest
@ValueSource(strings = {"CREATE ACCESS METHOD am TYPE TABLE",
"CREATE ACCESS METHOD am TYPE VIEW HANDLER fn",
"CREATE OR REPLACE ACCESS METHOD am TYPE TABLE HANDLER fn",
"CREATE ACCESS METHOD am TYPE TABLE HANDLER fn()"})
void rejectsIncompleteOrInvalidAccessMethodDefinitions(String sql) {
assertThrows(JSQLParserException.class, () -> CCJSqlParserUtil.parse(sql));
}
}
Loading