ODP.Net Merge ExecuteNonQuery() Affected Row Count???????????????
Functional World/Database 2015. 2. 28. 03:11어느날 아는 동생으로 부터... (나 보다 훨 스킬이 좋은 개발자다.) ODP.Net을 이용하여 Merge 쿼리를 작성 하면... 반환값이 언제나 무조건... -1이 나온다는 제보를 받았다.
물론 동생은 이걸 해결 하기 위하여 정말 열심히 검색을 했고 결국 얻어 낼 수 있는 정보는 오라클의 버그라는 것이었다.
이거 참... 나보다 훨 스킬이 좋은 동생이기에 이 이야기를 의심할 수 조차 없었다. 그 동생이 그렇다면 그런것이기에...
그럼 이걸 어떻게 해결 해야 할까? 오라클이 이런 버그를 만들어 놓고.. 패치는 하지 않은 걸까? 정말 열심히 찾았다... 그런데... 발견 할 수 있는 모든 글은.... 몇개 되지도 않았고 전부 다들 이걸 어떻게 해결 해야 할지에 대한 문의 와.. 간단하게 PL/SQL을 이용하여 sql%rowcount 를 활용하라는 내용이 전부 였다.
해결 방법 : 닭치고....
System.Data.OracleClient
을 쓰면 된다......
이렇게 이야기 하면... 정말 속 편하겠다... 근데 이눔의 호기심이 젠장..... 그냥 넘길 수 없었다.
일단 System.Data.OracleClient에 속한 ExecuteNonQuery 는 잘 동작하니까..... 마이크로소프트는 뭐라고 하는지 MSDN을 봤다...
https://msdn.microsoft.com/ko-kr/library/vstudio/system.data.oracleclient.oraclecommand.executenonquery(v=vs.100).aspx
물론 여기서 중요한 이야기는
UPDATE, INSERT 및 DELETE 문의 경우, 반환 값은 해당 명령의 영향을 받는 행의 수입니다. CREATE TABLE 및 DROP TABLE 문의 경우 반환 값은 0입니다. 다른 형식의 문의 경우에는 반환 값이 -1입니다.
이 이야기가 되시겠다...
자 그렇다면.... ODP.Net은 그럼 Merge문을 다른 형식의 문장으로 보고 있다는 말인가? 이런.. 퐝당한.....
Oracle.DataAccess.dll을 .Net Reflector로 까 봤다...
---- 중략 ----
if ((errCode != -1) && (((this.m_pOpoSqlValCtx.CommandType == 4) ||
(this.m_pOpoSqlValCtx.CommandType == 2)) ||
(this.m_pOpoSqlValCtx.CommandType == 3)))
{
this.m_rowsAffected = this.m_pOpoSqlValCtx.RowsAffected;
if ((this.m_arrayBindCount > 1) && (null != this.m_pOpoSqlValCtx.RowsAffectedForArrayBind))
{
this.m_rowsAffectedPerBind = new long[this.m_pOpoSqlValCtx.NoOfRowsInRowsAffectedForArrayBind];
for (num7 = 0; num7 < this.m_pOpoSqlValCtx.NoOfRowsInRowsAffectedForArrayBind; num7++)
{
this.m_rowsAffectedPerBind[num7] = this.m_pOpoSqlValCtx.RowsAffectedForArrayBind[num7];
}
}
}
else
{
this.m_rowsAffected = -1;
}
---- 중략 ----
보셨는가? 명령어 타입이.. 딱 3가지... 4, 2, 3이 아니면 무조건... 반환값은 -1 이다. 뭐 이쯤 되면 대충 짐작으로도 저건.. Insert, Delete, Update 쯤 될꺼란 짐작 될것이다.
아 퐝당~~~~
그럼 System.Data.OracleClient.dll 에 있는 코드는 어떻게 되지????? 그냥 넘길 수 없다.
역시나 .Net Reflector 로 까 봤다..
---- 중략 ----
int num = -1;
try
{
try
{
ArrayList resultParameterOrdinals = new ArrayList();
statementHandle = this.GetStatementHandle();
this.Execute(statementHandle, CommandBehavior.Default, needRowid, out rowidDescriptor, out resultParameterOrdinals);
if (resultParameterOrdinals != null)
{
num = 0;
foreach (int num2 in resultParameterOrdinals)
{
OracleParameter parameter = this._parameterCollection[num2];
if (OracleType.Cursor != parameter.OracleType)
{
num += (int) parameter.Value;
}
}
return num;
}
if (OCI.STMT.OCI_STMT_SELECT != this._statementType)
{
statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out num, this.ErrorHandle);
}
return num;
}
finally
{
if (statementHandle != null)
{
this.ReleaseStatementHandle(statementHandle);
}
}
}
catch
{
throw;
}
return num;
---- 중략 ----
뭐 대충 보면... 처음에 -1로 초기화 하고 실행 후 파라미터 반복하며,,,, 조건이 맞으면 하나씩 카운트 한 다음에 반환하는 것을 볼 수 있다..
Oracle 프로그램 졸라 잘 만드는지 알았더니.. 이거 참... 실망이다... 이런... 멍청한 것들...
그럼 이걸 어떻게 해결 하면 되는 건지 아니 궁금하다 하면 좀 그럴것이다... 뭐 결국 업데이트 갯수가 몇개가 되었다 보다 적용 된게 있느냐 없느냐가 관건이겠으므로 나는 다음과 같은 방법을 생각 했다..
using (OracleConnection conn = new OracleConnection(oradb))
{
conn.Open();
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = @"BEGIN
MERGE INTO employee
USING DUAL
ON (companyid = 1235)
WHEN MATCHED
THEN
UPDATE SET empname = '홍길동'
WHEN NOT MATCHED
THEN
INSERT (companyid, empname, phone)
VALUES ('1111', 'choi', '111111');
IF SQL%ROWCOUNT = 0
THEN
RAISE_APPLICATION_ERROR(-20801, '에러 났어요.');
END IF;
END;
";
cmd.CommandType = CommandType.Text;
try
{
int dr = cmd.ExecuteNonQuery();
}
catch (OracleException ex)
{
if (ex.Number == 20801)
{
System.Console.WriteLine(ex.Message);
}
else
{
throw;
}
}
}
뭐 대충 이렇게 말이다....... 만약 하나의 로우도 변경 되는 것이 없다면 오라클이 오류를 뱉을 것이다... 젠장 나 못해먹겠어... 라고 말이지......
BEGIN
MERGE INTO employee
USING DUAL
ON (companyid = 1235)
WHEN MATCHED
THEN
UPDATE SET empname = '홍길동'
WHEN NOT MATCHED
THEN
INSERT (companyid, empname, phone)
VALUES ('1111', 'choi', '111111');
IF SQL%ROWCOUNT > 0
THEN
RAISE_APPLICATION_ERROR(-20801, SQL%ROWCOUNT);
END IF;
END;
이렇게 하면 뭐... 적용된 갯수를 Exeception으로 잡아 낼 수도 있겠다... 에효... ㅜ,.ㅜ;;; 이런 꼼수는 싫은 데.....
오라클은 당췌 이 버그는 언제 수정해 줄껀지..... 알고는 있으려나?????????
'Functional World > Database' 카테고리의 다른 글
ODAC 12c Release 1 with Oracle Developer Tools for Visual Studio (2) | 2013.11.01 |
---|---|
문득 관심이 생겨버린 BigData.. MongoDB (0) | 2013.09.11 |