diff --git a/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java b/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java index 5f7453f41c..474f21cf83 100644 --- a/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java +++ b/core/src/main/java/lucee/commons/lang/PhysicalClassLoader.java @@ -32,6 +32,7 @@ import lucee.commons.digest.HashUtil; import lucee.commons.io.IOUtil; +import lucee.commons.io.SystemUtil; import lucee.commons.io.log.LogUtil; import lucee.commons.io.res.Resource; import lucee.commons.io.res.util.ResourceClassLoader; @@ -125,7 +126,7 @@ public Class loadClass(String name) throws ClassNotFoundException { @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - synchronized (this) { + synchronized (SystemUtil.createToken("pcl", name)) { return loadClass(name, resolve, true); } } @@ -153,7 +154,7 @@ private Class loadClass(String name, boolean resolve, boolean loadFromFS) thr @Override protected Class findClass(String name) throws ClassNotFoundException {// if(name.indexOf("sub")!=-1)print.ds(name); - synchronized (this) { + synchronized (SystemUtil.createToken("pcl", name)) { Resource res = directory.getRealResource(name.replace('.', '/').concat(".class")); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -175,7 +176,7 @@ private Class loadClass(String name, boolean resolve, boolean loadFromFS) thr public Class loadClass(String name, byte[] barr) throws UnmodifiableClassException { Class clazz = null; - synchronized (this) { + synchronized (SystemUtil.createToken("pcl", name)) { // new class , not in memory yet try { diff --git a/core/src/main/java/lucee/runtime/ComponentSpecificAccess.java b/core/src/main/java/lucee/runtime/ComponentSpecificAccess.java index c1fa62b779..f9cdab9531 100755 --- a/core/src/main/java/lucee/runtime/ComponentSpecificAccess.java +++ b/core/src/main/java/lucee/runtime/ComponentSpecificAccess.java @@ -491,7 +491,7 @@ public Object get(int access, Key key, Object defaultValue) { @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, int access) { - return toDumpData(pageContext, maxlevel, dp, access); + return component.toDumpData(pageContext, maxlevel, dp, access); } @Override diff --git a/core/src/main/java/lucee/runtime/PageContextImpl.java b/core/src/main/java/lucee/runtime/PageContextImpl.java index d5d8a4116a..30edaac100 100644 --- a/core/src/main/java/lucee/runtime/PageContextImpl.java +++ b/core/src/main/java/lucee/runtime/PageContextImpl.java @@ -315,7 +315,7 @@ public final class PageContextImpl extends PageContext { private PageSource base; private ApplicationContextSupport applicationContext; - private final ApplicationContextSupport defaultApplicationContext; + private final ApplicationContextSupport initApplicationContext; private ScopeFactory scopeFactory = new ScopeFactory(); @@ -388,7 +388,7 @@ public PageContextImpl(ScopeContext scopeContext, ConfigWebPro config, HttpServl this.scopeContext = scopeContext; undefined = new UndefinedImpl(this, getScopeCascadingType()); server = ScopeContext.getServerScope(this, jsr223); - defaultApplicationContext = new ClassicApplicationContext(config, "", true, null); + initApplicationContext = new ClassicApplicationContext(config, "", true, null); this.id = getIdCounter(); } @@ -435,6 +435,7 @@ public void initialize(Servlet servlet, ServletRequest req, ServletResponse rsp, */ public PageContextImpl initialize(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp, String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush, boolean isChild, boolean ignoreScopes, PageContextImpl tmplPC) { + applicationContext = initApplicationContext; parent = null; caller = null; callerTemplate = null; @@ -454,9 +455,7 @@ public PageContextImpl initialize(HttpServlet servlet, HttpServletRequest req, H ReqRspUtil.setContentType(rsp, "text/html; charset=" + config.getWebCharset().name()); this.isChild = isChild; - - applicationContext = defaultApplicationContext; - setFullNullSupport(); + fullNullSupport = config.getFullNullSupport(); startTime = System.currentTimeMillis(); startTimeNS = System.nanoTime(); @@ -592,6 +591,7 @@ else if (variables == null) { this.pathList.add(it.next()); } } + if (applicationContext == initApplicationContext) applicationContext = null; return this; } @@ -782,15 +782,15 @@ public void forceWrite(String str) throws IOException { @Override public void writePSQ(Object o) throws IOException, PageException { // is var usage allowed? - if (applicationContext != null && applicationContext.getQueryVarUsage() != ConfigPro.QUERY_VAR_USAGE_IGNORE) { + if (getApplicationContext().getQueryVarUsage() != ConfigPro.QUERY_VAR_USAGE_IGNORE) { // Warning - if (applicationContext.getQueryVarUsage() == ConfigPro.QUERY_VAR_USAGE_WARN) { + if (getApplicationContext().getQueryVarUsage() == ConfigPro.QUERY_VAR_USAGE_WARN) { DebuggerImpl.deprecated(this, "query.variableUsage", "Please do not use variables within the cfquery tag, instead use the tag \"cfqueryparam\" or the attribute \"params\""); } // Error - else if (applicationContext.getQueryVarUsage() == ConfigPro.QUERY_VAR_USAGE_ERROR) { + else if (getApplicationContext().getQueryVarUsage() == ConfigPro.QUERY_VAR_USAGE_ERROR) { throw new ApplicationException("Variables are not allowed within cfquery, please use the tag or the attribute \"params\" instead."); } } @@ -885,15 +885,15 @@ public PageSource[] getRelativePageSources(String realPath) { } public PageSource getPageSource(String realPath) { - return PageSourceImpl.best(config.getPageSources(this, applicationContext.getMappings(), realPath, false, useSpecialMappings, true)); + return PageSourceImpl.best(config.getPageSources(this, getApplicationContext().getMappings(), realPath, false, useSpecialMappings, true)); } public PageSource[] getPageSources(String realPath) { // to not change, this is used in the flex extension - return config.getPageSources(this, applicationContext.getMappings(), realPath, false, useSpecialMappings, true, false); + return config.getPageSources(this, getApplicationContext().getMappings(), realPath, false, useSpecialMappings, true, false); } public PageSource getPageSourceExisting(String realPath) { // do not change, this method is used in flex extension - return config.getPageSourceExisting(this, applicationContext.getMappings(), realPath, false, useSpecialMappings, true, false); + return config.getPageSourceExisting(this, getApplicationContext().getMappings(), realPath, false, useSpecialMappings, true, false); } public boolean useSpecialMappings(boolean useTagMappings) { @@ -907,12 +907,12 @@ public boolean useSpecialMappings() { } public Resource getPhysical(String realPath, boolean alsoDefaultMapping) { - return config.getPhysical(applicationContext.getMappings(), realPath, alsoDefaultMapping); + return config.getPhysical(getApplicationContext().getMappings(), realPath, alsoDefaultMapping); } @Override public PageSource toPageSource(Resource res, PageSource defaultValue) { - return config.toPageSource(applicationContext.getMappings(), res, defaultValue); + return config.toPageSource(getApplicationContext().getMappings(), res, defaultValue); } @Override @@ -1409,7 +1409,7 @@ public Request requestScope() { @Override public CGI cgiScope() { - CGI cgi = applicationContext == null || applicationContext.getCGIScopeReadonly() ? cgiR : cgiRW; + CGI cgi = getApplicationContext().getCGIScopeReadonly() ? cgiR : cgiRW; if (!cgi.isInitalized()) cgi.initialize(this); return cgi; } @@ -1417,7 +1417,7 @@ public CGI cgiScope() { @Override public Application applicationScope() throws PageException { if (application == null) { - if (!applicationContext.hasName()) + if (!getApplicationContext().hasName()) throw new ExpressionException("there is no application context defined for this application", hintAplication("you can define an application context")); application = scopeContext.getApplicationScope(this, true, DUMMY_BOOL); } @@ -1650,7 +1650,7 @@ public Session sessionScope(boolean checkExpires) throws PageException { public boolean hasCFSession() { if (session != null) return true; - if (!applicationContext.hasName() || !applicationContext.isSetSessionManagement()) return false; + if (!getApplicationContext().hasName() || !getApplicationContext().isSetSessionManagement()) return false; return scopeContext.hasExistingSessionScope(this); } @@ -1660,9 +1660,9 @@ public void invalidateUserScopes(boolean migrateSessionData, boolean migrateClie } private void checkSessionContext() throws ExpressionException { - if (!applicationContext.hasName()) + if (!getApplicationContext().hasName()) throw new ExpressionException("there is no session context defined for this application", hintAplication("you can define a session context")); - if (!applicationContext.isSetSessionManagement()) throw new ExpressionException("session scope is not enabled", hintAplication("you can enable session scope")); + if (!getApplicationContext().isSetSessionManagement()) throw new ExpressionException("session scope is not enabled", hintAplication("you can enable session scope")); } @Override @@ -1699,9 +1699,9 @@ public Cookie cookieScope() { @Override public Client clientScope() throws PageException { if (client == null) { - if (!applicationContext.hasName()) + if (!getApplicationContext().hasName()) throw new ExpressionException("there is no client context defined for this application", hintAplication("you can define a client context")); - if (!applicationContext.isSetClientManagement()) throw new ExpressionException("client scope is not enabled", hintAplication("you can enable client scope")); + if (!getApplicationContext().isSetClientManagement()) throw new ExpressionException("client scope is not enabled", hintAplication("you can enable client scope")); client = scopeContext.getClientScope(this); } @@ -1711,8 +1711,8 @@ public Client clientScope() throws PageException { @Override public Client clientScopeEL() { if (client == null) { - if (applicationContext == null || !applicationContext.hasName()) return null; - if (!applicationContext.isSetClientManagement()) return null; + if (!getApplicationContext().hasName()) return null; + if (!getApplicationContext().isSetClientManagement()) return null; client = scopeContext.getClientScopeEL(this); } return client; @@ -2679,13 +2679,13 @@ else if (StringUtil.endsWithIgnoreCase(pathInfo, ".java")) { @Override public final void execute(String realPath, boolean throwExcpetion, boolean onlyTopLevel) throws PageException { - setFullNullSupport(); + fullNullSupport = getConfig().getFullNullSupport(); _execute(realPath, throwExcpetion, onlyTopLevel); } @Override public final void executeCFML(String realPath, boolean throwExcpetion, boolean onlyTopLevel) throws PageException { - setFullNullSupport(); + fullNullSupport = getConfig().getFullNullSupport(); _execute(realPath, throwExcpetion, onlyTopLevel); } @@ -2789,36 +2789,36 @@ private final void execute(PageSource ps, boolean throwExcpetion, boolean onlyTo public boolean show() { if (isGatewayContext()) return false; - ApplicationContextSupport ac = (ApplicationContextSupport) getApplicationContext(); + ApplicationContextSupport ac = getApplicationContext(); if (ac == null) { - return config.getShowDoc() || config.getShowMetric() || config.getShowTest() || config.getShowDebug(); + return config.getShowDoc() || config.getShowMetric() || config.getShowTest() || (config.getShowDebug() /* && DebuggerImpl.getDebugEntry(this) != null */); } - return ac.getShowDoc() || ac.getShowMetric() || ac.getShowTest() || ac.getShowDebug(); + return ac.getShowDoc() || ac.getShowMetric() || ac.getShowTest() || (ac.getShowDebug() /* && DebuggerImpl.getDebugEntry(this) != null */); + } public boolean showDebug() { if (isGatewayContext()) return false; - return getApplicationContext() instanceof ApplicationContextSupport ? ((ApplicationContextSupport) getApplicationContext()).getShowDebug() : config.getShowDebug(); + return getApplicationContext().getShowDebug(); } public boolean showDoc() { if (isGatewayContext()) return false; - return getApplicationContext() instanceof ApplicationContextSupport ? ((ApplicationContextSupport) getApplicationContext()).getShowDoc() : config.getShowDoc(); + return getApplicationContext().getShowDoc(); } public boolean showMetric() { if (isGatewayContext()) return false; - return getApplicationContext() instanceof ApplicationContextSupport ? ((ApplicationContextSupport) getApplicationContext()).getShowMetric() : config.getShowMetric(); + return getApplicationContext().getShowMetric(); } public boolean showTest() { if (isGatewayContext()) return false; - return getApplicationContext() instanceof ApplicationContextSupport ? ((ApplicationContextSupport) getApplicationContext()).getShowTest() : config.getShowTest(); + return getApplicationContext().getShowTest(); } public boolean hasDebugOptions(int option) { - return getApplicationContext() instanceof ApplicationContextSupport ? ((ApplicationContextSupport) getApplicationContext()).hasDebugOptions(option) - : config.hasDebugOptions(option); + return getApplicationContext().hasDebugOptions(option); } private void initallog() { @@ -2888,10 +2888,7 @@ public void clear() { @Override public long getRequestTimeout() { if (requestTimeout == -1) { - if (applicationContext != null) { - return applicationContext.getRequestTimeout().getMillis(); - } - requestTimeout = config.getRequestTimeout().getMillis(); + return getApplicationContext().getRequestTimeout().getMillis(); } return requestTimeout; } @@ -3006,7 +3003,7 @@ else if ("cftoken".equalsIgnoreCase(name)) { cftoken = Caster.toString(oCftoken, "0"); } - if (setCookie && applicationContext.isSetClientCookies()) setClientCookies(); + if (setCookie && getApplicationContext().isSetClientCookies()) setClientCookies(); } private boolean isValidCfToken(String value) { @@ -3022,7 +3019,7 @@ public void resetIdAndToken() { cfid = CFIDUtil.createCFID(this); cftoken = ScopeContext.getNewCFToken(); - if (applicationContext.isSetClientCookies()) setClientCookies(); + if (getApplicationContext().isSetClientCookies()) setClientCookies(); } private void setClientCookies() { @@ -3095,11 +3092,7 @@ public void setPsq(boolean psq) { @Override public boolean getPsq() { if (_psq != null) return _psq.booleanValue(); - - if (applicationContext != null) { - return applicationContext.getQueryPSQ(); - } - return config.getPSQL(); + return getApplicationContext().getQueryPSQ(); } @Override @@ -3159,7 +3152,7 @@ public Tag use(String tagClassName, String tagBundleName, String tagBundleVersio if (currentTag instanceof TagImpl) ((TagImpl) currentTag).setSourceTemplate(template); if (attrType >= 0 && fullname != null) { - Map attrs = applicationContext.getTagAttributeDefaultValues(this, fullname); + Map attrs = getApplicationContext().getTagAttributeDefaultValues(this, fullname); if (attrs != null) { TagUtil.setAttributes(this, currentTag, attrs, attrType); } @@ -3237,10 +3230,10 @@ public Component getActiveComponent() { @Override public Credential getRemoteUser() throws PageException { if (remoteUser == null) { - Key name = KeyImpl.init(Login.getApplicationName(applicationContext)); + Key name = KeyImpl.init(Login.getApplicationName(getApplicationContext())); Resource roles = config.getConfigDir().getRealResource("roles"); - if (applicationContext.getLoginStorage() == Scope.SCOPE_SESSION) { + if (getApplicationContext().getLoginStorage() == Scope.SCOPE_SESSION) { if (hasCFSession()) { Object auth = sessionScope().get(name, null); if (auth != null) { @@ -3248,7 +3241,7 @@ public Credential getRemoteUser() throws PageException { } } } - else if (applicationContext.getLoginStorage() == Scope.SCOPE_COOKIE) { + else if (getApplicationContext().getLoginStorage() == Scope.SCOPE_COOKIE) { Object auth = cookieScope().get(name, null); if (auth != null) { remoteUser = CredentialImpl.decode(auth, roles, true); @@ -3261,7 +3254,7 @@ else if (applicationContext.getLoginStorage() == Scope.SCOPE_COOKIE) { @Override public void clearRemoteUser() { if (remoteUser != null) remoteUser = null; - String name = Login.getApplicationName(applicationContext); + String name = Login.getApplicationName(getApplicationContext()); cookieScope().removeEL(KeyImpl.init(name)); try { @@ -3396,21 +3389,26 @@ public FTPPoolImpl getFTPPool() { */ @Override - public ApplicationContext getApplicationContext() { + public ApplicationContextSupport getApplicationContext() { + if (applicationContext == null) { + synchronized (scopeFactory) { + if (applicationContext == null) { + applicationContext = new ClassicApplicationContext(config, "", true, null); + } + } + } return applicationContext; } @Override - public void setApplicationContext(ApplicationContext applicationContext) { + public void setApplicationContext(ApplicationContext ac) { session = null; application = null; client = null; - if (applicationContext != null) this.applicationContext = (ApplicationContextSupport) applicationContext; - else applicationContext = this.applicationContext; - - if (applicationContext == null) return; + if (ac != null) this.applicationContext = (ApplicationContextSupport) ac; + else return; setFullNullSupport(); int scriptProtect = applicationContext.getScriptProtect(); @@ -3439,7 +3437,7 @@ public boolean initApplicationContext(ApplicationListener listener) throws PageE boolean initSession = false; // AppListenerSupport listener = (AppListenerSupport) config.get ApplicationListener(); KeyLock lock = config.getContextLock(); - String name = StringUtil.emptyIfNull(applicationContext.getName()); + String name = StringUtil.emptyIfNull(getApplicationContext().getName()); // Application application = scopeContext.getApplicationScope(this, false, null);// this is needed that the @@ -3475,13 +3473,13 @@ public boolean initApplicationContext(ApplicationListener listener) throws PageE } // Session - initSession = applicationContext.isSetSessionManagement() && listener.hasOnSessionStart(this) && !scopeContext.hasExistingSessionScope(this); + initSession = getApplicationContext().isSetSessionManagement() && listener.hasOnSessionStart(this) && !scopeContext.hasExistingSessionScope(this); if (initSession) { String token = name + ":" + getCFID(); Lock tokenLock = lock.lock(token, getRequestTimeout()); try { // we need to check it again within the lock, to make sure the call is exclusive - initSession = applicationContext.isSetSessionManagement() && listener.hasOnSessionStart(this) && !scopeContext.hasExistingSessionScope(this); + initSession = getApplicationContext().isSetSessionManagement() && listener.hasOnSessionStart(this) && !scopeContext.hasExistingSessionScope(this); // init session if (initSession) { @@ -3814,8 +3812,7 @@ public ClassLoader getClassLoader(Resource[] reses) throws IOException { } private ResourceClassLoader getResourceClassLoader() throws IOException { - - JavaSettingsImpl js = (JavaSettingsImpl) applicationContext.getJavaSettings(); + JavaSettingsImpl js = (JavaSettingsImpl) getApplicationContext().getJavaSettings(); if (js != null) { Resource[] jars = js.getResourcesTranslated(); @@ -3829,7 +3826,7 @@ public ClassLoader getRPCClassLoader(boolean reload) throws IOException { } public ClassLoader getRPCClassLoader(boolean reload, ClassLoader[] parents) throws IOException { - JavaSettingsImpl js = (JavaSettingsImpl) applicationContext.getJavaSettings(); + JavaSettingsImpl js = (JavaSettingsImpl) getApplicationContext().getJavaSettings(); ClassLoader cl = config.getRPCClassLoader(reload, parents); if (js != null) { Resource[] jars = js.getResourcesTranslated(); @@ -3875,7 +3872,7 @@ public Password getServerPassword() { @Override public short getSessionType() { if (isGatewayContext()) return Config.SESSION_TYPE_APPLICATION; - return applicationContext.getSessionType(); + return getApplicationContext().getSessionType(); } // this is just a wrapper method for ACF @@ -3905,7 +3902,7 @@ public CacheConnection getCacheConnection(String cacheName, CacheConnection defa cacheName = cacheName.toLowerCase().trim(); CacheConnection cc = null; - if (getApplicationContext() != null) cc = ((ApplicationContextSupport) getApplicationContext()).getCacheConnection(cacheName, null); + if (getApplicationContext() != null) cc = getApplicationContext().getCacheConnection(cacheName, null); if (cc == null) cc = config.getCacheConnections().get(cacheName); if (cc == null) return defaultValue; @@ -3916,7 +3913,7 @@ public CacheConnection getCacheConnection(String cacheName) throws CacheExceptio cacheName = cacheName.toLowerCase().trim(); CacheConnection cc = null; - if (getApplicationContext() != null) cc = ((ApplicationContextSupport) getApplicationContext()).getCacheConnection(cacheName, null); + if (getApplicationContext() != null) cc = getApplicationContext().getCacheConnection(cacheName, null); if (cc == null) cc = config.getCacheConnections().get(cacheName); if (cc == null) throw CacheUtil.noCache(config, cacheName); @@ -3966,44 +3963,36 @@ public Charset getWebCharset() { } public short getScopeCascadingType() { - if (applicationContext == null) return config.getScopeCascadingType(); - return applicationContext.getScopeCascading(); + return getApplicationContext().getScopeCascading(); } public boolean getTypeChecking() { - if (applicationContext == null) return config.getTypeChecking(); - return applicationContext.getTypeChecking(); + return getApplicationContext().getTypeChecking(); } public boolean getAllowCompression() { - if (applicationContext == null) return config.allowCompression(); - return applicationContext.getAllowCompression(); + return getApplicationContext().getAllowCompression(); } public boolean getSuppressContent() { - if (applicationContext == null) return config.isSuppressContent(); - return applicationContext.getSuppressContent(); + return getApplicationContext().getSuppressContent(); } @Override public Object getCachedWithin(int type) { - if (applicationContext == null) return config.getCachedWithin(type); - return applicationContext.getCachedWithin(type); + return getApplicationContext().getCachedWithin(type); } // FUTURE add to interface public lucee.runtime.net.mail.Server[] getMailServers() { - if (applicationContext != null) { - lucee.runtime.net.mail.Server[] appms = applicationContext.getMailServers(); - if (ArrayUtil.isEmpty(appms)) return config.getMailServers(); + lucee.runtime.net.mail.Server[] appms = getApplicationContext().getMailServers(); + if (ArrayUtil.isEmpty(appms)) return config.getMailServers(); - lucee.runtime.net.mail.Server[] cms = config.getMailServers(); - if (ArrayUtil.isEmpty(cms)) return appms; + lucee.runtime.net.mail.Server[] cms = config.getMailServers(); + if (ArrayUtil.isEmpty(cms)) return appms; - lucee.runtime.net.mail.Server[] arr = ServerImpl.merge(appms, cms); - return arr; - } - return config.getMailServers(); + lucee.runtime.net.mail.Server[] arr = ServerImpl.merge(appms, cms); + return arr; } // FUTURE add to interface @@ -4012,7 +4001,7 @@ public boolean getFullNullSupport() { } private void setFullNullSupport() { - fullNullSupport = (applicationContext != null && applicationContext.getFullNullSupport()); + fullNullSupport = getApplicationContext().getFullNullSupport(); } public void registerLazyStatement(Statement s) { @@ -4069,40 +4058,30 @@ public int getAppListenerType() { } public Log getLog(String name) { - if (applicationContext != null) { - Log log = null; - try { - log = applicationContext.getLog(name); - } - catch (PageException e) { - config.getLog("application").error(getClass().getName(), e); - } - if (log != null) return log; + Log log = null; + try { + log = getApplicationContext().getLog(name); } + catch (PageException e) { + config.getLog("application").error(getClass().getName(), e); + } + if (log != null) return log; return config.getLog(name); } public Log getLog(String name, boolean createIfNecessary) throws PageException { - if (applicationContext != null) { - Log log = applicationContext.getLog(name); - if (log != null) return log; - } + Log log = getApplicationContext().getLog(name); + if (log != null) return log; return config.getLog(name, createIfNecessary); } public java.util.Collection getLogNames() throws PageException { java.util.Collection cnames = config.getLoggers().keySet(); - if (applicationContext != null) { - java.util.Collection anames = applicationContext.getLogNames(); - - java.util.Collection names = new HashSet(); - - copy(cnames, names); - copy(anames, names); - return names; - - } - return cnames; + java.util.Collection anames = getApplicationContext().getLogNames(); + java.util.Collection names = new HashSet(); + copy(cnames, names); + copy(anames, names); + return names; } private void copy(java.util.Collection src, java.util.Collection trg) { @@ -4149,18 +4128,12 @@ public PageContextImpl setDummy(boolean dummy) { } public TimeSpan getCachedAfterTimeRange() { // FUTURE add to interface - if (applicationContext != null) { - return applicationContext.getQueryCachedAfter(); - } - return config.getCachedAfterTimeRange(); + return getApplicationContext().getQueryCachedAfter(); } public ProxyData getProxyData() { - if (applicationContext != null) { - ProxyData pd = applicationContext.getProxyData(); - if (pd != null) return pd; - } - // TODO check application context + ProxyData pd = getApplicationContext().getProxyData(); + if (pd != null) return pd; return config.getProxyData(); } @@ -4173,13 +4146,11 @@ public boolean getListenSettings() { } public boolean allowImplicidQueryCall() { - if (applicationContext != null) return applicationContext.getAllowImplicidQueryCall(); - return config.allowImplicidQueryCall(); + return getApplicationContext().getAllowImplicidQueryCall(); } public Regex getRegex() { - if (applicationContext != null) return applicationContext.getRegex(); - return config.getRegex(); + return getApplicationContext().getRegex(); } private static int getIdCounter() { @@ -4192,8 +4163,7 @@ private static int getIdCounter() { } public boolean limitEvaluation() { - if (applicationContext != null) return applicationContext.getLimitEvaluation(); - return ((ConfigPro) config).limitEvaluation(); + return getApplicationContext().getLimitEvaluation(); } public long timeoutNoAction() { diff --git a/core/src/main/java/lucee/runtime/SuperComponent.java b/core/src/main/java/lucee/runtime/SuperComponent.java index 4c46647d7e..2dde8d1a3e 100755 --- a/core/src/main/java/lucee/runtime/SuperComponent.java +++ b/core/src/main/java/lucee/runtime/SuperComponent.java @@ -569,7 +569,7 @@ public Object get(int access, Key key, Object defaultValue) { @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, int access) { - return toDumpData(pageContext, maxlevel, dp, access); + return comp.toDumpData(pageContext, maxlevel, dp, access); } @Override diff --git a/core/src/main/java/lucee/runtime/debug/DebuggerUtil.java b/core/src/main/java/lucee/runtime/debug/DebuggerUtil.java index d54ef16bda..d04d1cf8e4 100644 --- a/core/src/main/java/lucee/runtime/debug/DebuggerUtil.java +++ b/core/src/main/java/lucee/runtime/debug/DebuggerUtil.java @@ -73,4 +73,18 @@ public static boolean debugQueryUsage(PageContext pageContext, Query query) { } return false; } + + public static boolean hasCustomDebugEntry(PageContext pc) { + + String addr = pc.getHttpServletRequest().getRemoteAddr(); + lucee.runtime.config.DebugEntry debugEntry = ((ConfigPro) pc.getConfig()).getDebugEntry(addr, null); + return debugEntry != null; + } + + public static boolean hasDebugOptions(PageContext pc) { + PageContextImpl pci = (PageContextImpl) pc; + return pci.hasDebugOptions(ConfigPro.DEBUG_DATABASE) || pci.hasDebugOptions(ConfigPro.DEBUG_DUMP) || pci.hasDebugOptions(ConfigPro.DEBUG_EXCEPTION) + || pci.hasDebugOptions(ConfigPro.DEBUG_IMPLICIT_ACCESS) || pci.hasDebugOptions(ConfigPro.DEBUG_QUERY_USAGE) || pci.hasDebugOptions(ConfigPro.DEBUG_TEMPLATE) + || pci.hasDebugOptions(ConfigPro.DEBUG_THREAD) || pci.hasDebugOptions(ConfigPro.DEBUG_TIMER) || pci.hasDebugOptions(ConfigPro.DEBUG_TRACING); + } } \ No newline at end of file diff --git a/core/src/main/java/lucee/runtime/functions/string/MarkdownToHTML.java b/core/src/main/java/lucee/runtime/functions/string/MarkdownToHTML.java index c998192ce2..836635a2a3 100644 --- a/core/src/main/java/lucee/runtime/functions/string/MarkdownToHTML.java +++ b/core/src/main/java/lucee/runtime/functions/string/MarkdownToHTML.java @@ -23,11 +23,11 @@ public Object invoke(PageContext pc, Object[] args) throws PageException { return call(pc, Caster.toString(args[0])); } - public static String call(PageContext pc, String markdown) throws PageException { + public static String call(PageContext pc, String markdown) { return call(pc, markdown, false, null); } - public static String call(PageContext pc, String markdown, boolean safeMode) throws PageException { + public static String call(PageContext pc, String markdown, boolean safeMode) { return call(pc, markdown, safeMode, null); } diff --git a/core/src/main/java/lucee/runtime/java/JavaObject.java b/core/src/main/java/lucee/runtime/java/JavaObject.java index ad5b7c7876..e506012bd2 100644 --- a/core/src/main/java/lucee/runtime/java/JavaObject.java +++ b/core/src/main/java/lucee/runtime/java/JavaObject.java @@ -324,9 +324,9 @@ private Object init(Object[] arguments) throws PageException { } private Object init(Object[] arguments, Object defaultValue) { - object = Reflector.callConstructor(clazz, arguments, defaultValue); - isInit = object != defaultValue; - return object; + object = Reflector.callConstructor(clazz, arguments, null); + isInit = object != null; + return isInit ? object : defaultValue; } @Override diff --git a/core/src/main/java/lucee/runtime/tag/Setting.java b/core/src/main/java/lucee/runtime/tag/Setting.java index f08a556103..e8afb1cb9d 100755 --- a/core/src/main/java/lucee/runtime/tag/Setting.java +++ b/core/src/main/java/lucee/runtime/tag/Setting.java @@ -22,6 +22,7 @@ import lucee.runtime.PageContextImpl; import lucee.runtime.debug.DebuggerImpl; +import lucee.runtime.debug.DebuggerUtil; import lucee.runtime.exp.PageException; import lucee.runtime.exp.PageExceptionImpl; import lucee.runtime.ext.tag.BodyTagImpl; @@ -50,56 +51,54 @@ public void setRequesttimeout(double requesttimeout) { } /** - * set the value showdebugoutput Yes or No. When set to No, showDebugOutput suppresses debugging - * information that would otherwise display at the end of the generated page.Default is Yes. + * for backward compatibility reason this setting only works enables debugging, if there is a custom + * debug template and at least one debug setting is enabled * * @param showdebugoutput value to set **/ - public void setShowdebugoutput(boolean showdebugoutput) { - ApplicationContextSupport acs = (ApplicationContextSupport) pageContext.getApplicationContext(); - if (acs != null) { - acs.setShowDebug(showdebugoutput); - acs.setShowDoc(showdebugoutput); - acs.setShowMetric(showdebugoutput); - acs.setShowTest(showdebugoutput); + public void setShowdebugoutput(boolean show) { + if (show) { + if (!DebuggerUtil.hasCustomDebugEntry(pageContext)) return; + if (!DebuggerUtil.hasDebugOptions(pageContext)) return; } + setShowdebug(show); } - public void setShow(boolean showdebugoutput) { + public void setShow(boolean show) { ApplicationContextSupport acs = (ApplicationContextSupport) pageContext.getApplicationContext(); if (acs != null) { - acs.setShowDebug(showdebugoutput); - acs.setShowDoc(showdebugoutput); - acs.setShowMetric(showdebugoutput); - acs.setShowTest(showdebugoutput); + acs.setShowDebug(show); + acs.setShowDoc(show); + acs.setShowMetric(show); + acs.setShowTest(show); } } - public void setShowdebug(boolean showdebugoutput) { + public void setShowdebug(boolean show) { ApplicationContextSupport acs = (ApplicationContextSupport) pageContext.getApplicationContext(); if (acs != null) { - acs.setShowDebug(showdebugoutput); + acs.setShowDebug(show); } } - public void setShowmetric(boolean showdebugoutput) { + public void setShowmetric(boolean show) { ApplicationContextSupport acs = (ApplicationContextSupport) pageContext.getApplicationContext(); if (acs != null) { - acs.setShowMetric(showdebugoutput); + acs.setShowMetric(show); } } - public void setShowdoc(boolean showdebugoutput) { + public void setShowdoc(boolean show) { ApplicationContextSupport acs = (ApplicationContextSupport) pageContext.getApplicationContext(); if (acs != null) { - acs.setShowDoc(showdebugoutput); + acs.setShowDoc(show); } } - public void setShowtest(boolean showdebugoutput) { + public void setShowtest(boolean show) { ApplicationContextSupport acs = (ApplicationContextSupport) pageContext.getApplicationContext(); if (acs != null) { - acs.setShowTest(showdebugoutput); + acs.setShowTest(show); } } diff --git a/core/src/main/java/lucee/runtime/tag/ThreadTag.java b/core/src/main/java/lucee/runtime/tag/ThreadTag.java index 3e00725359..547f9b6858 100755 --- a/core/src/main/java/lucee/runtime/tag/ThreadTag.java +++ b/core/src/main/java/lucee/runtime/tag/ThreadTag.java @@ -89,7 +89,7 @@ public final class ThreadTag extends BodyTagImpl implements DynamicAttributes { private int action = ACTION_RUN; private long duration = -1; - private Collection.Key _name; + private Collection.Key name; private int priority = Thread.NORM_PRIORITY; private long timeout = 0; private PageContext pc; @@ -103,7 +103,7 @@ public void release() { super.release(); action = ACTION_RUN; duration = -1; - _name = null; + name = null; priority = Thread.NORM_PRIORITY; type = TYPE_DAEMON; plans = EXECUTION_PLAN; @@ -142,17 +142,17 @@ public void setSeparatescopes(boolean separateScopes) { */ public void setName(String name) { if (StringUtil.isEmpty(name, true)) return; - this._name = KeyImpl.init(name); + this.name = KeyImpl.init(name); } private Collection.Key name(boolean create) { - if (_name == null && create) _name = KeyImpl.init("thread" + RandomUtil.createRandomStringLC(20)); - return _name; + if (name == null && create) name = KeyImpl.init("thread" + RandomUtil.createRandomStringLC(5)); + return name; } - private String nameAsString(boolean create) { + public String nameAsString(boolean create) { name(create); - return _name == null ? null : _name.getString(); + return name == null ? null : name.getString(); } /** @@ -296,7 +296,11 @@ public int doEndTag() throws PageException { } public void register(Page currentPage, int threadIndex) throws PageException { - if (ACTION_RUN != action) return; + _register(currentPage, threadIndex); + } + + public String _register(Page currentPage, int threadIndex) throws PageException { + if (ACTION_RUN != action) return null; Key name = name(true); try { @@ -327,6 +331,7 @@ public void register(Page currentPage, int threadIndex) throws PageException { finally { ((PageContextImpl) pc).reuse(this);// this method is not called from template when type is run, a call from template is to early, } + return name.getString(); } private static PageContext getRootPageContext(PageContext pc) { diff --git a/core/src/main/java/lucee/runtime/type/scope/UndefinedImpl.java b/core/src/main/java/lucee/runtime/type/scope/UndefinedImpl.java index 7ddd2b7a5a..b4d9af4311 100755 --- a/core/src/main/java/lucee/runtime/type/scope/UndefinedImpl.java +++ b/core/src/main/java/lucee/runtime/type/scope/UndefinedImpl.java @@ -762,8 +762,7 @@ public boolean isAllowImplicidQueryCall() { @Override public boolean setAllowImplicidQueryCall(boolean allowImplicidQueryCall) { boolean old = pc.allowImplicidQueryCall(); - ((ApplicationContextSupport) pc.getApplicationContext()).setAllowImplicidQueryCall(allowImplicidQueryCall); - // this.allowImplicidQueryCall = allowImplicidQueryCall; + pc.getApplicationContext().setAllowImplicidQueryCall(allowImplicidQueryCall); return old; } diff --git a/core/src/main/java/lucee/transformer/bytecode/expression/var/VariableImpl.java b/core/src/main/java/lucee/transformer/bytecode/expression/var/VariableImpl.java index 352bb28c08..624c78037e 100644 --- a/core/src/main/java/lucee/transformer/bytecode/expression/var/VariableImpl.java +++ b/core/src/main/java/lucee/transformer/bytecode/expression/var/VariableImpl.java @@ -37,7 +37,6 @@ import lucee.runtime.db.ClassDefinition; import lucee.runtime.engine.ThreadLocalPageContext; import lucee.runtime.exp.TemplateException; -import lucee.runtime.functions.other.CreateUniqueId; import lucee.runtime.tag.TagUtil; import lucee.runtime.type.scope.Scope; import lucee.runtime.type.util.ArrayUtil; @@ -278,22 +277,18 @@ else if (listener != null) { private Type _writeOutListener(BytecodeContext bc, int mode, Boolean asCollection) throws TransformerException { GeneratorAdapter ga = bc.getAdapter(); - // TODO better way to get it? - String name = "threadListener:" + Long.toString(System.currentTimeMillis(), Character.MAX_RADIX) + CreateUniqueId.invoke(); - LitString lname = bc.getFactory().createLitString(name); TagThread tt = new TagThread(bc.getFactory(), getStart(), listener.getEnd()); TagLibTag tlt = TagUtil.getTagLibTag((ConfigPro) ThreadLocalPageContext.getConfig(), "cf", "thread"); + tt.outputName(); tt.setTagLibTag(tlt); tt.addAttribute(new Attribute(false, "action", bc.getFactory().createLitString("run"), "string")); tt.addAttribute(new Attribute(false, "separatescopes", bc.getFactory().createLitBoolean(false), "boolean")); - tt.addAttribute(new Attribute(false, "name", lname, "string")); Body body = tt.getBody(); body.addStatement(new TryCatch(bc.getFactory(), getStart(), listener.getEnd(), this, listener, asCollection)); tt.setBody(body); tt.setParent(bc.getPage()); tt.init(); tt._writeOut(bc); - lname.writeOut(bc, Expression.MODE_REF); return Types.STRING; } diff --git a/core/src/main/java/lucee/transformer/bytecode/statement/tag/TagThread.java b/core/src/main/java/lucee/transformer/bytecode/statement/tag/TagThread.java index 965424a160..2193ff8bb0 100755 --- a/core/src/main/java/lucee/transformer/bytecode/statement/tag/TagThread.java +++ b/core/src/main/java/lucee/transformer/bytecode/statement/tag/TagThread.java @@ -38,14 +38,21 @@ public final class TagThread extends TagBaseNoFinal implements ATagThread { public static final Type THREAD_TAG = Type.getType(ThreadTag.class); private static final Method REGISTER = new Method("register", Types.VOID, new Type[] { Types.PAGE, Types.INT_VALUE }); + private static final Method _REGISTER = new Method("_register", Types.STRING, new Type[] { Types.PAGE, Types.INT_VALUE }); private int index; + private boolean outputName; + public TagThread(Factory f, Position start, Position end) { super(f, start, end); // print.e("::::"+ASMUtil.getAttributeString(this, "action","run")+":"+hashCode()); } + public void outputName() { + this.outputName = true; + } + public void init() throws TransformerException { String action = ASMUtil.getAttributeString(this, "action", "run"); // no body @@ -80,8 +87,7 @@ public void _writeOut(BytecodeContext bc) throws TransformerException { adapter.loadLocal(bc.getCurrentTag()); adapter.loadThis(); adapter.push(index); - adapter.invokeVirtual(THREAD_TAG, REGISTER); - + adapter.invokeVirtual(THREAD_TAG, outputName ? _REGISTER : REGISTER); } /** diff --git a/core/src/main/java/lucee/transformer/dynamic/DynamicClassLoader.java b/core/src/main/java/lucee/transformer/dynamic/DynamicClassLoader.java index f970af4581..c829725549 100644 --- a/core/src/main/java/lucee/transformer/dynamic/DynamicClassLoader.java +++ b/core/src/main/java/lucee/transformer/dynamic/DynamicClassLoader.java @@ -25,18 +25,17 @@ public final class DynamicClassLoader extends ExtendableClassLoader { boolean res = registerAsParallelCapable(); } private Resource directory; - // private final Set parents = new HashSet<>(); - private Map loadedClasses = new ConcurrentHashMap(); - private Map allLoadedClasses = new ConcurrentHashMap(); // this includes all renames - private Map unavaiClasses = new ConcurrentHashMap(); + private final Map loadedClasses = new ConcurrentHashMap<>(); + private final Map allLoadedClasses = new ConcurrentHashMap<>(); // this includes all renames + private final Map unavaiClasses = new ConcurrentHashMap<>(); - private Map> instances = new ConcurrentHashMap>(); + private final Map> instances = new ConcurrentHashMap<>(); private static long counter = 0L; private static long _start = 0L; private static String start = Long.toString(_start, Character.MAX_RADIX); - private static Object countToken = new Object(); + private static final Object countToken = new Object(); public static String uid() { synchronized (countToken) { @@ -114,7 +113,7 @@ public Object loadInstance(String name) throws ClassNotFoundException, Instantia @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded - synchronized (this) { + synchronized (SystemUtil.createToken("dcl", name)) { return loadClass(name, resolve, true); } } diff --git a/core/src/main/java/resource/context/admin/info/Info.cfc b/core/src/main/java/resource/context/admin/info/Info.cfc index 1c28b246df..e14a133726 100644 --- a/core/src/main/java/resource/context/admin/info/Info.cfc +++ b/core/src/main/java/resource/context/admin/info/Info.cfc @@ -21,7 +21,16 @@ "metric":"ldMetric" ,"ref":"loadRef" ]; - + // this should never happen + if(len(enabledKeys)==0){ + return; + } + + // only show the debug template + if(len(enabledKeys)==1 && (arguments.show.debug?:false) && !isNull(arguments.debugTemplate) && ((getMetaData(arguments.debugTemplate).fullname?:"")!="lucee.admin.debug.Modern")) { + arguments.debugTemplate.output(custom:arguments.debugArgs.custom,debugging:arguments.debugArgs.debugging); + return; + }

diff --git a/core/src/main/java/resource/tld/core-base.tld b/core/src/main/java/resource/tld/core-base.tld index 8ed391b30e..d4c6b3af10 100755 --- a/core/src/main/java/resource/tld/core-base.tld +++ b/core/src/main/java/resource/tld/core-base.tld @@ -5645,9 +5645,19 @@ To use cached data, the current query must use the same SQL statement, data sour boolean showDebugOutput false + deprecated true - Yes or No. When set to No, showDebugOutput suppresses monitor information that would - otherwise display at the end of the generated page. + +This attribute is deprecated, use instead one of the following attributes: +- showDebug +- showMetrics +- showDoc +- showTest +- show + +This attributes emulates as close as possible the behaviour of previous Lucee versions (6.0 or smaller). +This attribute only takes effect when a custom debug template is defined in the Lucee admin and at least one debug option is enabled. + boolean diff --git a/loader/build.xml b/loader/build.xml index 5f75c8e63f..d2cb6128fa 100644 --- a/loader/build.xml +++ b/loader/build.xml @@ -2,7 +2,7 @@ - + diff --git a/loader/pom.xml b/loader/pom.xml index a2149a1198..f6db1c8ed9 100644 --- a/loader/pom.xml +++ b/loader/pom.xml @@ -3,7 +3,7 @@ org.lucee lucee - 6.1.1.8-SNAPSHOT + 6.1.0.219-SNAPSHOT jar Lucee Loader Build diff --git a/test/functions/ArraySort.cfc b/test/functions/ArraySort.cfc index 7edbe7fbaf..0ae12c3e24 100644 --- a/test/functions/ArraySort.cfc +++ b/test/functions/ArraySort.cfc @@ -14,8 +14,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{ it(title="checking ArraySort(asc;localeSensitive=true) function", body = function( currentSpec ) { var arr=['a','b']; - arraySort(arr,'text','asc',true) - writedump(arrayToList(arr)=="a,b"); + arraySort(arr,'text','asc',true); assertEquals("a,b",arrayToList(arr)); }); it(title="checking ArraySort(desc;localeSensitive=true) function", body = function( currentSpec ) { diff --git a/test/general/FunctionListener.cfc b/test/general/FunctionListener.cfc index dd864f972f..6663575c9e 100644 --- a/test/general/FunctionListener.cfc +++ b/test/general/FunctionListener.cfc @@ -231,6 +231,15 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{ var result=b?mySuccess():"not b"; expect(result).toBe("Susi Sorglos"); }); + it(title="call the same multiple times", body=function() { + loop times=2 { + var t=mySuccess():function(result,error) { + variables.testFunctionListenerV=result; + thread.testFunctionListenerV=result; + }; + threadJoin(t); + } + }); }); } diff --git a/test/tickets/Issue0055.cfc b/test/tickets/Issue0055.cfc index be6dc5834e..55961e6dfa 100644 --- a/test/tickets/Issue0055.cfc +++ b/test/tickets/Issue0055.cfc @@ -25,7 +25,7 @@ - + diff --git a/test/tickets/LDEV0555.cfc b/test/tickets/LDEV0555.cfc index 796799ddba..3daa69a671 100644 --- a/test/tickets/LDEV0555.cfc +++ b/test/tickets/LDEV0555.cfc @@ -79,7 +79,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{ } catch ( any e ){ var encodeValue = e.message; } - writeDump(encodeValue); expect(encodeValue).toBe("aWQ9QkEtMzU3OSZ5PTIwMDEmbT1EQUtPVEEmeW1zPVBQJnVyZ2lkPU5ZMDImdmluPTNEN0hBMThONzJHMTc3Njg2tg=="); }); @@ -102,7 +101,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{ } catch ( any e ){ var encodeValue = e.message; } - writeDump(encodeValue); expect(encodeValue).toBe("aWQ9QkEtMzU3OSZ5PTIwMDEmbT1EQUtPVEEmeW1zPVBQJnVyZ2lkPU5ZMDImdmluPTNEN0hBThONzJHMTc3Nj2tkgQ=="); }); }); diff --git a/test/tickets/LDEV0677.cfc b/test/tickets/LDEV0677.cfc index 52a1211f5d..52865fc4a3 100644 --- a/test/tickets/LDEV0677.cfc +++ b/test/tickets/LDEV0677.cfc @@ -39,7 +39,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { // data should be copied over assertEquals("sorglos",sess1.susi); - dump(sess2); assertEquals("sorglos",sess2.susi); assertEquals("sorglos",sess3.susi); diff --git a/test/tickets/LDEV1718.cfc b/test/tickets/LDEV1718.cfc index 9c10d91544..7cccb35845 100644 --- a/test/tickets/LDEV1718.cfc +++ b/test/tickets/LDEV1718.cfc @@ -49,8 +49,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { // this should be resolved via the /sue mapping, because it is a match with that mapping and there is no other mapping, dahh! var path=slashify(expandPath("/sue/ellen/sub/")); - dump(label:"/susi/ellen/sub/",var:path); - dump(path== sue&"ellen/sub/"); expect( path ).toBe( sue&"ellen/sub/" ); }); @@ -63,8 +61,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { // now the sue/ellen mapping should be used var path=slashify(expandPath("/sue/ellen/sub/")); - dump(label:"/susi/ellen/sub/",var:path); - dump(path== sue_ellen_sub); expect( path ).toBe( sue_ellen_sub ); }); @@ -79,7 +75,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { // now we test sub sub that only exists in the /sue mapping var path=slashify(expandPath("/sue/ellen/sub/subsub/")); - dump(label:"/susi/ellen/sub/subsub/",var:path); // even that does not exist in the sue/ellen mapping, that mapping is used because of the "lucee.mapping.first" env var is true, so mapping over match expect( path ).toBe( sue_ellen_sub&"subsub/" ); diff --git a/test/tickets/LDEV3066.cfc b/test/tickets/LDEV3066.cfc index 2606c3f6fa..a084ab9830 100644 --- a/test/tickets/LDEV3066.cfc +++ b/test/tickets/LDEV3066.cfc @@ -9,8 +9,6 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { expect("abc").toBe(ReReplace( string, regex, "\1" )); expect("asdasd").toBe(ReReplace( string, regex, "\2" )); expect("").toBe(ReReplace( string, regex, "\3" )); - - writedump( ReFind( regex, string, 1, true ) ); }); diff --git a/test/tickets/LDEV4828.cfc b/test/tickets/LDEV4828.cfc index e547607022..6897d339cb 100644 --- a/test/tickets/LDEV4828.cfc +++ b/test/tickets/LDEV4828.cfc @@ -8,7 +8,6 @@ component extends = "org.lucee.cfml.test.LuceeTestCase" { for(var i=1; i<=numberOfColumns; i++) { queryAddColumn(q, "c#i#", ["x"]) } - dump(q) }); }); }