/* * NAME * * Error handling: * * all_callback dispatches callback events * message_handler handles MI_MESSAGE * exception_handler handles MI_EXCEPTION * fatal_handler handles MI_FATAL * sql_handler handles MI_SQL * die closes connection and exits * * Query Processing: * * exec_query executes query and processes query results * print_rows called by exec_query, outputs results coming * back from a select. * FILENAME * mi_services.c * * DESCRIPTION * A few centralized services to keep sample programs small. * * BUILD INSTRUCTIONS * cc -g -I$MI_HOME/h -c mi_services.c -o mi_services.o * * AUTHOR * From Dave Segleau's sample programs. * Send suggestions for improvement to jta@postgres.berkeley.edu. * * MODS * 4/11/94 jta works with Montage 2.0.9, libmontage '3.0.1 M' * 6/03/94 jta added parameter to exec_query to print/not print * column titles. Added sql_handler and MI_SQL case. * works with Illustra 2.0.12. * 7/22/94 jta works with 2.1 * * $Header: /usr/local/devel/montage/samples/programs/RCS/mi_services.c,v 1.4 1994/07/22 23:03:10 jta Exp $ */ #include #include "mi_services.h" /* all_callback() * * Dispatches callback events. It takes the connection type and figures * out which routine to call. */ void all_callback(type, conn, s1, s2) MI_EVENT_TYPE type; MI_CONNECTION *conn; void *s1; void *s2; { int ecode; char emsg[100]; char *s; switch (type) { /* * Some sort of Server error. */ case MI_Exception: ecode = mi_error_level(s1); switch (mi_error_level(s1)) { case MI_MESSAGE: message_handler(s1, s2); break; case MI_EXCEPTION: exception_handler(s1, s2); break; case MI_FATAL: fatal_handler(s1, s2); break; case MI_SQL: /* gets from 'errors' sys catalog */ sql_handler(s1, s2); break; } break; /* A Client Library Error is any type of internal library error, * library usage problem, or dropped connection. */ case MI_Client_Library_Error: ecode = mi_error_level(s1); switch (ecode) { case MI_LIB_BADARG: s = "MI_LIB_BADARG"; break; case MI_LIB_USAGE: s = "MI_LIB_USAGE"; break; case MI_LIB_INTERR: s = "MI_LIB_INTERR"; break; case MI_LIB_NOIMP: s = "MI_LIB_NOIMP"; break; case MI_LIB_DROPCONN: s = "MI_LIB_DROPCONN"; break; case MI_LIB_BADSERV: s = "MI_LIB_BADSERV"; break; default: s = "UNKNOWN"; break; } mi_errmsg(s1, emsg, 100); fprintf(stderr, "%s: %s\n", s, emsg); break; /* An Alerter event occured. */ case MI_Alerter_Fire_Msg: fprintf(stderr, "all_callback: Alerter %s %s\n", mi_alert_name(s1), mi_alert_status(s1) == MI_ALERTER_DROPPED ? "dropped" : "fired"); break; case MI_Query_Interrupt_Ack: fprintf(stderr, "all_callback: Caught a query interrupt.\n"); break; case MI_Xact_State_Change: fprintf(stderr, "all_callback: Caught a transaction state change.\n"); break; default: fprintf(stderr, "all_callback: Caught an unexpected event type\n"); break; } return; } /* message_handler() * * Used for MI_MESSAGE's. */ void message_handler(s1, s2) void *s1, *s2; { char buf[8192]; mi_errmsg(s1, buf, 8192); fprintf(stderr, "MI_MESSAGE: %s\n", buf); } /* exception_handler() * * Used for MI_EXCEPTION's. */ void exception_handler(s1, s2) void *s1, *s2; { char buf[8192]; mi_errmsg(s1, buf, 8192); fprintf(stderr, "MI_EXCEPTION: %s\n", buf); } /* fatal_handler() * * Used for FATAL's. */ void fatal_handler(s1, s2) void *s1, *s2; { char buf[8192]; mi_errmsg(s1, buf, 8192); fprintf(stderr, "MI_FATAL: %s\n", buf); } /* sql_handler() * * Used for MI_SQL's. */ void sql_handler(s1, s2) void *s1, *s2; { char buf[8192]; mi_errmsg(s1, buf, 8192); fprintf(stderr, "MI_SQL: %s\n", buf); } /* die() * * Outputs message, closes connection if it is valid, and exits. */ void die(msg, conn) char *msg; MI_CONNECTION *conn; { fprintf(stderr, "%s\n", msg); if (conn != NULL) mi_close(conn); exit(1); } /* * exec_query() * * Executes query and processes results. */ mi_integer exec_query(conn, query, titles) MI_CONNECTION *conn; char *query; int titles; /* to print or not to print.... */ { int ret = 0; if (mi_exec(conn, query, 0) == MI_ERROR) { fprintf(stderr, "exec_query: mi_exec() failed.\n"); return(MI_ERROR); } while ((ret = mi_get_result(conn)) != MI_NO_MORE_RESULTS) { switch (ret) { case MI_ERROR: fprintf(stderr, "exec_query: mi_get_result() failed.\n"); return(MI_ERROR); case MI_DDL: /* FALLTHROUGH */ case MI_DML: break; case MI_ROWS: if(print_rows(conn, titles) == MI_ERROR) return(MI_ERROR); break; default: fprintf(stderr, "exec_query: Unexpected result from mi_get_result()\n"); return(MI_ERROR); } } return(0); } /* print_rows() * * Outputs results, prints column heading if titles is nonzero. * */ mi_integer print_rows(conn, titles) MI_CONNECTION *conn; int titles; { MI_ROW *row; MI_ROW_DESC *desc; int error = 0, ncols, i; int entering = 1; while ((row = mi_next_row(conn, &error)) != NULL) { /* * Note that the row descriptor CAN change in * mid-query for some types of queries, * primarily those involving sets. */ if (entering) { desc = mi_get_row_desc(row); ncols = mi_column_count(desc); if(titles) { for (i = 0; i < ncols; i++) { printf("%s\t", mi_column_name(desc, i)); } printf("\n\n"); } entering = 0; } for (i = 0; i < ncols; i++) { char *col_val; int col_len; switch (mi_value(row, i, &col_val, &col_len)) { case MI_ERROR: fprintf(stderr, "exec_query: mi_value failed"); return(MI_ERROR); case MI_NULL_VALUE: col_val = "NULL"; break; case MI_NORMAL_VALUE: break; default: fprintf(stderr, "exec_query: Unexpected column type found."); return(MI_ERROR); } /* column value is null-terminated for ASCII returns */ printf("%s\t", col_val); } printf("\n"); } /* End process each row */ if (error == MI_ERROR) { fprintf(stderr, "exec_query: mi_next_row failed"); return(MI_ERROR); } return(0); }