I have a package that allows me to create a table from the output of a stored procedure REF_CURSOR
variable. I use this with DevPress XPO Source in order to return large results to my client application.
I used to create a solid table, add a key, index it and return the new table name to the client which is provided to the XPO source, and it is working. However, using solid tables is not the best solution, so I started using a GTT.
If I execute the package in TOAD, my data is preserved, but if I execute the command from C#, there is no data in my table right after execution. The connection is not closed yet, so I am not 100% sure why my data is not there.
Is there something in the Connection Context that I can set to make sure that all executions happen in the same session? There is an execute immediate
statement to populate the table, and I think that TOAD might use the same context when a I execute the package.
Here is some of my code:
FUNCTION Build_Table_from_Cursor(REF_CURSOR SYS_REFCURSOR, ID NUMBER, AddKeyField CHAR) RETURN VARCHAR2 AS
QueryCursor SYS_REFCURSOR;
CursorNumber NUMBER;
p_tablename varchar2(30);
pk_name varchar2(30);
BEGIN
QueryCursor := REF_CURSOR;
CursorNumber := DBMS_SQL.TO_CURSOR_NUMBER(QueryCursor);
p_tablename := 'TEMPTABLE';
UTIL.create_table_from_cursor(CursorNumber, p_tablename); --This creates the GTT with all the columns
Execute immediate 'TRUNCATE TABLE ' || p_tablename; --To Add the key this must be done otherwise there is an error
pk_name := substr(p_tablename, INSTR(p_tablename, '.') + 1);
IF(AddKeyField = 'Y') THEN --Sometimes the Key field already exists
EXECUTE IMMEDIATE 'ALTER TABLE ' || p_tablename || ' ADD (KEY_FIELD_ NUMBER)';
END IF;
EXECUTE IMMEDIATE 'CREATE UNIQUE INDEX ' || p_tablename || 'KEY_INDEX ON ' || p_tablename || ' (KEY_FIELD_)';
EXECUTE IMMEDIATE 'ALTER TABLE ' || p_tablename || ' ADD CONSTRAINT pk_' || pk_name || ' PRIMARY KEY( KEY_FIELD_ )';
QueryCursor := DBMS_SQL.TO_REFCURSOR(CursorNumber);
PDS.UTIL.POPULATE_TABLE_FROM_CURSOR(QueryCursor, p_tablename, 1000); --This populates the table
EXECUTE IMMEDIATE 'UPDATE ' || p_tablename || ' SET KEY_FIELD_ = ROWNUM';
COMMIT;
return p_tablename;
END Build_Table_from_Cursor;
This works perfectly when I execute in TOAD.
When I run this
using (var conn = factory.CreateConnection(Dal.ConnectionStrings[connectionString].ConnectionString))
{
conn.Open();
using (var cmd = factory.CreateCommand(CommandType.StoredProcedure, storedProcedureName))
{
var storedProcedureRow = commandExecuteDataSet.StoredProcedure[0];
foreach (var parametersRow in commandExecuteDataSet.Parameters)
{
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter(parametersRow.Name, parametersRow.Value ?? "", GetDBTypeFromString(parametersRow.OracleDbType)));
}
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter(storedProcedureRow.RefCursorName, DbType.Object, ParameterDirection.Output, true));
cmd.ExecuteNonQuery();
var refCursor = cmd.Parameters[storedProcedureRow.RefCursorName].Value;
cmd.Parameters.Clear();
cmd.CommandText = "SERVERMODE_UTIL.Build_Table_from_Cursor";
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("REF_CURSOR", refCursor));
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("ID", biID));
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("AddKeyField", "Y"));
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("p_tablename", DbType.String, ParameterDirection.ReturnValue));
cmd.ExecuteNonQuery();
var tempTableName = cmd.Parameters["p_tablename"].Value.ToString();
tempTableName = tempTableName.Substring(tempTableName.IndexOf(".") + 1);
}
}
As part of a larger package, this is the code that is executed to create the GTT
l_statement := 'CREATE GLOBAL TEMPORARY TABLE ' || l_tablename || ' (' || CHR(13) || CHR(10) || l_statement || CHR(13) || CHR(10) || ') ON COMMIT PRESERVE ROWS';
execute immediate l_statement;