Sybase et le C 4eme partie : Acceder a Sybase via UnixODBC

Dans cet article on va voir comment on peut accéder a Sybase en utilisant UnixODBC a partir d’un client distant (32 bits). Deux possibilités sont offertes soit :

1. Récupérer une ancienne version de Sybase 32 bits (la 15.5 par exemple) et installer les libs coté client et particulièrement (ASE ODBC Driver), on a déjà fait ça dans un précédent article.

Une fois le client 32 bits installé, on configure les fichiers /etc/odbc.ini et /etc/odbcinst.ini comme suit :

toc@tocNewServer:~$ cat /etc/odbc.ini
[SybasePubs2]
Description             = Sybase ODBC for pubs2 database
Driver					= /opt/sybase/DataAccess/ODBC/lib/libsybdrvodb.so
Server                  = 192.168.1.95
Port                    = 5000
Database                = pubs2
Trace                   = Yes
TraceFile               = /tmp/isql.log
ForceTrace              = Yes

toc@tocNewServer:~$ cat /etc/odbcinst.ini
[ODBC]
Trace		= yes
TraceFile	= /tmp/odbc.log

Ici on configure l’accès a la base pubs2 en utilisant le driver natif offert par Sybase, il s’agit de la librairie : /opt/sybase/DataAccess/ODBC/lib/libsybdrvodb.so. On peut ensuite tester tout ça avec (et exécuter une simple requête pour récupérer la version des composants installés coté serveur):

toc@tocNewServer:~$ isql -v SybasePubs2 tarek 123456
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> sp_version
+------------------+--------------------------------------------------------------------------------------------------------------------+---------+
| Script           | Version                                                                                                            | Status  |
+------------------+--------------------------------------------------------------------------------------------------------------------+---------+
| ODBC MDA Scripts | 15.7.0.403.1011/Fri Jul 06 UTC 00:41:49 2012                                                                       | Complete|
| OLEDB MDA Scripts| 15.7.0.403.1011/Fri Jul 06 UTC 00:16:26 2012                                                                       | Complete|
| installcommit    | 15.7.0/EBF 20373 SMP ESD#02 /P/x86_64/Enterprise Linux/ase157esd2/3109/64-bit/OPT/Sat Jul  7 01:11:56 2012         | Complete|
| installjdbc      | jConnect (TM) for JDBC(TM)/7.07 ESD #4 (Build 26793)/P/EBF20302/JDK 1.6.0/jdbcmain/OPT/Thu Jul  5 22:08:44 PDT 2012| Complete|
| installjsdb      | 15.7.0/EBF 20373 SMP ESD#02 /P/x86_64/Enterprise Linux/ase157esd2/3109/64-bit/OPT/Sat Jul  7 01:11:56 2012         | Complete|
| installmaster    | 15.7.0/EBF 20373 SMP ESD#02 /P/x86_64/Enterprise Linux/ase157esd2/3109/64-bit/OPT/Sat Jul  7 01:11:56 2012         | Complete|
| installmodel     | 15.7.0/EBF 20373 SMP ESD#02 /P/x86_64/Enterprise Linux/ase157esd2/3109/64-bit/OPT/Sat Jul  7 01:11:56 2012         | Complete|
| montables        | 15.7.0/20373/P/x86_64/Enterprise Linux/ase157esd2/3109/64-bit/OPT/Sat Jul 07 00:57:46 2012                         | Complete|
+------------------+--------------------------------------------------------------------------------------------------------------------+---------+
SQLRowCount returns 95
8 rows fetched

Si vous avez une erreur du genre :

toc@tocNewServer:~$ isql -v SybasePubs2 tarek 123456
[01000][unixODBC][Driver Manager]Can't open lib '/opt/sybase/DataAccess/ODBC/lib/libsybdrvodb.so' : file not found
[ISQL]ERROR: Could not SQLConnect

Faut modifier la valeur de LD_LIBRARY_PATH :

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/sybase/DataAccess/ODBC/lib

Notez le grand avantage de passer par ce driver est : le fait que vous pouvez faire des requêtes en utilisant les « Stored Procedures » offertes par Sybase (par exemple sp_help, sp_sendmsg, sp_….)

2. Utilisez le projet libre FreeTDS qui implémente les protocoles d’accès a Sybase. Vous pouvez l’installer soit en récupérant les source avec :

# wget ftp://ftp.freetds.org/pub/freetds/stable/freetds-stable.tgz
# tar zfvx freetds-stable.tgz
# cd freetds-*
# ./configure --prefix=/usr/local/freetds --with-tdsver=8.0 --with-unixodbc=/usr/local/unixODBC
# make
# make install

Ou en utilisant apt (sous Ubuntu par example) :

# apt-get install freetds-common freetds-dev freetds-bin

Une fois qu’on a installé FreeTDS, on configure /etc/odbc.ini et /etc/odbcinst.ini, dans mon cas ça ressemble a ceci :

