Skip to content

Commit

Permalink
INSERT with SetOperations (#1531)
Browse files Browse the repository at this point in the history
* INSERT with SetOperations

Simplify the INSERT production
Use SetOperations for Select and Values
Better Bracket handling for WITH ... SELECT ...
Fixes #1491

* INSERT with SetOperations

Appease Codazy/PMD

* INSERT with SetOperations

Appease Codazy/PMD

* Update Readme

List the changes
Minor rephrases
Correct the Maven Artifact Example

* Fix the two test cases (missing white space)

* Remove unused import
  • Loading branch information
manticore-projects authored May 15, 2022
1 parent e8f0750 commit b5672c5
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 224 deletions.
8 changes: 4 additions & 4 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: SQL Parser Error
about: Create a report to help us improve
title: 'JSQLParser Version : RDBMS : failing feature description'
labels: ''
labels: 'Parser Error', 'Feature Request', 'Documentation', 'Java API', 'RDBMS support'
assignees: ''

---
Expand All @@ -12,7 +12,7 @@ assignees: ''
- Example: `WITH ROLLUP` can't be parsed

**SQL Example**
- Simplyfied Query Exmple, focusing on the failing feature
- Simplified Query Example, focusing on the failing feature
```sql
-- Replace with your ACTUAL example
select 1
Expand All @@ -23,6 +23,6 @@ from dual
- JSqlParser version
- Database (e. g. Oracle, MS SQL Server, H2, PostgreSQL, IBM DB2 )

**Tipps**
Please write in English and avoid Screenshots (as we can't copy paste content from it).
**Tips**
Please write in English and avoid Screenshots (as we can't copy and paste content from it).
[Try your example online with the latest JSQLParser](http://217.160.215.75:8080/jsqlformatter/demo.html) and share the link in the error report.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,10 @@ To help JSqlParser's development you are encouraged to provide

**Please write in English, since it's the language most of the dev team knows.**

Also I would like to know about needed examples or documentation stuff.
Any requests for examples or any particular documentation will be most welcome.

## Extensions in the latest SNAPSHOT version 4.5

- Add support for `... ALTER COLUMN ... DROP DEFAULT`

Additionally, we have fixed many errors and improved the code quality and the test coverage.

## Extensions of JSqlParser releases
Expand All @@ -64,6 +62,9 @@ Additionally, we have fixed many errors and improved the code quality and the te
* Modifications before GitHub's release tagging are listed in the [Older Releases](https://github.com/JSQLParser/JSqlParser/wiki/Older-Releases) page.
* UnsupportedStatement support instead of throwing Exceptions
* support for **RETURNING** clause of a **DELETE** statement
* Add support for `... ALTER COLUMN ... DROP DEFAULT`
* `INSERT` supports `SetOperations` (e. g. `INSERT INTO ... SELECT ... FROM ... UNION SELECT ... FROM ...`), those `SetOperations` are used both for `SELECT` and `VALUES` clauses (API change) in order to simplify the Grammar
* `(WITH ... SELECT ...)` statements within brackets are now supported


## Building from the sources
Expand All @@ -80,7 +81,7 @@ gradle build

The project requires the following to build:
- Maven (or Gradle)
- JDK 8 or later. The jar will target JDK 8, but the version of the maven-compiler-plugin that JsqlParser uses requires JDK 8+
- JDK 8 or later. The JAR will target JDK 8, but the version of the maven-compiler-plugin that JSqlParser uses requires JDK 8+

This will produce the jsqlparser-VERSION.jar file in the `target/` directory (`build/libs/jsqlparser-VERSION.jar` in case of Gradle).

Expand Down Expand Up @@ -110,7 +111,7 @@ This is a valid piece of source code:

## Maven Repository

JSQLParser is deployed at sonatypes open source maven repository.
JSQLParser is deployed at Sonatype open source maven repository.
Starting from now I will deploy there. The first snapshot version there will be 0.8.5-SNAPSHOT.
To use it this is the repository configuration:

Expand All @@ -125,14 +126,14 @@ To use it this is the repository configuration:
</repository>
</repositories>
```
This repositories releases will be synched to maven central. Snapshots remain at sonatype.
These repository releases will be synchronised to Maven Central. Snapshots remain at Sonatype.

And this is the dependency declaration in your pom:
```xml
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.2</version>
<version>4.4</version>
</dependency>
```

93 changes: 40 additions & 53 deletions src/main/java/net/sf/jsqlparser/statement/insert/Insert.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.OracleHint;
import net.sf.jsqlparser.expression.RowConstructor;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
Expand All @@ -25,19 +28,18 @@
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.statement.values.ValuesStatement;

@SuppressWarnings({"PMD.CyclomaticComplexity"})
public class Insert implements Statement {

private Table table;
private OracleHint oracleHint = null;
private List<Column> columns;
private ItemsList itemsList;
private boolean useValues = true;
private Select select;
private boolean useSelectBrackets = true;
private boolean useDuplicate = false;
private List<Column> duplicateUpdateColumns;
private List<Expression> duplicateUpdateExpressionList;
Expand Down Expand Up @@ -95,20 +97,41 @@ public void setColumns(List<Column> list) {
*
* @return the values of the insert
*/
@Deprecated
public ItemsList getItemsList() {
return itemsList;
if (select!=null) {
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selects = setOperationList.getSelects();

if (selects.size() == 1) {
SelectBody selectBody1 = selects.get(0);
if (selectBody1 instanceof ValuesStatement) {
ValuesStatement valuesStatement = (ValuesStatement) selectBody1;
if (valuesStatement.getExpressions() instanceof ExpressionList) {
ExpressionList expressionList = (ExpressionList) valuesStatement.getExpressions();

if (expressionList.getExpressions().size() == 1 && expressionList.getExpressions().get(0) instanceof RowConstructor) {
RowConstructor rowConstructor = (RowConstructor) expressionList.getExpressions().get(0);
return rowConstructor.getExprList();
} else {
return expressionList;
}
} else {
return valuesStatement.getExpressions();
}
}
}
}
}
return null;
}

public void setItemsList(ItemsList list) {
itemsList = list;
}

@Deprecated
public boolean isUseValues() {
return useValues;
}

public void setUseValues(boolean useValues) {
this.useValues = useValues;
return select!=null && select.getSelectBody() instanceof ValuesStatement;
}

public List<SelectItem> getReturningExpressionList() {
Expand All @@ -127,12 +150,9 @@ public void setSelect(Select select) {
this.select = select;
}

@Deprecated
public boolean isUseSelectBrackets() {
return useSelectBrackets;
}

public void setUseSelectBrackets(boolean useSelectBrackets) {
this.useSelectBrackets = useSelectBrackets;
return false;
}

public boolean isUseDuplicate() {
Expand Down Expand Up @@ -235,28 +255,10 @@ public String toString() {
sql.append(PlainSelect.getStringList(columns, true, true)).append(" ");
}

if (outputClause!=null) {
outputClause.appendTo(sql);
if (select != null) {
sql.append(select);
}

if (useValues) {
sql.append("VALUES ");
}

if (itemsList != null) {
sql.append(itemsList);
} else {
if (useSelectBrackets) {
sql.append("(");
}
if (select != null) {
sql.append(select);
}
if (useSelectBrackets) {
sql.append(")");
}
}

if (useSet) {
sql.append("SET ");
for (int i = 0; i < getSetColumns().size(); i++) {
Expand Down Expand Up @@ -291,22 +293,12 @@ public Insert withWithItemsList(List<WithItem> withList) {
this.withItemsList = withList;
return this;
}

public Insert withUseValues(boolean useValues) {
this.setUseValues(useValues);
return this;
}

public Insert withSelect(Select select) {
this.setSelect(select);
return this;
}

public Insert withUseSelectBrackets(boolean useSelectBrackets) {
this.setUseSelectBrackets(useSelectBrackets);
return this;
}

public Insert withUseDuplicate(boolean useDuplicate) {
this.setUseDuplicate(useDuplicate);
return this;
Expand Down Expand Up @@ -367,11 +359,6 @@ public Insert withSetColumns(List<Column> columns) {
return this;
}

public Insert withItemsList(ItemsList itemsList) {
this.setItemsList(itemsList);
return this;
}

public Insert addColumns(Column... columns) {
List<Column> collection = Optional.ofNullable(getColumns()).orElseGet(ArrayList::new);
Collections.addAll(collection, columns);
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/select/Select.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class Select implements Statement {
private SelectBody selectBody;
private List<WithItem> withItemsList;

private boolean useWithBrackets = false;

@Override
public void accept(StatementVisitor statementVisitor) {
statementVisitor.visit(this);
Expand All @@ -41,11 +43,27 @@ public void setSelectBody(SelectBody body) {
selectBody = body;
}

public void setUsingWithBrackets(boolean useWithBrackets) {
this.useWithBrackets = useWithBrackets;
}

public Select withUsingWithBrackets(boolean useWithBrackets) {
this.useWithBrackets = useWithBrackets;
return this;
}

public boolean isUsingWithBrackets() {
return this.useWithBrackets;
}

@Override
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
public String toString() {
StringBuilder retval = new StringBuilder();
if (withItemsList != null && !withItemsList.isEmpty()) {
if (useWithBrackets) {
retval.append("( ");
}
retval.append("WITH ");
for (Iterator<WithItem> iter = withItemsList.iterator(); iter.hasNext();) {
WithItem withItem = iter.next();
Expand All @@ -57,6 +75,9 @@ public String toString() {
}
}
retval.append(selectBody);
if (withItemsList != null && !withItemsList.isEmpty() && useWithBrackets) {
retval.append(" )");
}
return retval.toString();
}

Expand Down
12 changes: 2 additions & 10 deletions src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,9 @@ public void deParse(Insert insert) {
buffer.append(")");
}

if (insert.getOutputClause()!=null) {
insert.getOutputClause().appendTo(buffer);
}

if (insert.getItemsList() != null) {
insert.getItemsList().accept(this);
}

if (insert.getSelect() != null) {
buffer.append(" ");
if (insert.isUseSelectBrackets()) {
if (insert.getSelect().isUsingWithBrackets()) {
buffer.append("(");
}
if (insert.getSelect().getWithItemsList() != null) {
Expand All @@ -98,7 +90,7 @@ public void deParse(Insert insert) {
buffer.append(" ");
}
insert.getSelect().getSelectBody().accept(selectVisitor);
if (insert.isUseSelectBrackets()) {
if (insert.getSelect().isUsingWithBrackets()) {
buffer.append(")");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ public void visit(Select select) {
expressionDeParser.setBuffer(buffer);
selectDeParser.setExpressionVisitor(expressionDeParser);
if (select.getWithItemsList() != null && !select.getWithItemsList().isEmpty()) {
if (select.isUsingWithBrackets()) {
buffer.append("( ");
}
buffer.append("WITH ");
for (Iterator<WithItem> iter = select.getWithItemsList().iterator(); iter.hasNext();) {
WithItem withItem = iter.next();
Expand All @@ -154,6 +157,9 @@ public void visit(Select select) {
}
}
select.getSelectBody().accept(selectDeParser);
if (select.isUsingWithBrackets()) {
buffer.append(" )");
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public enum H2Version implements Version {
// http://h2database.com/html/commands.html#insert
Feature.insert,
Feature.insertValues,
Feature.values,
Feature.insertFromSelect,
// http://h2database.com/html/commands.html#update
Feature.update,
Expand Down Expand Up @@ -136,7 +137,8 @@ public enum H2Version implements Version {
// http://www.h2database.com/html/commands.html#grant_role
Feature.grant,
// http://h2database.com/html/commands.html#commit
Feature.commit));
Feature.commit
));

private Set<Feature> features;
private String versionString;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public enum MariaDbVersion implements Version {
Feature.withItem, Feature.withItemRecursive,

// https://mariadb.com/kb/en/insert/
Feature.insert, Feature.insertValues,
Feature.insert, Feature.insertValues, Feature.values,
Feature.insertFromSelect, Feature.insertModifierPriority, Feature.insertModifierIgnore,
Feature.insertUseSet, Feature.insertUseDuplicateKeyUpdate, Feature.insertReturningExpressionList,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public enum MySqlVersion implements Version {
// https://dev.mysql.com/doc/refman/8.0/en/insert.html
Feature.insert,
Feature.insertValues,
Feature.values,
Feature.insertFromSelect, Feature.insertUseSet, Feature.insertModifierPriority,
Feature.insertModifierIgnore, Feature.insertUseDuplicateKeyUpdate,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public enum OracleVersion implements Version {
// https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/INSERT.html
Feature.insert,
Feature.insertValues,
Feature.values,
// https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/INSERT.html
// see "single_table_insert"
Feature.insertFromSelect,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public enum PostgresqlVersion implements Version {
// https://www.postgresql.org/docs/current/sql-insert.html
Feature.insert,
Feature.insertValues,
Feature.values,
Feature.insertFromSelect,
Feature.insertReturningAll, Feature.insertReturningExpressionList,
// https://www.postgresql.org/docs/current/sql-update.html
Expand Down
Loading

0 comments on commit b5672c5

Please sign in to comment.