Skip to content
Merged
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
2 changes: 2 additions & 0 deletions src/main/java/net/sf/jsqlparser/parser/feature/Feature.java
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ public enum Feature {
* @see UseStatement
*/
use,
/** SQL Server session permission to insert explicit identity values into a table. */
setIdentityInsert,
/**
* @see Grant
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*-
* #%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;

import java.util.Objects;
import java.util.function.Consumer;
import net.sf.jsqlparser.schema.Table;

/** SQL Server SET IDENTITY_INSERT [database.][schema.]table ON | OFF. */
public final class SetIdentityInsertStatement implements Statement {
private Table table;
private boolean on;

public SetIdentityInsertStatement(Table table, boolean on) {
setTable(table);
this.on = on;
}

public Table getTable() {
return table;
}

public void setTable(Table table) {
this.table = Objects.requireNonNull(table, "table");
}

public boolean isOn() {
return on;
}

public void setOn(boolean on) {
this.on = on;
}

/** Shares statement rendering while allowing deparsers to visit the existing Table AST. */
public StringBuilder appendTo(StringBuilder builder, Consumer<Table> tableRenderer) {
builder.append("SET IDENTITY_INSERT ");
tableRenderer.accept(table);
return builder.append(on ? " ON" : " OFF");
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
return appendTo(builder, builder::append).toString();
}

@Override
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
return statementVisitor.visit(this, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,11 @@ public <S> Void visit(ResetStatement reset, S context) {
return sessionOnly();
}

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

@Override
public <S> Void visit(UseStatement use, S context) {
return sessionOnly();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,14 @@ default void visit(Upsert upsert) {
this.visit(upsert, null);
}

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

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

<S> T visit(UseStatement use, S context);

default void visit(UseStatement use) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ public <S> T visit(Upsert upsert, S context) {
return null;
}

@Override
public <S> T visit(SetIdentityInsertStatement statement, S context) {
return statement.getTable().accept(fromItemVisitor, context);
}

@Override
public <S> T visit(UseStatement use, S context) {
return null;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.UnsupportedStatement;
import net.sf.jsqlparser.statement.UseStatement;
import net.sf.jsqlparser.statement.SetIdentityInsertStatement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.alter.AlterSession;
import net.sf.jsqlparser.statement.alter.AlterSystemStatement;
Expand Down Expand Up @@ -1938,6 +1939,11 @@ public void visit(Upsert upsert) {
StatementVisitor.super.visit(upsert);
}

@Override
public <S> Void visit(SetIdentityInsertStatement statement, S context) {
return statement.getTable().accept(this, context);
}

@Override
public <S> Void visit(UseStatement use, S context) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.UnsupportedStatement;
import net.sf.jsqlparser.statement.UseStatement;
import net.sf.jsqlparser.statement.SetIdentityInsertStatement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.alter.AlterSession;
import net.sf.jsqlparser.statement.alter.AlterSystemStatement;
Expand Down Expand Up @@ -378,6 +379,11 @@ public <S> StringBuilder visit(Upsert upsert, S context) {
return builder;
}

@Override
public <S> StringBuilder visit(SetIdentityInsertStatement statement, S context) {
return statement.appendTo(builder, table -> table.accept(selectDeParser, context));
}

@Override
public <S> StringBuilder visit(UseStatement use, S context) {
new UseStatementDeParser(builder).deParse(use);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public enum SqlServerVersion implements Version {
Feature.commit, // special sql-server features
// https://docs.microsoft.com/en-us/sql/relational-databases/xml/for-xml-sql-server?view=sql-server-ver15
Feature.selectForXmlPath,
Feature.use, Feature.allowSquareBracketQuotation, //
Feature.use, Feature.setIdentityInsert, Feature.allowSquareBracketQuotation, //
Feature.pivot, Feature.unpivot, Feature.pivotXml,
Feature.selectGroupByGroupingSets));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*-
* #%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.util.validation.validator;

import net.sf.jsqlparser.parser.feature.Feature;
import net.sf.jsqlparser.statement.SetIdentityInsertStatement;
import net.sf.jsqlparser.util.validation.metadata.NamedObject;

public class SetIdentityInsertValidator extends AbstractValidator<SetIdentityInsertStatement> {
@Override
public void validate(SetIdentityInsertStatement statement) {
validateFeatureAndName(Feature.setIdentityInsert, NamedObject.table,
statement.getTable().getFullyQualifiedName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.UnsupportedStatement;
import net.sf.jsqlparser.statement.UseStatement;
import net.sf.jsqlparser.statement.SetIdentityInsertStatement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.alter.AlterSession;
import net.sf.jsqlparser.statement.alter.AlterSystemStatement;
Expand Down Expand Up @@ -269,6 +270,12 @@ public <S> Void visit(Upsert upsert, S context) {
return null;
}

@Override
public <S> Void visit(SetIdentityInsertStatement statement, S context) {
getValidator(SetIdentityInsertValidator.class).validate(statement);
return null;
}

@Override
public <S> Void visit(UseStatement use, S context) {
getValidator(UseStatementValidator.class).validate(use);
Expand Down
22 changes: 22 additions & 0 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -2785,6 +2785,12 @@ Statement SingleStatement() :
LOOKAHEAD({ getToken(1).kind == K_DO && Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) })
stm = DoStatement()
|
LOOKAHEAD({ Dialect.SQLSERVER.name().equals(getAsString(Feature.dialect))
&& getToken(1).kind == K_SET && getToken(2).kind == S_IDENTIFIER
&& "IDENTITY_INSERT".equalsIgnoreCase(getToken(2).image)
&& !"=".equals(getToken(3).image) && !".".equals(getToken(3).image) })
stm = SetIdentityInsert()
|
stm = Set()
|
stm = Reset()
Expand Down Expand Up @@ -4387,6 +4393,22 @@ List<ExplainStatement.Option> ExplainStatementOptions():
}
}

SetIdentityInsertStatement SetIdentityInsert(): {
Table table;
boolean on;
}
{
<K_SET> AccessKeyword("IDENTITY_INSERT") table=Table()
{
requireAccessSyntax(table.getNameParts().size() <= 3,
"IDENTITY_INSERT requires a table name with at most three parts");
}
( <K_ON> { on = true; } | <K_OFF> { on = false; } )
{
return new SetIdentityInsertStatement(table, on);
}
}

UseStatement Use(): {
String name;
boolean hasSchemaKeyword = false;
Expand Down
11 changes: 11 additions & 0 deletions src/site/sphinx/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,17 @@ Parse procedure definitions one SQL Server batch at a time: a procedure consumes
remaining batch, including SQL after an ``END``. Client-side ``GO`` batch splitting is
not performed by this routine declaration parser.

SQL Server identity inserts
---------------------------

With ``Dialect.SQLSERVER``, ``SET IDENTITY_INSERT dbo.actor ON`` uses
``SetIdentityInsertStatement``. ``getTable()`` reuses the qualified ``Table`` AST;
``isOn()`` and ``setOn()`` expose the session setting. Table names may include a
database and schema, including SQL Server bracket-quoted identifiers. Table
visitors, both SQL renderers and metadata validation use this structured target.
Feature analysis reports ``MODIFIES_SESSION``; the directive itself inserts no rows.
The dedicated validation capability is ``setIdentityInsert``.

Legacy MySQL GROUP BY ordering
==============================

Expand Down
Loading
Loading