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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Copyright 2000 The FreeRADIUS server project
20 * Copyright 2000 Mattias Sjostrom <mattias@nogui.se>
34 typedef struct rlm_sql_sybase_sock {
36 CS_CONNECTION *connection;
42 } rlm_sql_sybase_sock;
45 #define MAX_DATASTR_LEN 256
47 /************************************************************************
48 * Handler for server messages. Client-Library will call this
49 * routine when it receives a message from the server.
50 ************************************************************************/
52 static CS_RETCODE CS_PUBLIC
53 servermsg_callback(cp, chp, msgp)
60 ** Print the message info.
63 "Sybase Server message:\n");
65 "number(%ld) severity(%ld) state(%ld) line(%ld)\n",
66 (long)msgp->msgnumber, (long)msgp->severity,
67 (long)msgp->state, (long)msgp->line);
70 ** Print the server and procedure names if supplied.
72 if (msgp->svrnlen > 0 && msgp->proclen > 0)
73 radlog(L_ERR, "Server name: %s Procedure name: %s", msgp->svrname, msgp->proc);
76 ** Print the null terminated message.
78 radlog(L_ERR, "%s\n", msgp->text);
81 ** Server message callbacks must return CS_SUCCEED.
86 /************************************************************************
87 * Client-Library error handler.
88 ************************************************************************/
90 static CS_RETCODE CS_PUBLIC
91 clientmsg_callback(context, conn, emsgp)
98 ** Error number: Print the error's severity, number, origin, and
99 ** layer. These four numbers uniquely identify the error.
102 "Client Library error:\n");
104 "severity(%ld) number(%ld) origin(%ld) layer(%ld)\n",
105 (long)CS_SEVERITY(emsgp->severity),
106 (long)CS_NUMBER(emsgp->msgnumber),
107 (long)CS_ORIGIN(emsgp->msgnumber),
108 (long)CS_LAYER(emsgp->msgnumber));
111 ** Error text: Print the error text.
113 radlog(L_ERR, "%s\n", emsgp->msgstring);
115 if (emsgp->osstringlen > 0)
118 "Operating system error number(%ld):\n",
119 (long)emsgp->osnumber);
120 radlog(L_ERR, "%s\n", emsgp->osstring);
126 /************************************************************************
127 * CS-Library error handler. This function will be invoked
128 * when CS-Library has detected an error.
129 ************************************************************************/
131 static CS_RETCODE CS_PUBLIC
132 csmsg_callback(context, emsgp)
138 ** Print the error number and message.
141 "CS-Library error:\n");
143 "\tseverity(%ld) layer(%ld) origin(%ld) number(%ld)",
144 (long)CS_SEVERITY(emsgp->msgnumber),
145 (long)CS_LAYER(emsgp->msgnumber),
146 (long)CS_ORIGIN(emsgp->msgnumber),
147 (long)CS_NUMBER(emsgp->msgnumber));
149 radlog(L_ERR, "%s\n", emsgp->msgstring);
152 ** Print any operating system error information.
154 if (emsgp->osstringlen > 0)
156 radlog(L_ERR, "Operating System Error: %s\n",
163 /*************************************************************************
165 * Function: sql_init_socket
167 * Purpose: Establish connection to the db
169 *************************************************************************/
170 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
172 rlm_sql_sybase_sock *sybase_sock;
175 if (!sqlsocket->conn) {
176 sqlsocket->conn = (rlm_sql_sybase_sock *)rad_malloc(sizeof(rlm_sql_sybase_sock));
177 if (!sqlsocket->conn) {
181 sybase_sock = sqlsocket->conn;
182 memset(sybase_sock, 0, sizeof(*sybase_sock));
184 sybase_sock->results=NULL;
186 /* Allocate a CS context structure. This should really only be done once, but because of
187 the connection pooling design of rlm_sql, we'll have to go with one context per connection */
189 if (cs_ctx_alloc(CS_VERSION_100, &sybase_sock->context) != CS_SUCCEED) {
190 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate CS context structure (cs_ctx_alloc())");
194 /* Initialize ctlib */
196 if (ct_init(sybase_sock->context, CS_VERSION_100) != CS_SUCCEED) {
197 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize Client-Library (ct_init())");
198 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
199 cs_ctx_drop(sybase_sock->context);
204 /* Install callback functions for error-handling */
206 if (cs_config(sybase_sock->context, CS_SET, CS_MESSAGE_CB, (CS_VOID *)csmsg_callback, CS_UNUSED, NULL) != CS_SUCCEED) {
207 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install CS Library error callback");
208 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
209 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
210 cs_ctx_drop(sybase_sock->context);
215 if (ct_callback(sybase_sock->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)clientmsg_callback) != CS_SUCCEED) {
216 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install client message callback");
217 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
218 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
219 cs_ctx_drop(sybase_sock->context);
224 if (ct_callback(sybase_sock->context, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *)servermsg_callback) != CS_SUCCEED) {
225 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to install client message callback");
226 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
227 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
228 cs_ctx_drop(sybase_sock->context);
233 /* Allocate a ctlib connection structure */
235 if (ct_con_alloc(sybase_sock->context, &sybase_sock->connection) != CS_SUCCEED) {
236 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate connection structure (ct_con_alloc())");
237 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
238 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
239 cs_ctx_drop(sybase_sock->context);
244 /* Initialize inline error handling for the connection */
246 /* if (ct_diag(sybase_sock->connection, CS_INIT, CS_UNUSED, CS_UNUSED, NULL) != CS_SUCCEED) {
247 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize error handling (ct_diag())");
248 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
249 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
250 cs_ctx_drop(sybase_sock->context);
257 /* Set User and Password properties for the connection */
259 if (ct_con_props(sybase_sock->connection, CS_SET, CS_USERNAME, config->sql_login,
260 strlen(config->sql_login), NULL) != CS_SUCCEED) {
261 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set username for connection (ct_con_props())\n%s",
262 sql_error(sqlsocket, config));
263 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
264 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
265 cs_ctx_drop(sybase_sock->context);
270 if (ct_con_props(sybase_sock->connection, CS_SET, CS_PASSWORD, config->sql_password,
271 strlen(config->sql_password), NULL) != CS_SUCCEED) {
272 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to set password for connection (ct_con_props())\n%s",
273 sql_error(sqlsocket, config));
274 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
275 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
276 cs_ctx_drop(sybase_sock->context);
281 /* Establish the connection */
283 if (ct_connect(sybase_sock->connection, config->sql_server, strlen(config->sql_server)) != CS_SUCCEED) {
284 radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to establish connection to symbolic servername %s\n%s",
285 config->sql_server, sql_error(sqlsocket, config));
286 if (sybase_sock->context != (CS_CONTEXT *)NULL) {
287 ct_exit(sybase_sock->context, CS_FORCE_EXIT);
288 cs_ctx_drop(sybase_sock->context);
296 /*************************************************************************
298 * Function: sql_destroy_socket
300 * Purpose: Free socket and private connection data
302 *************************************************************************/
303 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
305 free(sqlsocket->conn);
306 sqlsocket->conn = NULL;
310 /*************************************************************************
312 * Function: sql_query
314 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
317 *************************************************************************/
318 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
320 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
322 CS_RETCODE ret, results_ret;
325 if (config->sqltrace)
327 if (sybase_sock->connection == NULL) {
328 radlog(L_ERR, "Socket not connected");
332 if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
333 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
334 sql_error(sqlsocket, config));
338 if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
339 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to initiate command structure (ct_command())\n%s",
340 sql_error(sqlsocket, config));
344 if (ct_send(sybase_sock->command) != CS_SUCCEED) {
345 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to send command (ct_send())\n%s",
346 sql_error(sqlsocket, config));
351 ** We'll make three calls to ct_results, first to get a success indicator, secondly to get a done indicator, and
352 ** thirdly to get a "nothing left to handle" status.
356 ** First call to ct_results,
357 ** we need returncode CS_SUCCEED
358 ** and result_type CS_CMD_SUCCEED.
361 if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
362 if (result_type != CS_CMD_SUCCEED) {
363 if (result_type == CS_ROW_RESULT) {
364 radlog(L_ERR,"rlm_sql_sybase(sql_query): sql_query processed a query returning rows. Use sql_select_query instead!");
366 radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
367 sql_error(sqlsocket, config));
372 switch ((int) results_ret)
375 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
376 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
377 , sql_error(sqlsocket, config));
378 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
379 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
380 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
381 sql_close(sqlsocket, config);
387 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
388 sql_error(sqlsocket, config));
395 ** Second call to ct_results,
396 ** we need returncode CS_SUCCEED
397 ** and result_type CS_CMD_DONE.
400 if ((results_ret = ct_results(sybase_sock->command, &result_type)) == CS_SUCCEED) {
401 if (result_type != CS_CMD_DONE) {
402 radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected result type from query\n%s",
403 sql_error(sqlsocket, config));
408 switch ((int) results_ret)
411 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
412 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
413 , sql_error(sqlsocket, config));
414 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
415 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
416 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
417 sql_close(sqlsocket, config);
423 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
424 sql_error(sqlsocket, config));
431 ** Third call to ct_results,
432 ** we need returncode CS_END_RESULTS
433 ** result_type will be ignored.
436 results_ret = ct_results(sybase_sock->command, &result_type);
438 switch ((int) results_ret)
441 case CS_FAIL: /* Serious failure, sybase requires us to cancel and maybe even close connection */
442 radlog(L_ERR,"rlm_sql_sybase(sql_query): Failure retrieving query results\n%s"
443 , sql_error(sqlsocket, config));
444 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
445 radlog(L_ERR,"rlm_sql_sybase(sql_query): cleaning up.");
446 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
447 sql_close(sqlsocket, config);
452 case CS_END_RESULTS: /* This is where we want to end up */
456 radlog(L_ERR,"rlm_sql_sybase(sql_query): Unexpected return value from ct_results()\n%s",
457 sql_error(sqlsocket, config));
467 /*************************************************************************
469 * Function: sql_select_query
471 * Purpose: Issue a select query to the database
473 * Note: Only the first row from queries returning several rows
474 * will be returned by this function, consequitive rows will
477 *************************************************************************/
478 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
480 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
482 CS_RETCODE ret, results_ret;
484 CS_DATAFMT descriptor;
489 if (config->sqltrace)
491 if (sybase_sock->connection == NULL) {
492 radlog(L_ERR, "Socket not connected");
497 if (ct_cmd_alloc(sybase_sock->connection, &sybase_sock->command) != CS_SUCCEED) {
498 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to allocate command structure (ct_cmd_alloc())\n%s",
499 sql_error(sqlsocket, config));
503 if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
504 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to initiate command structure (ct_command())\n%s",
505 sql_error(sqlsocket, config));
509 if (ct_send(sybase_sock->command) != CS_SUCCEED) {
510 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unable to send command (ct_send())\n%s",
511 sql_error(sqlsocket, config));
515 results_ret = ct_results(sybase_sock->command, &result_type);
517 switch (results_ret) {
521 switch (result_type) {
526 ** Houston, we have a row.
528 ** We set up a target buffer for the results data, and
529 ** associate the buffer with the results, but the actual
530 ** fetching takes place in sql_fetch_row. The layer above
531 ** MUST call sql_fetch_row and/or sql_finish_select_query
532 ** or this socket will be unusable and may cause segfaults
533 ** if reused later on.
537 ** Set up the DATAFMT structure that describes our target array
538 ** and tells sybase what we want future ct_fetch calls to do.
540 descriptor.datatype = CS_CHAR_TYPE; /* The target buffer is a string */
541 descriptor.format = CS_FMT_NULLTERM; /* Null termination please */
542 descriptor.maxlength = MAX_DATASTR_LEN; /* The string arrays are this large */
543 descriptor.count = 1; /* Fetch one row of data */
544 descriptor.locale = NULL; /* Don't do NLS stuff */
547 colcount = sql_num_fields(sqlsocket, config); /* Get number of elements in row result */
550 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1)); /* Space for pointers */
551 memset(rowdata, 0, (sizeof(char *) * colcount+1)); /* NULL-pad the pointers */
553 for (i=0; i < colcount; i++) {
555 rowdata[i]=rad_malloc((MAX_DATASTR_LEN * sizeof(char))+1); /* Space to hold the result data */
557 /* Associate the target buffer with the data */
558 if (ct_bind(sybase_sock->command, i+1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
559 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): ct_bind() failed)\n%s",
560 sql_error(sqlsocket, config));
565 rowdata[i]=NULL; /* Terminate the array */
566 sybase_sock->results=rowdata;
572 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Query returned no data");
577 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected result type from query\n%s",
578 sql_error(sqlsocket, config));
579 sql_finish_select_query(sqlsocket, config);
588 ** Serious failure, sybase requires us to cancel
589 ** the results and maybe even close the connection.
592 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Failure retrieving query results\n%s"
593 , sql_error(sqlsocket, config));
594 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
595 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): cleaning up.");
596 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
597 sql_close(sqlsocket, config);
604 radlog(L_ERR,"rlm_sql_sybase(sql_select_query): Unexpected return value from ct_results()\n%s",
605 sql_error(sqlsocket, config));
613 /*************************************************************************
615 * Function: sql_store_result
617 * Purpose: database specific store_result function. Returns a result
620 *************************************************************************/
621 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
623 ** Not needed for Sybase, code that may have gone here is
624 ** in sql_select_query and sql_fetch_row
630 /*************************************************************************
632 * Function: sql_num_fields
634 * Purpose: database specific num_fields function. Returns number
635 * of columns from query
637 *************************************************************************/
638 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
640 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
643 if (ct_res_info(sybase_sock->command, CS_NUMDATA, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
644 radlog(L_ERR,"rlm_sql_sybase(sql_num_fields): error retrieving column count: %s",
645 sql_error(sqlsocket, config));
651 /*************************************************************************
653 * Function: sql_num_rows
655 * Purpose: database specific num_rows. Returns number of rows in
658 *************************************************************************/
659 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
661 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
664 if (ct_res_info(sybase_sock->command, CS_ROW_COUNT, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
665 radlog(L_ERR,"rlm_sql_sybase(sql_num_rows): error retrieving row count: %s",
666 sql_error(sqlsocket, config));
673 /*************************************************************************
675 * Function: sql_fetch_row
677 * Purpose: database specific fetch_row. Returns a SQL_ROW struct
678 * with all the data for the query in 'sqlsocket->row'. Returns
679 * 0 on success, -1 on failure, SQL_DOWN if 'database is down'.
681 *************************************************************************/
682 int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
684 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
687 sqlsocket->row = NULL;
690 ret = ct_fetch(sybase_sock->command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count);
697 ** Serious failure, sybase requires us to cancel
698 ** the results and maybe even close the connection.
701 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Failure fething row data\n%s"
702 , sql_error(sqlsocket, config));
703 if ((ret = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL)) == CS_FAIL) {
704 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): cleaning up.");
705 ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
706 sql_close(sqlsocket, config);
718 sqlsocket->row = sybase_sock->results;
724 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Recoverable failure fething row data, try again perhaps?");
729 radlog(L_ERR,"rlm_sql_sybase(sql_fetch_row): Unexpected returncode from ct_fetch");
738 /*************************************************************************
740 * Function: sql_free_result
742 * Purpose: database specific free_result. Frees memory allocated
745 *************************************************************************/
746 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
749 ** Not implemented, never called from rlm_sql anyway
750 ** result buffer is freed in the finish_query functions.
759 /*************************************************************************
761 * Function: sql_error
763 * Purpose: database specific error. Returns error associated with
766 *************************************************************************/
767 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
768 static char msg='\0';
770 static char msgbuf[2048];
772 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
778 char ctempbuf[2][512];
779 char stempbuf[2][512];
781 msgbuf[0]=(char)NULL;
782 ctempbuf[0][0]=(char)NULL;
783 ctempbuf[1][0]=(char)NULL;
784 stempbuf[0][0]=(char)NULL;
785 stempbuf[1][0]=(char)NULL;
787 if (ct_diag(sybase_sock->connection, CS_STATUS, CS_CLIENTMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
788 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Client messages");
791 radlog(L_ERR,"rlm_sql_sybase(sql_error): Number of pending Client messages: %d", (int)msgcount);
793 for (i=1; i<=msgcount; i++) {
794 if (ct_diag(sybase_sock->connection, CS_GET, CS_CLIENTMSG_TYPE, (CS_INT)i, &cmsg) != CS_SUCCEED) {
795 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to retrieve pending Client message");
798 sprintf(ctempbuf[i-1],"rlm_sql_sybase: Client Library Error: severity(%ld) number(%ld) origin(%ld) layer(%ld):\n%s",
799 (long)CS_SEVERITY(cmsg.severity),
800 (long)CS_NUMBER(cmsg.msgnumber),
801 (long)CS_ORIGIN(cmsg.msgnumber),
802 (long)CS_LAYER(cmsg.msgnumber),
807 if (ct_diag(sybase_sock->connection, CS_STATUS, CS_SERVERMSG_TYPE, CS_UNUSED, &msgcount) != CS_SUCCEED) {
808 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to get number of pending Server messages");
811 radlog(L_ERR,"rlm_sql_sybase(sql_error): Number of pending Server messages: %d", (int)msgcount);
813 for (i=1; i<=msgcount; i++) {
814 if (ct_diag(sybase_sock->connection, CS_GET, CS_SERVERMSG_TYPE, (CS_INT)i, &smsg) != CS_SUCCEED) {
815 radlog(L_ERR,"rlm_sql_sybase(sql_error): Failed to retrieve pending Server message");
818 sprintf(stempbuf[i-1],"rlm_sql_sybase: Server message: severity(%ld) number(%ld) origin(%ld) layer(%ld):\n%s",
819 (long)CS_SEVERITY(cmsg.severity),
820 (long)CS_NUMBER(cmsg.msgnumber),
821 (long)CS_ORIGIN(cmsg.msgnumber),
822 (long)CS_LAYER(cmsg.msgnumber),
825 sprintf(msgbuf,"%s || %s || %s || %s", ctempbuf[1], ctempbuf[2], stempbuf[1], stempbuf[2]);
833 /*************************************************************************
835 * Function: sql_close
837 * Purpose: database specific close. Closes an open database
838 * connection and cleans up any open handles.
840 *************************************************************************/
841 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
843 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
845 if (oracle_sock->conn) {
846 OCILogoff (oracle_sock->conn, oracle_sock->errHandle);
849 if (oracle_sock->queryHandle) {
850 OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT);
852 if (oracle_sock->errHandle) {
853 OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR);
855 if (oracle_sock->env) {
856 OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV);
859 oracle_sock->conn = NULL;
865 /*************************************************************************
867 * Function: sql_finish_query
869 * Purpose: End the query, such as freeing memory
871 *************************************************************************/
872 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
874 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
876 ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
878 if (ct_cmd_drop(sybase_sock->command) != CS_SUCCEED) {
879 radlog(L_ERR,"rlm_sql_sybase(sql_finish_query): Freeing command structure failed.");
888 /*************************************************************************
890 * Function: sql_finish_select_query
892 * Purpose: End the select query, such as freeing memory or result
894 *************************************************************************/
895 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
897 rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
900 ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
902 if (ct_cmd_drop(sybase_sock->command) != CS_SUCCEED) {
903 radlog(L_ERR,"rlm_sql_sybase(sql_finish_select_query): Freeing command structure failed.");
907 if (sybase_sock->results) {
908 while(sybase_sock->results[i]) free(sybase_sock->results[i++]);
909 free(sybase_sock->results);
910 sybase_sock->results=NULL;
918 /*************************************************************************
920 * Function: sql_affected_rows
922 * Purpose: Return the number of rows affected by the query (update,
925 *************************************************************************/
926 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
928 return sql_num_rows(sqlsocket, config);
935 /* Exported to rlm_sql */
936 rlm_sql_module_t rlm_sql_sybase = {
950 sql_finish_select_query,