'Functional World/Database' 카테고리의 글 목록 :: iopeni - Think of C#

어느날 아는 동생으로 부터... (나 보다 훨 스킬이 좋은 개발자다.) 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으로 잡아 낼 수도 있겠다... 에효... ㅜ,.ㅜ;;; 이런 꼼수는 싫은 데.....


오라클은 당췌 이 버그는 언제 수정해 줄껀지..... 알고는 있으려나?????????

Posted by 프로그래머란 카페인을 코드로 변환하는 기계다
,

http://www.oracle.com/technetwork/database/windows/downloads/index-101290.html


에 보면 Oracle Database 12 버젼을 지원하는 ODT가 업데이트 되었습니다.





그런데 말이죠 불행하게도 아직 Visual Studio 2013을 지원하지 않습니다.


언제 쯤 Visual Studio 2013을 지원하는 ODT가 발표 될까요? 기다려 지네요.


현재 제 개발 노트북의.. OS 는 Windows 8.1 Pro 입니다.


64bit Oracle Client 가 윈도우 8.1 에서는 설치 조차 되지 않는 군요. 


오라클이 빨리 지원해주기만을 학수 고대 합니다.


Posted by 프로그래머란 카페인을 코드로 변환하는 기계다
,

세상 사람들이 Big Data를 외치고

많은 프로젝트들이 Big Data로 만들어지고


남들은 이미 다 하고 있는 Big Data를 뒤늦게 관심 가지게 되었습니다.


예전 어떤 친구에서 빅데이타는 아무것도 모르는 초보 프로그래머가 가장 접근 하기 쉬운 DB는 MongoDB라는 이야기를 들었던 기억이 있어서 MongoDB로 학습하기로 결정 하였습니다. 


일단 뭐 학습을 하려면 프로그램부터 다운 받아야 하니 구글에서 몽고디비 검색... 쉽게 찾을 수 있었습니다.


http://www.mongodb.org 


32bit - http://downloads.mongodb.org/win32/mongodb-win32-i386-2.4.6.zip

64bit - http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2.4.6.zip


윈도우 프로그래머인 저는 윈도우 버젼으로... ^^ 다운 받았습니다.

이제 비쥬얼스튜디오에서... 몽고디비에 접속하여야 하므로 C#용 드라이버를 다운 로드 받아야 겠죠?


https://github.com/mongodb/mongo-csharp-driver/releases


일단 Visual Studio로 몽고디비를 사용해 보는 것은 뒤로 미루고 이 녀석이 어떻게 실행 되며 동작 되는지 부터 해봐야 겠기에...


압축 풀고... 

C:\mongoDB 생성 후 복사 

C:\mongoDB\data\db 폴더 생성


C:\mongoDB\bin\mongod --dbpath C:\mongodb\data\db


실행하면.. 디비 실행 완료




이제 시작 인가 봅니다.. 나의 몽고디비 학습기.... 빅데이타 학습기....


윈도우 서비스로 MongoDB 등록 하기.


mongod --install  --dbpath c:\mongodb\data\db --logpath c:\mongodb\log\mongo.log --logappend

http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/


C:\mongoDB\bin\mongo.exe


>db.user.insert({name:"길동이", age:6})

>db.user.find({name:"길동이"})


메뉴얼 참고 하여 첫 인서트와 셀렉트를 날려 보니.... 오옷 이거 컬렉션 입니다. 

그것도 제너릭 컬렉션이죠 자료 타입의 인자가 몇개가 들어가던 프로퍼티를 자동으로 생성하는 컬렉션 입니다.


정말 재미 있을 듯 합니다. 열심히 공부 해봐야 겠죠?



Posted by 프로그래머란 카페인을 코드로 변환하는 기계다
,