2 * sql_sybase.c Sybase (ctlibrary) routines for rlm_sql
3 * Error handling stolen from Sybase example code "firstapp.c"
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * Copyright 2000 The FreeRADIUS server project
20 * Copyright 2000 Mattias Sjostrom <mattias@nogui.se>
23 #include <freeradius-devel/autoconf.h>
30 #include <freeradius-devel/radiusd.h>
36 typedef struct rlm_sql_sybase_sock {
38 CS_CONNECTION *connection;
44 } rlm_sql_sybase_sock;
47 #define MAX_DATASTR_LEN 256
49 /************************************************************************
50 * Handler for server messages. Client-Library will call this
51 * routine when it receives a message from the server.
52 ************************************************************************/
54 static CS_RETCODE CS_PUBLIC
55 servermsg_callback(cp, chp, msgp)
62 ** Print the message info.
65 "Sybase Server message:\n");
67 "number(%ld) severity(%ld) state(%ld) line(%ld)\n",
68 (long)msgp->msgnumber, (long)msgp->severity,
69 (long)msgp->state, (long)msgp->line);
72 ** Print the server and procedure names if supplied.
74 if (msgp->svrnlen > 0 && msgp->proclen > 0)
75 radlog(L_ERR, "Server name: %s Procedure name: %s", msgp->svrname, msgp->proc);
78 ** Print the null terminated message.
80 radlog(L_ERR, "%s\n", msgp->text);
83 ** Server message callbacks must return CS_SUCCEED.
88 /************************************************************************
89 * Client-Library error handler.
90 ************************************************************************/
92 static CS_RETCODE CS_PUBLIC
93 clientmsg_callback(context, conn, emsgp)
100 ** Error number: Print the error's severity, number, origin, and
101 ** layer. These four numbers uniquely identify the error.
104 "Client Library error:\n");
106 "severity(%ld) number(%ld) origin(%ld) layer(%ld)\n",
107 (long)CS_SEVERITY(emsgp->severity),
108 (long)CS_NUMBER(emsgp->msgnumber),
109 (long)CS_ORIGIN(emsgp->msgnumber),
110 (long)CS_LAYER(emsgp->msgnumber));
113 ** Error text: Print the error text.
115 radlog(L_ERR, "%s\n", emsgp->msgstring);
117 if (emsgp->osstringlen > 0)
120 "Operating system error number(%ld):\n",
121 (long)emsgp->osnumber);
122 radlog(L_ERR, "%s\n", emsgp->osstring);
128 /************************************************************************
129 * CS-Library error handler. This function will be invoked
130 * when CS-Library has detected an error.
131 ************************************************************************/
133 static CS_RETCODE CS_PUBLIC
134 csmsg_callback(context, emsgp)
140 ** Print the error number and message.
143 "CS-Library error:\n");
145 "\tseverity(%ld) layer(%ld) origin(%ld) number(%ld)",
146 (long)CS_SEVERITY(emsgp->msgnumber),
147 (long)CS_LAYER(emsgp->msgnumber),
148 (long)CS_ORIGIN(emsgp->msgnumber),
149 (long)CS_NUMBER(emsgp->msgnumber));
151 radlog(L_ERR, "%s\n", emsgp->msgstring);
154 ** Print any operating system error information.
156 if (emsgp->osstringlen > 0)
158 radlog(L_ERR, "Operating System Error: %s\n",
165 /*************************************************************************
167 * Function: sql_init_socket
169 * Purpose: Establish connection to the db
171 *************************************************************************/
172 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
174 rlm_sql_sybase_sock *sybase_sock;
177 if (!sqlsocket->conn) {
178 sqlsocket->conn = (rlm_sql_sybase_sock *)rad_malloc(sizeof(rlm_sql_sybase_sock));
179 if (!sqlsocket->conn) {
183 sybase_sock = sqlsocket->conn;
184 memset(sybase_sock, 0, sizeof(*sybase_sock));
186 sybase_sock->results=NULL;
188 /* Allocate a CS context structure. This should really only be done once, but because of
189 the connection pooling design of rlm_sql, we'll have to go with one context per connection */
191 if (cs_ctx_alloc(CS_VERSION_100, &sybase_sock->context) != CS_SUCCEED) {
192 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate CS context structure (cs_ctx_alloc())");
196 /* Initialize ctlib */
198 if (ct_init(sybase_sock->context, CS_VERSION_100) != CS_SUCCEED) {
199 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize Client-Library (ct_init())");
200 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
201 cs_ctx_drop(sybase_sock->context);
206 /* Install callback functions for error-handling */
208 if (cs_config(sybase_sock->context, CS_SET, CS_MESSAGE_CB, (CS_VOID *)csmsg_callback, CS_UNUSED, NULL) != CS_SUCCEED) {
209 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install CS Library error callback");
210 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
211 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
212 cs_ctx_drop(sybase_sock->context);
217 if (ct_callback(sybase_sock->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)clientmsg_callback) != CS_SUCCEED) {
218 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install client message callback");
219 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
220 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
221 cs_ctx_drop(sybase_sock->context);
226 if (ct_callback(sybase_sock->context, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *)servermsg_callback) != CS_SUCCEED) {
227 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install client message callback");
228 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
229 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
230 cs_ctx_drop(sybase_sock->context);
235 /* Allocate a ctlib connection structure */
237 if (ct_con_alloc(sybase_sock->context, &sybase_sock->connection) != CS_SUCCEED) {
238 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate connection structure (ct_con_alloc())");
239 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
240 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
241 cs_ctx_drop(sybase_sock->context);
246 /* Initialize inline error handling for the connection */
248 /* if (ct_diag(sybase_sock->connection, CS_INIT, CS_UNUSED, CS_UNUSED, NULL) != CS_SUCCEED) {
249 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize error handling (ct_diag())");
250 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
251 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
252 cs_ctx_drop(sybase_sock->context);
259 /* Set User and Password properties for the connection */
261 if (ct_con_props(sybase_sock->connection, CS_SET, CS_USERNAME, config->sql_login,
262 strlen(config->sql_login), NULL) != CS_SUCCEED) {
263 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set username for connection (ct_con_props())\n%s",
264 sql_error(sqlsocket, config));
265 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
266 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
267 cs_ctx_drop(sybase_sock->context);
272 if (ct_con_props(sybase_sock->connection, CS_SET, CS_PASSWORD, config->sql_password,
273 strlen(config->sql_password), NULL) != CS_SUCCEED) {
274 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set password for connection (ct_con_props())\n%s",
275 sql_error(sqlsocket, config));
276 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
277 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
278 cs_ctx_drop(sybase_sock->context);
283 /* Establish the connection */
285 if (ct_connect(sybase_sock->connection, config->sql_server, strlen(config->sql_server)) != CS_SUCCEED) {
286 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to establish connection to symbolic servername %s\n%s",
287 config->sql_server, sql_error(sqlsocket, config));
288 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
289 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
290 cs_ctx_drop(sybase_sock->context);
298 /*************************************************************************
300 * Function: sql_destroy_socket
302 * Purpose: Free socket and private connection data
304 *************************************************************************/
305 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
307 free(sqlsocket->conn);
308 sqlsocket->conn = NULL;
312 /*************************************************************************
314 * Function: sql_query
316 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
319 *************************************************************************/
320 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
322 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
324 CS_RETCODE ret, results_ret;
327 if (config->sqltrace)
329 if (sybase_sock->connection == NULL) {
330 radlog(L_ERR, "Socket not connected");
334 if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
335 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
336 sql_error(sqlsocket, config));
340 if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
341 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to initiate command structure (ct_command())\n%s",
342 sql_error(sqlsocket, config));
346 if (ct_send(sybase_sock->command) != CS_SUCCEED) {
347 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to send command (ct_send())\n%s",
348 sql_error(sqlsocket, config));
353 ** We'll make three calls to ct_results, first to get a success indicator, secondly to get a done indicator, and
354 ** thirdly to get a "nothing left to handle" status.
358 ** First call to ct_results,
359 ** we need returncode CS_SUCCEED
360 ** and result_type CS_CMD_SUCCEED.
363 if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
364 if (result_type != CS_CMD_SUCCEED) {
365 if (result_type == CS_ROW_RESULT) {
366 radlog(L_ERR,"rlm_sql_sybase(sql_query): sql_query processed a query returning rows. Use sql_select_query instead!");
368 radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
369 sql_error(sqlsocket, config));
374 switch ((int) results_ret)
377 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
378 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
379 , sql_error(sqlsocket, config));
380 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
381 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
382 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
383 sql_close(sqlsocket, config);
389 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
390 sql_error(sqlsocket, config));
397 ** Second call to ct_results,
398 ** we need returncode CS_SUCCEED
399 ** and result_type CS_CMD_DONE.
402 if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
403 if (result_type != CS_CMD_DONE) {
404 radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
405 sql_error(sqlsocket, config));
410 switch ((int) results_ret)
413 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
414 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
415 , sql_error(sqlsocket, config));
416 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
417 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
418 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
419 sql_close(sqlsocket, config);
425 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
426 sql_error(sqlsocket, config));
433 ** Third call to ct_results,
434 ** we need returncode CS_END_RESULTS
435 ** result_type will be ignored.
438 results_ret = ct_results(sybase_sock->command, &result_type);
440 switch ((int) results_ret)
443 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
444 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
445 , sql_error(sqlsocket, config));
446 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
447 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
448 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
449 sql_close(sqlsocket, config);
454 case CS_END_RESULTS: /* This is where we want to end up */
458 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
459 sql_error(sqlsocket, config));
469 /*************************************************************************
471 * Function: sql_select_query
473 * Purpose: Issue a select query to the database
475 * Note: Only the first row from queries returning several rows
476 * will be returned by this function, consequitive rows will
479 *************************************************************************/
480 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
482 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
484 CS_RETCODE ret, results_ret;
486 CS_DATAFMT descriptor;
491 if (config->sqltrace)
493 if (sybase_sock->connection == NULL) {
494 radlog(L_ERR, "Socket not connected");
499 if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
500 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
501 sql_error(sqlsocket, config));
505 if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
506 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to initiate command structure (ct_command())\n%s",
507 sql_error(sqlsocket, config));
511 if (ct_send(sybase_sock->command) != CS_SUCCEED) {
512 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to send command (ct_send())\n%s",
513 sql_error(sqlsocket, config));
517 results_ret = ct_results(sybase_sock->command, &result_type);
519 switch (results_ret) {
523 switch (result_type) {
528 ** Houston, we have a row.
530 ** We set up a target buffer for the results data, and
531 ** associate the buffer with the results, but the actual
532 ** fetching takes place in sql_fetch_row. The layer above
533 ** MUST call sql_fetch_row and/or sql_finish_select_query
534 ** or this socket will be unusable and may cause segfaults
535 ** if reused later on.
539 ** Set up the DATAFMT structure that describes our target array
540 ** and tells sybase what we want future ct_fetch calls to do.
542 descriptor.datatype = CS_CHAR_TYPE; /* The target buffer is a string */
543 descriptor.format = CS_FMT_NULLTERM; /* Null termination please */
544 descriptor.maxlength = MAX_DATASTR_LEN; /* The string arrays are this large */
545 descriptor.count = 1; /* Fetch one row of data */
546 descriptor.locale = NULL; /* Don't do NLS stuff */
549 colcount = sql_num_fields(sqlsocket, config); /* Get number of elements in row result */
552 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1)); /* Space for pointers */
553 memset(rowdata, 0, (sizeof(char *) * colcount+1)); /* NULL-pad the pointers */
555 for (i=0; i < colcount; i++) {
557 rowdata[i]=rad_malloc((MAX_DATASTR_LEN * sizeof(char))+1); /* Space to hold the result data */
559 /* Associate the target buffer with the data */
560 if (ct_bind(sybase_sock->command, i+1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
561 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): ct_bind() failed)\n%s",
562 sql_error(sqlsocket, config));
567 rowdata[i]=NULL; /* Terminate the array */
568 sybase_sock->results=rowdata;
574 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Query returned no data");
579 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected result type from query\n%s",
580 sql_error(sqlsocket, config));
581 sql_finish_select_query(sqlsocket, config);
590 ** Serious failure, sybase requires us to cancel
591 ** the results and maybe even close the connection.
594 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Failure retrieving query results\n%s"
595 , sql_error(sqlsocket, config));
596 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
597 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): cleaning up.");
598 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
599 sql_close(sqlsocket, config);
606 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected return value from ct_results()\n%s",
607 sql_error(sqlsocket, config));
615 /*************************************************************************
617 * Function: sql_store_result
619 * Purpose: database specific store_result function. Returns a result
622 *************************************************************************/
623 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
625 ** Not needed for Sybase, code that may have gone here is
626 ** in sql_select_query and sql_fetch_row
632 /*************************************************************************
634 * Function: sql_num_fields
636 * Purpose: database specific num_fields function. Returns number
637 * of columns from query
639 *************************************************************************/
640 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
642 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
645 if (ct_res_info(sybase_sock->command, CS_NUMDATA, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
646 radlog(L_ERR,"rlm_sql_sybase(sql_num_fields): error retrieving column count: %s",
647 sql_error(sqlsocket, config));
653 /*************************************************************************
655 * Function: sql_num_rows
657 * Purpose: database specific num_rows. Returns number of rows in
660 *************************************************************************/
661 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
663 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
666 if (ct_res_info(sybase_sock->command, CS_ROW_COUNT, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
667 radlog(L_ERR,"rlm_sql_sybase(sql_num_rows): error retrieving row count: %s",
668 sql_error(sqlsocket, config));
675 /*************************************************************************
677 * Function: sql_fetch_row
679 * Purpose: database specific fetch_row. Returns a SQL_ROW struct
680 * with all the data for the query in 'sqlsocket->row'. Returns
681 * 0 on success, -1 on failure, SQL_DOWN if 'database is down'.
683 *************************************************************************/
684 int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
686 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
689 sqlsocket->row = NULL;
692 ret = ct_fetch(sybase_sock->command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count);
699 ** Serious failure, sybase requires us to cancel
700 ** the results and maybe even close the connection.
703 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Failure fething row data\n%s"
704 , sql_error(sqlsocket, config));
705 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
706 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): cleaning up.");
707 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
708 sql_close(sqlsocket, config);
720 sqlsocket->row = sybase_sock->results;
726 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Recoverable failure fething row data, try again perhaps?");
731 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Unexpected returncode from ct_fetch");
740 /*************************************************************************
742 * Function: sql_free_result
744 * Purpose: database specific free_result. Frees memory allocated
747 *************************************************************************/
748 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
751 ** Not implemented, never called from rlm_sql anyway
752 ** result buffer is freed in the finish_query functions.
761 /*************************************************************************
763 * Function: sql_error
765 * Purpose: database specific error. Returns error associated with
768 *************************************************************************/
769 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
770 static char msg='\0';
772 static char msgbuf[2048];
774 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
780 char ctempbuf[2][512];
781 char stempbuf[2][512];
783 msgbuf[0]=(char)NULL;
784 ctempbuf[0][0]=(char)NULL;
785 ctempbuf[1][0]=(char)NULL;
786 stempbuf[0][0]=(char)NULL;
787 stempbuf[1][0]=(char)NULL;
789 if (ct_diag(sybase_sock->connection, CS_STATUS, CS_CLIENTMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
790 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Client messages");
793 radlog(L_ERR,"rlm_sql_sybase(sql_error): Number of pending Client messages: %d", (int)msgcount);
795 for (i=1; i<=msgcount; i++) {
796 if (ct_diag(sybase_sock->connection, CS_GET, CS_CLIENTMSG_TYPE, (CS_INT)i, &cmsg) != CS_SUCCEED) {
797 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to retrieve pending Client message");
800 sprintf(ctempbuf[i-1],"rlm_sql_sybase: Client Library Error: severity(%ld) number(%ld) origin(%ld) layer(%ld):\n%s",
801 (long)CS_SEVERITY(cmsg.severity),
802 (long)CS_NUMBER(cmsg.msgnumber),
803 (long)CS_ORIGIN(cmsg.msgnumber),
804 (long)CS_LAYER(cmsg.msgnumber),
809 if (ct_diag(sybase_sock->connection, CS_STATUS, CS_SERVERMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
810 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Server messages");
813 radlog(L_ERR,"rlm_sql_sybase(sql_error): Number of pending Server messages: %d", (int)msgcount);
815 for (i=1; i<=msgcount; i++) {
816 if (ct_diag(sybase_sock->connection, CS_GET, CS_SERVERMSG_TYPE, (CS_INT)i, &smsg) != CS_SUCCEED) {
817 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to retrieve pending Server message");
820 sprintf(stempbuf[i-1],"rlm_sql_sybase: Server message: severity(%ld) number(%ld) origin(%ld) layer(%ld):\n%s",
821 (long)CS_SEVERITY(cmsg.severity),
822 (long)CS_NUMBER(cmsg.msgnumber),
823 (long)CS_ORIGIN(cmsg.msgnumber),
824 (long)CS_LAYER(cmsg.msgnumber),
827 sprintf(msgbuf,"%s || %s || %s || %s", ctempbuf[1], ctempbuf[2], stempbuf[1], stempbuf[2]);
835 /*************************************************************************
837 * Function: sql_close
839 * Purpose: database specific close. Closes an open database
840 * connection and cleans up any open handles.
842 *************************************************************************/
843 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
845 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
847 if (oracle_sock->conn) {
848 OCILogoff (oracle_sock->conn, oracle_sock->errHandle);
851 if (oracle_sock->queryHandle) {
852 OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT);
854 if (oracle_sock->errHandle) {
855 OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR);
857 if (oracle_sock->env) {
858 OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV);
861 oracle_sock->conn = NULL;
867 /*************************************************************************
869 * Function: sql_finish_query
871 * Purpose: End the query, such as freeing memory
873 *************************************************************************/
874 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
876 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
878 ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
880 if (ct_cmd_drop(sybase_sock->command) != CS_SUCCEED) {
881 radlog(L_ERR,"rlm_sql_sybase(sql_finish_query): Freeing command structure failed.");
890 /*************************************************************************
892 * Function: sql_finish_select_query
894 * Purpose: End the select query, such as freeing memory or result
896 *************************************************************************/
897 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
899 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
902 ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
904 if (ct_cmd_drop(sybase_sock->command) != CS_SUCCEED) {
905 radlog(L_ERR,"rlm_sql_sybase(sql_finish_select_query): Freeing command structure failed.");
909 if (sybase_sock->results) {
910 while(sybase_sock->results[i]) free(sybase_sock->results[i++]);
911 free(sybase_sock->results);
912 sybase_sock->results=NULL;
920 /*************************************************************************
922 * Function: sql_affected_rows
924 * Purpose: Return the number of rows affected by the query (update,
927 *************************************************************************/
928 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
930 return sql_num_rows(sqlsocket, config);
937 /* Exported to rlm_sql */
938 rlm_sql_module_t rlm_sql_sybase = {
952 sql_finish_select_query,