Var scoping issue possibly? - coldfusion

A few times in my functions I have stuff like this:
<cffunction name="mergeData">
<cfquery name="myQuery">
SELECT columnName FROM tableName
</cfquery>
<cfquery dbtype="query" name="myOtherQuery">
SELECT columnName FROM myQuery
</cfquery>
</cffunction>
<cfset resulta = mergeData(queryA) />
<cfset resultb = mergeData(queryB) />
<cfset resultc = mergeData(queryC) />
Occasionally then I get the error The select column reference [myQuery.columnname] is not found in table [myQuery].
So what could be causing this. How can I diagnose. I was thinking it could be a scoping issue, so I'm going to add <cfquery name="local.myQuery"> just to make sure things are contained in the function (I should be doing that anyway probably). But when something only happens sometimes I have a hard time figuring out how to diagnose.
EDIT: Added some clarity on why it's most likely a scoping issue. My thought is that myQuery is poossibly being referenced in other calls. I mean, it's not like it's running multiple threads on the data, but is it possible that that could be the cause? Are there other causes? This isn't always the case when I get the error. I also get it on a page where it function is only running once.

In the query of queries, use brackets around the local scope prefix.
<cffunction name="mergeData">
<cfquery name="local.myQuery">
SELECT columnName FROM tableName
</cfquery>
<cfquery dbtype="query" name="local.myOtherQuery">
SELECT columnName FROM [local].myQuery
</cfquery>
</cffunction>
<cfset resulta = mergeData(queryA) />
<cfset resultb = mergeData(queryB) />
<cfset resultc = mergeData(queryC) />

I've never gotten LOCAL to work in query of queries in a function.
So I do this....
<cffunction>
<cfquery name="VARIABLES.myQuery">
SELECT columnName FROM tableName
</cfquery>
<cfquery dbtype="query" name="myOtherQuery">
SELECT columnName FROM VARIABLES.myQuery
</cfquery>
<cffunction>
I strongly suggest using a more explicit name for your query, especially in query of queries.

Related

cftransaction will only run first cfquery, skips over second

I'm trying to write to two different tables, both in the same database. In one CFTRANSACTION with two CFQUERY, the first CFQUERY will INSERT properly but the second (also INSERT) is just skipped over. No errors are thrown, I can see the data in the first table, and commenting out the first INSERT will allow the second to go through as desired.
A simplified version of my code is:
<cffunction name="insertReport">
<cfset var strReturn="">
<cftransaction>
<cftry>
<cfquery name="updateTable1" datasource="DB1">
...
</cfquery>
<cfquery name="UpdateTable2" datasource="DB1">
...
</cfquery>
<cfcatch type="any">
<cfset errMsg = "#cfcatch.Message#">
</cfcatch>
</cftry>
<cfif trim(errMsg) eq ''>
<cftransaction action="commit">
<cfelse>
<cftransaction action="rollback">
<cfset strReturn = "Error: #errMsg#.">
</cfif>
</cftransaction>
<cfreturn strReturn>
</cffunction>
This is probably something really simple, but I'm stuck. Any help is appreciated.
Update
I just tried the below code on CF11 and it worked fine. The only error I received was that errMsg was undefined, which it isn't in your code until the <cfcatch> occurs. I defined errMsg and re-ran -- it was successful.
<cffunction name="insertReport">
<cfset var strReturn="">
<cfset errMsg = "">
<cftransaction>
<cftry>
<cfquery name="updateTable1" datasource="DS1">
INSERT INTO ...
</cfquery>
<cfquery name="UpdateTable2" datasource="DS1">
INSERT INTO ...
</cfquery>
<cfcatch type="any">
<cfset errMsg = "#cfcatch.Message#">
</cfcatch>
</cftry>
<cfif trim(errMsg) eq ''>
<cftransaction action="commit">
<cfelse>
<cftransaction action="rollback">
<cfset strReturn = "Error: #errMsg#.">
</cfif>
</cftransaction>
<cfreturn strReturn>
</cffunction>
<cfoutput>#insertReport()#</cfoutput>
Regarding multiple datasources
According to this Adobe forum and this SO post, you must commit changes to each datasource before continuing to the next.
According to the SO post, this will work:
<cftransaction action="begin">
<cfquery datasource="foo">
select * from foo_test
</cfquery>
<cftransaction action="commit"><!-- Commit before switching DSNs --->
<cfquery datasource="bar">
select * from bar_test
</cfquery>
</cftransaction>
Note that if you can access your data via one datasource using three part names, (e.g. fooDB.dbo.table ) you can write to different databases in one <cftransaction>
Thanks to everyone who helped. It turns out the problem was the fact that we're using CFQUERYPARAMs in the CFQUERY instead of hard-coding the values, and they were throwing Null Pointer exceptions.
It seems like those CFQUERYPARAM elements would write to the database properly when we only had one CFQUERY, but still threw that Null Pointer exception that would skip over the second CFQUERY. Because the Null Pointer only threw a "#cfcatch.type#" value, not "#cfcatch.Message#" or "#cfcatch.detail#" that our error-checking was looking for, we didn't flag the problem.
We're looking unto using jTDS now to see if that will solve the issue.

