Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix to the local variables bug (#12) #14

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
12 changes: 7 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2'
}
}

Expand All @@ -24,14 +24,16 @@ repositories {
url 'https://oss.sonatype.org/content/groups/public/'
}
maven {
url 'http://maven.njol.ch/repo/'
url 'http://jitpack.io/'
}
}

dependencies {
shadow 'org.spigotmc:spigot-api:1.11-R0.1-SNAPSHOT'
shadow 'ch.njol:skript:2.2-SNAPSHOT'
compile 'com.zaxxer:HikariCP:2.6.2'
shadow 'org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT'
shadow('com.github.SkriptLang:Skript:2.3.6') {
transitive = false
}
compile 'com.zaxxer:HikariCP:3.3.1'
}

task buildReadme(type: Javadoc) {
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the gradle wrapper since I am currently using Java 11, which 3.3 has no support for. I am fine if you want me to revert this change.

68 changes: 3 additions & 65 deletions src/main/java/com/btk5h/skriptdb/SkriptUtil.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
package com.btk5h.skriptdb;

import org.bukkit.event.Event;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.VariableString;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;

import ch.njol.skript.Skript;
import ch.njol.skript.effects.Delay;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.Variable;
import ch.njol.skript.lang.VariableString;

public class SkriptUtil {

private static final Field STRING;
private static final Field SIMPLE;
private static final Field DELAYED;
private static final Field EXPR;
private static final Field VARIABLE_NAME;

static {
Field _FIELD = null;
Expand All @@ -32,25 +24,6 @@ public class SkriptUtil {
}
STRING = _FIELD;

try {
_FIELD = VariableString.class.getDeclaredField("simple");
_FIELD.setAccessible(true);
} catch (NoSuchFieldException e) {
Skript.error("Skript's 'simple' field could not be resolved.");
e.printStackTrace();
}
SIMPLE = _FIELD;

try {
_FIELD = Delay.class.getDeclaredField("delayed");
_FIELD.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
Skript.warning("Skript's 'delayed' method could not be resolved. Some Skript warnings may " +
"not be available.");
}
DELAYED = _FIELD;

try {
Optional<Class<?>> expressionInfo = Arrays.stream(VariableString.class.getDeclaredClasses())
.filter(cls -> cls.getSimpleName().equals("ExpressionInfo"))
Expand All @@ -67,33 +40,6 @@ public class SkriptUtil {
Skript.error("Skript's 'expr' field could not be resolved.");
}
EXPR = _FIELD;

try {
_FIELD = Variable.class.getDeclaredField("name");
_FIELD.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
Skript.error("Skript's 'variable name' method could not be resolved.");
}
VARIABLE_NAME = _FIELD;
}

@SuppressWarnings("unchecked")
public static void delay(Event e) {
if (DELAYED != null) {
try {
((Set<Event>) DELAYED.get(null)).add(e);
} catch (IllegalAccessException ignored) {
}
}
}

public static String getSimpleString(VariableString vs) {
try {
return (String) SIMPLE.get(vs);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}

public static Object[] getTemplateString(VariableString vs) {
Expand All @@ -112,12 +58,4 @@ public static Expression<?> getExpressionFromInfo(Object o) {
}
}

public static VariableString getVariableName(Variable<?> var) {
try {
return (VariableString) VARIABLE_NAME.get(var);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
153 changes: 81 additions & 72 deletions src/main/java/com/btk5h/skriptdb/skript/EffExecuteStatement.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
package com.btk5h.skriptdb.skript;

import ch.njol.skript.Skript;
import ch.njol.skript.effects.Delay;
import ch.njol.skript.lang.*;
import ch.njol.skript.variables.Variables;
import ch.njol.util.Kleenean;
import ch.njol.util.Pair;
import com.btk5h.skriptdb.SkriptDB;
import com.btk5h.skriptdb.SkriptUtil;
import com.zaxxer.hikari.HikariDataSource;

import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

import javax.sql.DataSource;
import javax.sql.rowset.CachedRowSet;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.sql.rowset.CachedRowSet;

import ch.njol.skript.Skript;
import ch.njol.skript.effects.Delay;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.TriggerItem;
import ch.njol.skript.lang.Variable;
import ch.njol.skript.lang.VariableString;
import ch.njol.skript.variables.Variables;
import ch.njol.util.Kleenean;

/**
* Executes a statement on a database and optionally stores the result in a variable. Expressions
* embedded in the query will be escaped to avoid SQL injection.
Expand Down Expand Up @@ -65,11 +57,20 @@ public class EffExecuteStatement extends Delay {
private VariableString var;
private boolean isLocal;
private boolean isList;
private Map<String, Object> doLater = new HashMap<>();

@Override
protected void execute(Event e) {
DataSource ds = dataSource.getSingle(e);
Pair<String, List<Object>> query = parseQuery(e);
String baseVariable = var != null ? var.toString(e).toLowerCase(Locale.ENGLISH) : null;

if (ds == null)
return;

Object locals = Variables.removeLocals(e);
CompletableFuture<String> sql =
CompletableFuture.supplyAsync(() -> executeStatement(e), threadPool);
CompletableFuture.supplyAsync(() -> executeStatement(ds, baseVariable, query), threadPool);

sql.whenComplete((res, err) -> {
if (err != null) {
Expand All @@ -80,7 +81,12 @@ protected void execute(Event e) {
lastError = res;

if (getNext() != null) {
if (locals != null)
Variables.setLocalVariables(e, locals);
doLater.forEach((name, value) -> setVariable(e, name, value));
doLater.clear();
TriggerItem.walk(getNext(), e);
Variables.removeLocals(e);
}
});
});
Expand All @@ -89,62 +95,24 @@ protected void execute(Event e) {
@Override
protected TriggerItem walk(Event e) {
debug(e, true);
SkriptUtil.delay(e);
Delay.addDelayedEvent(e);
execute(e);
return null;
}

private String executeStatement(Event e) {
HikariDataSource ds = dataSource.getSingle(e);

if (ds == null) {
return "Data source is not set";
}

try (Connection conn = ds.getConnection();
PreparedStatement stmt = createStatement(e, conn)) {

boolean hasResultSet = stmt.execute();

if (var != null) {
String baseVariable = var.toString(e)
.toLowerCase(Locale.ENGLISH);
if (isList) {
baseVariable = baseVariable.substring(0, baseVariable.length() - 1);
}

if (hasResultSet) {
CachedRowSet crs = SkriptDB.getRowSetFactory().createCachedRowSet();
crs.populate(stmt.getResultSet());

if (isList) {
populateVariable(e, crs, baseVariable);
} else {
crs.last();
setVariable(e, baseVariable, crs.getRow());
}
} else if (!isList) {
setVariable(e, baseVariable, stmt.getUpdateCount());
}
}
} catch (SQLException ex) {
return ex.getMessage();
}
return null;
}

private PreparedStatement createStatement(Event e, Connection conn) throws SQLException {
private Pair<String, List<Object>> parseQuery(Event e) {
if (!(query instanceof VariableString)) {
return conn.prepareStatement(query.getSingle(e));
return new Pair<>(query.getSingle(e), null);
}

if (((VariableString) query).isSimple()) {
return conn.prepareStatement(SkriptUtil.getSimpleString(((VariableString) query)));
VariableString q = (VariableString) query;
if (q.isSimple()) {
return new Pair<>(q.toString(e), null);
}

StringBuilder sb = new StringBuilder();
List<Object> parameters = new ArrayList<>();
Object[] objects = SkriptUtil.getTemplateString(((VariableString) query));
Object[] objects = SkriptUtil.getTemplateString(q);

for (int i = 0; i < objects.length; i++) {
Object o = objects[i];
if (o instanceof String) {
Expand Down Expand Up @@ -183,11 +151,52 @@ private PreparedStatement createStatement(Event e, Connection conn) throws SQLEx
}
}
}
return new Pair<>(sb.toString(), parameters);
}

private String executeStatement(DataSource ds, String baseVariable, Pair<String, List<Object>> query) {
if (ds == null) {
return "Data source is not set";
}

try (Connection conn = ds.getConnection();
PreparedStatement stmt = createStatement(conn, query)) {

PreparedStatement stmt = conn.prepareStatement(sb.toString());
boolean hasResultSet = stmt.execute();

if (baseVariable != null) {
if (isList) {
baseVariable = baseVariable.substring(0, baseVariable.length() - 1);
}

for (int i = 0; i < parameters.size(); i++) {
stmt.setObject(i + 1, parameters.get(i));
if (hasResultSet) {
CachedRowSet crs = SkriptDB.getRowSetFactory().createCachedRowSet();
crs.populate(stmt.getResultSet());

if (isList) {
populateVariable(crs, baseVariable);
} else {
crs.last();
doLater.put(baseVariable, crs.getRow());
}
} else if (!isList) {
doLater.put(baseVariable, stmt.getUpdateCount());
}
}
} catch (SQLException ex) {
return ex.getMessage();
}
return null;
}

private PreparedStatement createStatement(Connection conn, Pair<String, List<Object>> query) throws SQLException {
PreparedStatement stmt = conn.prepareStatement(query.getFirst());
List<Object> parameters = query.getSecond();

if (parameters != null) {
for (int i = 0; i < parameters.size(); i++) {
stmt.setObject(i + 1, parameters.get(i));
}
}

return stmt;
Expand All @@ -211,28 +220,28 @@ private void setVariable(Event e, String name, Object obj) {
Variables.setVariable(name.toLowerCase(Locale.ENGLISH), obj, e, isLocal);
}

private void populateVariable(Event e, CachedRowSet crs, String baseVariable)
private void populateVariable(CachedRowSet crs, String baseVariable)
throws SQLException {
ResultSetMetaData meta = crs.getMetaData();
int columnCount = meta.getColumnCount();

for (int i = 1; i <= columnCount; i++) {
String label = meta.getColumnLabel(i);
setVariable(e, baseVariable + label, label);
doLater.put(baseVariable + label, label);
}

int rowNumber = 1;
while (crs.next()) {
for (int i = 1; i <= columnCount; i++) {
setVariable(e, baseVariable + meta.getColumnLabel(i).toLowerCase(Locale.ENGLISH)
doLater.put(baseVariable + meta.getColumnLabel(i).toLowerCase(Locale.ENGLISH)
+ Variable.SEPARATOR + rowNumber, crs.getObject(i));
}
rowNumber++;
}
}

@Override
public String toString(@Nullable Event e, boolean debug) {
public String toString(Event e, boolean debug) {
return "execute " + query.toString(e, debug) + " in " + dataSource.toString(e, debug);
}

Expand All @@ -253,7 +262,7 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
Expression<?> expr = exprs[2];
if (expr instanceof Variable) {
Variable<?> varExpr = (Variable<?>) expr;
var = SkriptUtil.getVariableName(varExpr);
var = varExpr.getName();
isLocal = varExpr.isLocal();
isList = varExpr.isList();
} else if (expr != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ExprDataSource extends SimpleExpression<HikariDataSource> {
static {
Skript.registerExpression(ExprDataSource.class, HikariDataSource.class,
ExpressionType.COMBINED, "[the] data(base|[ ]source) [(of|at)] %string% " +
"[with [a] [max[imum]] [connection] life[ ]time of %timespan%]");
"[with [a] [max[imum]] [connection] life[ ]time of %-timespan%]");
}

private static Map<String, HikariDataSource> connectionCache = new HashMap<>();
Expand Down
Loading