views:

463

answers:

6

I'm writing a CFC on a server running Coldfusion MX 7. The CFC needs to be able to query a database the location of which will be determined at runtime. The database is SQL Server 2005. The CFC takes the IP address of the server and the name of the database as arguments, and the built-in Windows Authentication should allow connections from the machine. However, I can't figure out how to code the connection. The <cfquery> tag hasn't supported the connectstring attribute since CF5. Setting up a System DSN isn't dynamic enough. I know there's probably some way to connect to SQL Server without using a DSN, but the method escapes me at the moment. Does anyone know how to do this?

A: 

not in CF7, but you can add, modify, and delete ColdFusion data sources in CF8 via Administrator API

Henry
Not running CF8, unfortunately. And anyway, I can't get the cf admin password from the server administrator until he gets back from vacation.
Joshua Carmody
A: 

Use Web Services to hit the DB.

AnApprentice
Unfortunately I'm not at liberty set up web services on the DB machine.
Joshua Carmody
A: 

bypass cfquery, do JDBC in Java?

Henry
That'd be fine... I'm not quite sure how though.
Joshua Carmody
write the query in JDBC in java, compile to .jar, consume it in CF. However, CF8's Admin API solution is way easier.
Henry
+2  A: 

Google search proposes this solution: http://cfsilence.com/blog/client/index.cfm/2007/11/8/More-cfquery--Now-With-cfqueryparam

Have you tried it?

Don't have CF7 so can't say that all Java stuff from that tag works. At least it does not use ServiceFactory (aka solution for CF8).

Sergii
+4  A: 

You can modify the datasource on CF7 using the datasourceService. Something along these lines might work:

<cfset service = createobject("java","coldfusion.server.ServiceFactory").getDatasourceService()>
<cfset uname = "yourUserName">
<cfset pw = service.encryptPassword("yourPassword")>
<cfdump var="#createobject("java","coldfusion.server.ServiceFactory").getDatasourceService()#">
<cfset ds = service.getDatasources()>
<cfset dsn = "MyDSN">
<cfset thisDS = service.getDatasource(dsn)>
<cfset thisDS.getDatasourceDef().setPassword(pw)><!--- if you need to set the password programmatically --->
<!--- do stuff to set the URL... you can get the appropriate functions from the cfdump of the datasourceservice, above --->
Verifying datasource: #service.verifyDatasource(dsn)# <br>
marc esher
Oh, I thought this works only for CF8+. This solution is great except the need to know PASSWORD >> "I can't get the cf admin password from the server administrator" (end of quote)
Sergii
with the ServiceFactory, you don't need to know the cfadmin password.In my example, that password stuff is for the DSN you're modifying, not the use of the factory itself. If you don't need to change the DSN credentials on the fly, then you can get rid of that stuff.I'm not 100% certain this will work on CF7... particularly the password stuff if you need it. But I know you can use the ServiceFactory to change the URL, which it sounds like all the OP needs to do.
marc esher
This is interesting. Who knew that ColdFusion had all these behind-the-scenes features? One concern though: if you use this method to call a lot of different datasources, would you end up with lots of "junk" DSNs in ColdFusion? Should there be some clean up or deletion being done at the bottom of the page?
Joshua Carmody
@Marc - I may not be following the intent correctly. But what effect would that have if multiple threads changed "MyDSN" at the same time?
Leigh
Leigh: that one's easy: sh*t would be breaking all over the joint. If the OP needs this to be threadsafe, then he'll need to cflock the code that changes the dsn. I was kind of under the impression that this was sort of a "today at noon, the DSN is going to have a URL change".If that's not the case, then probably the safest and most efficient way would be to create a new dsn using the ServiceFactory, run the query, and then delete it immediately. This gets around the threadsafety problem and the junk dsn problem
marc esher
@Marc - Gotcha. Yes, for more than a one-time change, unique dsn's sound like a better way to go.
Leigh
+1  A: 

After looking at everyone's answers and doing some more Google searches, I got a simple solution worked out. This solution uses some Java code, as Henry suggested, but doesn't require compiling a jar. It can be done inline using <cfscript>.

<cfscript>
    classLoader = createObject("java", "java.lang.Class");
    classLoader.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 
    dm = createObject("java","java.sql.DriverManager");
    con = dm.getConnection("jdbc:odbc:DRIVER={SQL Server};Database=""DATABASENAME"";Server=SERVERNAME;","USERNAME","PASSWORD");
    st = con.createStatement();
    rs = st.ExecuteQuery("SELECT * FROM TABLE");
    q = createObject("java", "coldfusion.sql.QueryTable").init(rs);
</cfscript>

I think this is easier than programatically adding datasources to ColdFusion Administrator, although that seems like a good solution too. I'm guessing the custom tag Sergii linked works similarly, although I didn't see the link until after I tried this solution, so I haven't examined the code in detail.

Joshua Carmody
I think you are missing your definition for the dm object
Goyuix
@Goyuix - Whoops! Quite so, and another line too. I fail at copy/paste. Fixed.
Joshua Carmody
@Joshua - Is there a reason you are using the jdbc.odbc bridge as opposed to a type 4 driver? Also, you must ALWAYS close all of your database objects when finished. Even if an error occurs. This includes resultsets, statements and connections. Otherwise, the resources and connections may not be released properly. Example: (Repeat for all objects) <cfif structKeyExists(variables, "rs")> <cfset rs.close() /></cfif>
Leigh
@Leigh - The standard SQL server JDBC driver isn't installed on the machine, and I don't have access to install it. This is a very weird situation where I'm modifying a 3rd party application that my organization is licensing, which is hosted on a 3rd party server.
Joshua Carmody
@Leigh - Point taken about closing the result set. I'll add that to my answer.
Joshua Carmody