conditional query in coldfusion

I need to provide some status on items in my table which I do in the last column of my table.
First I go and query one table to see if I have a confirmation for the item .
<cfquery name="focnotice" datasource="******" result="FocResult">
SELECT ecspc
FROM tbl_CNR_H
WHERE icsc = '#myarray[i].ICSC#'
AND asr_no = '#myarray[i].ASR#'
</cfquery>
The ECSPC is a field in my Table, so logic is see if there is a record. If so, see if the ECSPC value is something other then "". If so, query another table to see if there is a matching record for this ECSPC.
<cfset ISUPStatus = "#focnotice.ecspc#">
<cfif ISUPStatus NEQ "">
<cfquery name="isupStatus" datasource="******" result="ISUPResult">
select *
from tbl_ISUP
where dpc = '#ISUPStatus#'
</cfquery>
<cfset isupcount = #ISUPResult.RecordCount#>
<cfif #isupcount# GT 0>
<cfset ISUPorder = "Yes">
<cfelse>
<cfset ISUPorder = "No">
</cfif>
<cfelse>
<cfset ISUPorder = "No">
</cfif>
I get the following error in my debug
Complex object types cannot be converted to simple values.
The expression has requested a variable or an intermediate expression
result as a simple value. However, the result cannot be converted to a
simple value. Simple values are strings, numbers, boolean values, and
date/time values. Queries, arrays, and COM objects are examples of
complex values. The most likely cause of the error is that you tried
to use a complex value as a simple one. For example, you tried to use
a query variable in a cfif tag.
What am I missing here ?
You are passing invalid parameter into the Query "myarray[i].ICSC",'#myarray[i].ASR#'. You need to specify what index of array you are using.
<cfquery name="focnotice" datasource="*******" result="FocResult">
Select ecspc
From tbl_CNR_H
Where icsc = <cfqueryparam cfsqltype="cf_sql_varchar" value="#myarray[1].ICSC#">
AND
asr_no = <cfqueryparam cfsqltype="cf_sql_varchar" value="#myarray[1].ASR#">
</cfquery>
I believe the error causing you the issue lies in:
<cfset isupcount = #ISUPResult.RecordCount#>
From a quick look of your code, try using instead:
<cfset isUpCount = isUpStatus.recordCount>
But in addition please look at the comments above, especially joins.

ColdFusion Query-of-Queries Wildcard LIKE condition not working with single quotes?

