carolastra
asked on
The 'CREATE TABLE' command is not allowed within a multi-statement transaction in the 'tempdb' database.
I have a Java program in WebLogic, the database is Sybase.
When the Java program run a stored procedure return the error:
com.sybase.jdbc2.jdbc.SybS QLExceptio n: The 'CREATE TABLE' command is not allowed within a multi-statement transaction in the 'tempdb' database.
When the Java program run a stored procedure return the error:
com.sybase.jdbc2.jdbc.SybS
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
> DBA told me this option is dangerous because if a transaction is dead lock is impossible kill it and the only solucion is re-start the server.
Uh, I have no idea why your DBA would have said that. As written it is 100% wrong.
If a transaction gets deadlocked, ASE automatically finds a deadlock victim based on whoever has done the least work so far. The "ddl in tran" option does not change this.
If a process is sleeping, any attempt to kill it (whether by the system in the case of a deadlock or manually by a DBA) will only work when it next wakes up. If it never wakes up (hung?) then indeed the only solution is to restart ASE... *but* again, the "ddl in tran" option does not change this.
A quick look in the manuals confirms this. "ddl in tran" does not make any deadlock situation more difficult to handle.
What it *can* do (and this is why it is disabled by default) is to cause more locks on system tables, which are held for the duration of your transaction. If your transaction is "long" (hard to define but 5 minutes is definitely long) then blocking system table access is a lot more intrusive. So it can need some attention to transaction design to make sure those locks are released as soon as possible. Also, don't enable this in tempdb as problems with locked system tables in tempdb can pretty much halt the server - maybe this was what your DBA was thinking of?
Still, in fast transactions outside tempdb, this option is not dangerous and is fine to use.
That being said there are an awful lot of "exciting opportunities for improvement" in your code, but that's beyond the scope of this question (and would need a new question raised)... but very very briefly: don't use cursors, and avoid local variables (and use procedure parameters plus calls to subprocedures) where possible.
SUMMARY: the database option "ddl in tran" is the answer to your problem.
Uh, I have no idea why your DBA would have said that. As written it is 100% wrong.
If a transaction gets deadlocked, ASE automatically finds a deadlock victim based on whoever has done the least work so far. The "ddl in tran" option does not change this.
If a process is sleeping, any attempt to kill it (whether by the system in the case of a deadlock or manually by a DBA) will only work when it next wakes up. If it never wakes up (hung?) then indeed the only solution is to restart ASE... *but* again, the "ddl in tran" option does not change this.
A quick look in the manuals confirms this. "ddl in tran" does not make any deadlock situation more difficult to handle.
What it *can* do (and this is why it is disabled by default) is to cause more locks on system tables, which are held for the duration of your transaction. If your transaction is "long" (hard to define but 5 minutes is definitely long) then blocking system table access is a lot more intrusive. So it can need some attention to transaction design to make sure those locks are released as soon as possible. Also, don't enable this in tempdb as problems with locked system tables in tempdb can pretty much halt the server - maybe this was what your DBA was thinking of?
Still, in fast transactions outside tempdb, this option is not dangerous and is fine to use.
That being said there are an awful lot of "exciting opportunities for improvement" in your code, but that's beyond the scope of this question (and would need a new question raised)... but very very briefly: don't use cursors, and avoid local variables (and use procedure parameters plus calls to subprocedures) where possible.
SUMMARY: the database option "ddl in tran" is the answer to your problem.
ASKER
My code:
create proc dbo.sps_saldo_consulta_ad2
@as_usuario varchar(10),
@ai_tipo integer,
@ai_nombres integer = null,
@ai_consoli integer = null
AS
declare
@ls_usuario varchar(20),
@ls_parametro varchar(255),
@ls_sucursal varchar(3),
@ls_moneda varchar(2),
@ls_mayor varchar(3),
@ls_analitico varchar(15),
@ls_futuro varchar(10),
@ls_pasado varchar(10),
@li_sucursal integer,
@li_mayor integer,
@ldt_futuro datetime,
@ldt_pasado datetime,
@ls_oficina varchar(255),
@ldt_switch datetime,
@ld_minimo numeric(20,4),
@ld_maximo numeric(20,4),
@ld_switch numeric(20,4),
@ls_minimo varchar(22),
@ls_maximo varchar(22),
@ls_cuenta varchar(18)
DECLARE
@ldt_inicio
@ldt_fin
@ln_registros double precision
begin
select @ldt_inicio = getdate()
select @ls_usuario = @as_usuario, --Obtiene el nombre del usuario
/* execute ctrlcontable.dbo.sps_ofici
select @ls_oficina = rtrim(@ls_oficina)
print "permisos en oficina '%1!'", @ls_oficina
*/
/*if exists (select 1 from OFICINA WHERE (charindex(","+ofi_identif
begin*/
select @ls_oficina = '*' --Oficina Privilegiada
--end
create table #SALDO_RESULTADO
(fecha datetime,
sucursal int,
moneda char(2),
mayor int,
analitico varchar(15),
naturaleza int ,
cargo numeric(20,4),
abono numeric(20,4),
saldo numeric(20,4),
nombre varchar(60) NUll
)
SELECT con_parametro
INTO #CONSULTA_USUARIO
FROM CONSULTA
WHERE usu_identificador = @ls_usuario
AND con_tipo = @ai_tipo
ORDER BY con_subconsulta
DECLARE SIG_CONSULTA CURSOR FOR --Cursor que extrae las consultas definidas para un tipo y un usuario
SELECT con_parametro
FROM #CONSULTA_USUARIO
OPEN SIG_CONSULTA
FETCH SIG_CONSULTA
INTO @ls_parametro
WHILE @@sqlstatus = 0
BEGIN
--print "consulta de fecha '%1!' --> '%2!' --> '%3!' --> '%4!' --> '%5!' --> '%6!'", @ldt_futuro,
--
--
--
ELSE IF @ai_tipo = 2
ELSE IF @ai_tipo = 3
--print "pasado '%1!' futuro '%2!' ",@ls_pasado, @ls_futuro
--print "pasado '%1!' futuro '%2!' ",@ls_pasado, @ls_futuro
--print "maximo '%1!' '%2!'",@ld_maximo,@ld_mini
--print "-->pasado '%1!' futuro '%2!' ",@ls_pasado, @ls_futuro
--print "periodo de fechas"
ELSE IF @ai_tipo = 17
END
exito:
if @ai_nombres = 1 execute dbo.sps_saldo_nombres @ai_tipo
create table #NOREPETIDOS
if @ai_consoli = 1
IF @ai_tipo = 17
else
IF @ai_tipo = 17
select @ln_registros = @@rowcount
select @ldt_fin = getdate()
execute dbo.spi_bitacora
@ldt_inicio
@ldt_fin
@ls_usuario
@ai_tipo
@ln_registros
error:
salir:
CLOSE SIG_CONSULTA
DEALLOCATE CURSOR SIG_CONSULTA
drop table #SALDO_RESULTADO
drop table #CONSULTA_USUARIO
end