3. ODBC 프로그래밍#
이 장은 Altibase ODBC 드라이버를 사용해서 ODBC 애플리케이션을 작성하는 방법을 예제와 함께 설명한다.
연결 문자열 (Connection String)#
Altibase ODBC를 사용하여 ODBC 애플리케이션을 작성할 때 DSN을 사용하는 대신에 연결 문자열을 사용할 수도 있다. 연결 문자열은 아래의 속성으로 구성된다.
속성 | 설명 |
---|---|
DRIVER | ODBC 드라이버의 이름. ODBC 데이터 원본 관리자 창에서 확인할 수 있다. |
User | 데이터베이스 사용자 이름 |
Password | 데이터베이스 사용자 비밀번호 |
Server | 접속할 Altibase 서버의 IP 주소 |
PORT | Altibase 서버의 listening 포트 번호 |
NLS_USE | 클라이언트의 캐릭터셋 |
LongDataCompat | ON 또는 OFF BLOB 같은 대용량 데이터를 사용할 경우 ON으로 설정하길 권장한다. 디폴트는 OFF이다. |
다음은 위의 속성들을 이용해서 구성한 연결 문자열의 예이다.
"DRIVER=ALTIBASE_HDB_ODBC_64bit;User=SYS;Password=xxx;Server=127.0.0.1;PORT=20300;NLS_USE=US7ASCII;LongDataCompat=OFF"
기본 프로그래밍 예제#
ODBC애플리케이션에서 Altibase 서버에 접속하고 종료하는 예제 코드과 애플리케이션 수행결과는 다음과 같다.
예제#
/* test_odbc.cpp */
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <stdlib.h>
#define SQL_LEN 1000
#define MSG_LEN 1024
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
void execute_err(SQLHSTMT stat, char* q)
{
printf("Error : %s\n",q);
SQLINTEGER errNo;
SQLSMALLINT msgLength;
SQLTCHAR errMsg[MSG_LEN];
if (SQL_SUCCESS == SQLError ( henv, hdbc, stat, NULL, &errNo, errMsg, MSG_LEN, &msgLength ))
{
printf(" Error : # %lld, %s\n", errNo, errMsg);
}
SQLFreeStmt(stat, SQL_DROP);
if (SQL_ERROR == SQLDisconnect(hdbc))
{
printf("disconnect error\n");
}
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
exit (1);
}
void main()
{
char *DSN, *DBNAME, *USERNAME, *PASSWD, *PORTNO;
char query[SQL_LEN], name[21];
int age;
SQLCHAR constr[100];
SQLINTEGER len;
DSN = "ALTIBASE"; // Domain Server Name
/* Environment 을 위한 메모리를 할당 */
if(SQLAllocEnv(&henv) == SQL_ERROR)
{
printf("AllocEnv error!!\n");
exit(1);
}
/* Connection 을 위한 메모리를 할당 */
if(SQLAllocConnect(henv, &hdbc) == SQL_ERROR)
{
printf("AllocDbc error!!\n");
SQLINTEGER errNo;
SQLSMALLINT msgLength;
SQLTCHAR errMsg[MSG_LEN];
if (SQL_SUCCESS == SQLError ( henv, NULL, NULL, NULL, &errNo,
errMsg, MSG_LEN, &msgLength ))
{
printf(" Error : # %lld, %s\n", errNo, errMsg);
}
exit(1);
}
/* Connection을 형성 */
sprintf((char*)constr,
"DSN=%s", DSN);
if ( SQLDriverConnect(hdbc, NULL, constr, SQL_NTS, NULL, 0, NULL,
SQL_DRIVER_COMPLETE))
{
printf("DBNAME = %s\n", DBNAME);
printf("USERNAME = %s\n", USERNAME);
printf("Connection error!!\n");
SQLINTEGER errNo;
SQLSMALLINT msgLength;
SQLTCHAR errMsg[MSG_LEN];
if (SQL_SUCCESS == SQLError ( henv, hdbc, NULL, NULL, &errNo,
errMsg, MSG_LEN, &msgLength ))
{
printf(" Error : # %lld, %s\n", errNo, errMsg);
}
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
exit(1);
}
printf("connected...\n");
/* statement을 위한 메모리를 할당 */
if ( SQLAllocStmt(hdbc, &hstmt) == SQL_ERROR )
{
printf("AllocStmt error!!\n");
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
exit(1);
}
/* 쿼리수행 */
sprintf(query,"DROP TABLE TEST001");
SQLExecDirect(hstmt,(SQLTCHAR*)query, SQL_NTS);
sprintf(query,"CREATE TABLE TEST001 ( name varchar(20), age number(3) )");
if (SQL_ERROR == SQLExecDirect(hstmt,(SQLTCHAR*)query, SQL_NTS))
{
execute_err(hstmt, query);
}
/* statement를 준비하고 변수를 바인드한다. */
sprintf(query,"INSERT INTO TEST001 VALUES( ?, ? )");
if (SQL_ERROR == SQLPrepare(hstmt, (SQLTCHAR*)query, SQL_NTS))
{
execute_err(hstmt, query);
}
if (SQL_ERROR == SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, 0, 0, name,
19, &len))
{
printf("SQLBindParameter error!!! ==> %s \n",query);
exit(1);
}
if (SQL_ERROR == SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT,
SQL_C_SLONG, SQL_NUMERIC, 0, 0,
&age, 0, &len))
{
printf("SQLBindParameter error!!! ==> %s \n",query);
exit(1);
}
/* 준비된 statement를 수행 */
sprintf(name, "김민석");
age = 28;
if (SQL_ERROR == SQLExecute(hstmt))
{
execute_err(hstmt, query);
}
sprintf(name, "홍길동");
age = 25;
if (SQL_ERROR == SQLExecute(hstmt))
{
execute_err(hstmt, query);
}
sprintf(name, "아무개");
age = 34;
if (SQL_ERROR == SQLExecute(hstmt))
{
execute_err(hstmt, query);
}
sprintf(query,"SELECT * FROM TEST001");
if (SQL_ERROR == SQLExecDirect(hstmt,(SQLTCHAR*)query, SQL_NTS))
{
execute_err(hstmt, query);
}
/* Select의 결과값을 변수에 저장 */
if (SQL_ERROR == SQLBindCol(hstmt, 1, SQL_C_CHAR, name, 21, &len))
{
printf("SQLBindCol error!!!\n");
exit(1);
}
if (SQL_ERROR == SQLBindCol(hstmt, 2, SQL_C_SLONG,&age, 0, &len))
{
printf("SQLBindCol error!!!\n");
exit(1);
}
while ( SQLFetch(hstmt) == SQL_SUCCESS)
// 결과값이 있는 동안 결과값을 받아 화면에 출력 */
{
printf("Name : %5s, Age : %5ld\n",name,age);
}
/* 모든 handle을 해제하고 접속을 종료 */
SQLFreeStmt(hstmt, SQL_DROP);
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
}
실행결과
Visual C++에서 컴파일 후 생성된 exe 파일을 실행시키면 다음과 같은 결과를 볼 수 있다.
LOB 사용 예제#
이 절은 Altibase ODBC 드라이버를 사용해서 LOB 데이터를 조작하는 방법을 예제를 통해 살펴본다.
Altibase의 LOB Locator 특성상 세션의 자동커밋을 해제한 상태(Non-autocommit)에서 LOB 데이터를 조작해야 한다. 자세한 내용은 Altibase CLI Manual에서 3장 LOB 인터페이스를 참조한다.
또한 다음과 같이 연결 문자열에서 LongDataCompat 속성을 ON으로 설정해야 한다.
"DSN=ALTIBASE;LongDataCompat=ON"
또는
"DRIVER=ALTIBASE_HDB_ODBC_64bit;User=SYS;Password=xxx;Server=127.0.0.1;PORT=20300;NLS_USE=US7ASCII;LongDataCompat=ON"
아래는 C#에서 BLOB 데이터를 테이블에 삽입하고 조회하는 예제이다.
FileStream fs = new FileStream("c:\\test.dat", FileMode.Open, FileAccess.Read);
Byte[] blob = new byte[fs.Length];
fs.Read(blob, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
OdbcTransaction tx = cn.BeginTransaction();
cmd.Transaction = tx;
cmd.CommandText = "INSERT INTO T1 (C1, C2) VALUES (?, ?)";
cmd.Parameters.Add("C1", OdbcType.Int);
cmd.Parameters.Add("C2", OdbcType.Binary);
cmd.Parameters[0].Value = 1;
cmd.Parameters[1].Value = blob;
cmd.ExecuteNonQuery();
tx.Commit();
// BLOB SELECT
cmd.CommandText = "SELECT binary_length(C2), C2 FROM T1";
tx = cn.BeginTransaction();
cmd.Transaction = tx;
OdbcDataReader dr = cmd.ExecuteReader();
int len;
while (dr.Read())
{
len = dr.GetInt32(0);
Byte[] ff = new Byte[len];
dr.GetBytes(1, 0, ff, 0, len);
fs = new FileStream("c:\\test.dat", FileMode.CreateNew, FileAccess.Write);
fs.Write(ff, 0, len);
fs.Close();
}