I have a query-of-queries that performs a LIKE condition on a variable string:
When the variable contains a single word that includes a single quote, some results are returned, but not all:
<cfset _myVar = "Women's" />
<cfquery name="_qData" dbtype="Query">
SELECT
ID
FROM MyQoQ
WHERE NAME LIKE '%#_myvar#%'
OR DESCRIPTION LIKE '%#_myvar#%'
</cfquery>
When the variable contains more than one word, and one of those words includes a single quote, no records are returned:
<cfset _myVar = "Women's Initiative" />
<cfquery name="_qData" dbtype="Query">
SELECT
ID
FROM MyQoQ
WHERE NAME LIKE '%#_myvar#%'
OR DESCRIPTION LIKE '%#_myvar#%'
</cfquery>
I've tried PreserveSingleQuotes() as well as wrapping the varaibles with CFQUERYPARAM, but, to no avail - I get the same results.
Is there a way to make this work?
Adding in a repro case
<cfset myQuery = queryNew('hello')>
<cfset queryAddRow(myQuery,5)>
<cfset querySetCell(myQuery,"hello","what up",1)>
<cfset querySetCell(myQuery,"hello","what's up",2)>
<cfset querySetCell(myQuery,"hello","what's up friends",3)>
<cfset querySetCell(myQuery,"hello","what u",4)>
<cfset querySetCell(myQuery,"hello","what",5)>
<cfdump var="#myQuery#">
<cfquery name="res" dbtype="query">
SELECT *
FROM myQuery
WHERE hello LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%$what's up%">
</cfquery>
<cfdump var="#res#">
Railo 4.1.1.009 - returns both results (rows 2 and 3)
ColdFusion 10,0,13,287689 - returns no results
If I change my SQL to
WHERE hello LIKE '%what''s up%'
I still get no results
aarh!! a classic case of royal pain in the rear.
To solve this, you have to add an extra ' to every ' in your search term, there by escaping it.
<cfset myQuery = queryNew('hello')>
<cfset queryAddRow(myQuery,5)>
<cfset querySetCell(myQuery,"hello","what up",1)>
<cfset querySetCell(myQuery,"hello","what's up",2)>
<cfset querySetCell(myQuery,"hello","what's up friends",3)>
<cfset querySetCell(myQuery,"hello","what u",4)>
<cfset querySetCell(myQuery,"hello","what",5)>
<cfdump var="#myQuery#">
<cfset x = "what's up" />
<cfquery name="res" dbtype="query">
SELECT *
FROM myQuery
WHERE hello LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="#replace(x, "'", "''", "all")#%">
</cfquery>
<cfdump var="#res#">
if you do this directly, as you mentioned,
WHERE hello LIKE '%what''s up%'
the parser is going bonkers. But, if you pass the value via a function return value, the run time assignment of values via a variable somehow makes the parser happy.
I remember using such tricks in sending multiple SQL statements delimited with ';' in cfquery. Directly writing
"DECLARE x NUMBER; SELECT 2 INTO x FROM DUAL;"
inside cfquery fails, but assigning them to a string and then sending the string as a return value for any string manipulator function (lcase, ucase, etc) worked perfectly.
Note: the problem is solved, but if my explanation and approach is diff, feel free to correct and comment.
I'm running ColdFusion 10 u13.
Modifying your repo code this seemed to work:
<cfset myQuery = queryNew('hello')>
<cfset queryAddRow(myQuery,5)>
<cfset querySetCell(myQuery,"hello","what up",1)>
<cfset querySetCell(myQuery,"hello","what's up",2)>
<cfset querySetCell(myQuery,"hello","what's up friends",3)>
<cfset querySetCell(myQuery,"hello","what u",4)>
<cfset querySetCell(myQuery,"hello","what",5)>
<cfdump var="#myQuery#">
<cfquery name="res" dbtype="query">
SELECT *
FROM [myQuery]
WHERE [hello] LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%what''s up%">
</cfquery>
Note the double single quotes in the <cfqueryparam> tag. Like Dan I would have thought that the <cfqueryparam> tag would have taken care of this for you automatically. Perhaps this is a bug in QoQ?

Is it possible to have dynamically generated query names in ColdFusion?

