Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 414ca1c

Browse files
authored
#2230 enhance variable handling in SQL script (#2467) [skip ci[
1 parent cd2d275 commit 414ca1c

16 files changed

Lines changed: 345 additions & 93 deletions

e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.arcadedb.query.sql.executor.Result;
2525
import com.arcadedb.query.sql.executor.ResultSet;
2626
import com.arcadedb.remote.RemoteDatabase;
27+
import com.arcadedb.schema.Schema;
2728
import com.arcadedb.utility.CollectionUtils;
2829
import org.junit.jupiter.api.AfterEach;
2930
import org.junit.jupiter.api.BeforeEach;
@@ -136,9 +137,11 @@ void createTypesAndDataWithSqlScripts() {
136137

137138
database.command("sqlscript",
138139
"""
139-
BEGIN;LET photo = CREATE VERTEX Photos SET id = "p5555", name = "download3.jpg";
140+
BEGIN;
141+
LET photo = CREATE VERTEX Photos SET id = "p5555", name = "download3.jpg";
140142
LET user = SELECT FROM Users WHERE id = "u1111";
141-
LET userEdge = CREATE EDGE HasUploaded FROM $user TO $photo SET kind = "User_Photos";
143+
LET edgeType = 'HasUploaded';
144+
LET userEdge = CREATE EDGE $edgeType FROM $user TO $photo SET kind = "User_Photos";
142145
COMMIT RETRY 30;
143146
RETURN $photo;""");
144147

@@ -164,6 +167,47 @@ void renameTypeAndAliases() {
164167

165168
}
166169

170+
@Test
171+
void createSchemaWithDynamicSqlScript() {
172+
database.command("sqlscript", """
173+
BEGIN;
174+
175+
LET vTypes = ['V1', 'V2', 'V3'];
176+
FOREACH ($vType IN $vTypes) {
177+
CREATE VERTEX TYPE $vType;
178+
}
179+
180+
LET eTypes = ['E1', 'E2', 'E3'];
181+
FOREACH ($eType IN $eTypes) {
182+
CREATE EDGE TYPE $eType;
183+
}
184+
185+
LET dTypes = ['D1', 'D2', 'D3'];
186+
FOREACH ($dType IN $dTypes) {
187+
CREATE DOCUMENT TYPE $dType ;
188+
}
189+
190+
LET types = ['V1', 'V2', 'V3','E1', 'E2', 'E3','D1', 'D2', 'D3'];
191+
FOREACH ($type IN $types) {
192+
CREATE PROPERTY $type.id STRING;
193+
CREATE INDEX ON $type (id) UNIQUE NULL_STRATEGY SKIP;
194+
}
195+
COMMIT;
196+
""");
197+
198+
Schema schema = database.getSchema();
199+
System.out.println("schema.toString() = " + schema.toString());
200+
assertThat(schema.existsType("V1")).isTrue();
201+
assertThat(schema.existsType("V2")).isTrue();
202+
assertThat(schema.existsType("V3")).isTrue();
203+
assertThat(schema.existsType("D1")).isTrue();
204+
assertThat(schema.existsType("D2")).isTrue();
205+
assertThat(schema.existsType("D3")).isTrue();
206+
assertThat(schema.existsType("E1")).isTrue();
207+
assertThat(schema.existsType("E2")).isTrue();
208+
assertThat(schema.existsType("E3")).isTrue();
209+
}
210+
167211
@Test
168212
@Disabled
169213
void testMultipleInsert() throws SQLException, ClassNotFoundException {

engine/src/main/java/com/arcadedb/query/sql/SQLScriptQueryEngine.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,9 @@ private ResultSet executeInternal(final List<Statement> statements, final Comman
213213
throw new CommandSQLParsingException("Found COMMIT statement without a BEGIN");
214214
}
215215

216-
if (stm instanceof LetStatement letStatement)
216+
if (stm instanceof LetStatement letStatement) {
217217
scriptContext.declareScriptVariable(letStatement.getVariableName().getStringValue());
218+
}
218219
}
219220

220221
return new LocalResultSet(plan);

engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
import com.arcadedb.database.DatabaseInternal;
2424
import com.arcadedb.database.Document;
2525

26-
import java.util.*;
26+
import java.util.HashMap;
27+
import java.util.HashSet;
28+
import java.util.Map;
29+
import java.util.Set;
2730

2831
/**
2932
* Basic implementation of CommandContext interface that stores variables in a map. Supports parent/child context to build a tree
@@ -109,47 +112,62 @@ public Object getVariable(final String name) {
109112
return getVariable(name, null);
110113
}
111114

112-
public Object getVariable(String name, final Object iDefault) {
115+
public Object getVariable(String name, final Object defaultValue) {
113116
if (name == null)
114-
return iDefault;
117+
return defaultValue;
115118

116-
final Object result;
119+
Object result;
117120

118121
if (name.startsWith("$"))
119122
name = name.substring(1);
120123

121-
final String firstPart;
122-
firstPart = name;
124+
String fieldName = null;
125+
if (name.contains(".")) {
126+
final String[] parts = name.split("\\.");
127+
if (parts.length > 2) {
128+
throw new com.arcadedb.exception.CommandSQLParsingException(
129+
"Nested property access is not supported in this context: " + name);
130+
}
131+
name = parts[0];
132+
if (parts.length > 1) {
133+
fieldName = parts[1];
134+
}
135+
}
123136

124-
if (firstPart.equalsIgnoreCase("CONTEXT"))
137+
if (name.equalsIgnoreCase("CONTEXT"))
125138
result = getVariables();
126-
else if (firstPart.equalsIgnoreCase("PARENT"))
139+
else if (name.equalsIgnoreCase("PARENT"))
127140
result = parent;
128-
else if (firstPart.equalsIgnoreCase("ROOT")) {
141+
else if (name.equalsIgnoreCase("ROOT")) {
129142
CommandContext p = this;
130143
while (p.getParent() != null)
131144
p = p.getParent();
132145
result = p;
146+
133147
} else {
134-
if (variables != null && variables.containsKey(firstPart))
135-
result = variables.get(firstPart);
148+
if (variables != null && variables.containsKey(name))
149+
result = variables.get(name);
136150
else {
137151
if (child != null)
138-
result = child.getVariable(firstPart);
152+
result = child.getVariable(name);
139153
else
140-
result = getVariableFromParentHierarchy(firstPart);
154+
result = getVariableFromParentHierarchy(name);
141155
}
142156
}
143157

144-
return result != null ? result : iDefault;
158+
if (fieldName != null) {
159+
if (result instanceof Result result1)
160+
result = result1.getProperty(fieldName);
161+
}
162+
return result != null ? result : defaultValue;
145163
}
146164

147-
protected Object getVariableFromParentHierarchy(final String varName) {
148-
if (this.variables != null && variables.containsKey(varName)) {
149-
return variables.get(varName);
165+
protected Object getVariableFromParentHierarchy(final String name) {
166+
if (this.variables != null && variables.containsKey(name)) {
167+
return variables.get(name);
150168
}
151169
if (parent != null && parent instanceof BasicCommandContext context) {
152-
return context.getVariableFromParentHierarchy(varName);
170+
return context.getVariableFromParentHierarchy(name);
153171
}
154172
return null;
155173
}

engine/src/main/java/com/arcadedb/query/sql/executor/CommandContext.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ public interface CommandContext {
3535

3636
Object getVariablePath(String name, Object iDefault);
3737

38-
Object getVariable(String iName);
38+
Object getVariable(String name);
3939

40-
Object getVariable(String iName, Object iDefaultValue);
40+
Object getVariable(String name, Object iDefaultValue);
4141

42-
CommandContext setVariable(String iName, Object iValue);
42+
CommandContext setVariable(String name, Object iValue);
4343

4444
CommandContext incrementVariable(String getNeighbors);
4545

4646
Map<String, Object> getVariables();
4747

4848
CommandContext getParent();
4949

50-
CommandContext setParent(CommandContext iParentContext);
50+
CommandContext setParent(CommandContext parentContext);
5151

5252
CommandContext setChild(CommandContext context);
5353

engine/src/main/java/com/arcadedb/query/sql/executor/CreateEdgeExecutionPlanner.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import com.arcadedb.database.Database;
2222
import com.arcadedb.exception.CommandSQLParsingException;
23-
import com.arcadedb.index.TypeIndex;
2423
import com.arcadedb.query.sql.parser.CreateEdgeStatement;
2524
import com.arcadedb.query.sql.parser.Expression;
2625
import com.arcadedb.query.sql.parser.Identifier;
@@ -29,7 +28,6 @@
2928
import com.arcadedb.query.sql.parser.JsonArray;
3029
import com.arcadedb.query.sql.parser.UpdateItem;
3130
import com.arcadedb.schema.DocumentType;
32-
import com.arcadedb.schema.EdgeType;
3331

3432
import java.util.ArrayList;
3533
import java.util.List;
@@ -39,7 +37,7 @@
3937
*/
4038
public class CreateEdgeExecutionPlanner {
4139

42-
protected Identifier targetClass;
40+
protected Identifier targetType;
4341
protected final Identifier targetBucketName;
4442
protected final Expression leftExpression;
4543
protected final Expression rightExpression;
@@ -48,7 +46,7 @@ public class CreateEdgeExecutionPlanner {
4846
protected final InsertBody body;
4947

5048
public CreateEdgeExecutionPlanner(final CreateEdgeStatement statement) {
51-
this.targetClass = statement.getTargetType() == null ? null : statement.getTargetType().copy();
49+
this.targetType = statement.getTargetType() == null ? null : statement.getTargetType().copy();
5250
this.targetBucketName = statement.getTargetBucketName() == null ? null : statement.getTargetBucketName().copy();
5351
this.leftExpression = statement.getLeftExpression() == null ? null : statement.getLeftExpression().copy();
5452
this.rightExpression = statement.getRightExpression() == null ? null : statement.getRightExpression().copy();
@@ -65,15 +63,20 @@ public CreateEdgeExecutionPlanner(final CreateEdgeStatement statement) {
6563

6664
public InsertExecutionPlan createExecutionPlan(final CommandContext context) {
6765

68-
if (targetClass == null) {
66+
if (targetType.getStringValue().startsWith("$")) {
67+
String variable = (String) context.getVariable(targetType.getStringValue());
68+
targetType = new Identifier(variable);
69+
}
70+
71+
if (targetType == null) {
6972
if (targetBucketName == null) {
7073
throw new CommandSQLParsingException("Missing target");
7174
} else {
7275
final Database db = context.getDatabase();
7376
final DocumentType typez = db.getSchema()
7477
.getTypeByBucketId((db.getSchema().getBucketByName(targetBucketName.getStringValue()).getFileId()));
7578
if (typez != null) {
76-
targetClass = new Identifier(typez.getName());
79+
targetType = new Identifier(typez.getName());
7780
} else {
7881
throw new CommandSQLParsingException("Missing target");
7982
}
@@ -100,10 +103,10 @@ public InsertExecutionPlan createExecutionPlan(final CommandContext context) {
100103
// .findFirst()
101104
// .orElse(null);
102105
// } else
103-
uniqueIndexName = null;
106+
uniqueIndexName = null;
104107

105108
result.chain(
106-
new CreateEdgesStep(targetClass, targetBucketName, uniqueIndexName, new Identifier("$__ARCADEDB_CREATE_EDGE_fromV"),
109+
new CreateEdgesStep(targetType, targetBucketName, uniqueIndexName, new Identifier("$__ARCADEDB_CREATE_EDGE_fromV"),
107110
new Identifier("$__ARCADEDB_CREATE_EDGE_toV"), unidirectional, ifNotExists, context));
108111

109112
handleSetFields(result, body, context);
@@ -118,8 +121,8 @@ private void handleGlobalLet(final InsertExecutionPlan result, final Identifier
118121
}
119122

120123
private void handleCheckType(final InsertExecutionPlan result, final CommandContext context) {
121-
if (targetClass != null) {
122-
result.chain(new CheckIsEdgeTypeStep(targetClass.getStringValue(), context));
124+
if (targetType != null) {
125+
result.chain(new CheckIsEdgeTypeStep(targetType.getStringValue(), context));
123126
}
124127
}
125128

engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020

2121
import com.arcadedb.exception.CommandSQLParsingException;
2222
import com.arcadedb.query.sql.parser.CreateVertexStatement;
23+
import com.arcadedb.query.sql.parser.Identifier;
2324

24-
import java.util.*;
25+
import java.util.ArrayList;
26+
import java.util.List;
2527

2628
/**
2729
* @author Luigi Dell'Aquila (luigi.dellaquila-(at)-gmail.com)
2830
*/
2931
public class CreateVertexExecutionPlanner extends InsertExecutionPlanner {
32+
3033
public CreateVertexExecutionPlanner(final CreateVertexStatement statement) {
3134
this.targetType = statement.getTargetType() == null ? null : statement.getTargetType().copy();
3235
this.targetBucketName = statement.getTargetBucketName() == null ? null : statement.getTargetBucketName().copy();
@@ -40,6 +43,7 @@ public CreateVertexExecutionPlanner(final CreateVertexStatement statement) {
4043

4144
@Override
4245
public InsertExecutionPlan createExecutionPlan(final CommandContext context) {
46+
4347
final InsertExecutionPlan prev = super.createExecutionPlan(context);
4448
final List<ExecutionStep> steps = new ArrayList<>(prev.getSteps());
4549
final InsertExecutionPlan result = new InsertExecutionPlan(context);

engine/src/main/java/com/arcadedb/query/sql/executor/DeleteExecutionPlanner.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,12 @@ private void handleLimit(final UpdateExecutionPlan plan, final CommandContext co
168168
plan.chain(new LimitExecutionStep(limit, context));
169169
}
170170

171-
private void handleTarget(final UpdateExecutionPlan result, final CommandContext context, final FromClause target,
171+
private void handleTarget(final UpdateExecutionPlan result,
172+
final CommandContext context,
173+
final FromClause fromClause,
172174
final WhereClause whereClause) {
173175
final SelectStatement sourceStatement = new SelectStatement(-1);
174-
sourceStatement.setTarget(target);
176+
sourceStatement.setTarget(fromClause);
175177
sourceStatement.setWhereClause(whereClause);
176178
final SelectExecutionPlanner planner = new SelectExecutionPlanner(sourceStatement);
177179
result.chain(

engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
import com.arcadedb.query.sql.parser.SelectStatement;
2929
import com.arcadedb.query.sql.parser.UpdateItem;
3030

31-
import java.util.*;
31+
import java.util.ArrayList;
32+
import java.util.List;
3233

3334
/**
3435
* Created by luigidellaquila on 08/08/16.
@@ -55,14 +56,20 @@ public InsertExecutionPlanner(final InsertStatement statement) {
5556
}
5657

5758
public InsertExecutionPlan createExecutionPlan(final CommandContext context) {
59+
60+
if (targetType != null && targetType.getStringValue().startsWith("$")) {
61+
String variable = (String) context.getVariable(targetType.getStringValue());
62+
targetType = new Identifier(variable);
63+
}
64+
5865
final InsertExecutionPlan result = new InsertExecutionPlan(context);
5966

6067
if (selectStatement != null) {
6168
handleInsertSelect(result, this.selectStatement, context);
6269
} else {
6370
handleCreateRecord(result, this.insertBody, context);
6471
}
65-
handleTargetClass(result, targetType, context);
72+
handleTargetType(result, targetType, context);
6673
handleSetFields(result, insertBody, context);
6774
if (targetBucket != null) {
6875
String name = targetBucket.getBucketName();
@@ -113,9 +120,9 @@ private void handleSetFields(final InsertExecutionPlan result, final InsertBody
113120
}
114121
}
115122

116-
private void handleTargetClass(final InsertExecutionPlan result, final Identifier targetClass, final CommandContext context) {
117-
if (targetClass != null)
118-
result.chain(new SetDocumentStepStep(targetClass, context));
123+
private void handleTargetType(final InsertExecutionPlan result, final Identifier targetType, final CommandContext context) {
124+
if (targetType != null)
125+
result.chain(new SetDocumentStepStep(targetType, context));
119126
}
120127

121128
private void handleCreateRecord(final InsertExecutionPlan result, final InsertBody body, final CommandContext context) {

0 commit comments

Comments
 (0)