윈도우즈계에서의 데이터베이스 접근을 위한 표준 인터페이스. SqlServer 같이 네이티브 API를 제공하지 않는 DBMS의 경우에는 ODBC를 사용해야한다. 그런데 API도 지저분하고, 설명도 난잡하고, 여러 모로 짜증 좀 나네…
MSDN이 보기 어렵게 되어 있어, 따로 정리했다. 근데 뭔가 모르는 것들이 잔뜩 있네.
속성 | 타입 | 가능한 값 | 의미 |
---|---|---|---|
SQL_ATTR_CONNECTION_POOLING | UINT | SQL_CP_OFF SQL_CP_ONE_PER_DRIVER SQL_CP_ONE_PER_HENV | 커넥션 풀링 on/off |
SQL_ATTR_CP_MATCH | UINT | SQL_CP_STRICT_MATCH SQL_CP_RELAXED_MATCH | 커넥션 풀링 설정 |
SQL_ATTR_ODBC_VERSION | UINT | SQL_OV_ODBC3 SQL_OV_ODBC2 | 드라이버 설정 |
SQL_ATTR_OUTPUT_NTS | UINT | SQL_TRUE SQL_FALSE | 문자열 취급 방법 설정 |
속성 | 타입 | 가능한 값 | 의미 | 설정 가능 시점 |
---|---|---|---|---|
SQL_ATTR_ACCESS_MODE | UINT | SQL_MODE_READ_ONLY SQL_MODE_READ_WRITE | 읽기, 쓰기 | Either |
SQL_ATTR_ASYNC_ENABLE | UINT | SQL_ASYNC_ENABLE_OFF SQL_ASYNC_ENABLE_ON | 비동기 모드 | Either |
SQL_ATTR_AUTOCOMMIT | UINT | SQL_AUTOCOMMIT_OFF SQL_AUTOCOMMIT_ON | 자동 커밋 | Either |
SQL_ATTR_CONNECTION_DEAD | UINT | SQL_CD_TRUE SQL_CD_FALSE | 커넥션 ALIVE 여부 | After |
SQL_ATTR_CONNECTION_TIMEOUT | UINT | 초 | 쿼리 후 기다릴 시간, 0 == INFINITE | Either |
SQL_ATTR_CURRENT_CATALOG | STRING | 데이터베이스 이름 | 현재 작업 중인 데이터베이스 | Either |
SQL_ATTR_LOGIN_TIMEOUT | UINT | 초 | 로그인 성공/실패때까지 기다릴 시간, 0 == INFINITE | Before |
SQL_ATTR_METADATA_ID | UINT | SQL_TRUE SQL_FALSE | 대소문자 구별. 이외에도 뭔가 있다. | Either |
SQL_ATTR_ODBC_CURSORS | UINT | SQL_CUR_USE_IF_NEEDED SQL_CUR_USE_ODBC SQL_CUR_USE_DRIVER | 커서 종류 설정 | Before |
SQL_ATTR_PACKET_SIZE | UINT | 바이트 크기 | 네트워크를 통해 오가는 패킷 크기 | Before |
SQL_ATTR_QUIET_MODE | UINT | 32비트 윈도우 핸들 | NULL이면 대화창 표시하지 않는다. | Either |
SQL_ATTR_TRACE | UINT | SQL_OPT_TRACE_OFF SQL_OPT_TRACE_ON | 트레이스 여부 | Either |
SQL_ATTR_TRACEFILE | STRING | 파일 이름 | 트레이스 파일 이름 | Either |
SQL_ATTR_TRANSLATE_LIB | STRING | 파일 이름 | 아 몰라 | After |
SQL_ATTR_TRANSLATE_OPTION | UINT | 32비트 플래그 | 아 몰라 | After |
SQL_ATTR_TXN_ISOLATION | UINT | 32비트 비트 마스크. SQL_TXN_ISOLATION_OPTIONS 참고 | 트랜잭션 락 레벨 | Either |
속성 | 타입 | 가능한 값 | 의미 |
---|---|---|---|
SQL_ATTR_APP_PARAM_DESC | UINT | APD에 대한 핸들, SQL_NULL_DESC | APD가 뭐지? |
SQL_ATTR_APP_ROW_DESC | UINT | ARD에 대한 핸들, SQL_NULL_DESC | ARD가 뭐지? |
SQL_ATTR_ASYNC_ENABLE | UINT | SQL_ASYNC_ENABLE_OFF SQL_ASYNC_ENABLE_ON | 비동기 처리 설정 |
SQL_ATTR_CONCURRENCY | UINT | SQL_CONCUR_READ_ONLY SQL_CONCUR_LOCK SQL_CONCUR_ROWVER SQL_CONCUR_VALUES | 락 설정 |
SQL_ATTR_CURSOR_SCROLLABLE | UINT | SQL_NONSCROLLABLE SQL_SCROLLABLE | 커서 스크롤 설정 |
SQL_ATTR_CURSOR_SENSITIVITY | UINT | SQL_UNSPECIFIED SQL_INSENSITIVE SQL_SENSITIVE | 결과를 다른 커서와 공유하는가? |
SQL_ATTR_CURSOR_TYPE | UINT | SQL_CURSOR_FORWARD_ONLY SQL_CURSOR_STATIC SQL_CURSOR_KEYSET_DRIVEN SQL_CURSOR_DYNAMIC | 커서 종류 설정 |
SQL_ATTR_ENABLE_AUTO_IPD | UINT | SQL_FALSE SQL_TRUE | ? |
SQL_ATTR_FETCH_BOOKMARK_PTR | UINT | 포인터 | 이진 북마크에 대한 값이라는데, 이건 또 뭐지? |
SQL_ATTR_IMP_PARAM_DESC | UINT | IPD에 대한 핸들 | IPD가 뭐지? |
SQL_ATTR_IMP_ROW_DESC | UINT | IRD에 대한 핸들 | IRD가 뭐지? |
SQL_ATTR_KEYSET_SIZE | UINT | 행의 수 | 키셋 기반 커서에서 다룰 행의 수 |
SQL_ATTR_MAX_LENGTH | UINT | 바이트 길이 | 결과셋 안의 문자열 혹은 바이너리 컬럼의 최대 길이 |
SQL_ATTR_MAX_ROWS | UINT | 행의 수 | 결과셋의 최대 행 수 |
SQL_ATTR_METADATA_ID | UINT | SQL_TRUE SQL_FALSE | 대소문자 구별 여부. 이외에도 뭔가 있다. |
SQL_ATTR_NOSCAN | UINT | SQL_NOSCAN_OFF SQL_NOSCAN_ON | 이스케이프 문자 검색 여부 |
SQL_ATTR_PARAM_BIND_OFFSET_PTR | UINT* | 포인터 옵셋 변수에 대한 포인터 | 동적 파라미터 바인딩 시에 더하는 값이라는데 뭔지 모르겠다. |
SQL_ATTR_PARAM_BIND_TYPE | UINT | SQL_PARAM_BIND_BY_COLUMN or 구조체의 크기 | 음, 나중에 읽어보자 |
SQL_ATTR_PARAM_OPERATION_PTR | USINT* | SQL_PARAM_PROCEED, SQL_PARAM_IGNORE 값으로 이루어진 배열에 대한 포인터 | 배열을 한번에 바인딩하는 것과 관련된 속성인 듯? |
SQL_ATTR_PARAM_STATUS_PTR | USINT* | 배열의 포인터 | 쿼리 실행 결과를 받아오기 위한 배열 |
SQL_ATTR_PARAMS_PROCESSED_PTR | UINT* | 배열의 포인터 | 리 실행 결과를 받아오기 위한 배열 |
SQL_ATTR_PARAMSET_SIZE | UINT | 한 파라미터에 들어있는 값의 숫자 | 배열을 바인딩하기 위해 설정하는 값 |
SQL_ATTR_QUERY_TIMEOUT | UINT | 초 | 쿼리를 수행하고 결과셋을 기다릴 시간, 0 == INFINITE |
SQL_ATTR_RETRIEVE_DATA | UINT | SQL_RD_ON SQL_RD_OFF | 커서가 움직이면 데이터를 바로 가져오는지 여부 |
SQL_ATTR_ROW_ARRAY_SIZE | UINT | 행의 수 | 결과셋을 페치할 때마다 가져올 행의 수 |
SQL_ATTR_ROW_BIND_OFFSET_PTR | UINT* | ? | ? |
SQL_ATTR_ROW_BIND_TYPE | UINT | ? | ? |
SQL_ATTR_ROW_NUMBER | UINT | 행 번호 | 현재 행이 전체 결과셋에서 차지하는 번호 |
SQL_ATTR_ROW_OPERATION_PTR | USINT* | ? | ? |
SQL_ATTR_ROW_STATUS_PTR | USINT* | ||
SQL_ATTR_ROWS_FETCHED_PTR | UINT* | 행 갯수를 집어넣을 변수의 포인터 | 결과셋을 가져올 때마다 안의 행 숫자를 집어넣을 변수 설정 |
SQL_ATTR_SIMULATE_CURSOR | UINT | SQL_SC_NON_UNIQUE SQL_SC_TRY_UNIQUE | Positioned update and delete statements? |
SQL_ATTR_USE_BOOKMARKS | UINT | SQL_UB_OFF SQL_UB_VARIABLE | 북마크 사용 여부 |
SQLGetData 함수를 이용해 BLOB/TEXT 컬럼을 읽어올 때에는, BLOB/TEXT 컬럼이 SELECT 구문의 마지막에 오도록 해야한다.
SELECT ID, BLOB_COLUMN, INT_COLUMN FROM SomeTable -- ERROR SELECT ID, INT_COLUMN, BLOB_COLUMN FROM SomeTable -- OK
자세한 사항은 Getting Long Data 페이지를 참고.
There are a number of restrictions on using SQLGetData. In general, columns accessed with SQLGetData:
SQLDriverConnect에 사용하는 주소 문자열.
connection-string ::= empty-string[;] | attribute[;] | attribute; connection-string empty-string ::= attribute ::= attribute-keyword=attribute-value | DRIVER=[{]attribute-value[}] attribute-keyword ::= DSN | UID | PWD | driver-defined-attribute-keyword attribute-value ::= character-string driver-defined-attribute-keyword ::= identifier
SQL Server
DRIVER=SQL Server;SERVER=myserver;DATABASE=testdb;Trusted_Connection=Yes DRIVER=SQL Server;SERVER=myserver;DATABASE=testdb;UID=testuser;PWD=testpwd
File DSN
FILEDSN=C:\sample.dsn
sample.dsn
DRIVER = SQL Server UID = Larry DATABASE = MyDB
File DSN에는 패스워드를 지정할 수 없다.
별다른 옵션을 주지 않을 경우, 기본적으로 생성되는 커서는 forward-only 커서다. 커서를 앞뒤로 움직이거나, 특정 옵셋으로 가기 위해서는 scrollable cursor 를 사용해야한다.
// Statement 핸들에다가 사용할 커서의 타입과 한번에 가져올 행의 갯수를 설정한다. SQLSetStmtAttr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)1, 0); SQLSetStmtAttr(hStmt, SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER)SQL_SCROLLABLE, 0); ... // SQLFetchScroll 함수를 통해 결과셋을 가져온다. SQLFetchScroll(hStmt, SQL_FETCH_NEXT, 0); SQLFetchScroll(hStmt, SQL_FETCH_PRIOR, 0);
커넥션 풀링이 뭐하는 기능인지는 이름이 다 말해주고 있다. 서버와의 커넥션을 만드는 비용이 비싸기 때문에 애플리케이션 레벨에서 커넥션을 닫아도 실제로 닫지는 않고 있다가 해당 서버와의 연결 요청이 들어오면 기존의 커넥션을 재이용하는 기능이다. 기본적으로 커넥션 스트링을 이용해 커넥션을 구분한다. 같은 서버에 연결한다고 하더라도 커넥션 스트링이 한 바이트라도 틀리면 다른 커넥션으로 인식한다는 이야기다.
커넥션 풀링을 사용할 때 주의할 점은 다음과 같다.
커넥션 풀링을 사용할 때 살펴볼 값 중의 하나가 CPTimeout 값과 RetryWait 값이다. CPTimeout 값은 사용하고 있지 않은 커넥션을 풀에 담아둘 시간이고, RetryWait 값은 서버에서 응답이 없을 경우, 다음 커넥션 재생성을 위해 기다릴 시간이다.
RetryWait 값은 제어판 → 관리도구 → 데이터원본 (ODBC) → 연결 풀링 탭에서 수정할 수 있다. CPTimeout 값은 해당 드라이버를 더블 클릭하면 뜨는 윈도우에서 수정할 수 있다. 레지스트리에서도 수정할 수 있다. HKLM\Software\Odbc\Odbcinst.ini\<drivername> 항목을 찾아보기 바란다. 값은 초단위다.
풀링은 ODBC API를 통해 설정할 수도 있다.
SQLSetEnvAttr( hEnv, SQL_ATTR_CONNECTION_POOLING, ULongToPtr(SQL_CP_ONE_PER_HENV or SQL_CP_ONE_PER_DRIVER), SQL_IS_UINTEGER );
내부 네트워크 부하에 의해, 커넥션이 이상하게 끊어지는 경우가 있다고 한다. 이 문제를 해결하기 위해서 쿼리를 실행할 때마다 커넥션 객체를 생성하되, 커넥션 풀링을 이용하라…라는 이야기가 있던데…
커넥션 풀링을 사용하는 애플리케이션을 빠르게 실행했다, 죽였다를 반복하면, SQLConnect 내부에서 Access Violation이 발생하는 경우가 있었다. 윈도우즈 2003 서버, SQL Server 2005 기준이다. 설정이 뭔가 잘못된 것인지, ODBC 내부 문제인지 모르겠네.
찾아보니 이런 글이 있었다. 이 문제가 맞나? .NET 이랑은 아무 관련 없는데… http://support.microsoft.com/?kbid=328476 요런 글도 있고…