Skip to content

Commit

Permalink
#56: Support column references in value expressions (#58)
Browse files Browse the repository at this point in the history
* #56: Support column references in value expressions
  • Loading branch information
redcatbear authored Dec 5, 2019
1 parent 43dd149 commit df0b293
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 28 deletions.
11 changes: 11 additions & 0 deletions doc/user_guide/common_constructs/value_tables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Value Tables

Value tables are lists of content definitions for rows. They can appear in [`INSERT`](../statements/insert.md) and [`MERGE`](../statements/merge.md) statements.

## Defining Value Tables

The class `ValueTable` contains multiple methods for defining value tables.

The `appendRow()` methods allow adding all values for a complete row at once. They are especially useful in case all columns have the same type.

The `add()` methods on the other hand amend the last row with an additional value.
4 changes: 4 additions & 0 deletions doc/user_guide/statements/merge.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ merge.using("src") //
.where(gt(column("src", "c5"), integerLiteral(1000)));
```

### Using Value Tables in `MERGE` Insert Clauses

In the insert clause of a merge statement, you can use `VALUES` to insert [value tables](../common_constructs/value_tables.md).

### Rendering `MERGE` Statements

Use the `MergeRenderer` to render `Merge` objects into SQL strings.
Expand Down
2 changes: 1 addition & 1 deletion launch/sql-statement-builder mvn package.launch
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/java-1.8.0-openjdk-1.8.0.181-7.b13.fc28.x86_64"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/java-1.8.0-openjdk-1.8.0.222.b10-0.fc30.x86_64"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:/sql-statement-builder}"/>
</launchConfiguration>
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.exasol</groupId>
<artifactId>sql-statement-builder</artifactId>
<version>3.1.0</version>
<version>3.2.0</version>
<name>Exasol SQL Statement Builder</name>
<description>This module provides a Builder for SQL statements that helps creating the correct structure and validates variable parts of the statements.</description>
<url>https://github.com/exasol/sql-statement-builder</url>
Expand Down
58 changes: 42 additions & 16 deletions src/main/java/com/exasol/sql/ValueTable.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package com.exasol.sql;

import java.util.ArrayList;
import java.util.List;
import java.util.*;

import com.exasol.sql.expression.ValueExpression;

/**
* Value tables are pseudo-tables constructed from rows and columns of expressions (e.g. literals)
* Value tables are pseudo-tables constructed from rows and columns of expressions (e.g. literals).
*
*/
// [impl->dsn~value-table~1]
public class ValueTable extends AbstractFragment {
private final List<ValueTableRow> rows = new ArrayList<>();

/**
* Create a new {@link ValueTable}
* Create a new {@link ValueTable}.
*
* @param root SQL statement this table belongs to
*/
Expand All @@ -21,7 +22,7 @@ public ValueTable(final Fragment root) {
}

/**
* Append a value table row consisting of value literals to the value table
* Append a value table row consisting of value literals to the value table.
*
* @param literals literals to be appended
*
Expand All @@ -33,7 +34,7 @@ public ValueTable appendRow(final String... literals) {
}

/**
* Append a {@link ValueTableRow} to the {@link ValueTable}
* Append a {@link ValueTableRow} to the {@link ValueTable}.
*
* @param row row to be appended
*
Expand All @@ -45,7 +46,7 @@ public ValueTable appendRow(final ValueTableRow row) {
}

/**
* Get a list of all rows in the value table
* Get a list of all rows in the value table.
*
* @return rows
*/
Expand All @@ -54,22 +55,14 @@ public List<ValueTableRow> getRows() {
}

/**
* Adds values to the last row of the value table
* Add string values to the last row of the value table.
*
* @param values values to be added
*/
public void add(final String... values) {
amendLastRow(createLastRowBuilder().add(values).build());
}

private ValueTableRow.Builder createLastRowBuilder() {
final ValueTableRow.Builder builder = ValueTableRow.builder(this.root);
if (!isEmpty()) {
builder.add(getLastRow().getExpressions());
}
return builder;
}

private synchronized void amendLastRow(final ValueTableRow row) {
if (isEmpty()) {
this.rows.add(row);
Expand All @@ -79,14 +72,42 @@ private synchronized void amendLastRow(final ValueTableRow row) {

}

private ValueTableRow.Builder createLastRowBuilder() {
final ValueTableRow.Builder builder = ValueTableRow.builder(this.root);
if (!isEmpty()) {
builder.add(getLastRow().getExpressions());
}
return builder;
}

/**
* Add integer values to the last row of the value table.
*
* @param values values to be added
*/
public void add(final int... values) {
amendLastRow(createLastRowBuilder().add(values).build());
}

/**
* Add an unnamed placeholder to the value table.
* <p>
* Unnamed placeholders are the "?" in a prepared statement which are replaced by the actual variable values.
* </p>
*/
public void addPlaceholder() {
amendLastRow(createLastRowBuilder().addPlaceholder().build());
}

/**
* Add a list of value expressions to the last row of the value table.
*
* @param expressions value expressions to be added
*/
public void add(final ValueExpression... expressions) {
amendLastRow(createLastRowBuilder().add(Arrays.asList(expressions)).build());
}

private ValueTableRow getLastRow() {
return this.rows.get(this.rows.size() - 1);
}
Expand All @@ -95,6 +116,11 @@ protected boolean isEmpty() {
return this.rows.isEmpty();
}

/**
* Accept a visitor.
*
* @param visitor to be accepted
*/
public void accept(final ValueTableVisitor visitor) {
visitor.visit(this);
for (final ValueTableRow row : this.rows) {
Expand Down
25 changes: 15 additions & 10 deletions src/main/java/com/exasol/sql/ValueTableRow.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public class ValueTableRow extends AbstractFragment {
private final List<ValueExpression> expressions;

/**
* Create a value table row from a list of expressions
* Create a value table row from a list of expressions.
*
* @param root root node of the SQL statement
* @param root root node of the SQL statement
* @param expressions value expressions
*/
public ValueTableRow(final Fragment root, final ValueExpression... expressions) {
Expand All @@ -23,9 +23,9 @@ public ValueTableRow(final Fragment root, final ValueExpression... expressions)
}

/**
* Create a value table row from a list of string literals
* Create a value table row from a list of string literals.
*
* @param root root node of the SQL statement
* @param root root node of the SQL statement
* @param values sting literals
*/
public ValueTableRow(final Fragment root, final String... values) {
Expand All @@ -42,21 +42,26 @@ private ValueTableRow(final Builder builder) {
}

/**
* Get the list of expressions the row consists of
* Get the list of expressions the row consists of.
*
* @return list of expressions
*/
public List<ValueExpression> getExpressions() {
return this.expressions;
}

/**
* Accept a visitor.
*
* @param visitor to accept.
*/
public void accept(final ValueTableVisitor visitor) {
visitor.visit(this);
visitor.leave(this);
}

/**
* Get a {@link Builder} for a {@link ValueTableRow}
* Get a {@link Builder} for a {@link ValueTableRow}.
*
* @param root root fragment of the SQL statement
*
Expand All @@ -78,7 +83,7 @@ public Builder(final Fragment root) {
}

/**
* Add one or more string literals to the row
* Add one or more string literals to the row.
*
* @param values strings to be added
* @return <code>this</code> for fluent programming
Expand All @@ -91,7 +96,7 @@ public Builder add(final String... values) {
}

/**
* Add one or more integer literals to the row
* Add one or more integer literals to the row.
*
* @param values integers to be added
* @return <code>this</code> for fluent programming
Expand All @@ -114,7 +119,7 @@ public Builder addPlaceholder() {
}

/**
* Add a list of expressions to the {@link ValueTableRow}
* Add a list of expressions to the {@link ValueTableRow}.
*
* @param expressions expressions to be added
* @return <code>this</code> for fluent programming
Expand All @@ -125,7 +130,7 @@ public Builder add(final List<ValueExpression> expressions) {
}

/**
* Build a new {@link ValueTableRow}
* Build a new {@link ValueTableRow}.
*
* @return new {@link ValueTableRow}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.exasol.sql.dml.insert;

import com.exasol.sql.*;
import com.exasol.sql.expression.ValueExpression;

/**
* Abstract base class for SQL fragments that contain a insert value table (for example {@code INSERT}, {@code MERGE}).
Expand Down Expand Up @@ -82,6 +83,19 @@ public T values(final int... values) {
return self();
}

/**
* Insert a list of value expressions.
*
* @param expressions value expressions to be inserted
* @return <code>this</code> for fluent programming
*/
// [impl->dsn~values-as-insert-source~1]
public T values(final ValueExpression... expressions) {
createInsertValueInstanceIfItDoesNotExist();
this.insertValueTable.add(expressions);
return self();
}

/**
* Add an unnamed value placeholder to the value list (this is useful for prepared statements).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,17 @@ void testComplexMerge() {
+ " WHEN MATCHED THEN UPDATE SET c2 = DEFAULT, c3 = 'foo', c4 = 42" //
+ " WHEN NOT MATCHED THEN INSERT (c3, c5) VALUES ('foo', 'bar')"));
}

@Test
void testColumnReferenceInInsertValueList() {
this.merge //
.using("src") //
.on(eq(column("src", "c1"), column("dst", "c1"))) //
.whenNotMatched() //
.thenInsert() //
.field("c2") //
.values(column("src", "c2"));
assertThat(this.merge, rendersTo("MERGE INTO dst USING src ON src.c1 = dst.c1" //
+ " WHEN NOT MATCHED THEN INSERT (c2) VALUES (src.c2)"));
}
}

0 comments on commit df0b293

Please sign in to comment.