You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2009/07/30 01:53:46 UTC
svn commit: r799134 - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/
openjpa-kernel/src/main/java/org...
Author: fancy
Date: Wed Jul 29 23:53:46 2009
New Revision: 799134
URL: http://svn.apache.org/viewvc?rev=799134&view=rev
Log:
OPENJPA-1185 JPA2 fix thread-safe problems of subquery restructured code.
Committing patch provided by Fay Wang.
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java Wed Jul 29 23:53:46 2009
@@ -102,6 +102,7 @@
}
private final transient JDBCStore _store;
+ private static ThreadLocalContext localContext = new ThreadLocalContext();
/**
* Constructor. Supply store manager.
@@ -143,27 +144,14 @@
return new JDBCExpressionFactory((ClassMapping) meta);
}
- private void resetSelect(Context ctx) {
- List<Context> subselCtxs = ctx.getSubselContexts();
- if (subselCtxs != null) {
- for (Context subselCtx : subselCtxs) {
- SelectImpl sel = (SelectImpl)subselCtx.getSelect();
- sel.reset();
- resetSelect(subselCtx);
- }
- }
- }
-
protected ResultObjectProvider executeQuery(Executor ex,
ClassMetaData base, ClassMetaData[] metas, boolean subclasses,
ExpressionFactory[] facts, QueryExpressions[] exps, Object[] params,
Range range) {
- Context expCtx = exps[0].ctx();
- if (expCtx != null) {
- expCtx.resetAliasCount();
- expCtx.setSelect(null);
- resetSelect(expCtx);
- }
+ Context[] ctxs = new Context[exps.length];
+ for (int i = 0; i < exps.length; i++)
+ ctxs[i] = exps[i].ctx();
+ localContext.set(clone(ctxs, null));
if (metas.length > 1 && exps[0].isAggregate())
throw new UserException(Localizer.forPackage(JDBCStoreQuery.class).
get("mult-mapping-aggregate", Arrays.asList(metas)));
@@ -254,6 +242,8 @@
if ((rops != null && range.end != Long.MAX_VALUE)
|| start != range.start || end != range.end)
rop = new RangeResultObjectProvider(rop, range.start, range.end);
+
+ localContext.remove();
return rop;
}
@@ -465,12 +455,10 @@
private Number executeBulkOperation(ClassMetaData[] metas,
boolean subclasses, ExpressionFactory[] facts, QueryExpressions[] exps,
Object[] params, Map updates) {
- Context expCtx = exps[0].ctx();
- if (ctx != null) {
- expCtx.resetAliasCount();
- expCtx.setSelect(null);
- resetSelect(expCtx);
- }
+ Context[] ctxs = new Context[exps.length];
+ for (int i = 0; i < exps.length; i++)
+ ctxs[i] = exps[i].ctx();
+ localContext.set(clone(ctxs, null));
// we cannot execute a bulk delete statement when have mappings in
// multiple tables, so indicate we want to use in-memory with null
@@ -551,6 +539,8 @@
} finally {
try { conn.close(); } catch (SQLException se) {}
}
+
+ localContext.remove();
return Numbers.valueOf(count);
}
@@ -634,6 +624,10 @@
protected String[] getDataStoreActions(ClassMetaData base,
ClassMetaData[] metas, boolean subclasses, ExpressionFactory[] facts,
QueryExpressions[] exps, Object[] params, Range range) {
+ Context[] ctxs = new Context[exps.length];
+ for (int i = 0; i < exps.length; i++)
+ ctxs[i] = exps[i].ctx();
+ localContext.set(clone(ctxs, null));
ClassMapping[] mappings = (ClassMapping[]) metas;
JDBCFetchConfiguration fetch = (JDBCFetchConfiguration) ctx.
getFetchConfiguration();
@@ -691,6 +685,8 @@
String[] sql = new String[sels.size()];
for (int i = 0; i < sels.size(); i++)
sql[i] = ((Select) sels.get(i)).toSelect(false, fetch).getSQL(true);
+
+ localContext.remove();
return sql;
}
@@ -986,4 +982,88 @@
throw new UnsupportedException();
}
}
+
+ private static class ThreadLocalContext extends ThreadLocal<Context[]> {
+ public Context[] initialValue() {
+ return null;
+ }
+ }
+
+ public static Context[] getThreadLocalContext() {
+ return localContext.get();
+ }
+
+ public static Context getThreadLocalContext(Context orig) {
+ Context[] root = localContext.get();
+ for (int i = 0; i < root.length; i++) {
+ Context lctx = getThreadLocalContext(root[i], orig);
+ if (lctx != null)
+ return lctx;
+ }
+ return null;
+ }
+
+ public static Select getThreadLocalSelect(Select select) {
+ if (select == null)
+ return null;
+ Context[] lctx = JDBCStoreQuery.getThreadLocalContext();
+ Context cloneFrom = select.ctx();
+ for (int i = 0; i < lctx.length; i++) {
+ Context cloneTo = getThreadLocalContext(lctx[i], cloneFrom);
+ if (cloneTo != null)
+ return (Select)cloneTo.getSelect();
+ }
+ return select;
+ }
+
+ public static Context getThreadLocalContext(Context lctx, Context cloneFrom) {
+ if (lctx.cloneFrom == cloneFrom)
+ return lctx;
+ java.util.List<Context> subselCtxs = lctx.getSubselContexts();
+ if (subselCtxs != null) {
+ for (Context subselCtx : subselCtxs) {
+ Context ctx = getThreadLocalContext(subselCtx, cloneFrom);
+ if (ctx != null)
+ return ctx;
+ }
+ }
+ return null;
+ }
+
+ private static Context[] clone(Context[] orig, Context parent) {
+ Context[] newCtx = new Context[orig.length];
+ for (int i = 0; i < orig.length; i++) {
+ newCtx[i] = clone(orig[i], parent);
+ }
+ return newCtx;
+ }
+
+ private static Context clone(Context orig, Context parent) {
+ Context myParent = null;
+ if (parent == null) {
+ Context origParent = orig.getParent();
+ if (origParent != null)
+ myParent = clone(orig.getParent(), null);
+ } else
+ myParent = parent;
+
+ Context newCtx = new Context(orig.parsed, null, myParent);
+ newCtx.from = orig.from;
+ newCtx.meta = orig.meta;
+ newCtx.schemaAlias = orig.schemaAlias;
+ newCtx.setSchemas(orig.getSchemas());
+ newCtx.setVariables(orig.getVariables());
+ newCtx.cloneFrom = orig;
+ Object select = orig.getSelect();
+ if (select != null)
+ newCtx.setSelect(((SelectImpl)select).clone(newCtx));
+ newCtx.subquery = orig.subquery;
+ List<Context> subsels = orig.getSubselContexts();
+ if (subsels != null) {
+ for (Context subsel : subsels)
+ newCtx.addSubselContext(clone(subsel, newCtx));
+ }
+
+ return newCtx;
+ }
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java Wed Jul 29 23:53:46 2009
@@ -26,6 +26,7 @@
import org.apache.commons.lang.ObjectUtils;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCStoreQuery;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.Discriminator;
import org.apache.openjpa.jdbc.meta.FieldMapping;
@@ -596,8 +597,10 @@
break;
}
prevaction = action;
- if (prevaction != null && prevaction.context != null)
- pstate.joins = pstate.joins.setJoinContext(prevaction.context);
+ if (prevaction != null && prevaction.context != null) {
+ Context jCtx = JDBCStoreQuery.getThreadLocalContext(prevaction.context);
+ pstate.joins = pstate.joins.setJoinContext(jCtx);
+ }
}
if (_varName != null)
pstate.joins = pstate.joins.setVariable(_varName);
@@ -627,7 +630,7 @@
return pstate;
}
- public String findSubqAlias(Select sel) {
+ private String findSubqAlias(Select sel) {
Select pSel = sel.getParent();
if (pSel == null)
return null;
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SelectConstructor.java Wed Jul 29 23:53:46 2009
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
+import org.apache.openjpa.jdbc.kernel.JDBCStoreQuery;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.Joins;
@@ -122,18 +123,28 @@
*/
private Select newSelect(ExpContext ctx, Select parent,
String alias, QueryExpressions exps, QueryExpressionsState state) {
- Select sel = parent != null ? _subselect
+ Select subselect = JDBCStoreQuery.getThreadLocalSelect(_subselect);
+ Select sel = parent != null ? subselect
: ctx.store.getSQLFactory().newSelect();
sel.setAutoDistinct((exps.distinct & exps.DISTINCT_AUTO) != 0);
sel.setJoinSyntax(ctx.fetch.getJoinSyntax());
sel.setParent(parent, alias);
+ Context[] qryCtx = JDBCStoreQuery.getThreadLocalContext();
+ Context lctx = null;
+ for (int i = 0; i < qryCtx.length; i++) {
+ if (qryCtx[i].cloneFrom == exps.ctx()) {
+ lctx = qryCtx[i];
+ break;
+ }
+ }
+
if (sel.ctx() == null)
- sel.setContext(exps.ctx());
+ sel.setContext(lctx);
- if (parent == null && exps.ctx().getSubselContexts() != null) {
+ if (parent == null && lctx.getSubselContexts() != null) {
// this is the case subselect was created before parent got created
- List<Context> subselCtxs = exps.ctx().getSubselContexts();
+ List<Context> subselCtxs = lctx.getSubselContexts();
for (Context subselCtx : subselCtxs) {
Select subsel = (Select) subselCtx.getSelect();
Subquery subquery = subselCtx.getSubquery();
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java Wed Jul 29 23:53:46 2009
@@ -22,6 +22,7 @@
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCStoreQuery;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
import org.apache.openjpa.jdbc.sql.Result;
@@ -119,9 +120,10 @@
}
public ExpState initialize(Select sel, ExpContext ctx, int flags) {
- _select.setParent(sel, null);
+ Select select = JDBCStoreQuery.getThreadLocalSelect(_select);
+ select.setParent(sel, null);
if (_exps.projections.length == 1) {
- return ((Val) _exps.projections[0]).initialize(_select, ctx, flags);
+ return ((Val) _exps.projections[0]).initialize(select, ctx, flags);
}
return ExpState.NULL;
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java Wed Jul 29 23:53:46 2009
@@ -2214,36 +2214,15 @@
private static class Placeholder {
}
- public void reset() {
- _aliases = null;
- _eager = null;
- _eagerKeys = null;
- _expectedResultCount = 0;
- _flags = 0;
- _from = null;
- _grouped = null;
- _grouping = null;
- _having = null;
- _joins = null;
- _joinSyntax = 0;
- _nullIds = 0;
- _ordered = null;
- _ordering = null;
- _orders = 0;
- _outer = null;
- _parent = null;
- _placeholders = 0;
- _preJoins = null;
- _schemaAlias = null;
- _selects._aliases = null;
- _selects._ids = null;
- _subPath = null;
- _subsels = null;
- _tables = null;
- _where = null;
-
+ public SelectImpl clone(Context ctx) {
+ SelectImpl sel = (SelectImpl) _conf.getSQLFactoryInstance().newSelect();
+ sel._ctx = ctx;
+ if (_parent != null && _parent.ctx() != null)
+ sel._parent = (SelectImpl)_parent.ctx().getSelect();
+ sel._schemaAlias = _schemaAlias;
+ sel._flags = _flags;
+ return sel;
}
-
/**
* Key type used for aliases.
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Context.java Wed Jul 29 23:53:46 2009
@@ -39,10 +39,11 @@
public String schemaAlias;
public Subquery subquery;
public Expression from = null;
- private Context parent = null;
+ public Context cloneFrom = null;
+ private final Context parent;
private List<Context> subsels = null;
private Object select = null;
- private int aliasCount = -1;
+ protected int aliasCount = -1;
private Map<String,Value> variables = new HashMap<String,Value>();
private Map<String,ClassMetaData> schemas =
new HashMap<String,ClassMetaData>();
@@ -120,7 +121,9 @@
* Register the subquery context in this context.
* @param sub
*/
- private void addSubselContext(Context sub) {
+ public void addSubselContext(Context sub) {
+ if (sub == null)
+ return;
if (subsels == null)
subsels = new ArrayList<Context>();
subsels.add(sub);
@@ -146,14 +149,18 @@
return parent;
}
- public void setParent(Context parent) {
- this.parent = parent;
- }
-
public void addVariable(String id, Value var) {
variables.put(id.toLowerCase(), var);
}
+ public Map<String,Value> getVariables() {
+ return variables;
+ }
+
+ public void setVariables(Map<String,Value> variables) {
+ this.variables = variables;
+ }
+
public void addSchema(String id, ClassMetaData meta) {
schemas.put(id.toLowerCase(), meta);
}
@@ -164,14 +171,22 @@
return null;
}
+ public Map<String,ClassMetaData> getSchemas() {
+ return schemas;
+ }
+
+ public void setSchemas(Map<String,ClassMetaData> schemas) {
+ this.schemas = schemas;
+ }
+
/**
* Given an alias and return its associated variable.
- * @param var
+ * @param alias
* @return
*/
- public Value getVariable(String var) {
- Value variable = var == null ? null
- : variables.get(var.toLowerCase());
+ public Value getVariable(String alias) {
+ Value variable = alias == null ? null
+ : variables.get(alias.toLowerCase());
return variable;
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java?rev=799134&r1=799133&r2=799134&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java Wed Jul 29 23:53:46 2009
@@ -1418,10 +1418,8 @@
// parse the subquery
ParsedJPQL parsed = new ParsedJPQL(node.parser.jpql, node);
- Context parent = ctx();
Context subContext = new Context(parsed, null, ctx());
contexts.push(subContext);
- subContext.setParent(parent);
ClassMetaData candidate = getCandidateMetaData(node);
Subquery subq = subContext.getSubquery();