给定Oracle存储过程:
CREATE TYPE stringlist AS TABLE OF VARCHAR2(100);
/
CREATE PROCEDURE test_proc(
list IN stringlist,
output OUT VARCHAR2
)
AS
BEGIN
IF list IS NULL OR list IS EMPTY THEN
RETURN;
END IF;
output := list(1);
FOR i IN 2 .. list.COUNT LOOP
output := output || ',' || list(i);
END LOOP;
END;
/
如何从ColdFusion中调用它?
<cfscript>
arr = [ 'A', 'B', 'C' ];
sp = new StoredProc(
dataSource = "orcl",
procedure = "test_proc",
result = "NA",
parameters = [
{ cfsqltype = "CF_SQL_ARRAY", type="in", value = arr },
{ cfsqltype = "CF_SQL_VARCHAR", type="out", variable = "out" }
]
).execute();
// WriteDump( sp.getProcOutVariables().out );
</cfscript>
失败:
Error Executing Database Query
Fail to convert to internal representation: [A, B, C]
答案 0 :(得分:3)
首先,设置使用Oracle JDBC drivers的数据源。下载相应的JAR文件并将其放在coldfusion实例的lib
目录中,然后通过CFIDE管理面板,您可以设置如下数据源:
CF Data Source Name: orcl
JDBC URL: jdbc:oracle:thin:@localhost:1521:orcl
Driver Class: oracle.jdbc.OracleDriver
Driver Name: Other
(注意:驱动程序名称为“其他”而不是“Oracle” - 这将使用adobe的Oracle驱动程序而不是指定的Oracle驱动程序。)
然后,您可以通过下拉到原始Java来调用存储过程,而不是使用<cfstoredproc>
或new StoredProc()
。
<cfscript>
array = JavaCast( "string[]", [ 'A', 'B', 'C' ] );
try {
connection = createObject( 'java', 'coldfusion.server.ServiceFactory' )
.getDataSourceService()
.getDataSource( 'orcl' )
.getConnection()
.getPhysicalConnection();
description = createObject( 'java', 'oracle.sql.ArrayDescriptor' )
.createDescriptor( 'STRINGLIST', connection );
oracleArray = createObject( 'java', 'oracle.sql.ARRAY' )
.init( description, connection, array );
statement = connection.prepareCall( '{call test_proc( :input, :output )}' );
statement.setARRAYAtName( "input", oracleArray );
stringType = createObject( 'java', 'java.sql.Types' ).VARCHAR;
statement.registerOutParameter( "output", stringType );
statement.executeQuery();
returnValue = statement.getString( "output" );
}
finally
{
if ( isDefined( "statement" ) )
statement.close();
if ( isDefined( "connection" ) )
connection.close();
}
</cfscript>
顺便说一句,您也可以将数组传递给查询(然后获得可以在<cfloop>
中使用的结果),如下所示:
try {
// set-up connection, etc. as above
statement = connection.prepareStatement( 'SELECT * FROM TABLE( :input )' );
statement.setARRAYAtName( "input", oracleArray );
resultSet = statement.executeQuery();
queryResult = createObject( 'java', 'coldfusion.sql.QueryTable' )
.init( resultSet )
.FirstTable();
}
finally
{
if ( isDefined( "resultSet" ) )
resultSet.close();
if ( isDefined( "statement" ) )
statement.close();
if ( isDefined( "connection" ) )
connection.close();
}
答案 1 :(得分:2)
我正在玩这个,我发现一旦Oracle阵列被正确创建(包括创建连接,如上所述,并创建适当类型的Oracle数组(在这种情况下,STRINGLIST
)从原始数组中,然后可以使用<cfstoredproc>
(并且我假设<cfquery>
)使用类型CF_SQL_ARRAY
的参数来执行存储过程(或查询):
<cfset the_datasource = "oratest" />
<cfset the_array = javaCast("string[]", ["A","B","C"]) />
<cfset return_value = "" />
<cftry>
<cfset the_connection = createObject("java", "coldfusion.server.ServiceFactory")
.getDataSourceService()
.getDataSource("#the_datasource#")
.getConnection()
.getPhysicalConnection()
/>
<!---
<cfset type_desc = createObject("java", "oracle.sql.ArrayDescriptor").createDescriptor("STRINGLIST", the_connection) />
<cfset oracle_array = createObject("java", "oracle.sql.ARRAY").init(type_desc, the_connection, the_array) />
--->
<!--- oracle.SQL.ARRAY is deprecated; use this instead: --->
<cfset oracle_array = the_connection.createOracleArray("STRINGLIST", the_array) />
<cfset the_connection.close() />
<cfstoredproc procedure="test_proc" datasource="#the_datasource#">
<cfprocparam cfsqltype="CF_SQL_ARRAY" type="in" value="#oracle_array#" />
<cfprocparam cfsqltype="CF_SQL_VARCHAR" type="out" variable="return_value" />
</cfstoredproc>
<cfcatch>
<cfdump var="#cfcatch#" />
</cfcatch>
</cftry>
<cfdump var="#return_value#" />
请注意,在上面的代码中,我只打开了与数据库的连接以创建Oracle数组。我还没想出是否可以尝试使用现有连接或在<cfstoredproc>
的调用中重新使用连接。
希望这有帮助。
修改强>
要将数组传递给查询,您只需执行以下操作:
<cfquery name="get_table" datasource="#the_datasource#">
SELECT * FROM TABLE( <cfqueryparam cfsqltype="CF_SQL_ARRAY" value="#oracle_array#" /> )
</cfquery>