none
Linux PHP 환경에서 SQL Server 2008 R2 로 ODBC 연결 문제 RRS feed

  • 질문

  • 안녕하세요.

    윈도우 PHP 에서는 sqlsrv 드라이버로 SQL Serer 2008 r2 연동에 문제가 없는데.. (PDO-SQLSRV)
    리눅스 시스템에서 구동중인 PHP 에서는 sqlsrv 를 사용할 수 없고.. 기존의 FreeTDS 를 이용한 연동도 문제가 있어 못쓰다가,
    이번에 MS 에서 리눅스용 ODBC Driver 를 내놓았길래 설치하고 테스트 중인데 문제 해결이 힘들어 도움을 구합니다.

    SQLServer 쪽에 비슷한 이슈 피드백이 있길래 그쪽에도 코멘트 달아 두긴 했는데요..
    (https://connect.microsoft.com/SQLServer/feedback/details/737751/cannot-bind-parameters-with-php-pdo-odbc-and-sql-native-client-11-0)

    드라이버는 아래에서 받아 설치 메뉴얼 대로 설치하였습니다. (RHEL-5)

    드라이버 - http://www.microsoft.com/download/en/details.aspx?id=28160
    메뉴얼 - http://msdn.microsoft.com/en-us/library/hh477150(v=sql.10).aspx

    테스트로 사용한 SQL Server 는 2008 R2 express 입니다.

    테스트한 리눅스 환경은 아래와 같습니다.

    CentOS 5.7 (RHEL-5)
    Microsoft SQL Server ODBC Driver for Linux (RHEL-5)
    PHP 5.3.3
    unixODBC 2.3.0

    PDO-ODBC 를 통해 연결했고.. 일반 쿼리는 잘 동작하는 것 같습니다만, 바인드만 사용하면 오류가 발생합니다.

    <?php
    ini_set('display_errors', true);
    ini_set('error_reporting', E_ALL ^ E_NOTICE );
    try{
     $dbh = new PDO("odbc:MSTEST", "test", 3045);
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     $query = "SELECT * FROM dbo.test_table WHERE c2 = ?";
     $stmt = $dbh->prepare($query);
     $stmt->bindParam(1,$v=5,PDO::PARAM_INT);
     $result = $stmt->execute();
     print_r( $stmt->fetch() );
    }catch(Exception $e){
     die($e->getMessage());
    }
    ?>
    

    SQLSTATE[22018]: Invalid character value for cast specification: 0 [Microsoft][SQL Server Native Client 11.0]Invalid character value for cast specification (SQLExecute[0] at /builddir/build/BUILD/php-5.3.3/ext/pdo_odbc/odbc_stmt.c:254)

    SQL Server 프로파일러로 보면.. 제가 날린 쿼리는 아직 들어오지도 않았고..
    바인딩 대상 컬럼만 set fmtonly on 상태로 조회한 직후
    Invalid character value for cast specification이 발생하고 있네요.

    User Error Message 데이터베이스 컨텍스트가 'TestDB'(으)로 변경되었습니다. test 59 2012-04-26 14:11:56.677
    User Error Message 언어 설정이 한국어(으)로 변경되었습니다. test 59 2012-04-26 14:11:56.677
    Audit Login -- network protocol: TCP/IP
    set quoted_identifier on
    set arithabort off
    set numeric_roundabort off
    set ansi_warnings on
    set ansi_padding on
    set ansi_nulls on
    set concat_null_yields_null on
    set cursor_close_on_commit off
    set implicit_transactions off
    set language 한국어
    set dateformat ymd
    set datefirst 7
    set transaction isolation level read committed
    test 59 2012-04-26 14:11:56.677 0X2000002838F4010000000000
    SP:CacheHit set fmtonly on select  c2 from dbo.test_table where 1=2 set fmtonly off test 59 2012-04-26 14:11:56.680
    SQL:BatchStarting set fmtonly on select  c2 from dbo.test_table where 1=2 set fmtonly off test 59 2012-04-26 14:11:56.680
    SQL:StmtStarting set fmtonly on test 59 2012-04-26 14:11:56.680
    SQL:StmtCompleted set fmtonly on test 0 0 0 0 59 2012-04-26 14:11:56.680 2012-04-26 14:11:56.680
    SQL:StmtStarting select  c2 from dbo.test_table where 1=2 test 59 2012-04-26 14:11:56.680
    Audit Schema Object Access Event select  c2 from dbo.test_table where 1=2 test 59 2012-04-26 14:11:56.680
    SQL:StmtCompleted select  c2 from dbo.test_table where 1=2 test 0 0 0 0 59 2012-04-26 14:11:56.680 2012-04-26 14:11:56.680
    SQL:StmtStarting set fmtonly off test 59 2012-04-26 14:11:56.680
    SQL:StmtCompleted set fmtonly off test 0 0 0 0 59 2012-04-26 14:11:56.680 2012-04-26 14:11:56.680
    SQL:BatchCompleted set fmtonly on select  c2 from dbo.test_table where 1=2 set fmtonly off test 0 0 0 0 59 2012-04-26 14:11:56.680 2012-04-26 14:11:56.680
    Audit Logout test 0 0 0 3 59 2012-04-26 14:11:56.677 2012-04-26 14:11:56.680

    저희쪽 엔지니어분이 설치해주신 환경과는 완전히 별개로.. 제가 개인적으로 리눅스와 PHP/ODBC 를 구성해 재현해도 똑같이 오류가 발생하는걸 보면..
    문제가 좀 있어보이는데 해결 방법이 있을지 문의 드립니다.

    사담으로.. 이게 안되면.. 안되는데;; 요즘 oracle 을 ms-sql 로 변경하는 케이스도 있고, 애초에 ms-sql 로 들어오는 장비들도 최근 늘어서..
    기존 리눅스 시스템에서 돌고있는 PHP 랑 연동할 일이 점점 늘어나고 있거든요.

    바인드를 쓰지않고 날쿼리로 파라미터를 셋팅하는건 금지되어있고..

    모쪼록 긍정적인 답변 부탁 드립니다. _ _)

    2012년 4월 26일 목요일 오전 5:59