toc@tocNewServer:~$ cat /etc/odbc.ini
[Sybase]
Description             = Sybase ODBC
Driver                  = /usr/local/lib/libtdsodbc.so
Server                  = 192.168.1.95
Port                    = 5000

toc@tocNewServer:~$ cat /etc/odbcinst.ini
[ODBC]
Trace		= yes
TraceFile	= /tmp/odbc.log

Pareil, vous testez avec quelque chose du genre :

toc@tocNewServer:~$ isql -v Sybase tarek 123456
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> select getdate()
+------------------------+
|                        |
+------------------------+
| 2013-06-24 22:42:50.487|
+------------------------+
SQLRowCount returns 1
1 rows fetched

Une fois qu’on a configuré l’ODBC, on peux alors écrire un fichier C, hello-sybase-odbc.c :

/*
 * hello-sybase-odbc.c : ce programme demontre
 * une simple utilisation d'UnixODBC avec Sybase
 */
#include
#include
#include
#include

#define	BUFFER_LEN		1024
#define	OK			0
#define	KO			-1
#define	TIMEOUT			5	/* Le timeout est fixe a 5 seconds */
#define	REC_NUMBER		1	/* Pour la fonction SQLGetDiagRec */
#define	SQLSTATE_LEN		7
#define	DB_NAME_LEN		128
#define	DB_VERSION_LEN		32

int odbc_connection(char *datasource, char *user, char *pwd)
{
	long status;
	SQLCHAR	 state[SQLSTATE_LEN];		/* Pour SQLSTATE code qui designe une erreur ou un warning */
	SQLINTEGER odbc_error;
	SQLSMALLINT error_text_len;
	SQLCHAR error_text[BUFFER_LEN];
	SQLCHAR db_name[DB_NAME_LEN];		/* Nom de la base de donnees */
	SQLCHAR db_version[DB_VERSION_LEN];	/* Version de la base de donnes */
	SQLHENV environment_handle;     	/* Pour mettre en place notre environnement */
	SQLHDBC connection_handle;      	/* Pour la connexion a la source de donnees */
	SQLHSTMT statment_handle;		/* Pour notre requete */
	char result_buffer[1024];		/* Pour chaque ligne du resultat */
	SQLRETURN ret;
	SQLSMALLINT columns;			/* Nombre de colonnes dans le resultat */
	int i;

	/* Etape 1. allocation de la memoire pour mettre en place notre environnement ODBC */
	status = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &environment_handle);
	if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
		fprintf(stderr, "SQLAllocHandle: SQL_HANDLE_ENV Failed\n");
		return KO;
	}
	/* Tous les recents driver ODBC supporte la version 3 d'ODBC */
	status = SQLSetEnvAttr(environment_handle, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, SQL_IS_INTEGER);
	if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
		fprintf(stderr, "SQLSetEnvAttr Failed\n");
		SQLFreeHandle(SQL_HANDLE_ENV, environment_handle);
		return KO;
	}
	/* Etape 2. allocation de la memoire pour le handle de la connexion */
	status = SQLAllocHandle(SQL_HANDLE_DBC, environment_handle, &connection_handle);
	if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
		fprintf(stderr, "SQLAllocHandle: SQL_HANDLE_DBC Failed\n");
		SQLFreeHandle(SQL_HANDLE_ENV, environment_handle);
		return KO ;
	}
	/* Mise en place d'un timeout : temps d'attente d'une connexion */
	SQLSetConnectAttr(connection_handle, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) TIMEOUT, 0);
	/* Etape 3. connexion a la source de donnees "datasource" */
	/* On peut aussi utiliser la fonction SQLDriverConnect qui prend plus de parametres */
	status = SQLConnect(connection_handle, (SQLCHAR *) datasource, SQL_NTS, (SQLCHAR *) user, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS);
	if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
		fprintf(stderr, "SQLConnect failed\n");
		SQLGetDiagRec(SQL_HANDLE_DBC, connection_handle, REC_NUMBER, state, &odbc_error, error_text, BUFFER_LEN, &error_text_len);
		fprintf(stderr, "%s (error number : %d)\n", error_text, (int)odbc_error);
		SQLFreeHandle(SQL_HANDLE_DBC, connection_handle);
		SQLFreeHandle(SQL_HANDLE_ENV, environment_handle);
		return KO;
	}
	fprintf(stdout, "Connection to DataSource %s succeeded\n", datasource);
	/* Le nom et la version de la base de donnees */
	SQLGetInfo(connection_handle, SQL_DBMS_NAME, (SQLPOINTER)db_name, sizeof(db_name), NULL);
	SQLGetInfo(connection_handle, SQL_DBMS_VER, (SQLPOINTER)db_version, sizeof(db_version), NULL);
	fprintf(stdout, "Database name : %s\n", db_name);
	fprintf(stdout, "Database version : %s\n", db_version);
	/* Etape 3. allocation de la memoire pour la requete */
	status = SQLAllocHandle(SQL_HANDLE_STMT, connection_handle, &statment_handle);
	if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
		fprintf(stderr, "SQLAllocHandle: SQL_HANDLE_STMT Failed\n");
		/* On se deconnecte avant de quitter */
		status = SQLDisconnect(connection_handle);
		if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
			fprintf(stderr, "SQLDisconnect failed\n");
			SQLGetDiagRec(SQL_HANDLE_DBC, connection_handle, REC_NUMBER, state, &odbc_error, error_text, BUFFER_LEN, &error_text_len);
			fprintf(stderr, "%s (error number : %d)\n", error_text, (int)odbc_error);
		}
		SQLFreeHandle(SQL_HANDLE_DBC, connection_handle);
		SQLFreeHandle(SQL_HANDLE_ENV, environment_handle);
		return KO;
	}
	/* Etape 4. Envoyer une requete via la procedure sp_clearstats, qui affiche les stats.
	 * CECI NE FONCTIONNERA PAS SI VOTRE DRIVER ODBC EST FREETDS!
	 */
	status = SQLExecDirect(statment_handle, (SQLCHAR *)"sp_clearstats", SQL_NTS);
	if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
		fprintf(stderr, "SQLExecDirect Failed\n");
		/* On se deconnecte avant de quitter */
		status = SQLDisconnect(connection_handle);
		if ((status != SQL_SUCCESS) && (status != SQL_SUCCESS_WITH_INFO)) {
			fprintf(stderr, "SQLDisconnect failed\n");
			SQLGetDiagRec(SQL_HANDLE_DBC, connection_handle, REC_NUMBER, state, &odbc_error, error_text, BUFFER_LEN, &error_text_len);
			fprintf(stderr, "%s (error number : %d)\n", error_text, (int)odbc_error);
		}
		SQLFreeHandle(SQL_HANDLE_STMT, statment_handle);
		SQLFreeHandle(SQL_HANDLE_DBC, connection_handle);
		SQLFreeHandle(SQL_HANDLE_ENV, environment_handle);
		return KO;
	}

	SQLNumResultCols(statment_handle, &columns);
	/* Etape 5. recuperer les resultats de la requete */
	while(SQL_NO_DATA != (status = SQLFetch(statment_handle))) {
		for (i = 1; i <= columns; i++) {
			/* On recupere le buffer de chaque ligne du resultat */
			ret = SQLGetData(statment_handle, i, SQL_C_CHAR, result_buffer, sizeof(result_buffer), NULL);
			if (ret == SQL_SUCCESS) {
				fprintf(stdout, "%s | ",  result_buffer);
			}
		}
		fprintf(stdout, "\n");
	}

	SQLFreeHandle(SQL_HANDLE_STMT, statment_handle);
	SQLFreeHandle(SQL_HANDLE_DBC, connection_handle);
	SQLFreeHandle(SQL_HANDLE_ENV, environment_handle);
	return OK;
}

