SQLRETURN SQL_API SQLProceduresA(SQLHSTMT StatementHandle, SQLCHAR *CatalogName, SQLSMALLINT NameLength1, SQLCHAR *SchemaName, SQLSMALLINT NameLength2, SQLCHAR *ProcName, SQLSMALLINT NameLength3) { return SQLProcedures(StatementHandle, CatalogName, NameLength1, SchemaName, NameLength2, ProcName, NameLength3); }
SQLRETURN SQLProceduresA( SQLHSTMT statement_handle, SQLCHAR *sz_catalog_name, SQLSMALLINT cb_catalog_name, SQLCHAR *sz_schema_name, SQLSMALLINT cb_schema_name, SQLCHAR *sz_proc_name, SQLSMALLINT cb_proc_name ) { return SQLProcedures( statement_handle, sz_catalog_name, cb_catalog_name, sz_schema_name, cb_schema_name, sz_proc_name, cb_proc_name ); }
static int odbc_dispatch1(void) { unsigned long retval; PWord rval; int rtype; PWord arg1; int type1; PWord arg2; int type2; PWord arg3; int type3; PWord arg4; int type4; PWord arg5; int type5; PWord arg6; int type6; PWord arg7; int type7; PWord arg8; int type8; PWord arg9; int type9; PI_getan(&arg1,&type1,1); if (type1 != PI_INT) if (!CI_get_integer((unsigned long *)&arg1,type1)) PI_FAIL; PI_getan(&arg2,&type2,2); if (type2 != PI_INT) if (!CI_get_integer((unsigned long *)&arg2,type2)) PI_FAIL; PI_getan(&arg3,&type3,3); if (type3 == PI_SYM) arg3 = (unsigned long) PI_getsymname(0,arg3,0); else if (!CI_get_integer((unsigned long *)&arg3,type3)) PI_FAIL; PI_getan(&arg4,&type4,4); if (type4 != PI_INT) if (!CI_get_integer((unsigned long *)&arg4,type4)) PI_FAIL; PI_getan(&arg5,&type5,5); if (type5 == PI_SYM) arg5 = (unsigned long) PI_getsymname(0,arg5,0); else if (!CI_get_integer((unsigned long *)&arg5,type5)) PI_FAIL; PI_getan(&arg6,&type6,6); if (type6 != PI_INT) if (!CI_get_integer((unsigned long *)&arg6,type6)) PI_FAIL; PI_getan(&arg7,&type7,7); if (type7 == PI_SYM) arg7 = (unsigned long) PI_getsymname(0,arg7,0); else if (!CI_get_integer((unsigned long *)&arg7,type7)) PI_FAIL; PI_getan(&arg8,&type8,8); if (type8 != PI_INT) if (!CI_get_integer((unsigned long *)&arg8,type8)) PI_FAIL; PI_getan(&arg9,&type9,9); switch(arg1) { case 0: retval = (unsigned long) SQLTablePrivileges(((SQLHSTMT ) arg2),((SQLCHAR * ) arg3),((SQLSMALLINT ) arg4),((SQLCHAR * ) arg5),((SQLSMALLINT ) arg6),((SQLCHAR * ) arg7),((SQLSMALLINT ) arg8)); break; case 1: retval = (unsigned long) SQLProcedures(((SQLHSTMT ) arg2),((SQLCHAR * ) arg3),((SQLSMALLINT ) arg4),((SQLCHAR * ) arg5),((SQLSMALLINT ) arg6),((SQLCHAR * ) arg7),((SQLSMALLINT ) arg8)); break; case 2: retval = (unsigned long) SQLPrimaryKeys(((SQLHSTMT ) arg2),((SQLCHAR * ) arg3),((SQLSMALLINT ) arg4),((SQLCHAR * ) arg5),((SQLSMALLINT ) arg6),((SQLCHAR * ) arg7),((SQLSMALLINT ) arg8)); break; case 3: retval = (unsigned long) SQLConnect(((SQLHDBC ) arg2),((SQLCHAR * ) arg3),((SQLSMALLINT ) arg4),((SQLCHAR * ) arg5),((SQLSMALLINT ) arg6),((SQLCHAR * ) arg7),((SQLSMALLINT ) arg8)); break; default: PI_FAIL; } PI_makedouble(&rval,&rtype,(double) retval); if (PI_unify(arg9,type9,rval,rtype)) PI_SUCCEED; PI_FAIL; }
/* --------------------------------------------------------- TestSQLProcedures --------------------------------------------------------- */ PassFail TestMXSQLProcedures(TestInfo *pTestInfo) { TEST_DECLARE; char Heading[MAX_HEADING_SIZE]; RETCODE returncode; SQLHANDLE henv; SQLHANDLE hdbc; SQLHANDLE hstmt; CHAR *ProcStr; CHAR *myTestSch = "ODBC_PROC_TEST"; CHAR createSchStr[128]; CHAR setSchStr[128]; CHAR dropSchStr[128]; CHAR ProcName[NAME_LEN]; CHAR ServerName[NAME_LEN]; char SerName[4]; SQLSMALLINT serLen; SWORD ProcType = SQL_PT_PROCEDURE; CHAR opqua[NAME_LEN],opowner[NAME_LEN],opname[NAME_LEN],oremark[REM_LEN]; SWORD onuminpar,onumoutpar,onumresset,optype; SQLLEN opqualen,opownerlen,opnamelen,onuminparlen,onumoutparlen,onumressetlen,oremarklen,optypelen; struct { CHAR *DropProc; CHAR *CrtProc; } CreateProc[] = { {"DROP PROCEDURE N4210_REG", "CREATE PROCEDURE N4210_REG (IN IN1 TIME) EXTERNAL NAME 'Procs.N4210' EXTERNAL PATH '/home/SQFQA/SPJRoot/odbctest_spjs' LANGUAGE JAVA PARAMETER STYLE JAVA NO SQL NO ISOLATE"}, {"DROP PROCEDURE N4260_REG", "CREATE PROCEDURE N4260_REG (IN IN1 REAL, INOUT INOUT1 INTEGER) EXTERNAL NAME 'Procs.N4260' EXTERNAL PATH '/home/SQFQA/SPJRoot/odbctest_spjs' LANGUAGE JAVA PARAMETER STYLE JAVA NO SQL NO ISOLATE"}, {"DROP PROCEDURE N4261_REG", "CREATE PROCEDURE N4261_REG (IN IN1 NUMERIC, INOUT INOUT1 REAL) EXTERNAL NAME 'Procs.N4261' EXTERNAL PATH '/home/SQFQA/SPJRoot/odbctest_spjs' LANGUAGE JAVA PARAMETER STYLE JAVA NO SQL NO ISOLATE"}, {"DROP PROCEDURE N4264_REG", "CREATE PROCEDURE N4264_REG (IN IN1 VARCHAR(30), OUT OUT1 VARCHAR(45)) EXTERNAL NAME 'Procs.N4264' EXTERNAL PATH '/home/SQFQA/SPJRoot/odbctest_spjs' LANGUAGE JAVA PARAMETER STYLE JAVA NO SQL NO ISOLATE"}, {"DROP PROCEDURE N4267_REG", "CREATE PROCEDURE N4267_REG (IN IN1 NUMERIC, INOUT INOUT1 REAL) EXTERNAL NAME 'Procs.N4267' EXTERNAL PATH '/home/SQFQA/SPJRoot/odbctest_spjs' LANGUAGE JAVA PARAMETER STYLE JAVA NO SQL NO ISOLATE"}, {"endloop","endloop"} }; struct { CHAR *ProcName; SDWORD NumInParams; SDWORD NumOutParams; SDWORD NumResSet; CHAR *Remark; } Procedure[] = { {"N4210_REG",0,0,0,""}, {"N4260_REG",0,0,0,""}, {"N4261_REG",0,0,0,""}, {"N4264_REG",0,0,0,""}, {"N4267_REG",0,0,0,""}, {"endloop",0,0,0,""} }; int i = 0, k = 0; //=========================================================================================================== // Initialization Test Case LogMsg(LINEBEFORE+SHORTTIMESTAMP,"Begin testing API => MX Specific SQLProcedures | SQLProcedures | MXProc.c\n"); TEST_INIT; TESTCASE_BEGIN("Setup for SQLProcedures tests\n"); if(!FullConnectWithOptions(pTestInfo, CONNECT_ODBC_VERSION_3)) { LogMsg(NONE,"Unable to connect\n"); TEST_RETURN; } henv = pTestInfo->henv; hdbc = pTestInfo->hdbc; hstmt = (SQLHANDLE)pTestInfo->hstmt; returncode = SQLAllocHandle(SQL_HANDLE_STMT, (SQLHANDLE)hdbc, &hstmt); if(!CHECKRC(SQL_SUCCESS,returncode,"SQLAllocHandle")) { LogAllErrorsVer3(henv,hdbc,hstmt); FullDisconnect3(pTestInfo); TEST_RETURN; } returncode = SQLGetInfo(hdbc, SQL_SERVER_NAME, (SQLPOINTER)&ServerName, NAME_LEN, &serLen); strncpy(SerName, ServerName+1, 3); SerName[3] = '\0'; /* sq: This test calls SQLProcedures() with wildcard characters. It * needs its own empty schema to create the procedures, Otherwise the * standard schema that everybody uses may already have other procedures * created and will be returned by SQLProcedures() to confuse the test. */ sprintf (createSchStr, "CREATE SCHEMA %s.%s", pTestInfo->Catalog, myTestSch); sprintf (setSchStr, "SET SCHEMA %s.%s", pTestInfo->Catalog, myTestSch); sprintf (dropSchStr, "DROP SCHEMA %s.%s cascade", pTestInfo->Catalog, myTestSch); returncode = SQLExecDirect(hstmt,(SQLCHAR*) dropSchStr,SQL_NTS); returncode = SQLExecDirect(hstmt,(SQLCHAR*) createSchStr,SQL_NTS); returncode = SQLExecDirect(hstmt,(SQLCHAR*) setSchStr,SQL_NTS); ProcStr = (char *)malloc(MAX_NOS_SIZE); while (_stricmp(CreateProc[i].DropProc,"endloop") != 0) { sprintf(ProcStr,"%s",CreateProc[i].DropProc); returncode = SQLExecDirect(hstmt,(SQLCHAR*) ProcStr,SQL_NTS); // cleanup sprintf(ProcStr,"%s",CreateProc[i].CrtProc); replace_str(ProcStr,"$$$",SerName); sprintf(Heading,"Procedure => %s\n",ProcStr); TESTCASE_BEGIN(Heading); returncode = SQLExecDirect(hstmt,(SQLCHAR*)ProcStr,SQL_NTS); if(returncode != SQL_SUCCESS) { TEST_FAILED; LogAllErrors(henv,hdbc,hstmt); } TESTCASE_END; i++; } sprintf(Heading,"Test Positive Functionality of SQLProcedures \n"); TESTCASE_BEGIN(Heading); returncode = SQLProcedures(hstmt,(SQLCHAR*)pTestInfo->Catalog,(SWORD)strlen(pTestInfo->Catalog),(SQLCHAR*)myTestSch/*pTestInfo->Schema*/,(SWORD)strlen(myTestSch/*pTestInfo->Schema*/),(SQLCHAR *)"%",(SWORD)1); if(!CHECKRC(SQL_SUCCESS,returncode,"SQLProcedures")) { TEST_FAILED; LogAllErrors(henv,hdbc,hstmt); } if (returncode == SQL_SUCCESS) { strcpy(opqua,""); strcpy(opowner,""); strcpy(opname,""); onuminpar = 0; onumoutpar = 0; onumresset = 0; strcpy(oremark,""); optype = 0; SQLBindCol(hstmt,1,SQL_C_CHAR,opqua,NAME_LEN,&opqualen); SQLBindCol(hstmt,2,SQL_C_CHAR,opowner,NAME_LEN,&opownerlen); SQLBindCol(hstmt,3,SQL_C_CHAR,opname,NAME_LEN,&opnamelen); SQLBindCol(hstmt,4,SQL_C_SHORT,&onuminpar,0,&onuminparlen); SQLBindCol(hstmt,5,SQL_C_SHORT,&onumoutpar,0,&onumoutparlen); SQLBindCol(hstmt,6,SQL_C_SHORT,&onumresset,0,&onumressetlen); SQLBindCol(hstmt,7,SQL_C_CHAR,oremark,NAME_LEN,&oremarklen); SQLBindCol(hstmt,8,SQL_C_SHORT,&optype,0,&optypelen); k = 0; i = 0; while (returncode == SQL_SUCCESS) { if(strcmp(Procedure[i].ProcName,"endloop") == 0) break; returncode = SQLFetch(hstmt); if((returncode!=SQL_NO_DATA_FOUND) &&(!CHECKRC(SQL_SUCCESS,returncode,"SQLFetch"))) { LogAllErrors(henv,hdbc,hstmt); TEST_FAILED; } else { if (returncode == SQL_SUCCESS) { k++; sprintf(Heading,"SQLProcedures: Comparing Results\n"); TESTCASE_BEGIN(Heading); if ((_stricmp(pTestInfo->Catalog,opqua) == 0) && (_stricmp(myTestSch/*pTestInfo->Schema*/,opowner) == 0) && (_stricmp(Procedure[i].ProcName,opname) == 0) && (Procedure[i].NumInParams == onuminpar) && (Procedure[i].NumOutParams == onumoutpar) && (Procedure[i].NumResSet == onumresset) && (_stricmp(Procedure[i].Remark,oremark) == 0) && (ProcType == optype)) { //LogMsg(NONE,"Catalog Name expect: %s and actual: %s are matched\n",pTestInfo->Catalog,opqua); //LogMsg(NONE,"Schema Name expect: %s and actual: %s are matched\n",pTestInfo->Schema,opowner); //LogMsg(NONE,"ProcName expect: %s and actual: %s are matched\n",Procedure[i].ProcName,opname); //LogMsg(NONE,"NumInParams expect: %d and actual: %d are matched\n",Procedure[i].NumInParams,onuminpar); //LogMsg(NONE,"NumOutParams expect: %d and actual: %d are matched\n",Procedure[i].NumOutParams,onumoutpar); //LogMsg(NONE,"NumResSet expect: %d and actual: %d are matched\n",Procedure[i].NumResSet, onumresset); //LogMsg(NONE,"Remark expect: %s and actual: %s are matched\n",Procedure[i].Remark,oremark); //LogMsg(NONE,"ProcType expect: %d and actual: %d are matched\n",ProcType,optype); } else { TEST_FAILED; if (_stricmp(pTestInfo->Catalog,opqua) != 0) LogMsg(ERRMSG,"Catalog Name expect: %s and actual: %s are not matched\n",pTestInfo->Catalog,opqua); if (_stricmp(myTestSch/*pTestInfo->Schema*/,opowner) != 0) LogMsg(ERRMSG,"Schema Name expect: %s and actual: %s are not matched\n",myTestSch/*pTestInfo->Schema*/,opowner); if (_stricmp(Procedure[i].ProcName,opname) != 0) LogMsg(ERRMSG,"ProcName expect: %s and actual: %s are not matched\n",Procedure[i].ProcName,opname); if (Procedure[i].NumInParams != onuminpar) LogMsg(ERRMSG,"NumInParams expect: %d and actual: %d are not matched\n",Procedure[i].NumInParams,onuminpar); if (Procedure[i].NumOutParams != onumoutpar) LogMsg(ERRMSG,"NumOutParams expect: %d and actual: %d are not matched\n",Procedure[i].NumOutParams,onumoutpar); if (Procedure[i].NumResSet != onumresset) LogMsg(ERRMSG,"NumResSet expect: %d and actual: %d are not matched\n",Procedure[i].NumResSet, onumresset); if (_stricmp(Procedure[i].Remark,oremark) != 0) LogMsg(ERRMSG,"Remark expect: %s and actual: %s are not matched\n",Procedure[i].Remark,oremark); if (ProcType != optype) LogMsg(ERRMSG,"ProcType expect: %d and actual: %d are not matched\n",ProcType,optype); } } } if(k == 0) { TEST_FAILED; LogMsg(ERRMSG,"No Data Found => Atleast one row should be fetched\n"); } TESTCASE_END; i++; } // while } SQLFreeStmt(hstmt,SQL_UNBIND); SQLFreeStmt(hstmt,SQL_CLOSE); //======================================================================================================== sprintf(Heading,"SQLProcedures: Negative test with NULL handle\n"); TESTCASE_BEGIN(Heading); hstmt = (SQLHANDLE)NULL; strcpy(ProcName,"junkproc"); returncode = SQLProcedures(hstmt,(SQLCHAR*)pTestInfo->Catalog,(SWORD)strlen(pTestInfo->Catalog),(SQLCHAR*)myTestSch/*pTestInfo->Schema*/,(SWORD)strlen(myTestSch/*pTestInfo->Schema*/),(SQLCHAR*)ProcName,(SWORD)strlen(ProcName)); if(!CHECKRC(SQL_INVALID_HANDLE,returncode,"SQLProcedures")) { TEST_FAILED; LogAllErrors(henv,hdbc,hstmt); } returncode = SQLExecDirect(hstmt,(SQLCHAR*) dropSchStr,SQL_NTS); TESTCASE_END; //======================================================================================================== free(ProcStr); FullDisconnect3(pTestInfo); LogMsg(SHORTTIMESTAMP+LINEAFTER,"End testing API => MX Specific SQLProcedures.\n"); TEST_RETURN; }
int main(int argc, char **argv) { int rc; HSTMT hstmt = SQL_NULL_HSTMT; /* Cases where output is limited to relevant information only */ SQLSMALLINT sql_tab_privileges_ids[6] = {1, 2, 3, 4, 6, 7}; SQLSMALLINT sql_column_ids[6] = {1, 2, 3, 4, 5, 6}; test_connect(); rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt); if (!SQL_SUCCEEDED(rc)) { print_diag("failed to allocate stmt handle", SQL_HANDLE_DBC, conn); exit(1); } /* Check for SQLGetTypeInfo */ printf("Check for SQLTypeInfo\n"); rc = SQLGetTypeInfo(hstmt, SQL_VARCHAR); CHECK_STMT_RESULT(rc, "SQLGetTypeInfo failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLTables */ printf("Check for SQLTables\n"); rc = SQLTables(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "%", SQL_NTS, (SQLCHAR *) "TABLE", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLTables failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLColumns */ printf("Check for SQLColumns\n"); rc = SQLColumns(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "%", SQL_NTS, NULL, 0); CHECK_STMT_RESULT(rc, "SQLColumns failed", hstmt); print_result_meta(hstmt); /* * Print only the 6 first columns, we do not want for example * to get the OID in output, and this information looks to be * enough. */ print_result_series(hstmt, sql_column_ids, 6); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLColumnPrivileges */ //printf("Check for SQLColumnPrivileges\n"); //rc = SQLColumnPrivileges(hstmt, // NULL, 0, // (SQLCHAR *) "public", SQL_NTS, // (SQLCHAR *) "testtab1", SQL_NTS, // (SQLCHAR *) "id", SQL_NTS); //CHECK_STMT_RESULT(rc, "SQLColumnPrivileges failed", hstmt); //print_result_meta(hstmt); //print_result(hstmt); //rc = SQLFreeStmt(hstmt, SQL_CLOSE); //CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLSpecialColumns */ printf("Check for SQLSpecialColumns\n"); rc = SQLSpecialColumns(hstmt, SQL_ROWVER, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "testtab1", SQL_NTS, SQL_SCOPE_SESSION, SQL_NO_NULLS); CHECK_STMT_RESULT(rc, "SQLSpecialColumns failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* * Check for SQLStatistics. It is important to note that this function * returns statistics like the number of pages used and the number of * index scans. */ printf("Check for SQLStatistics\n"); rc = SQLStatistics(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "testtab1", SQL_NTS, 0, 0); CHECK_STMT_RESULT(rc, "SQLStatistics failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLPrimaryKeys */ printf("Check for SQLPrimaryKeys\n"); rc = SQLPrimaryKeys(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "testtab1", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLPrimaryKeys failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLForeignKeys */ printf("Check for SQLForeignKeys\n"); rc = SQLForeignKeys(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "testtab1", SQL_NTS, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "testtab_fk", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLForeignKeys failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLProcedures */ printf("Check for SQLProcedures\n"); rc = SQLProcedures(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "simple_add", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLProcedures failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLProcedureColumns */ printf("Check for SQLProcedureColumns\n"); rc = SQLProcedureColumns(hstmt, NULL, 0, (SQLCHAR *) "public", SQL_NTS, (SQLCHAR *) "simple_add", SQL_NTS, NULL, 0); CHECK_STMT_RESULT(rc, "SQLProcedureColumns failed", hstmt); print_result_meta(hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Check for SQLTablePrivileges */ printf("Check for SQLTablePrivileges\n"); rc = SQLTablePrivileges(hstmt, NULL, 0, (SQLCHAR *) "public", 0, (SQLCHAR *) "testtab1", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLTablePrivileges failed", hstmt); print_result_meta(hstmt); print_result_series(hstmt, sql_tab_privileges_ids, 6); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* * Extra tests. * Older versions of the driver had a bug in handling table-types lists * longer than 32 entries. Check for that. */ rc = SQLTables(hstmt, "", SQL_NTS, "public", SQL_NTS, "testtab%", SQL_NTS, "1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5, TABLES", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLTables failed", hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* Clean up */ test_disconnect(); return 0; }