What I am trying to do is
<cfloop array="#LOCAL.someArray" index="LOCAL.aString">
<cfset LOCAL.queryName = "uniqueQueryName_" & LOCAL.aString />
<cfquery name="#LOCAL.queryName#" datasource="db" cachedwithin="#CreateTimeSpan(1,0,0,0)#">
SELECT count(*) AS c FROM someTable
</cfquery>
<cfdump var="#LOCAL.queryName#" />
</cfloop>
is this possible, or is there a better way to do it?
Edit
This works with <cfloop query="LOCAL.queryName"> but not when I try to do <cfset ArrayAppend(LOCAL.returnArray, LOCAL.queryName.c) />
There is no need to use evaluate() to do this, and one shouldn't (so I've down-voted that answer, sorry).
All you need to do is use associative array notation:
<cfdump var="#local[qname]#">
If one wants to access a column of that query, it's:
#local[qname][columnName]#
And for a specific cell:
#local[qname][columnName][rowNumber]#
There are very very very few situations in which evaluate() is the correct answer to anything. One cannot rely on the Adobe docs because - unfortunately - an awful lot of it was not written by very experienced ColdFusion developers.
You can dump the query, and I imagine also access it by doing something like this:
<cfloop list="q1,q2,q3" index="qname">
<cfquery name="#qname#" datasource="dsn">
SELECT * from some_table;
</cfquery>
<cfdump var="#Evaluate('#qname#')#" />
</cfloop>
The Evaluate function is what allows you to do what you want.

How to pass a parameter value to a ColdFusion database query

I have written a database query to extract information in ColdFusion and I want to know how may I pass a value to the WHERE clause to get the relevant data. This is my code sample. can any one help?
<cfquery name="FILM_STRIP_QUERY" datasource="#dsn#">
select distinct tm.id as teachingmoduleid,
(select concat(prs.first_name, ' ',prs.last_name) AS Video_presenter from presentations pss
inner join topics tpcs on tpcs.id = pss.topic_id
inner join presenters prs on prs.id = pss.presenter_id
where pss.name = ps.name
and tpcs.title = tp.title
) AS video_presenter,
(select pss.43_png from presentations pss
inner join topics tpcs on tpcs.id = pss.topic_id
inner join presenters prs on prs.id = pss.presenter_id
where pss.name = ps.name
and tpcs.title = tp.title) AS png_name
from teaching_modules tm
inner join tm_segments sg on sg.module_id = tm.id
inner join topics tp on tp.id = sg.topic_id
inner join presenters prs on prs.id = tm.presenter_id
left outer join presentations ps on ps.id = sg.presentation_id
where tm.id =
</cfquery>
and this is the calling function
<cfloop = "FILM_STRIP_QUERY">
<!--- this is where I wanna pass the parameter--->
</cfloop>
Do you mean something like this?
<cfset tmId = 5 />
<!--- or something like <cfset tmId = url.id /> --->
<cfquery name="FILM_STRIP_QUERY" datasource="#dsn#">
<!--- SELECT cols FROM wherever etc... --->
WHERE tm.id = <cfqueryparam cfsqltype="cf_sql_integer" value="#tmId#" />
</cfquery>
You could just do #tmid# without the CFQueryParam tag, but it's a good idea to use it for added security (validation) and the database will also cache the execution plan, hopefully improving performance the next time the query executes.
If you are using a CFC, then a function like this would work, including the query name ensuring CF releases the memory from the local variable declaration. Also uses the parameter and the cfqueryparam function.
<cffunction name="getFILM_STRIP" access="public" returntype="query" output="false">
<cfargument name="id" required="Yes" type="numeric">
<cfset FILM_STRIP_QUERY = "">
<cfquery name="FILM_STRIP_QUERY" datasource="#variables.dsn#">
<!--- select statement --->
WHERE colname = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#arguments.id# />
</cfquery>
<cfreturn FILM_STRIP_QUERY>
</cffunction>
You should use the cfqueryparam tag to do this. This helps DB execution and also helps prevent SQL injection. e.g.
where tm.id = <cfqueryparam value="#form.ID#" CFSQLType="CF_SQL_INTEGER">