I have the form where user have to select the value from the list. List is created by administrators. In one of the lists there is an option for user to pick NO value that stands for some reserved code. Something like Not Occupied. So I use JQuery and AJAX to communicate with the server. On the back end I use ColdFusion 9 on my production server. So in order to bring back NO I have to convert that to 'NO ' with the space. If I don't do this function will return false value on the client side. Here is example of my code conversion:
<cfset convertYesNo = {
YES : "YES ",
NO : "NO "
}>
<cfset qryRecs['value'] = URLEncodedFormat(structKeyExists(convertYesNo, myInfo[CurrentRow]) ? convertYesNo[myInfo[CurrentRow]] : myInfo[CurrentRow])>
Code above worked fine on my development site. The only difference is that on development we have ColdFusion 10 and on the live we have ColdFusion 9. So once I moved the code to live I started getting error message:
ColdFusion was looking at the following text:<p>{</p><p>The CFML compiler was processing:<ul><li>A cfset tag beginning on line 1071, column 18.<li>A cfset tag beginning on line 1071, column 18.
<pre>1069 : }>
1070 :
<b>1071 : <cfset convertYesNo = {</b>
1072 : "Yes" : "Yes ",
1073 : "No" : "No "
</pre>
I have tried to put quotes around YES and NO but that did not help. If anyone knows the way how to fix this problem please let me know. thanks in advance!
I think structure notation for CF9 did not support this syntax. Try the following (= instead of : separating key-value pairs).
<cfset convertYesNo = {
YES = "YES ",
NO = "NO "
}>
<cfset qryRecs['value'] = URLEncodedFormat(structKeyExists(convertYesNo, myInfo[CurrentRow]) ? convertYesNo[myInfo[CurrentRow]] : myInfo[CurrentRow])>
Structs (HashTables) are great at fast finding of keys, but you only have 2 key here, so a much more efficient construct would be (example in cfscript syntax):
qryRecs['value'] = URLEncodedFormat(
listFindNoCase("YES,NO", myInfo[CurrentRow]) ?
uCase(myInfo[CurrentRow]) & " "
:
myInfo[CurrentRow]
);
Though for better readability and code maintenance you should consider to break it into multiple statements:
value = myInfo[CurrentRow];
if (value == "YES" || value == "NO") // use EQ operator in CFML syntax
value = uCase(value) & " ";
qryRecs['value'] = URLEncodedFormat(value);
Related
I have a snippet of code from my python 2.7 program:
cur.execute("UPDATE echo SET ? = ? WHERE ID = ?", (cur_class, fdate, ID,))
that when run, keeps throwing the following error:
sqlite3.OperationalError: near "?": syntax error
The program is supposed to insert today's date, into the class column that matches the student ID supplied. If I remove the first "?" like so and hard code the parameter:
cur.execute("UPDATE echo SET math = ? WHERE ID = ?", (fdate, ID,))
everything works just fine. I've googled all over the place and haven't found anything that works yet so I'm throwing out a lifeline.
I've tried single quotes, double quotes, with and without parenthesis and a few other things I can't remember now. So far nothing works other than hard coding that first parameter which is really inconvenient.
As a troubleshooting step I had my program print the type() of each of the variables and they're all strings. The data type of the the cur_class field is VARCHAR, fdate is DATE, and ID is VARCHAR.
Thanks to the tip from #Shawn earlier I solved the issue with the following code and it works great:
sqlcommand = "UPDATE echo SET " + cur_class + " = " + fdate + " WHERE ID = " + ID
cur.execute(sqlcommand)
This way python does the heavy lifting and constructs my string with all the variables expanded, then has the db execute the properly formatted SQL command.
I created sample code using the Microsoft SQL Server Northwind demo database. If you don't have access to this demo database here is a simple (MS-SQL) script to create the table and a row of data for this question.
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](40) NOT NULL,
[SupplierID] [int] NULL,
[CategoryID] [int] NULL,
[QuantityPerUnit] [nvarchar](20) NULL,
[UnitPrice] [money] NULL CONSTRAINT [DF_Products_UnitPrice] DEFAULT (0),
[UnitsInStock] [smallint] NULL CONSTRAINT [DF_Products_UnitsInStock] DEFAULT (0),
[UnitsOnOrder] [smallint] NULL CONSTRAINT [DF_Products_UnitsOnOrder] DEFAULT (0),
[ReorderLevel] [smallint] NULL CONSTRAINT [DF_Products_ReorderLevel] DEFAULT (0),
[Discontinued] [bit] NOT NULL CONSTRAINT [DF_Products_Discontinued] DEFAULT (0),
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Products] ON
GO
INSERT [dbo].[Products] ([ProductID], [ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (1, N'Chai', 1, 1, N'10 boxes x 20 bags', 18.0000, 39, 0, 10, 0)
GO
SET IDENTITY_INSERT [dbo].[Products] OFF
GO
Here is the ColdFusion code:
<cfset variables.useTempVar = false>
<cfquery datasource="Northwind2014" name="qryNWProducts">
SELECT TOP 1 * from Products;
</cfquery>
<cfdump var="#qryNWProducts#" label="qryNWProducts">
<cfset variables['stProduct'] = {}>
<cfloop index="vcColName" list="#qryNWProducts.columnlist#">
<cfif variables.useTempVar>
<cfset variables['temp'] = qryNWProducts[vcColName]>
<cfset variables['stProduct'][vcColName] = variables.temp>
<cfelse>
<cfset variables['stProduct'][vcColName] = qryNWProducts[vcColName]>
</cfif>
</cfloop>
<cfdump var="#variables['stProduct']#" label="variables['stProduct']">
<cfloop collection="#variables['stProduct']#" item="key"><cfoutput>
variables['stProduct']['#key#'] JVM datatype = #getMetadata(variables['stProduct'][key]).getName()#<br>
</cfoutput></cfloop>
<br>
This always works:<br>
<cfset variables['aPhrase'] = "I ordered " & variables.stProduct.ProductName & " for " & DollarFormat(variables.stProduct.UnitPrice) & ".">
<cfoutput>#variables['aPhrase']#<br></cfoutput>
<br>
With "variables.useTempVar = false", the next line will throw a "Complex object types cannot be converted to simple values. " error.<br>
<cfset variables['aPhrase'] = "I ordered " & variables['stProduct']['ProductName'] & " for " & DollarFormat(variables['stProduct']['UnitPrice']) & ".">
<cfoutput>#variables['aPhrase']#<br></cfoutput>
The code above has a boolean variable named "variables.useTempVar" at the top that can be flipped to see the error that I'm getting.
It looks like the direct assignment (when variables.useTempVar = false) from the query to the structure causes the structure values to be of JVM type "coldfusion.sql.QueryColumn".
Another note: if this line of code:
<cfset variables['stProduct'][vcColName] = variables.temp>
is changed to:
<cfset variables['stProduct'][vcColName] = variables['temp']>
The JVM datatype will be "coldfusion.sql.QueryColumn".
When the dot notation temp variable is used to assign the query field (when variables.useTempVar = true); the JVM datatypes are simple types that matches up pretty well with the database column types (java.lang.Integer, java.math.BigDecimal, java.lang.String, etc.).
I've also experiemented with statements like this and that provided some odd results:
<cfset variables['stProduct'][vcColName] = qryNWProducts[vcColName].toString()>
Here's the question. Is this the best way to transfer the simple values from a query to a structure? It seems odd to be forced to use a temp variable and dot notation to make this work.
Comment: I've always thought that dot notation and associative array notation were equivalent. This code example appears to contradict that opinion.
#Leigh is correct in that you need to supply the row number when using associative array notation with a query object. So you'd reference row 1 like: qryNWProducts[vcColName][1]
As for your question
Is this the best way to transfer the simple values from a query to a structure?
Are you sure you need a struct? Your question doesn't really specify the use case, so it is entirely possible that you would be better off using the query object as-is.
If you do need it to be a struct (and since you are using ColdFusion 11) might I suggest you take a look at serializeJSON/deSerializeJSON to convert this to a struct. The serializeJSON has a new attribute that will properly serialize a query object into an "AJAX friendly" JSON array of structs. You can then deSerialize the JSON into a CF array, like so:
NWProducts = deSerializeJSON( serializeJSON( qryNWProducts, 'struct' ) )[1];
Which would return a struct representation of the first row in that query object.
Although it's not obvious from the Adobe docs for serializeJSON, the second parameter can be one of: true|false|struct|row|column which will change how the resulting data is formatted.
Here's a runnable example of using the above technique showcasing each serializeQueryAs option.
It's also a better practice to start moving that kind of code into cfscript. queryExecute is quite easy to use and makes script based queries very easy to develop. See the How To Create a Query in cfscript tutorial at trycf.com for more on how to develop script based queries.
Final note, and this is a bit off topic but it is a generally accepted best practice to not use Hungarian Notation when naming variables.
#Abram's covered the mains answer, but just to pick up one tangential point you raise.
Dot notation and associative array notation are generally equivalent in CFML. However in the case of queries, there is a slight variation. Dot notation: query.columnName is treated as shorthand for query.columnName[currentRow] (where currentRow defaults to 1).
Associative array notation with queries does not have this "syntactic sugar", so query["columnName"] refers to the entire column, as the syntax actually indicates.
There are no functions I am aware of in CFML that take a query column as an argument, however the CFML engine will convert the column to an array if it's used in an array function. This is quite handy sometimes.
I'm trying to modify existing codes in my ColdFusion application left by previous programmer. I don't understand the meaning of this line of code (the one with question marks):
<cfset Application[#form.username#] = 0> ??????
<cfset Session.loggedin="Yes">
<cfset Session.username="#Trim(Form.username)#">
Maybe I haven't been working with CF long enough to see this syntax so I don't know what this mean.
When setting an application variable I usually use this syntax:
<cfset application.variableName = "some value">
Can someone explain to me what is this ?
Thank you
As well as explicitly stating variable names at "code time" with dot notation, CFML allows one to reference them dynamically at runtime via a string value.
This is done via associative array notation (using square brackets), eg:
myVariableName = "foo";
variables[myVariableName] = "moo"; // equivalent to variables.foo = "moo"
ColdFusion is converting a string to number when passing to JS via a SerializeJSON and deSerializeJSON.
This is only happening when an 'E' is used between two set of numbers. like 3E6, 65E3, 56e45 etc. This is the code inside cfscript.
x = "2e9";
writedump(SerializeJSON(x));
writedump(deSerializeJSON(SerializeJSON(x)));
Output:
2.0E9 2000000000
Please suggest, if is there any other way for such issues.
It is this: https://bugbase.adobe.com/index.cfm?event=bug&id=3695627: "SerializeJSON turns strings that look like scientific notation into floats."
It's a known bug in CF9, and it's fixed in CF10.
In the meantime, you will just have to pad the string with something to force ColdFusion to not see it as a number in scientific notation.
Or upgrade to CF10 (CF9 is end of life next month, btw). Or to Railo.
I have resolved this using below solution
let's say ItemUnit = 12E45
stcReturn.firstname = "Yes";
stcReturn.lastname = "Man";
stcReturn.ItemUnit = "12E45"
error output after deSerializeJSON stcReturn.ItemUnit = 12e+46
<cfset stcReturn.ItemUnit = ItemUnit />
<cfset StructSetMetaData(stcReturn.ItemUnit, {ItemUnit :
{"type":"string","name":"ItemUnit"}})/>
deSerializeJSON(stcReturn)
Correct Output:12E45
How would I use use a string function to select everything in a variable after the last "/"
http://domain.com/g34/abctest.html
So in this case I would like to select "abctest.html"
Running ColdFusion 8.
Any suggestions?
Um, a bit strange to give very similar answer within few days, but ListLast looks as most compact and straightforward approach:
<cfset filename = ListLast("http://domain.com/g34/abctest.html","/") />
And yes, IMO you should start with this page before asking such questions on SO.
Joe I'd use the listToArray function, passing the "/" as the delimiter, get the length of the array and get the value in the last slot. See sample below
<cfset str = "http://domain.com/g34/abctest.html"/>
<cfset arr = ListToArray(str,"/","false")/>
<cfset val = arr[ArrayLen(arr)]/>
<cfoutput>#str# : #val#</cfoutput>
produces
http://domain.com/g34/abctest.html : abctest.html