int main(int argc, char **argv)
{
	if (argc != 4) {
		fprintf(stdout, "Usage : %s dataSource user password\n", argv[0]);
		return KO;
	}
	odbc_connection(argv[1], argv[2], argv[3]);
	return OK;
}

Ce programme execute la procedure sp_clearstats, dans ce cas il faut utiliser le driver ODBC natif de Sybase (libsybdrvodb.so). Le driver fourni par FreeTDS ne permet que l’execution des requetes standards (SELECT, INSERT, UPADTE, CREATE, …etc)

Qu’on compile et execute comme suit :

toc@tocNewServer:~/toc_src/DATABASES/Sybase$ gcc -Wall hello-sybase-odbc.c -o hello-sybase-odbc -lodbc
toc@tocNewServer:~/toc_src/DATABASES/Sybase$ ./hello-sybase-odbc Sybase tarek 123456
Connection to DataSource Sybase succeeded
Database name : SQL Server
Database version : 15.7.0
sa | Jun 26 2013 | 0 | 0.0000% | 0 | 0.0000% |
probe | Jun 26 2013 | 0 | 0.0000% | 0 | 0.0000% |
jstask | Jun 26 2013 | 0 | 0.0000% | 0 | 0.0000% |
tarek | Jun 26 2013 | 0 | 0.0000% | 3 | 100.0000% |
Publicité

2 réflexions sur “Sybase et le C 4eme partie : Acceder a Sybase via UnixODBC

  1. Bonjour jubin,
    Ici j’ai mis uniquement comment on y accède a partir d’un Linux 32 bits (car Sybase ne supporte plus de façon gratuite cette architecture), pour y accéder a partir d’une machine 64 bits c’est plus simple il suffit de suivre le tuto d’install de Sybase et normalement tu trouveras le Driver ODBC dans le répertoire : /opt/sybase/DataAccess64/ODBC/lib/libsybdrvodb.so (moi j’ai installé sybase dans /opt/sybase).

Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s