Eu tenho uma sequência do Oracle definida assim:
CREATE SEQUENCE "DALLAS"."X_SEQ"
MINVALUE 0
MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 0 NOCACHE NOORDER NOCYCLE ;
É usado em um procedimento armazenado para inserir um registro:
PROCEDURE Insert_Record
(p_name IN VARCHAR2,
p_userid IN INTEGER,
cur_out OUT TYPES_PKG.RefCursor)
IS
v_id NUMBER := 0;
BEGIN
-- Get id value from sequence
SELECT x_seq.nextval
INTO v_id
FROM dual;
-- Line below is X_PKG line 40
INSERT INTO X
(the_id,
name,
update_userid)
VALUES
(v_id,
p_name,
p_userid);
-- Return new id
OPEN cur_out FOR
SELECT v_id the_id
FROM dual;
END;
Ocasionalmente, esse procedimento retorna um erro quando executado a partir do código do aplicativo.
ORA-01400: cannot insert NULL into ("DALLAS"."X"."THE_ID")
ORA-06512: at "DALLAS.X_PKG", line 40
ORA-06512: at line 1
Detalhes que podem ou não ser relevantes:
- Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Produção de 64 bits
- O procedimento é executado via Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader(comando DbCommand)
- O aplicativo não agrupa a chamada em uma transação explícita.
- A inserção falha intermitentemente - menos de 1%
Em que circunstâncias poderia x_seq.nextval
ser nulo?
Tenho certeza de que isso acabará sendo um artefato do seu código ou do driver .net que você está usando. Criei uma demonstração rápida para você usando SQL puro - PL/SQL e nunca perca um valor de sequência. Aliás, o cursor de referência que você está usando provavelmente é desnecessário e provavelmente afeta o desempenho e a legibilidade do código - minha demonstração inclui um procedimento insert_record2 que executa consistentemente 10% mais rápido - em cerca de 26s no meu laptop contra 36 para a versão do cursor de referência. Eu pelo menos também acho que é mais fácil de entender. Obviamente, você poderia executar uma versão modificada em seu banco de dados de teste completo com gatilho de auditoria.
Tente fazer um caso de teste. Faça uma tabela fictícia e insira 100.000 registros usando sua sequência do banco de dados. Aposto que não terá problemas. Em seguida, tente inserir a mesma coisa do seu aplicativo.
Isso pode ser causado por outros problemas, como uma incompatibilidade do cliente Oracle?
Outra solução que resolveria o problema, mas não o problema, é adicionar um gatilho na tabela.
Antes de inserir na tabela em Dallas.X IF :the_id é nulo ENTÃO SELECT x_seq.nextval INTO :the_id FROM dual; FIM SE;
Ainda não tenho privilégios para fazer comentários, portanto, escrevendo isso como resposta: Como você está usando a versão Oracle >= 11.1, que permite sequências em expressões PL/SQL em vez de SQL, tente o seguinte:
Em vez disso:
Ou, embora eu tenha ouvido dúvidas / armadilhas ao usar ".currval", talvez omita a atribuição separada de v_id e use apenas este código?:
Desculpe, eu não tenho uma instância 11g à mão agora para tentar isso.