QueryDeleteColumn errors out with java.lang.NegativeArraySizeException
Copy link to clipboard
Copied
I need help with an error I can't find an explanation for anywhere.
On ColdFusion 2021, I'm trying to delete a column from a query. The query for sure contains the column I am trying to delete, as you can see from the code snippet, which works otherwise when I comment QueryDeleteColumn.
<cftry>
<cfset local.newColumnArray = ArrayNew(1)>
<cfloop query="Data">
<cfif len(Data.columName)>
<cfset ArrayAppend(local.newColumnArray, Data.columName)>
<cfelse>
<cfset ArrayAppend(local.newColumnArray, otherMethod(Data.differentColumn))>
</cfif>
</cfloop>
<cfset QueryAddColumn(Data,"newColumn","VarChar", local.newColumnArray)>
<cfset QueryDeleteColumn(Data,"columName")>
<cfcatch type="any">
<cf_mcabort message="xxx [line #cfcatch.tagContext[1].line#]: #CFCATCH.Message#" except="#cfcatch#">
</cfcatch>
</cftry>
However, when I try do include that call, I get the following error:
java.lang.NegativeArraySizeException: -1
at coldfusion.sql.QueryTableMetaData.deleteColumnNameAndType(QueryTableMetaData.java:539)
at coldfusion.sql.imq.imqTable.deleteColumnnNameAndType(imqTable.java:321)
at coldfusion.sql.QueryTable.deleteColumn(QueryTable.java:705)
at coldfusion.runtime.QueryFunction.QueryDeleteColumn(QueryFunction.java:1025)
at coldfusion.runtime.CFPage.QueryDeleteColumn(CFPage.java:2508)
at cfTransactions2ecfc627721595$funcLOOKUPTRANSACTION.runFunction(xxxxxx:68)
at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:623)
at coldfusion.filter.SilentFilter.invoke(SilentFilter.java:47)
at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:516)
at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:95)
at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:463)
at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:438)
at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:681)
at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:980)
at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:762)
at coldfusion.filter.ComponentFilter.invoke(ComponentFilter.java:261)
at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:606)
at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:43)
at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
at coldfusion.filter.PathFilter.invoke(PathFilter.java:162)
at coldfusion.filter.LicenseFilter.invoke(LicenseFilter.java:30)
at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:97)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:60)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.xml.rpc.CFCServlet.invoke(CFCServlet.java:167)
at coldfusion.xml.rpc.CFCServlet.doGet(CFCServlet.java:318)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:311)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:46)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:47)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:377)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:829)
My best guess is that this has to do with the query, as I use this method elsewhere with very similar code and it works fine. I've tried deleting different columns, including the one I dinamically add there, to no avail. I haven't figured out how, though.
Copy link to clipboard
Copied
I received this exact same error message. I am also using CF2021, fully patched. Did you ever find a solution or workaround?
In my case I am calling queryExecute() to run a SQL statement. My T-SQL code utilizes OFFET-FETCH and CTEs to return the total number of records in a column named [totalCount]. From the CF side, this should be a basic query result. I get the first value of [totalCount] and then try to delete that column before returning the results:
local.data = queryExecute(sql=sql, params={ offset:arguments.offset, limit:arguments.limit })
local.recordcount = local.data.totalCount
queryDeleteColumn(local.data, "totalCount")
Copy link to clipboard
Copied
The query is an object, and you have been manipulating it. So, before calling queryDeleteColumn, you have to first test for the existence of the column:
<cfif queryKeyExists(Data, "columName")>
<cfset queryDeleteColumn(Data,"columName")>
</cfif>
Copy link to clipboard
Copied
It's been a year plus since the last reply, and I get the same error from an attempt to delete a column from a SP (sproc) generated cfprocresult set (Azure MS-SQL) in CF2021:
<cfstoredproc procedure="Get_Centers" datasource="#application.datasource#" cachedwithin="#createTimespan(0,0,0,2)#">
<cfprocparam variable="IdClient" cfsqltype="CF_SQL_INTEGER" value="#val(struReturn.sessionStruct.client_id)#" />
<cfprocresult name="struReturn.data" />
</cfstoredProc>
<cfset queryDeleteColumn(struReturn.data,'SECRETCOL') /> <!--- NegativeArraySizeException ERROR --->
My fix was a QoQ to "re-cast" the results as a query type - that CF apparently likes better:
<cfstoredproc procedure="Get_Centers" datasource="#application.datasource#" cachedwithin="#createTimespan(0,0,0,2)#">
<cfprocparam variable="IdClient" cfsqltype="CF_SQL_INTEGER" value="#val(struReturn.sessionStruct.client_id)#" />
<cfprocresult name="qResults" />
</cfstoredProc>
<cfquery name="struReturn.data" dbtype="query"> <!--- DUMB BUT NEEDED --->
SELECT * FROM qResults
</cfquery>
<cfset queryDeleteColumn(struReturn.data,'SECRETCOL') /> <!--- WORKS --->
Hope this helps someone.
Copy link to clipboard
Copied
@AlHolden , With the error message
java.lang.NegativeArraySizeException
ColdFusion may be trying to tell you something. Chances are that, unknown to you, the query object is being modified by some underlying process.
For example, your code contains an existential issue. The query object qResults is cached for just 2 seconds. So the code assumes that the query-of-query runs within 2 seconds after the stored procedure. That is a pretty tight timespan, hence an unrealistic assumption.
There might be circumstances where the assumption is not true. Think, for example, of network latency between ColdFusion and the database server. There is then this fundamental question:
- Which query object does the query of query refer to: the cached query or a newly generated query?
That makes me ask what the point is of such a shortly lived cache.
In any case, I have already suggested a neat way to avoid any such misunderstanding. Before deleting a query-column, first test whether it exists.
In your case, the code will be something like
<!---
Suggestion: Raise 'cachedWithin' to a more realistic value (10 seconds, say), to ensure that the same object is reused.
Test whether a column exists before deleting it. If it unexpectedly doesn't exist, then an underlying process might have modified the query.
--->
<cfstoredproc procedure="Get_Centers" datasource="#application.datasource#" cachedwithin="#createTimespan(0,0,0,10)#">
<cfprocparam variable="IdClient" cfsqltype="CF_SQL_INTEGER" value="#val(struReturn.sessionStruct.client_id)#" />
<cfprocresult name="qResults" />
</cfstoredProc>
<cfif queryKeyExists(qResults, "SECRETCOL")>
<cfset queryDeleteColumn(qResults,"SECRETCOL")>
<cfelse>
<!--- An underlying process has probably modified the query. Investigate. --->
<!--- Dump any errors in the logs folder --->
<cftry>
<cfdump var="#qResults#" format="html" output="#server.coldfusion.rootDir#\logs\qResultsQueryDump.html">
<cfcatch type="any">
<cfdump var="#cfcatch#" format="html" output="#server.coldfusion.rootDir#\logs\qResultsCfcatch.html">
</cfcatch>
</cftry>
</cfif>
Copy link to clipboard
Copied
Wow, jumping in on a Satruday. Thanks @BKBK !
Good catch, you are correct that the application of a cache appears to be the pivoting factor in this example's error.
However, I'm not sure the time span of the cache is the issue. I've created a simplified standalone example which employs a full one day cache - and the error is still present, even when employing the "does it exist?" test first.
Here is the "broken" version:
<cfstoredproc procedure="Get_Centers" datasource="[redacted]" cachedwithin="#createTimespan(1,0,0,0)#">
<cfprocparam variable="IdClient" cfsqltype="CF_SQL_INTEGER" value="2" />
<cfprocresult name="qResults" />
</cfstoredProc>
<cfdump var="#qResults#" />
<hr/>
<cfdump var="#qResults.columnList#" />
<hr/>
<cfdump var="#queryKeyExists(qResults, "ADDED_IDUSERS")#" />
<hr/>
<cfif queryKeyExists(qResults, "ADDED_IDUSERS")>
<cfset queryDeleteColumn(qResults,'ADDED_IDUSERS') />
</cfif>
<hr/>
<cfdump var="#qResults.columnList#" />
Which produces this:
Next, here is the "fixed" version:
<cfstoredproc procedure="Get_Centers" datasource="[redacted]" cachedwithin="#createTimespan(1,0,0,0)#">
<cfprocparam variable="IdClient" cfsqltype="CF_SQL_INTEGER" value="2" />
<cfprocresult name="qResults" />
</cfstoredProc>
<!--- ADDED --->
<cfquery name="qResults" dbtype="query">
SELECT * FROM qResults
</cfquery>
<cfdump var="#qResults#" />
<hr/>
<cfdump var="#qResults.columnList#" />
<hr/>
<cfdump var="#queryKeyExists(qResults, "ADDED_IDUSERS")#" />
<hr/>
<cfif queryKeyExists(qResults, "ADDED_IDUSERS")>
<cfset queryDeleteColumn(qResults,'ADDED_IDUSERS') />
</cfif>
<hr/>
<cfdump var="#qResults.columnList#" />
Here's the error-free result, after the ADDED interim step "turn this query into a query" step
So to me, it seems a bit buggy. The application of the cache seems to affect some internal column array, no matter how long the life span of the cache. The queryKeyExists function considers the column extant, while the queryDeleteColumn disagrees, perhaps using a different test.
Can you audit my logic? Thanks again.
Copy link to clipboard
Copied
Hi @AlHolden ,
Thanks for the update. Hats-off to you.
I now consider what you have presented to be a compelling demonstration that
"java.lang.NegativeArraySizeException: -1"
is a bug. Please report it.
In fact, you could just copy-paste your last post as the bug report. Then include your query-of-query trick as a workaround.
Additional information: the cause of the bug is the function
deleteColumnNameAndType()
within the Java class
coldfusion.sql.QueryTableMetaData
Apparently, the function attempts to use an array whose index is -1, hence the exception.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Thanks, @AlHolden .