모든 응답

  • 안녕하십니까? bitofsky 님,
    Microsoft TechNet의Forum 사이트를 방문해 주셔서 감사합니다.

    현재 문의 하신 ”Linux PHP 환경에서 SQL Server 2008 R2 로 ODBC 연결 문제" 대해 답변을 드리겠습니다.

    오래전에 발생되었던 버그로 현재는 제 생각에는 아래 설치를 통해서 해결가능하지 않나 싶습니다.
    [참고 자료]
    SQL Server 2008 누적 업데이트 패키지 8

    제시해 드린 답변이 도움이 되었기를 바랍니다.

    답변이 문제 해결에 도움이 되었다면 답변으로 채택을 부탁드립니다.
    하지만 문제 해결이 되지 않아서 정확한 답변을 원하는 경우에는 문제의 정보를 더 자세하게 답변으로 제공해주시기 바랍니다.

    2012년 4월 27일 금요일 오전 3:13
    중재자
  • 누적 업데이트 패키지 8 은 2008 R2 에 설치되지 않네요.

    대신 윈도우 업데이트를 통해 2008 R2 서비스팩을 설치하니 오류 메시지가 바뀌었습니다.

    SQLSTATE[22001]: String data, right truncated: 0 [Microsoft][SQL Server Native Client 11.0]String data, right truncation (SQLExecute[0] at /builddir/build/BUILD/php-5.3.3/ext/pdo_odbc/odbc_stmt.c:254)

    여기서 bindParam 시 output length 를 넣으니 이전에 넘어가지 못했던 
     set fmtonly on select  c1, c2 from dbo.test_table where 1=2 set fmtonly off
    문을 넘어서 쿼리가 MSSQL 에 실행 되네요.
    <?php
    ini_set('display_errors', true);
    ini_set('error_reporting', E_ALL ^ E_NOTICE );
    try{
     $dbh = new PDO("odbc:MSTEST", "test", 3045);
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     $query = "SELECT * FROM dbo.test_table WHERE c1 = ? AND c2 = ?";
     $stmt = $dbh->prepare($query);
     $stmt->bindParam(1,$v1=5, PDO::PARAM_INT, 10);
     $stmt->bindParam(2,$v2=1, PDO::PARAM_INT, 10);
     $result = $stmt->execute();
     print_r( $stmt->fetch() );
    }catch(Exception $e){
     die($e->getMessage());
    }
    ?>
    
    declare @p1 int
    set @p1=NULL
    declare @p4 nvarchar(50)
    set @p4=NULL
    declare @p5 int
    set @p5=NULL
    exec sp_prepexec @p1 output,N'@P1 nvarchar(50) OUTPUT,@P2 int OUTPUT',N'SELECT * FROM dbo.test_table WHERE c1 = @P1 OUTPUT AND c2 = @P2 OUTPUT',@p4 output,@p5 output
    select @p1, @p4, @p5

    'OUTPUT' 근처의 구문이 잘못되었습니다.

    SELECT 문에 OUTPUT 이 들어갔으니 오류가 나는데..
    output length 를 지정하지 않으면 아예 여기까지 쿼리가 나가지도 못하니.. 이걸 어찌해야 하나요?

    2012년 4월 30일 월요일 오전 1:07
  • 일단 아래 부분의 코드에 대한 점검이 필요합니다.

    $stmt->bindParam(1,$v1=5, PDO::PARAM_INT, 10);
    $stmt
    ->bindParam(2,$v2=1, PDO::PARAM_INT, 10);

    매개변수는 출력방향이 OUTPUT로 잘못 지정되어 출력매개변수로 인식되고 있습니다.

    이를 입력매개변수로 지정해 주야 하겠습니다.

    또한, 첫번째 매개변수에 값을 할당하고 있으나, 첫번쨰 매개변수인 @P1(@p4)은 nvarchar(50)로 설정되어 있으며,

    실제 입력된 값이 해당 범위를 벗어났기 때문에 "문자열오른쪽이 잘렸다는 오류"가 발생하고 있는 것입니다.

    SQLSTATE[22001]: String data, right truncated: 0 [Microsoft][SQL Server Native Client 11.0]String data, right truncation (SQLExecute[0] at /builddir/build/BUILD/php-5.3.3/ext/pdo_odbc/odbc_stmt.c:254)

    실제 매개변수에 입력된 값을 확인하셔야 할 것 같습니다.

    실제 데이터는 정수형을 입력하고 있는 것 같습니다.(해당 테이블 칼럼이 정수형인지 다시 한 번 확인해 보시기 바립니다)

    또한, bindParam 메서드를 확인하셔서 실제 정확한 칼럼의 데이터형과 길이를 지정해 주시는 것이 바람직합니다.

    아래 자료를 참조하시면 되겠습니다.

    SQL Server Native Client (ODBC)

    http://msdn.microsoft.com/en-us/library/ms131415

    감사합니다.

    씨퀄로(SQLRoad.com)


    Best Regards, Daejoong Samuel Sung Microsoft SQL Server MVP,MCITP,MSTS, Senior Consultant @ SQLRoad.COM

    2012년 5월 11일 금요일 오전 5:15
    중재자
  • 답변 감사합니다.

    위 응답에 쓰긴 했지만.. 

    $stmt->bindParam(1,$v1=5, PDO::PARAM_INT, 10);
    $stmt
    ->bindParam(2,$v2=1, PDO::PARAM_INT, 10);

    이걸 작성한건 오류 메시지의 변화를 알려드리고자 함이었습니다.
    4번째 인자 10 은 말씀하신 대로 출력(OUTPUT) 인자의 길이를 의미 합니다.

    문제는 이 인자를 입력하지 않으면 쿼리가 실행 단계까지 가지도 않는데에 있습니다.
    4번째 인자를 제외하고 실행하면 아래와 같습니다.

     $dbh = new PDO("odbc:MSTEST", "test", 3045);
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     $query = "SELECT * FROM dbo.test_table WHERE c1 = ?";
     $stmt = $dbh->prepare($query);
     $stmt->bindParam(1,$v1='aaa', PDO::PARAM_STR);
     $result = $stmt->execute();
    
    오류는 아래..
    SQLSTATE[22001]: String data, right truncated: 0 [Microsoft][SQL Server Native Client 11.0]String data, right truncation (SQLExecute[0] at /builddir/build/BUILD/php-5.3.3/ext/pdo_odbc/odbc_stmt.c:254)

    오른쪽이 잘렸다고 하는데.. 뭐가 짤렸나.. sql profiler 를 보면, 아예 제가 실행한 쿼리와 파라메터는 들어오지도 않은 상태입니다.

    Audit Login -- network protocol: TCP/IP
    set quoted_identifier on
    set arithabort off
    set numeric_roundabort off
    set ansi_warnings on
    set ansi_padding on
    set ansi_nulls on
    set concat_null_yields_null on
    set cursor_close_on_commit off
    set implicit_transactions off
    set language 한국어
    set dateformat ymd
    set datefirst 7
    set transaction isolation level read committed
    test 54 2012-05-01 15:13:29.913
    SP:CacheInsert set fmtonly on select  c1, c2 from dbo.test_table where 1=2 set fmtonly off test 54 2012-05-01 15:13:29.923
    SQL:BatchStarting set fmtonly on select  c1, c2 from dbo.test_table where 1=2 set fmtonly off test 54 2012-05-01 15:13:29.917
    SQL:StmtStarting set fmtonly on test 54 2012-05-01 15:13:29.923
    SQL:StmtCompleted set fmtonly on test 0 0 0 0 54 2012-05-01 15:13:29.923 2012-05-01 15:13:29.923
    SQL:StmtStarting select  c1, c2 from dbo.test_table where 1=2 test 54 2012-05-01 15:13:29.923
    SQL:StmtCompleted select  c1, c2 from dbo.test_table where 1=2 test 0 8 0 0 54 2012-05-01 15:13:29.923 2012-05-01 15:13:29.923
    SQL:StmtStarting set fmtonly off test 54 2012-05-01 15:13:29.923
    SQL:StmtCompleted set fmtonly off test 0 0 0 0 54 2012-05-01 15:13:29.923 2012-05-01 15:13:29.923
    SQL:BatchCompleted set fmtonly on select  c1, c2 from dbo.test_table where 1=2 set fmtonly off test 0 196 0 6 54 2012-05-01 15:13:29.917 2012-05-01 15:13:29.923
    Audit Logout test 0 380 0 73 54 2012-05-01 15:13:29.913 2012-05-01 15:13:29.987

    보시다시피

    set fmtonly on select  c1, c2 from dbo.test_table where 1=2 set fmtonly off

    이 명령이 실행된 후 제가 실행한 쿼리가 들어 와야 할텐데.. Audit Logout 찍히고 끝입니다.
    그리고 제 PHP 서버에서는 저 오류를 내는 상태이구요.

    제가 추측하기엔 리눅스 드라이버(unixodbc 또는 sqlcli 11) 가 set fmtonly on 을 해서 바인딩 인자로 들어가는 컬럼의 메타데이터를 획득하고 이 메타데이터를 기반으로 prepare 및 bind parameter 를 시도할 차례인데.. 메타 데이터를 가져오다가 String data, right truncation 가 발생한 것이 아닌가 추측 하고 있습니다.

    이 동일한 코드가 윈도우 PHP 서버와 SQLSRV 드라이버로 실행하면 완벽히 잘 실행됩니다. ㅠㅠ

    끙...

    2012년 5월 14일 월요일 오전 6:24
  • 저도 동일한 문제를 겪고 있는데요.. 혹시 해결방안을 찾으셨는지 궁금합니다.


    2012년 10월 17일 수요일 오후 5:13