In the "Locking enhancements" section of "What's News in 4.5", as they are
discussing the new admin features, it says:

"Choosing 'full checking' will cause ColdFusion to raise an error if any
read or write of data in one of the scopes occurs outside of the scope of a
CFLOCK. This includes accesses to any data that is aliased by being assigned
to a variable outside of the shared data scopes and the data is not copied;
this can occur for struct and query variables."

It goes on to give an example where they CFSET a local variable to an
application variable.  I don't know whether they are passing by reference or
not, but leads me to think that locking aliased local variables that refer
to Application or Session scoped variables is a good idea.

Coincidentally, after thinking for the last year that locking was a good
idea, but not really necessary, I got burned pretty bad by an app that died
under load this weekend because I didn't lock some application variables..
Live and learn, I guess.


Chris Evans
[EMAIL PROTECTED]
http://www.fuseware.com


-----Original Message-----
From: Dave Watts [mailto:[EMAIL PROTECTED]]
Sent: Sunday, April 09, 2000 6:03 PM
To: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Subject: RE: CFLOCK revisited, part 2


> This is what I do.  Since most of my cached data is either strings
> or structures I use one of two methods to create "local" copies.
>
> 1) If the cached data is a string, I create a local copy by
> using (in a CFLOCK of course):
> <CFSET strLocal = Application.strCached & "">
>
> Since CF passes by reference if you leave out the concatenation
> with the blank string then strLocal is simply a reference to the
> data in the shared scope. It is my understanding that referring
> to this variable outside a CFLOCK would, in effect, be an unlocked
> read of the shared scope, and thus subject to corruption. (Note:
> this was pointed out to me on the Allaire forums by one of the CF
> "gurus" such as Hal Helms, Ben Forta, or Nate Weiss)
>
> By assigning the local variable the value of an operation (such as
> the concatenation) CF creates a new variable, rather than creating
> a reference to the data in the shared scope.

This may have been the case in the past, but it no longer seems to be the
case, at least in CF 4.5.1 RTM. Here's a four-line sample which demonstrates
that CF is passing strings by value, rather than by reference:

<CFSET Application.testvar = "Joe">
<CFSET mylocalvar = Application.testvar>
<CFSET Application.testvar = "Bob">
<CFOUTPUT>#mylocalvar#</CFOUTPUT>

If CF passed Application.testvar by reference in line two, then when I
output the variable "mylocalvar", it should be just a pointer to
Application.testvar, and should then output "Bob". Yet when I tested it, it
output "Joe".

> 2) If the cached data is a structure, then I use StructCopy() inside
> a CFLOCK to create a local copy of the structure.  Again, since
> CF passes by reference simply assigning a local variable to the
> structure in the shared scope (<CFSET stcLocal = Application.stcCached>)
> only creates a reference to the data in the shared scope.
>
> 3) NOTE: I do NOT know of any way to create a local copy of a
> query saved in a shared scope. If I have a query in
> Application.qryCached, creating a "local" copy seems to be a
> moot point. Example:
> <CFSET qryLocal = Application.qryCached>
> only creates qryLocal as a reference to the shared data.  Any
> writes to that query (QuerySetCell, QueryAddRow, etc) *will*
> affect the data in the shared scope. This indicates to me that
> in order to truly protect accesses to the shared scopes, CFLOCK
> must be used around every single access to any query stored in
> those scopes, and that trying to create a "local" copy of said
> queries is a pointless venture.

CF passes simple variables by value, and passes complex objects by
reference. So, you're correct in saying that if you simply set a variable
and assign it an existing query, that query is passed by reference.

In addition, if you simply copy the entire Application scope into a local
variable, any complex objects contained in that scope are only copied by
reference into the local variable, which is kind of annoying, to say the
least.

However, with just a little work, you can copy a query by value. Here's a
custom tag which will do just that:

<!--- CF_QUERYCOPY --->
<CFIF NOT CompareNoCase(ThisTag.ExecutionMode,"START")>

        <CFPARAM NAME="Attributes.SourceQuery" DEFAULT="">
        <CFPARAM NAME="Attributes.OutputQuery" DEFAULT="NewQuery">

        <CFTRY>

                <CFIF NOT IsQuery(Evaluate(Attributes.SourceQuery))>
                        <CFTHROW MESSAGE="The SOURCEQUERY parameter must contain the 
name of a
valid query object!">
                </CFIF>

                <CFCATCH>
                        <CFRETHROW>
                </CFCATCH>

        </CFTRY>

        <CFSET rs = SetVariable("Caller." & Attributes.OutputQuery, QueryNew(""))>
        <CFSET lSourceQueryColumns = Evaluate(Attributes.SourceQuery &
".ColumnList")>

        <CFLOOP LIST="#lSourceQueryColumns#" INDEX="i">
                <CFSET aColumn = ListToArray(Evaluate("ValueList(" &
Attributes.SourceQuery & "." & i & ")"))>
                <CFSET rs = QueryAddColumn(Evaluate("Caller." & 
Attributes.OutputQuery),
i, aColumn)>
        </CFLOOP>

</CFIF>

Here's a sample page using it:

<html>
<head>
        <title>CF_QUERYCOPY test</title>
</head>

<body>

<CFQUERY NAME="Application.testquery" DATASOURCE="cfexamples">
        SELECT strEmpID, strFname, strLname, strTitle FROM tblEmp
</CFQUERY>

<CF_QUERYCOPY SOURCEQUERY="Application.testquery">

<CFSET rs = QuerySetCell(Application.testquery, "strFname", "Bill", 1)>

<H1>Application.testquery</H1>
<CFOUTPUT QUERY="Application.testquery">
#strEmpID#, #strFname# #strLname#, #strTitle#<BR>
</CFOUTPUT>

<H1>newquery</H1>
<CFOUTPUT QUERY="newquery">
#strEmpID#, #strFname# #strLname#, #strTitle#<BR>
</CFOUTPUT>

</body>
</html>

Note that this doesn't implement locking, so you'd want to lock it yourself:

<CFLOCK SCOPE="APPLICATION" TIMEOUT="2" THROWONTIMEOUT="TRUE">
        <CF_QUERYCOPY SOURCEQUERY="Application.testquery"
OUTPUTQUERY="qMyNewLocalQuery">
</CFLOCK>

I'd also like to include the disclaimer that the custom tag I've just thrown
together could probably bear improvements, but it's just supposed to be a
demonstration of copying queries.

Now, beyond whether we can copy queries, which I hope I've answered, is the
larger and more important question, which is whether we should copy queries,
or whether we're better off simply using CFLOCK throughout our pages. I
don't have a definitive answer for that one.

Dave Watts, CTO, Fig Leaf Software
http://www.figleaf.com/
voice: (202) 797-5496
fax: (202) 797-5444

----------------------------------------------------------------------------
--
Archives: http://www.eGroups.com/list/cf-talk
To Unsubscribe visit
http://www.houseoffusion.com/index.cfm?sidebar=lists&body=lists/cf_talk or
send a message to [EMAIL PROTECTED] with 'unsubscribe' in
the body.


------------------------------------------------------------------------------
Archives: http://www.eGroups.com/list/cf-talk
To Unsubscribe visit 
http://www.houseoffusion.com/index.cfm?sidebar=lists&body=lists/cf_talk or send a 
message to [EMAIL PROTECTED] with 'unsubscribe' in the body.

Reply via email to