#include #include #include #include #include #include const char *DSN = "testdb"; const char *USER = "test"; const char *PASSWORD = "test"; SQLHENV env = SQL_NULL_HENV; /* ODBC environment handle */ SQLHDBC db_handle = SQL_NULL_HDBC; /* Database connection handle */ SQLHSTMT stmt = SQL_NULL_HSTMT; /* Statement handle */ SQLRETURN ret; /* Function return code */ SQLBIGINT param1 = 1; SQLBIGINT param2 = 2; SQLINTEGER param3 = 3; SQLINTEGER param4 = 4; SQL_TIMESTAMP_STRUCT param5 = {2017 + 1900, 2 + 1, 2, 13, 30, 0, 0}; SQLINTEGER param6 = 6; SQLINTEGER param7 = 7; SQLINTEGER param8 = 8; SQLINTEGER param9 = 9; SQLINTEGER param10 = 10; SQLINTEGER param11 = 11; SQLCHAR param12[] = "param12"; SQLCHAR param13[] = "param13"; SQLBIGINT param14 = 0; void perform_cleanup(); void print_odbc_error_info(SQLSMALLINT handle_type, SQLHANDLE handle); #define ON_ERROR(sql_ret, err_msg, ...) \ if (!(SQL_SUCCEEDED(sql_ret))) { \ fprintf(stderr, err_msg, ##__VA_ARGS__); \ perform_cleanup(); \ exit(1); \ } #define ON_ERROR_WITH_HANDLE(sql_ret, handle_type, handle) \ if (!(SQL_SUCCEEDED(sql_ret))) { \ print_odbc_error_info(handle_type, handle); \ perform_cleanup(); \ exit(1); \ } int main(int argc, char *argv[]) { /* 1. Allocate environment handle and register version */ ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); ON_ERROR(ret, "Unable to allocate SQL environment handle: " "SQLAllocHandle returned %d\n", ret); ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); ON_ERROR(ret, "Unable to set SQL environment ODBC version: " "SQLSetEnvAttr returned %d\n", ret); /* 2. Allocate connection handle and set some attributes */ ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &db_handle); ON_ERROR(ret, "Unable to allocate DB handle: SQLAllocHandle " "returned %d\n", ret); ret = SQLSetConnectAttr(db_handle, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); ON_ERROR(ret, "Unable to set DB handle attribute: " "SQLSetConnectAttr returned %d\n", ret); /* 3. Connect to the datasource */ ret = SQLConnect(db_handle, (SQLCHAR *)DSN, SQL_NTS, (SQLCHAR *)USER, SQL_NTS, (SQLCHAR *)PASSWORD, SQL_NTS); ON_ERROR(ret, "Unable to connect to '%s': SQLConnect " "returned %d\n", DSN, ret); printf("Successfully connected to '%s'!\n", DSN); /* 4. Allocate SQL statement handle */ ret = SQLAllocHandle(SQL_HANDLE_STMT, db_handle, &stmt); ON_ERROR(ret, "Unable to allocate SQL statement handle: " "SQLAllocHandle returned %d\n", ret); ret = SQLPrepare(stmt, "{call my_function3(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " "?, ?, ?, ?)}", SQL_NTS); ON_ERROR(ret, "Unable to prepare statement: SQLPrepare " "returned %d\n", ret); ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, (SQLPOINTER)¶m1, sizeof(param1), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 1: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, (SQLPOINTER)¶m2, sizeof(param2), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 2: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m3, sizeof(param3), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 3: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m4, sizeof(param4), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 4: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 0, 0, (SQLPOINTER)¶m5, sizeof(param5), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 5: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m6, sizeof(param6), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 6: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m7, sizeof(param7), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 7: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m8, sizeof(param8), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 8: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m9, sizeof(param9), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 9: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m10, sizeof(param10), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 10: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)¶m11, sizeof(param11), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 11: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)param12, sizeof(param12), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 12: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)param13, sizeof(param13), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 13: " "SQLBindParameter returned %d\n", ret); ret = SQLBindParameter(stmt, 14, SQL_PARAM_OUTPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, (SQLPOINTER)¶m14, sizeof(param14), NULL); ON_ERROR(ret, "Unable to prepare statement: bind parameter 14: " "SQLBindParameter returned %d\n", ret); ret = SQLExecute(stmt); ON_ERROR_WITH_HANDLE(ret, SQL_HANDLE_STMT, stmt); printf("my_function executed successfully!\n"); printf("Output: %d\n", param6); perform_cleanup(); return 0; } void perform_cleanup() { if (stmt != SQL_NULL_HSTMT) { SQLFreeHandle(SQL_HANDLE_STMT, stmt); } if (db_handle != SQL_NULL_HDBC) { SQLDisconnect(db_handle); SQLFreeHandle(SQL_HANDLE_DBC, db_handle); } if (env != SQL_NULL_HENV) { SQLFreeHandle(SQL_HANDLE_ENV, env); } } void print_odbc_error_info(SQLSMALLINT handle_type, SQLHANDLE handle) { int i = 1; SQLRETURN ret = 0; SQLCHAR sql_state[6] = {"\0"}; SQLINTEGER native_error = 0; SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH] = {"\0"}; SQLSMALLINT msg_len = 0; ret = SQLGetDiagRec(handle_type, handle, i, sql_state, &native_error, msg, sizeof(msg), &msg_len); if (!(SQL_SUCCEEDED(ret))) { printf("Unable to retrieve ODBC error information"); return; } // There may be multiple status records associated to the handle. Retrieve // each one. do { printf("Status record: %d\n", i); printf("SQL state: %s\n", sql_state); printf("Native error: %d\n", native_error); printf("Message: %s\n", msg); i++; ret = SQLGetDiagRec(handle_type, handle, i, sql_state, &native_error, msg, sizeof(msg), &msg_len); } while (SQL_SUCCEEDED(ret)); }