ODBC setup and simple examples in linux
Table of Contents
1 Installation ArchLinux packages
1.1 Installing odbc
sudo pacman -S unixodbc
1.2 Installing drivers
sudo pacman -S myodbc # mysql sudo pacman -S psqlodbc # postgres yaourt -S sqliteodbc # sqlite
2 Local ODBC setup
Configurations for odbc drivers are written in /etc/odbcinst.ini file:
[PostgreSQL] Description = ODBC driver for postgres Driver = /usr/lib/psqlodbcw.so FileUsage = 1 [MySQL] Description = ODBC driver for mariaDB Driver = /usr/lib/libmyodbc.so Setup = /usr/lib/libmyodbc5S.so FileUsage = 1 [FreeTDS] Description = ODBC driver for Microsoft SQL Driver = /usr/lib/libtdsodbc.so UsageCount = 1
Configuration for odbc sources are in /etc/odbc.ini file:
[mariadb-connector] Description = connection to mariadb version of mysql Driver = MySQL Database = test Server = 127.0.0.1 UserName = keutoi Trace = No Port = 3306 [psql-connector] Description = connection to postgres Driver = PostgreSQL Database = test Server = 127.0.0.1 Port = 5432 UserName = keutoi Trace = No
3 Testing the installation
isql is a CLI for unixodbc.
3.1 Postgres
isql -v psql-connector connects using psql-connector source specification in /etc/odbc.ini or in local ~/.odbc.ini (I'm not
sure of overrides) and opens a sql like prompt to execute sql commands.
echo "select * from mytable" |isql -v psql-connector
gives output:
+---------------------------------------+ | Connected! | | | | sql-statement | | help [tablename] | | quit | | | +---------------------------------------+ SQL> select * from mytable +-----------------------------------------+------------+ | name | id | +-----------------------------------------+------------+ | keutoi0 | 0 | | keutoi1 | 1 | +-----------------------------------------+------------+ SQLRowCount returns 2 2 rows fetched SQL>
3.2 MySQL
myodbc driver was not working in my system. some segmentation errors in driver lib. I had to downgrade myodbc pkg from 5.3.4-1 to 5.2.6-1 to get it working
echo "select * from mytable" | isql -v mariadb-connector
3.3 TODO freetds, sqlite testing
4 Sample Programs
4.1 Sample C Interfaces
#include <stdio.h> #include <sql.h> #include <sqlext.h> int main() { SQLHENV env; SQLCHAR driver[256]; SQLCHAR attr[256]; SQLSMALLINT driver_ret; SQLSMALLINT attr_ret; SQLUSMALLINT direction; SQLRETURN ret; /* * Initializing lib vars */ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); direction = SQL_FETCH_FIRST; /* * Get the list of available drivers. * This is equivalent to odbcinst -q -d */ while(SQL_SUCCEEDED(ret = SQLDrivers(env, direction, driver, sizeof(driver), &driver_ret, attr, sizeof(attr), &attr_ret))) { direction = SQL_FETCH_NEXT; printf("%s - %s\n", driver, attr); if (ret == SQL_SUCCESS_WITH_INFO) printf("\tdata truncation\n"); } SQLCHAR dsn[256]; SQLCHAR desc[256]; SQLSMALLINT dsn_ret; SQLSMALLINT desc_ret; /* * Get the list of available data sources. * This is equivalent to odbcinst -q -s */ while(SQL_SUCCEEDED(ret = SQLDataSources(env, direction, dsn, sizeof(dsn), &dsn_ret, desc, sizeof(desc), &desc_ret))) { direction = SQL_FETCH_NEXT; printf("%s - %s\n", dsn, desc); if (ret == SQL_SUCCESS_WITH_INFO) printf("\tdata truncation\n"); } return 0; }
4.2 Simple Query Example in C++
#include<stdio.h> #include<sql.h> #include<sqlext.h> #include<exception> #include<iostream> #define NAME_LEN 50 #define ID_LEN 20 void show_error() { printf("SQL fetch Error"); } /** * @brief error handling for SQL* functions */ void check_error(SQLRETURN ret_val, std::string act_str) { switch (ret_val) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: break; case SQL_NO_DATA: std::cerr << "end of data\n"; break; default: throw std::runtime_error(act_str); } } int main() { SQLHENV henv; SQLHDBC hdbc; SQLHSTMT hstmt = 0; SQLRETURN retcode; SQLCHAR outstr[1024]; SQLSMALLINT outstrlen; SQLCHAR szName[NAME_LEN], szID[ID_LEN]; SQLLEN cbName = 0, cbID = 0; try { //Allocate environment handle retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); check_error(retcode, "Allocate Environment Handle"); //Set the ODBC version environment attribute retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0); check_error(retcode, "Set ODBC version enviroment attribute"); //Allocate connection handle retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); check_error(retcode, "Allocate connection Handle"); //Set login timeout to 5 seconds SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); check_error(retcode, "set login timeout attribute"); /** * Connect to data source */ retcode = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)"DSN=mariadb-connector;", SQL_NTS, outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE); check_error(retcode, "connect to the data source"); //Allocate statement handle retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); check_error(retcode, "allocate a statement handle"); /** * statement to be executed. */ retcode = SQLExecDirect (hstmt, (SQLCHAR *) "select * from mytable", SQL_NTS); check_error(retcode, "execute the statement"); /** * Bind a column to a variable */ retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR, szName, NAME_LEN, &cbName); check_error(retcode, "bind 1 column to the statement"); retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, szID, ID_LEN, &cbID); check_error(retcode, "bind 2 column to the statement"); /** * fetch sql hstmt untill there is no data and print */ for (int i=0 ; ; i++) { retcode = SQLFetch(hstmt); if(retcode == SQL_NO_DATA)break; else printf( "%d: %s %s %s\n", i + 1, szID, szName); } SQLCancel(hstmt); SQLFreeHandle(SQL_HANDLE_STMT, hstmt); SQLDisconnect(hdbc); SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); } catch(std::exception &e) { std::cerr << e.what() << std::endl; return 1; } return 0; }