diff options
author | unknown <magnus@neptunus.(none)> | 2004-04-14 10:53:21 +0200 |
---|---|---|
committer | unknown <magnus@neptunus.(none)> | 2004-04-14 10:53:21 +0200 |
commit | 6386c55cee50bad6a9979d1fab28e03bb8612ca7 (patch) | |
tree | 3fbbacf704304b69228474b9f03549ccd585a017 /ndb/test/odbc | |
parent | 0ba6cb48d84f1ff951d09871a96be6cdef3f2c3c (diff) | |
download | mariadb-git-6386c55cee50bad6a9979d1fab28e03bb8612ca7.tar.gz |
Initial revision of NDB Cluster files
BitKeeper/etc/logging_ok:
Logging to logging@openlogging.org accepted
Diffstat (limited to 'ndb/test/odbc')
76 files changed, 20604 insertions, 0 deletions
diff --git a/ndb/test/odbc/Makefile b/ndb/test/odbc/Makefile new file mode 100644 index 00000000000..eab61ebd359 --- /dev/null +++ b/ndb/test/odbc/Makefile @@ -0,0 +1,13 @@ +include .defs.mk + +DIRS += driver + +ifneq ($(findstring odbc, $(wildcard /usr/lib/libodbc.so)),) +DIRS += dm-unixodbc +endif + +ifneq ($(findstring $(NDB_OS), SOLARIS),) +DIRS += dm-iodbc +endif + +include ${NDB_TOP}/Epilogue.mk diff --git a/ndb/test/odbc/SQL99_test/Makefile b/ndb/test/odbc/SQL99_test/Makefile new file mode 100644 index 00000000000..3ac06016670 --- /dev/null +++ b/ndb/test/odbc/SQL99_test/Makefile @@ -0,0 +1,26 @@ +include .defs.mk + +TYPE = odbcdriver + +BIN_TARGET = SQL99_test + +SOURCES = SQL99_test.cpp + +CCFLAGS_LOC += -I/usr/local/include \ + -I$(NDB_TOP)/test/include \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/src/client/odbc/common + + +CCFLAGS_WARNINGS += -Wno-unused + +LIBS_SPEC += \ + -lNDBT \ + -lodbc \ + -lodbcinst \ + -lportlib + + + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/test/odbc/SQL99_test/SQL99_test.cpp b/ndb/test/odbc/SQL99_test/SQL99_test.cpp new file mode 100644 index 00000000000..eda9ff33834 --- /dev/null +++ b/ndb/test/odbc/SQL99_test/SQL99_test.cpp @@ -0,0 +1,2138 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// ODBC.cpp : Defines the entry point for the console application. +// + +#include "SQL99_test.h" +#include <iostream> // Loose later + +using namespace std; // + +#define MAXCOL 64 +#define DEFCOL 4 + +#define MAXROW 64 +#define DEFROW 8 + +#define MAXTHREADS 24 +#define DEFTHREADS 2 + +#define MAXTABLES 16 +#define DEFTABLES 2 + +#define MAXLOOPS 100000 +#define DEFLOOPS 4 + +#define UPDATE_VALUE 7 + +#define PKSIZE 2 + + +static int nNoOfThreads = 1 ; +static int nNoOfCol = 4 ; +static int nNoOfRows = 2 ; +static int nNoOfLoops = 0 ; +static int nNoOfTables = 2 ; +static int nAPI = 0 ; +static int tAttributeSize = sizeof(char) ; +static attr_type AttributeType = T_CHAR ; +static int nAggregate = 0 ; +static int nArithmetic = 0 ; +static int nPrint = 0 ; +static int nColList = 0 ; +static char szColNames[MAXCOL*MAX_COL_NAME] = { 0 } ; +int createTables(char* szTableName, int nTables) ; + + +/************************************************* +Function: main - the entry point +*************************************************/ +int main(int argc, char* argv[]){ + + int nRetrunValue = NDBT_FAILED ; + SQLRETURN rc = SQL_ERROR ; + double dResultA = 0 ; + double dResultB = 0 ; + double dInput = 0 ; + int x = 0, y = 0 ; + int* pIntRefBuffer = NULL ; + float* pFloatRefBuffer = NULL ; + double* pDoubleRefBuffer = NULL ; + char* pCharRefBuffer = NULL ; + char szColBuffer[MAX_COL_NAME] = { 0 } ; + + + ParseArguments(argc, (const char**)argv) ; + + PARAMS* pparams = (PARAMS*)malloc(sizeof(PARAMS)*nNoOfThreads) ; + memset(pparams, 0, (sizeof(PARAMS)*nNoOfThreads)) ; + + char* szTableNames = (char*)malloc(sizeof(char)*nNoOfTables*MAX_TABLE_NAME) ; + memset(szTableNames, 0, sizeof(char)*nNoOfTables*MAX_TABLE_NAME) ; + + UintPtr pThreadHandles[MAXTHREADS] = { NULL } ; + + AssignTableNames(szTableNames, nNoOfTables) ; + + if(nAPI){ + if(0 != createTables(szTableNames, nNoOfTables)){ + printf("Failed to create tables through NDB API; quitting...\n") ; + NDBT_ProgramExit(NDBT_FAILED) ; + return NDBT_FAILED ; + } + }else{ + + //CreateDemoTables(szTableNames, nNoOfTables, DROP) ; + rc = CreateDemoTables(szTableNames, nNoOfTables, CREATE) ; + if(!(SQL_SUCCESS == rc || SQL_SUCCESS_WITH_INFO == rc)){ + printf("Failed to create tables, quiting now.\n") ; + NDBT_ProgramExit(NDBT_FAILED) ; + return NDBT_FAILED ; + } + } + + // Store column names in the buffer for use in some stmts + int k = 0 ; + for(;;){ + memset((char*)szColBuffer, 0, strlen(szColBuffer)) ; + sprintf((char*)szColBuffer, "COL%d", k) ; + strcat((char*)szColNames, (char*)szColBuffer) ; + ++k ; + if( k == nNoOfCol ){ + break ; + } + strcat((char*)szColNames, ", ") ; + } // for + + + switch(AttributeType){ + case T_INT: + pIntRefBuffer = (int*)malloc(sizeof(int)*nNoOfRows*nNoOfCol*nNoOfThreads) ; + memset(pIntRefBuffer, 0, sizeof(int)*nNoOfRows*nNoOfCol*nNoOfThreads) ; + AssignRefNumValues(pIntRefBuffer, T_INT, nPrint) ; + StartThreads(pparams, (void*)pIntRefBuffer, nNoOfTables, szTableNames, AttributeType, pThreadHandles) ; + break ; + case T_FLOAT: + pFloatRefBuffer = (float*)malloc(sizeof(float)*nNoOfRows*nNoOfCol*nNoOfThreads) ; + memset(pFloatRefBuffer, 0, sizeof(float)*nNoOfRows*nNoOfCol*nNoOfThreads) ; + AssignRefNumValues(pFloatRefBuffer, T_FLOAT, nPrint) ; + StartThreads(pparams, (void*)pFloatRefBuffer, nNoOfTables, szTableNames, AttributeType, pThreadHandles) ; + break ; +/* case T_DOUBLE: + pDoubleRefBuffer = (double*)malloc(sizeof(double)*nNoOfRows*nNoOfCol*nNoOfThreads) ; + memset(pDoubleRefBuffer, 0, sizeof(double)*nNoOfRows*nNoOfCol*nNoOfThreads) ; + AssignRefNumValues(pDoubleRefBuffer, T_DOUBLE, 0) ; + StartThreads(pparams, (void*)pDoubleRefBuffer, nNoOfTables, szTableNames, AttributeType, pThreadHandles) ; + break ; +*/ + case T_CHAR: + pCharRefBuffer = (char*)malloc(sizeof(char)*nNoOfRows*nNoOfCol*nNoOfThreads*MAX_CHAR_ATTR_LEN) ; + memset(pCharRefBuffer, 0, sizeof(char)*nNoOfRows*nNoOfCol*nNoOfThreads*MAX_CHAR_ATTR_LEN) ; + AssignRefCharValues(pCharRefBuffer, nPrint ) ; + StartThreads(pparams, (void*)pCharRefBuffer, nNoOfTables, szTableNames, AttributeType, pThreadHandles) ; + break ; + default: + break ; + } + + NdbThread_SetConcurrencyLevel(nNoOfThreads + 2) ; + + + printf("\nPerforming inserts...") ; + SetThreadOperationType(pparams, T_INSERT) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; + PrintAll(szTableNames, nNoOfTables, AttributeType) ; + + printf("\nVerifying inserts...") ; + SetThreadOperationType(pparams, T_READ_VERIFY) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; + + printf("\nPerforming updates...") ; + SetThreadOperationType(pparams, T_UPDATE) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; + //PrintAll(szTableNames, nNoOfTables, AttributeType) ; + + printf("\nVerifying updates...") ; + SetThreadOperationType(pparams, T_READ_VERIFY) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; + + printf("\nPerforming reads...") ; + SetThreadOperationType(pparams, T_READ) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; + PrintAll(szTableNames, nNoOfTables, AttributeType) ; + + + if(T_CHAR != AttributeType && nAggregate){ + printf("\nTesting aggregate functions for each table\n\n") ; + printf("FN\tCOLUMN\tVALUE\t\t\tTOTAL ROWS WHERE\n\t\t\t\t\tVALUE(S) > VALUE\n--------------------------------------------------------\n\n") ; + + for(y = 0 ; y < nNoOfTables ; ++y){ + for(x = 0; x < nNoOfCol ; ++x){ + dResultA = dResultB = 0 ; + AggregateFn(FN_MIN, (char*)(szTableNames + MAX_TABLE_NAME*y), x, NULL, &dResultA, AttributeType) ; + AggregateFn(FN_COUNT, (char*)(szTableNames + MAX_TABLE_NAME*y) , x, &dResultA, &dResultB, AttributeType) ; + ATTR_TYPE_SWITCH_AGR("MIN", x, dResultA, dResultB, AttributeType) ; + } + } + + for(y = 0; y < nNoOfTables ; ++y){ + for(x = 0; x < nNoOfCol ; ++x){ + dResultA = dResultB = 0 ; + AggregateFn(FN_MAX, (char*)(szTableNames + MAX_TABLE_NAME*y), x, NULL, &dResultA, AttributeType) ; + AggregateFn(FN_COUNT, (char*)(szTableNames + MAX_TABLE_NAME*y), x, &dResultA, &dResultB, AttributeType) ; + ATTR_TYPE_SWITCH_AGR("MAX", x, dResultA, dResultB, AttributeType) ; + } + } + + for(y = 0 ; y < nNoOfTables ; ++y){ + for(x = 0; x < nNoOfCol ; ++x){ + dResultA = dResultB = 0 ; + AggregateFn(FN_AVG, (char*)(szTableNames + MAX_TABLE_NAME*y), x, NULL, &dResultA, AttributeType) ; + AggregateFn(FN_COUNT, (char*)(szTableNames + MAX_TABLE_NAME*y), x, &dResultA, &dResultB, AttributeType) ; + ATTR_TYPE_SWITCH_AGR("AVG", x, dResultA, dResultB, AttributeType) + } + } + + printf("--------------------------------------------------------\n\n") ; + } + + if(T_CHAR != AttributeType && nArithmetic){ + + float nVal = (rand() % 10) /1.82342 ; + + for(int h = 0 ; h < nNoOfTables ; ++h){ + + printf("\nTesting arithmetic operators\nfor each column in %s:\n----------------------\n", (char*)(szTableNames + MAX_TABLE_NAME*sizeof(char)*h) ) ; + + printf("\nOperator [ * ]... \t\t") ; + ArithOp((char*)(szTableNames + MAX_TABLE_NAME*sizeof(char)*h), nNoOfCol, &nVal, AttributeType, MULTI) ; + printf("done\n") ; + + printf("\nOperator [ / ]... \t\t") ; + ArithOp((char*)(szTableNames + MAX_TABLE_NAME*sizeof(char)*h), nNoOfCol, &nVal, AttributeType, DIVIDE) ; + printf("done\n") ; + + printf("\nOperator [ + ]... \t\t") ; + ArithOp((char*)(szTableNames + MAX_TABLE_NAME*sizeof(char)*h), nNoOfCol, &nVal, AttributeType, PLUS) ; + printf("done\n") ; + + printf("\nOperator [ - ]... \t\t") ; + ArithOp((char*)(szTableNames + MAX_TABLE_NAME*sizeof(char)*h), nNoOfCol, &nVal, AttributeType, MINUS) ; + printf("done\n\n") ; + /* + printf("\nOperator [ % ]... \t\t") ; + ArithOp((char*)szTableNames, nNoOfCol, &nVal, AttributeType, MODULO) ; + printf("done\n\n") ; + */ + } + } +/* + printf("\nPerforming deletes...") ; + SetThreadOperationType(pparams, T_DELETE) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; + + printf("\nVerifying deletes...") ; + SetThreadOperationType(pparams, T_DELETE_VERIFY) ; + if(0 < WaitForThreads(pparams)){ + printf("\t\t%d thread(s) failed\n") ; + }else{ + printf("\t\tdone\n") ; + } + printf("----------------------\n\n") ; +*/ + StopThreads(pparams, pThreadHandles) ; + + //PrintAll(szTableNames, nNoOfTables, AttributeType) ; + + //CreateDemoTables(szTableNames, nNoOfTables, DROP) ; + + free((void*)szTableNames) ; + free((void*)pparams) ; + free((void*)pIntRefBuffer) ; + free((void*)pFloatRefBuffer) ; + free((void*)pDoubleRefBuffer) ; + free((void*)pCharRefBuffer) ; + + return 0; +} + + + +/************************************************** +Function: ParseArguments +***************************************************/ +void ParseArguments(int argc, const char** argv){ + + int i = 1; + + while (argc > 1){ + + if (strcmp(argv[i], "-t") == 0) + { + nNoOfThreads = atoi(argv[i+1]); + if ((nNoOfThreads < 1) || (nNoOfThreads > MAXTHREADS)) + nNoOfThreads = DEFTHREADS ; + } + else if (strcmp(argv[i], "-c") == 0) + { + nNoOfCol = atoi(argv[i+1]); + if ((nNoOfCol < 2) || (nNoOfCol > MAXCOL)) + nNoOfCol = DEFCOL ; + } + else if (strcmp(argv[i], "-l") == 0) + { + nNoOfLoops = atoi(argv[i+1]); + if ((nNoOfLoops < 0) || (nNoOfLoops > MAXLOOPS)) + nNoOfLoops = DEFLOOPS ; + } + else if (strcmp(argv[i], "-r") == 0) + { + nNoOfRows = atoi(argv[i+1]);; + if ((nNoOfRows < 0) || (nNoOfRows > MAXROW)) + nNoOfRows = DEFROW ; + } + else if (strcmp(argv[i], "-m") == 0) + { + nArithmetic = 1 ; + argc++ ; + i-- ; + } + else if (strcmp(argv[i], "-g") == 0) + { + nAggregate = 1 ; + argc++ ; + i-- ; + } + else if (strcmp(argv[i], "-n") == 0) + { + nAPI = 1 ; + argc++ ; + i-- ; + } + else if (strcmp(argv[i], "-v") == 0) + { + nPrint = 1 ; + argc++ ; + i-- ; + } + else if (strcmp(argv[i], "-a") == 0) + { + if(strcmp(argv[i+1], "int") == 0){ + AttributeType = T_INT ; + tAttributeSize = 32 ; + }else if(strcmp(argv[i+1], "float") == 0){ + AttributeType = T_FLOAT ; + tAttributeSize = 64 ; + }else if(strcmp(argv[i+1], "char") == 0){ + AttributeType = T_CHAR ; + } + } + else + { + cout << "Arguments:\n"; + cout << "-n Create tables using NDB API (vs ODBC by default)" << endl; + cout << "-t Number of threads; maximum 24, default 2\n" << endl; + cout << "-c Number of columns per table; maximum 64, default 4\n" << endl; + cout << "-r Number of rows; maximum 64, default 8\n" << endl; + cout << "-a Type of attribute to use: int, double or char; default int " << endl; + cout << "-g Test aggregate functions" << endl; + cout << "-m Test arithmetic operators" << endl; + cout << "-v Print executed statements" << endl; + exit(-1); + } + + argc -= 2 ; + i = i + 2 ; + } + +char *szAttrType[MAX_STR_LEN] = { 0 } ; +switch(AttributeType){ + case T_INT: + strcpy((char*)szAttrType, "Integer") ; + break ; + case T_FLOAT: + strcpy((char*)szAttrType, "Float") ; + break ; +/* case T_DOUBLE: + strcpy((char*)szAttrType, "Double") ; + break ; +*/ + case T_CHAR: + strcpy((char*)szAttrType, "Character") ; + break ; + default: + strcpy((char*)szAttrType, "Not defined") ; + break ; + } + + +printf("\n\nCurrent parameters: %d thread(s), %d tables, %d rows, %d colums, attribute type: %s\n\n", nNoOfThreads, nNoOfTables, nNoOfRows, nNoOfCol, szAttrType) ; + } + + + + +/************************************************* +Function: ThreadFnInt - thread function +for int attributes +*************************************************/ +void* ThreadFnInt(void* pparams){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR szStmtBuffer[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szValueBuffer[MAX_VALUE_LEN] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLINTEGER cbInt = 0 ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + + int r = 0, j = 0 ; + //Get thread parameters + PARAMS* p = (PARAMS*)pparams ; + int* pRef = (int*)p->pThreadRef ; + + int* pBindBuffer = (int*)malloc(sizeof(int)*nNoOfCol) ; + + //printf("Thread #%d\n", p->nThreadID) ; + + retcode = GetHandles(&stHandles, GET, 0) ; + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ) { + p->report_status = S_STARTED ; + }else{ + printf("Thread #%d failed to allocate handles, exiting now.\n", p->nThreadID) ; + free((void*)pBindBuffer) ; + p->nError = 1 ; + p->report_status = S_EXIT ; + return 0 ; + } + + //p->report_status = S_STARTED ; + + //Main thread loop + for(;;){ + + while(S_IDLE == p->thread_status){ + NdbSleep_MilliSleep(1) ; + } + + if(S_STOP == p->thread_status) { + break ; + }else{ + p->thread_status = S_BUSY ; + } + + switch(p->op_type){ + + + /************************************** T_INSERT case **************************************/ + case T_INSERT: + + for(r = 0 ; r < nNoOfRows ; ++r){ + + if(!nColList){ + sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; + }else{ + sprintf((char*)szStmtBuffer, "INSERT INTO %s (%s) VALUES(", p->szTableName, szColNames) ; + } + + //sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; + + for(j = 0 ;;){ + sprintf((char*)szValueBuffer,"%d", pRef[nNoOfCol*r + j]) ; + strncat((char*)szStmtBuffer, (char*)szValueBuffer, strlen((char*)szValueBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + strcat((char*)szStmtBuffer, ")") ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else{ + p->nError = 1 ; + printf("INSERT in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** T_READ case **************************************/ + case T_READ: + + for(r = 0 ; r < nNoOfRows ; r++){ + + sprintf((char*)szStmtBuffer, "SELECT * FROM %s WHERE COL0 = %d", p->szTableName, pRef[nNoOfCol*r]) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmtBuffer, SQL_NTS), retcode) ; + + for(j = 0 ; j < nNoOfCol ; ++j){ + ODBC_FN(SQLBindCol(stHandles.hstmt, (j+1), SQL_C_SLONG, (void*)&pBindBuffer[j], sizeof(SQLINTEGER), &cbInt), retcode) ; + } + + for (;;) { + retcode = SQLFetch(stHandles.hstmt); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + for(int k = 0 ; k < nNoOfCol ; ++k){ + if(p->nVerifyFlag){ + if(pBindBuffer[k] != pRef[nNoOfCol*r + k]) + printf("Expected: %d Actual: %d\n", pBindBuffer[k], pRef[nNoOfCol*r + k]) ; + } + } + }else if(SQL_NO_DATA == retcode){ + break ; + }else{ + p->nError = 1 ; + printf("READ in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + //printf("\n") ; + } + SQLCloseCursor(stHandles.hstmt) ; + } + break ; + + + /************************************** T_UPDATE case **************************************/ + case T_UPDATE: + for(r = 0 ; r < nNoOfRows ; ++r){ + + sprintf((char*)szStmtBuffer, "UPDATE %s SET ", p->szTableName) ; + for(j = 1 ;;){ + pRef[nNoOfCol*r + j] = pRef[nNoOfCol*r + j] + UPDATE_VALUE ; + sprintf((char*)szColBuffer,"COL%d = %d", j, pRef[nNoOfCol*r + j]) ; + strncat((char*)szStmtBuffer, (char*)szColBuffer, strlen((char*)szColBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + sprintf((char*)szAuxBuffer, " WHERE COL0 = %d ;", pRef[nNoOfCol*r]) ; + strcat((char*)szStmtBuffer, (char*)szAuxBuffer); + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else{ + p->nError = 1 ; + printf("UPDATE in thread %d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** T_DELETE case **************************************/ + case T_DELETE: + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "DELETE * FROM %s WHERE COL0 = %d", p->szTableName, pRef[nNoOfCol*r]) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else if( 1 == p->nVerifyFlag && SQL_NO_DATA != retcode){ + p->nError = 1 ; + printf("\nVerification failed: the row found\n") ; + }else{ + p->nError = 1 ; + printf("INSERT in thread %d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + + } + break ; + + + /************************************** default case **************************************/ + default: + break ; + }//switch +p->thread_status = S_IDLE ; + } //for + +free((void*)pBindBuffer) ; +GetHandles(&stHandles, FREE, 0) ; +p->thread_status = S_EXIT ; +return 0 ; + }; + + + +/************************************************* +Function: ThreadFnFloat - thread function +for float attributes +*************************************************/ +void* ThreadFnFloat(void* pparams){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR szStmtBuffer[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szValueBuffer[MAX_VALUE_LEN] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLINTEGER cbFloat = 0 ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + + int r = 0, j = 0 ; + //Get thread parameters + PARAMS* p = (PARAMS*)pparams ; + + float* pRef = (float*)p->pThreadRef ; + float* pBindBuffer = (float*)malloc(sizeof(float)*nNoOfCol) ; + + //printf("Thread #%d\n", p->nThreadID) ; + + retcode = GetHandles(&stHandles, GET, 0) ; + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ) { + p->report_status = S_STARTED ; + }else{ + printf("Thread #%d failed to allocate handles, exiting now.\n", p->nThreadID) ; + free((void*)pBindBuffer) ; + p->nError = 1 ; + p->report_status = S_EXIT ; + return 0 ; + } + + //p->report_status = S_STARTED ; + + //Main thread loop + for(;;){ + + while(S_IDLE == p->thread_status){ + NdbSleep_MilliSleep(1) ; + } + + if(S_STOP == p->thread_status) { + break ; + }else{ + p->thread_status = S_BUSY ; + } + + switch(p->op_type){ + + + /************************************** T_INSERT case **************************************/ + case T_INSERT: + + for(r = 0 ; r < nNoOfRows ; ++r){ + + if(!nColList){ + sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; + }else{ + sprintf((char*)szStmtBuffer, "INSERT INTO %s (%s) VALUES(", p->szTableName, szColNames) ; + } + + //sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; + + for(j = 0 ;;){ + sprintf((char*)szValueBuffer,"%f", pRef[nNoOfCol*r + j]) ; + strncat((char*)szStmtBuffer, (char*)szValueBuffer, strlen((const char*)szValueBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + strcat((char*)szStmtBuffer, ")") ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else{ + p->nError = 1 ; + printf("INSERT in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** T_READ case **************************************/ + case T_READ: + + for(r = 0 ; r < nNoOfRows ; ++r){ + + sprintf((char*)szStmtBuffer, "SELECT * FROM %s WHERE COL0 = %f", p->szTableName, pRef[nNoOfCol*r]) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmtBuffer, SQL_NTS), retcode) ; + + for(j = 0 ; j < nNoOfCol ; ++j){ + ODBC_FN(SQLBindCol(stHandles.hstmt, (j+1), SQL_C_FLOAT, (void*)&pBindBuffer[j], sizeof(SQLFLOAT), &cbFloat), retcode) ; + } + + for (;;) { + retcode = SQLFetch(stHandles.hstmt); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + for(int k = 0 ; k < nNoOfCol ; ++k){ + if(p->nVerifyFlag){ + if(abs(pBindBuffer[k] - pRef[nNoOfCol*r + k]) > FLTDEV ) + printf("Expected: %f Actual: %f\n", pBindBuffer[k], pRef[nNoOfCol*r + k]) ; + } + } + }else if(SQL_NO_DATA == retcode){ + break ; + }else{ + p->nError = 1 ; + printf("READ in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + //printf("\n") ; + } + SQLCloseCursor(stHandles.hstmt) ; + } + break ; + + + /************************************** T_UPDATE case **************************************/ + case T_UPDATE: + for(r = 0 ; r < nNoOfRows ; ++r){ + + sprintf((char*)szStmtBuffer, "UPDATE %s SET ", p->szTableName) ; + for(j = 1 ;;){ + pRef[nNoOfCol*r + j] = pRef[nNoOfCol*r + j] + UPDATE_VALUE ; + sprintf((char*)szColBuffer,"COL%d = %f", j, pRef[nNoOfCol*r + j]) ; + strncat((char*)szStmtBuffer, (char*)szColBuffer, strlen((char*)szColBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + sprintf((char*)szAuxBuffer, " WHERE COL0 = %f ;", pRef[nNoOfCol*r]) ; + strcat((char*)szStmtBuffer, (char*)szAuxBuffer); + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else{ + p->nError = 1 ; + printf("UPDATE in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** T_DELETE case **************************************/ + case T_DELETE: + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "DELETE * FROM %s WHERE COL0 = %f", p->szTableName, pRef[nNoOfCol*r]) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else if( 1 == p->nVerifyFlag && SQL_NO_DATA != retcode){ + p->nError = 1 ; + printf("\nVerification failed: still row exists\n") ; + }else{ + p->nError = 1 ; + printf("DELETE in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** default case **************************************/ + default: + break ; + }//switch +p->thread_status = S_IDLE ; + } //for + +free((void*)pBindBuffer) ; +GetHandles(&stHandles, FREE, 0) ; +p->thread_status = S_EXIT ; +return 0 ; + }; + + + +/************************************************* +Function: ThreadFnDouble - thread function +for double attributes +*************************************************/ +/* +void* ThreadFnDouble(void* pparams){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR szStmtBuffer[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szValueBuffer[MAX_VALUE_LEN] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLINTEGER cbDouble = 0 ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + int r = 0, j = 0 ; + + //Get thread parameters + PARAMS* p = (PARAMS*)pparams ; + double* pRef = (double*)p->pThreadRef ; + + double* pBindBuffer = (double*)malloc(sizeof(double)*nNoOfCol) ; + + //printf("Thread #%d\n", p->nThreadID) ; + + retcode = GetHandles(&stHandles, GET, 0) ; + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ) { + p->report_status = S_STARTED ; + }else{ + printf("Thread #%d failed to allocate handles, exiting now.\n", p->nThreadID) ; + free((void*)pBindBuffer) ; + p->report_status = S_EXIT ; + return 0 ; + } + //p->report_status = S_STARTED ; + + //Main thread loop + for(;;){ + + while(S_IDLE == p->thread_status){ + NdbSleep_MilliSleep(1) ; + } + + if(S_STOP == p->thread_status) { + break ; + }else{ + p->thread_status = S_BUSY ; + } + + switch(p->op_type){ + + + /************************************** T_INSERT case **************************************/ + /* case T_INSERT: + + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; + for(j = 0 ;;){ + sprintf((char*)szValueBuffer,"%.9f", pRef[nNoOfCol*r + j]) ; + strncat((char*)szStmtBuffer, (char*)szValueBuffer, strlen((const char*)szValueBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + strcat((char*)szStmtBuffer, ")") ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS), retcode) ; + } + + break ; + + + /************************************** T_READ case **************************************/ + /* case T_READ: + + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "SELECT * FROM %s WHERE COL0 = %.9f", p->szTableName, pRef[nNoOfCol*r]) ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmtBuffer, SQL_NTS), retcode) ; + for(j = 0 ; j < nNoOfCol ; ++j){ + ODBC_FN(SQLBindCol(stHandles.hstmt, (j+1), SQL_C_DOUBLE, (void*)&pBindBuffer[j], sizeof(SQLDOUBLE), &cbDouble), retcode) ; + } + for (;;) { + retcode = SQLFetch(stHandles.hstmt); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + for(int k = 0 ; k < nNoOfCol ; ++k){ + if(p->nVerifyFlag){ + if(abs(pBindBuffer[k] - pRef[nNoOfCol*r + k]) > DBLDEV) + printf("Expected: %.9f Actual: %.9f\n", pBindBuffer[k], pRef[nNoOfCol*r + k]) ; + } + } + }else if(SQL_NO_DATA == retcode){ + break ; + }else{ + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + //printf("\n") ; + } + SQLCloseCursor(stHandles.hstmt) ; + } + break ; + + + /************************************** T_UPDATE case **************************************/ + /* case T_UPDATE: + for(r = 0 ; r < nNoOfRows ; ++r){ + + sprintf((char*)szStmtBuffer, "UPDATE %s SET ", p->szTableName) ; + for(j = 1 ;;){ + pRef[nNoOfCol*r + j] = pRef[nNoOfCol*r + j] + UPDATE_VALUE ; + sprintf((char*)szColBuffer,"COL%d = %.9f", j, pRef[nNoOfCol*r + j]) ; + strncat((char*)szStmtBuffer, (char*)szColBuffer, strlen((char*)szColBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + sprintf((char*)szAuxBuffer, " WHERE COL0 = %.9f ;", pRef[nNoOfCol*r]) ; + strcat((char*)szStmtBuffer, (char*)szAuxBuffer); + ODBC_FN(SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS), retcode) ; + } + break ; + + + /************************************** T_DELETE case **************************************/ + /* case T_DELETE: + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "DELETE FROM %s WHERE COL0 = %.9f", p->szTableName, pRef[nNoOfCol*r]) ; + retcode = SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmtBuffer, SQL_NTS) ; + if( 1 == p->nVerifyFlag && SQL_NO_DATA != retcode ){ + printf("\nVerification failed: still row exists\n") ; + } + } + break ; + + + /************************************** default case **************************************/ + /* default: + break ; + }//switch +p->thread_status = S_IDLE ; + } //for + +free((void*)pBindBuffer) ; +GetHandles(&stHandles, FREE, 0) ; +p->thread_status = S_EXIT ; +return 0 ; + }; + + + +/************************************************* +Function: ThreadFnChar - thread function +for character attributes +*************************************************/ +void* ThreadFnChar(void* pparams){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR szStmtBuffer[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szValueBuffer[MAX_VALUE_LEN] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLINTEGER cbChar = 0 ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + int r = 0, j = 0 ; + + //Get thread parameters + PARAMS* p = (PARAMS*)pparams ; + char* pRef = (char*)p->pThreadRef ; + char* pBindBuffer = (char*)malloc(sizeof(char)*nNoOfCol*MAX_CHAR_ATTR_LEN) ; + + //printf("Thread #%d\n", p->nThreadID) ; + + retcode = GetHandles(&stHandles, GET, 0) ; + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ) { + p->report_status = S_STARTED ; + }else{ + printf("Thread #%d failed to allocate handles, retcode = %d, exiting now.\n", p->nThreadID, retcode) ; + p->nError = 1 ; + free((void*)pBindBuffer) ; + p->report_status = S_EXIT ; + return 0 ; + } + + //Main thread loop + for(;;){ + + while(S_IDLE == p->thread_status){ + NdbSleep_MilliSleep(1) ; + } + + if(S_STOP == p->thread_status) { + break ; + }else{ + p->thread_status = S_BUSY ; + } + + switch(p->op_type){ + + + /************************************** T_INSERT case **************************************/ + case T_INSERT: + + for(r = 0 ; r < nNoOfRows ; ++r){ + memset(szStmtBuffer, 0, strlen(szStmtBuffer)) ; + if(!nColList){ + sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; + }else{ + sprintf((char*)szStmtBuffer, "INSERT INTO %s (%s) VALUES(", p->szTableName, szColNames) ; + } + + for(j = 0 ;;){ + sprintf((char*)szValueBuffer,"'%s'", (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char) + j*MAX_CHAR_ATTR_LEN*sizeof(char))) ; + strncat((char*)szStmtBuffer, (char*)szValueBuffer, strlen((const char*)szValueBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + strcat((char*)szStmtBuffer, ")") ; + + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else{ + p->nError = 1 ; + printf("INSERT in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + + break ; + + + /************************************** T_READ case **************************************/ + case T_READ: + + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "SELECT * FROM %s WHERE COL0 = '%s'", p->szTableName, (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char))) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmtBuffer, SQL_NTS), retcode) ; + for(j = 0 ; j < nNoOfCol ; ++j){ + ODBC_FN(SQLBindCol(stHandles.hstmt, (j+1), SQL_C_CHAR, (void*)(pBindBuffer+j*MAX_CHAR_ATTR_LEN*sizeof(char)), MAX_CHAR_ATTR_LEN, &cbChar), retcode) ; + } + for (;;) { + retcode = SQLFetch(stHandles.hstmt); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + for(int k = 0 ; k < nNoOfCol ; ++k){ + if(p->nVerifyFlag){ + if(!strcmp((char*)(pBindBuffer + k*MAX_CHAR_ATTR_LEN*sizeof(char)), (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char) + k*MAX_CHAR_ATTR_LEN*sizeof(char)))) + printf("Expected: %s Actual: %s\n", (char*)(pBindBuffer + k*MAX_CHAR_ATTR_LEN*sizeof(char)), (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char) + k*MAX_CHAR_ATTR_LEN*sizeof(char))) ; + } + } + }else if(SQL_NO_DATA == retcode){ + break ; + }else{ + p->nError = 1 ; + printf("READ in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + //printf("\n") ; + } + SQLCloseCursor(stHandles.hstmt) ; + } + break ; + + + /************************************** T_UPDATE case **************************************/ + case T_UPDATE: + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "UPDATE %s SET ", p->szTableName) ; + for(j = 1 ;;){ + swab((char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char) + j*MAX_CHAR_ATTR_LEN*sizeof(char)), (char*)szColBuffer, MAX_CHAR_ATTR_LEN*sizeof(char)) ; + memcpy((void*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char) + j*MAX_CHAR_ATTR_LEN*sizeof(char)), (void*)szColBuffer, MAX_CHAR_ATTR_LEN*sizeof(char)) ; + sprintf((char*)szColBuffer,"COL%d = '%s'", j, (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char) + j*MAX_CHAR_ATTR_LEN*sizeof(char))) ; + strncat((char*)szStmtBuffer, (char*)szColBuffer, strlen((char*)szColBuffer)) ; + ++j ; + if(nNoOfCol == j) break ; + strcat((char*)szStmtBuffer, ", ") ; + } + sprintf( (char*)szAuxBuffer, " WHERE COL0 = '%s';", (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char)) ) ; + strcat((char*)szStmtBuffer, (char*)szAuxBuffer) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else{ + p->nError = 1 ; + printf("UPDATE in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** T_DELETE case **************************************/ + case T_DELETE: + for(r = 0 ; r < nNoOfRows ; ++r){ + sprintf((char*)szStmtBuffer, "DELETE FROM %s WHERE COL0 = '%s\'", p->szTableName, (char*)(pRef + nNoOfCol*r*MAX_CHAR_ATTR_LEN*sizeof(char))) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + if(SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + }else if(1 == p->nVerifyFlag && SQL_NO_DATA != retcode){ + p->nError = 1 ; + printf("\nVerification failed: still row exists\n") ; + }else{ + p->nError = 1 ; + printf("INSERT in thread #%d failed\n", p->nThreadID) ; + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + } + break ; + + + /************************************** default case **************************************/ + default: + break ; + }//switch + p->thread_status = S_IDLE ; + } //for + + free((void*)pBindBuffer) ; + GetHandles(&stHandles, FREE, 0) ; + p->thread_status = S_EXIT ; + return 0 ; +}; + + + +/************************************************* +Function: CreateDemoTable +*************************************************/ +SQLRETURN CreateDemoTables(char* szTableName, int nTables, table_opt op){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR szStmtBuffer[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLCHAR szAuxBuffer[32] = { 0 } ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + int c = 0 ; + + GetHandles(&stHandles, GET, 0) ; + + if(CREATE == op){ + + for(c = 0; c < nTables ; ++c){ + sprintf((char*)szStmtBuffer, "CREATE TABLE %s (", (char*)(szTableName+MAX_TABLE_NAME*c)) ; + int j = 0 ; + for(;;){ + sprintf((char*)szColBuffer, "COL%d ", j) ; + strcat((char*)szStmtBuffer, (char*)szColBuffer) ; + ++j ; + + switch(AttributeType){ + case T_INT: + strcat((char*)szStmtBuffer, "INTEGER") ; + break ; + case T_FLOAT: + strcat((char*)szStmtBuffer, "FLOAT") ; + break ; + +/* case T_DOUBLE: + strcat((char*)szStmtBuffer, "DOUBLE") ; + break ; +*/ + case T_CHAR: + sprintf((char*)szAuxBuffer, "CHAR(%d)", MAX_CHAR_ATTR_LEN) ; + strcat((char*)szStmtBuffer, (char*)szAuxBuffer) ; + break ; + default: + break ; + } + + if(nNoOfCol <= j){ + strcat((char*)szStmtBuffer, ")") ; + break ; + } + strcat((char*)szStmtBuffer, ", ") ; + } //for(;;) + + + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS), retcode) ; + if(SQL_SUCCESS != retcode) HandleError(stHandles.hstmt , SQL_HANDLE_STMT) ; + + + }// for() + + }else{ + + for(c = 0 ; c < nTables ; ++c){ + sprintf((char*)szStmtBuffer, "DROP TABLE %s ", (char*)(szTableName + MAX_TABLE_NAME*c)) ; + //ODBC_FN(SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS), retcode) ; + if(nPrint) printf("\n> %s\n", szStmtBuffer) ; + retcode = SQLExecDirect(stHandles.hstmt, szStmtBuffer, SQL_NTS) ; + } + + } + + GetHandles(&stHandles, FREE, 0) ; + + return retcode ; +} + + + +/************************************************* +Function: AssignTableNames() +*************************************************/ +inline void AssignTableNames(char* szBuffer, int nTables){ + for(int c = 0 ; c < nTables ; ++c){ + sprintf((char*)(szBuffer + MAX_TABLE_NAME*sizeof(char)*c), "TAB%d", c) ; + } +return ; + } + + + + +/************************************************* +Function: StartThreads() +*************************************************/ + +inline void StartThreads(PARAMS* p, void* pRef, int nTables, char* szTables, attr_type attrType, UintPtr* pHandles) { + + int* pInt = NULL ; + float* pFloat = NULL ; + double* pDouble = NULL ; + char* pChar = NULL ; + UintPtr pTmpThread = NULL ; + + bool bFlap = 1 ; + for(int f = 0 ; f < nNoOfThreads ; ++f){ + p[f].nThreadID = f ; + p[f].nError = 0 ; + p[f].thread_status = S_IDLE ; + p[f].op_type = T_WAIT ; + if(bFlap){ + strncpy((char*)p[f].szTableName, (char*)szTables, MAX_TABLE_NAME) ; + }else{ + strncpy((char*)p[f].szTableName, (char*)(szTables + MAX_TABLE_NAME*sizeof(char)), MAX_TABLE_NAME) ; + } + bFlap = !bFlap ; + //pTmpThread = pHandles[ ; + + switch(attrType){ + case T_INT: + pInt = (int*)pRef ; + p[f].pThreadRef = (void*)&pInt[nNoOfRows*nNoOfCol*f] ; + pHandles[f] = (UintPtr)NdbThread_Create(ThreadFnInt, (void**)&p[f], 32768, "SQL99_test", NDB_THREAD_PRIO_MEAN) ; + break ; + case T_FLOAT: + pFloat = (float*)pRef ; + p[f].pThreadRef = (void*)&pFloat[nNoOfRows*nNoOfCol*f] ; + pHandles[f] = (UintPtr)NdbThread_Create(ThreadFnFloat, (void**)&p[f], 32768, "SQL99_test", NDB_THREAD_PRIO_MEAN) ; + break ; + /* + case T_DOUBLE: + pDouble = (double*)pRef ; + p[f].pThreadRef = (void*)&pDouble[nNoOfRows*nNoOfCol*f] ; + pHandles[f] = (UintPtr)NdbThread_Create(ThreadFnDouble, (void**)&p[f], 32768, "SQL99_test", NDB_THREAD_PRIO_MEAN) ; + break ; + */ + case T_CHAR: + pChar = (char*)pRef ; + p[f].pThreadRef = (void*)&pChar[nNoOfRows*nNoOfCol*f*MAX_CHAR_ATTR_LEN] ; + pHandles[f] = (UintPtr)NdbThread_Create(ThreadFnChar, (void**)&p[f], 32768, "SQL99_test", NDB_THREAD_PRIO_MEAN) ; + default: + break ; + } + while(!(S_STARTED != p[f].report_status || S_EXIT != p[f].report_status)){ + NdbSleep_MilliSleep(1) ; + } + } + return ; +} + + + +/************************************************* +Function: SetThreadOperationType() +*************************************************/ +inline void SetThreadOperationType(PARAMS* p, type op){ + + for(int e = 0 ; e < nNoOfThreads ; ++e){ + p[e].nVerifyFlag = 0 ; + if(T_READ_VERIFY == op){ + p[e].nVerifyFlag = 1 ; + p[e].op_type = T_READ ; + }else if(T_DELETE_VERIFY == op){ + p[e].nVerifyFlag = 1 ; + p[e].op_type = T_DELETE ; + }else{ + p[e].op_type = op ; + } + p[e].thread_status = S_GET_BUSY ; + } +return ; + } + + + +/************************************************* +Function: WaitForThreads() +*************************************************/ +inline int WaitForThreads(PARAMS* p) { + + int ret_value = 0 ; + for(int w = 0 ; w < nNoOfThreads ; ++w){ + while(!(S_IDLE != p[w].thread_status || S_EXIT != p[w].report_status)) { + NdbSleep_MilliSleep(1) ; + } + ret_value += p[w].nError ; + } + return ret_value ; +} + + + +/************************************************* +Function: StopThreads() +*************************************************/ +inline void StopThreads(PARAMS* p, UintPtr* pHandles) { + + for(int k = 0 ; k < nNoOfThreads ; ++k){ + while(!(S_IDLE != p[k].thread_status || S_EXIT != p[k].report_status)){ + NdbSleep_MilliSleep(1) ; + } + p[k].thread_status = S_STOP ; + while(!(S_EXIT != p[k].thread_status || S_EXIT != p[k].report_status)){ + NdbSleep_MilliSleep(1) ; + } + NdbThread_Destroy((NdbThread**)&pHandles[k]) ; + } + + return ; +} + + + +/************************************************* +Function: PrintAll() +*************************************************/ +inline void PrintAll(char* szTableName, int nTables, attr_type attrType){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR* szStmt[MAX_SQL_STMT] = { 0 } ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + double* pDoubleBuffer = NULL ; + char* pCharBuffer = NULL ; + + if(T_CHAR != attrType){ + pDoubleBuffer = (double*)malloc(sizeof(double)*nNoOfCol) ; + }else{ + pCharBuffer = (char*)malloc(sizeof(char)*nNoOfCol*MAX_CHAR_ATTR_LEN) ; + } + + SQLINTEGER cbLen = 0 ; + + GetHandles(&stHandles, GET, 0) ; + + for(int c = 0 ; c < nTables ; ++c){ + + int nCol = 0, nRows = 0 ; + + printf("Table: \"%s\":\n------------------\n", (char*)(szTableName + MAX_TABLE_NAME*c*sizeof(char))) ; + + sprintf((char*)szStmt, "SELECT * FROM %s", (char*)(szTableName + MAX_TABLE_NAME*c*sizeof(char))) ; + if(nPrint) printf("\n> %s\n", szStmt) ; + ODBC_FN(SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmt, SQL_NTS), retcode) ; + + for(int i = 0 ; i < nNoOfCol ; ++i){ + + if(T_CHAR != attrType){ + ODBC_FN(SQLBindCol(stHandles.hstmt, (i+1), SQL_C_DOUBLE, (void*)&pDoubleBuffer[i], sizeof(SQLDOUBLE), &cbLen), retcode) ; + }else{ + ODBC_FN(SQLBindCol(stHandles.hstmt, (i+1), SQL_C_CHAR, (void*)(pCharBuffer + i*MAX_CHAR_ATTR_LEN*sizeof(char)), MAX_CHAR_ATTR_LEN*sizeof(char), &cbLen), retcode) ; + } + nCol++ ; + + } + + int k = 0 ; //out of the <for> loop + for (;;) { + + retcode = SQLFetch(stHandles.hstmt); + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ){ + for(k = 0 ; k < nNoOfCol ; ++k){ + if(T_CHAR != attrType){ + ATTR_TYPE_SWITCH_T(pDoubleBuffer[k], AttributeType) ; + }else{ + printf("%s\t", (char*)(pCharBuffer + k*MAX_CHAR_ATTR_LEN)) ; + } + } + }else if(SQL_NO_DATA == retcode){ + if(0 == k){ + printf("<empty>\n") ; + break ; + }else{ + break ; + } + }else{ + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + + ++nRows ; + printf("\n") ; + } + + SQLCloseCursor(stHandles.hstmt) ; + + printf("------------------\n") ; + printf("Rows: %d Columns: %d\n\n", nRows, nCol) ; + + } + + free((void*)pDoubleBuffer) ; + free((void*)pCharBuffer) ; + GetHandles(&stHandles, FREE, 0) ; + + return ; +} + + + +/************************************************* +Function: AssignRefCharValues() +*************************************************/ +void AssignRefCharValues(char* pRef, bool bVerbose) { + + int count = 0, rows = 0, nThreadOffset = 0, nRowOffset = 0 ; + char szStrBuffer[MAX_CHAR_ATTR_LEN] = { 0 } ; + int char_count = sizeof(szANSI)/sizeof(char) ; + + for(int c = 0 ; c < nNoOfThreads ; ++c){ + nThreadOffset = nNoOfRows*nNoOfCol*c*MAX_CHAR_ATTR_LEN*sizeof(char) ; + for(int d = 0 ; d < nNoOfRows ; ++d){ + nRowOffset = nNoOfCol*d*MAX_CHAR_ATTR_LEN*sizeof(char) ; ++rows ; + for(int i = 0 ; i < nNoOfCol ; ++i){ + for(int j = 0 ; j < (MAX_CHAR_ATTR_LEN - 2) ; ++j){ + int h = (char)(rand() % (char_count-1)) ; + szStrBuffer[j] = szANSI[h] ; + } + szStrBuffer[MAX_CHAR_ATTR_LEN - 1] = '\0' ; + + strcpy((char*)(pRef + nThreadOffset + nRowOffset + i*MAX_CHAR_ATTR_LEN*sizeof(char)), (char*)szStrBuffer) ; + count++ ; + if(bVerbose){ + printf(" %s ", (char*)(pRef + nThreadOffset + nRowOffset + i*MAX_CHAR_ATTR_LEN*sizeof(char))) ; + } + } + if(bVerbose) { + printf("\n") ; + NdbSleep_MilliSleep(10) ; + } + } + } + +if(bVerbose){ + printf("_____________________") ; + printf("\nRows: %d Values: %d\n\n", rows, count) ; + } + +return ; + } + + +/* + + +sprintf((char*)szStmtBuffer, "INSERT INTO %s VALUES(", p->szTableName) ; +for(j = 0 ;;){ +strcat((char*)szStmtBuffer, "?") ; +++j ; +if(nNoOfCol == j) break ; +strcat((char*)szStmtBuffer, ", ") ; +} +strcat((char*)szStmtBuffer, ")") ; + +ODBC_FN(SQLPrepare(stHandles.hstmt, szStmtBuffer, SQL_NTS), retcode) ; + +for(j = 0 ; j < nNoOfCol ; ++j){ +ODBC_FN(SQLBindParameter(stHandles.hstmt, (j+1), SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, (void*)&pBindBuffer[j], 0, &cbFloat), retcode) ; +HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; +} + +for(r = 0 ; r < nNoOfRows ; ++r){ +for(j = 0 ; j < nNoOfCol ; ++j){ +pBindBuffer[j] = pRef[nNoOfCol*r + j] ; +} +ODBC_FN(SQLExecute(stHandles.hstmt), retcode) ; +HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; +} + +*/ + + + + +/************************************************* +Function: HandleError +*************************************************/ + +void HandleError(void* handle, SQLSMALLINT HandleType){ + + SQLCHAR szError[MAX_STR_LEN], szSqlState[32] ; + SQLINTEGER nError = 0 ; + SQLSMALLINT nHandleType = HandleType ; + SQLSMALLINT nLength = 0 ; + SQLHANDLE SQLHandle = handle ; + SQLGetDiagRec(nHandleType, SQLHandle, 1, szSqlState, &nError, szError, 128, &nLength) ; + printf("Error: %s\nSqlState: %s\n", szError, szSqlState) ; + + return ; + } + + + +/************************************************* +Function: ReportError +*************************************************/ + +void ReportError(char* szFn, char* szBuffer, char* szFile, int iLine){ + + printf("%s %s\nFile: %s\nLine: %d\n", szFn, szBuffer, szFile, iLine) ; + + return ; +} + + + +/************************************************* +Function: GetHandles() +*************************************************/ + +SQLRETURN GetHandles(ODBC_HANDLES* pHandles, handle_op op, bool bDriverInfo){ + + SQLRETURN retcode = SQL_ERROR ; + + if(GET == op){ + + retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &pHandles->henv); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ) { + retcode = SQLSetEnvAttr(pHandles->henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC2, 0); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode) { + retcode = SQLAllocHandle(SQL_HANDLE_DBC, pHandles->henv, &pHandles->hdbc); + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode) { + + //SQLSetConnectAttr(pHandles->hdbc, SQL_LOGIN_TIMEOUT, (void*)5, 0); + + retcode = SQLConnect(pHandles->hdbc, (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS ) ; + + SQL_SUCCESS == SQLSetConnectAttr(pHandles->hdbc, SQL_ATTR_AUTOCOMMIT, (void*)SQL_AUTOCOMMIT_ON, 0) ; + //printf("AUTOCOMMIT is on\n") ; + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode) { + // retcode still holds the value returned by SQLConnect + retcode = SQLAllocHandle(SQL_HANDLE_STMT, pHandles->hdbc, &pHandles->hstmt) ; + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode) { + if(bDriverInfo) GetDriverAndSourceInfo(pHandles->hdbc) ; + // printf("All handles allocated OK\n", retcode); + }else{ // SQLAllocHandle() + REPORTERROR((char*)"SQLAllocHandle()", (char*)"failed") ; + HandleError(pHandles->hdbc, SQL_HANDLE_DBC) ; + ODBC_FN(SQLDisconnect(pHandles->hdbc), retcode) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_DBC, pHandles->hdbc), retcode) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_ENV, pHandles->henv), retcode) ; + retcode = SQL_ERROR ; + } + }else{ // SQLConnect() + REPORTERROR((char*)"SQLConnect()", (char*)"failed" ) ; + HandleError(pHandles->hdbc, SQL_HANDLE_DBC) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_DBC, pHandles->hdbc), retcode) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_ENV, pHandles->henv), retcode) ; + retcode = SQL_ERROR ; + } + }else{ // SQLAllocHandle() + REPORTERROR((char*)"SQLAllocHandle()", "failed" ) ; + HandleError(pHandles->hdbc, SQL_HANDLE_DBC) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_ENV, pHandles->henv), retcode) ; + retcode = SQL_ERROR ; + } + }else{ // SQLSetEnvAttr() + REPORTERROR((char*)"SQLSetEnvAttr()", "failed" ) ; + HandleError(pHandles->henv, SQL_HANDLE_ENV) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_ENV, pHandles->henv), retcode) ; + retcode = SQL_ERROR ; + } + }else{ // SQLAllocHandle() + REPORTERROR((char*)"SQLAllocHandle()", "failed" ) ; + HandleError(pHandles->henv, SQL_HANDLE_ENV) ; + retcode = SQL_ERROR ; + } + }else{ + ODBC_FN(SQLFreeHandle(SQL_HANDLE_STMT, pHandles->hstmt), retcode) ; + ODBC_FN(SQLDisconnect(pHandles->hdbc), retcode) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_DBC, pHandles->hdbc), retcode) ; + ODBC_FN(SQLFreeHandle(SQL_HANDLE_ENV, pHandles->henv), retcode) ; + } + + return retcode ; +} + + + +/************************************************* +Function: AggretateFn(): +<aggr_fn fn> - name of the aggregate function to use +<char* szTableName> - name of the table +<int nCol> - number of the column +<double* pdIn> - pointer to double containing the value to be used in a call to COUNT; used only by this function +<double* pdOut> - pointer to double that will recieve the result +<attr_type attrType> - type of the attribute +*************************************************/ +SQLRETURN AggregateFn(aggr_fn fn, char* szTableName, int nCol, double* pdIn, double* pdOut, attr_type attrType){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR* szStmt[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szValueBuffer[MAX_VALUE_LEN] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + SQLINTEGER cbDouble = 0 ; + + GetHandles(&stHandles, GET, 0) ; + + switch(fn){ + case FN_COUNT: + switch(attrType){ + case T_INT: + sprintf((char*)szStmt, "SELECT COUNT(*) FROM %s WHERE COL%d > %d", szTableName, nCol, (int)*pdIn) ; + break ; + case T_FLOAT: + sprintf((char*)szStmt, "SELECT COUNT(*) FROM %s WHERE COL%d > %f", szTableName, nCol, (float)*pdIn) ; + break ; +/* case T_DOUBLE: + sprintf((char*)szStmt, "SELECT COUNT(*) FROM %s WHERE COL%d > %.15f", szTableName, nCol, *pdIn) ; + break ; +*/ + default: + break ; + } + break ; + case FN_SUM: + sprintf((char*)szStmt, "SELECT SUM(COL%d) FROM %s", nCol, szTableName) ; + break ; + case FN_AVG: + sprintf((char*)szStmt, "SELECT AVG(COL%d) FROM %s", nCol, szTableName) ; + break ; + case FN_MAX: + sprintf((char*)szStmt, "SELECT MAX(COL%d) FROM %s", nCol, szTableName) ; + break ; + case FN_MIN: + sprintf((char*)szStmt, "SELECT MIN(COL%d) FROM %s", nCol, szTableName) ; + break ; + case FN_VARIANCE: // not implemented + //sprintf((char*)szStmt, "SELECT VARIANCE(COL%d) FROM %s;", nCol, szTableName) ; + break ; + case FN_STDDEV: // not implemented + //sprintf((char*)szStmt, "SELECT STDDEV(COL%d) FROM %s;", nCol, szTableName) ; + break ; + default: + break ; + } +//printf("%s\n", szStmt) ; + +retcode = SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmt, SQL_NTS) ; +if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ){ + retcode = SQLBindCol(stHandles.hstmt, 1, SQL_C_DOUBLE, (void*)pdOut, sizeof(SQLDOUBLE), &cbDouble) ; + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode ){ + retcode = SQLFetch(stHandles.hstmt) ; + } + } + +if(SQL_SUCCESS != retcode && SQL_SUCCESS_WITH_INFO != retcode){ + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + +SQLCloseCursor(stHandles.hstmt) ; + +GetHandles(&stHandles, FREE, 0) ; + +return retcode ; + + }; + + + +/************************************************* +Function: GetDriverAndSourceInfo() +*************************************************/ +SQLRETURN GetDriverAndSourceInfo(SQLHDBC hdbc){ + + SQLRETURN retcode = SQL_ERROR ; + + SQLCHAR buffer[255] ; + SQLUSMALLINT snValue = 0 ; + SQLSMALLINT outlen = 0 ; + + printf( "-------------------------------------------\n" ) ; + + retcode = SQLGetInfo( hdbc, SQL_DATA_SOURCE_NAME, buffer, 255, &outlen ) ; + + printf( "Connected to Server: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_DATABASE_NAME, buffer, 255, &outlen ) ; + printf( " Database name: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_SERVER_NAME, buffer, 255, &outlen ) ; + printf( " Instance name: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_DBMS_NAME, buffer, 255, &outlen ) ; + printf( " DBMS name: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_DBMS_VER, buffer, 255, &outlen ) ; + printf( " DBMS version: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_ODBC_VER, buffer, 255, &outlen ) ; + printf( " ODBC version: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_DRIVER_NAME, buffer, 255, &outlen ) ; + printf( " Driver name: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_DRIVER_VER, buffer, 255, &outlen ) ; + printf( " Driver version: %s\n", buffer ) ; + + retcode = SQLGetInfo( hdbc, SQL_MAX_DRIVER_CONNECTIONS, &snValue, sizeof(SQLSMALLINT), &outlen ) ; + printf( " Max connections: %d\n", snValue ) ; + + retcode = SQLGetInfo( hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, &snValue, sizeof(SQLSMALLINT), &outlen ) ; + printf( "Autocommit behavior:") ; + + switch(snValue){ + case SQL_CB_DELETE: + printf(" SQL_CB_DELETE\n") ; + break ; + case SQL_CB_CLOSE: + printf(" SQL_CB_CLOSE\n") ; + break ; + case SQL_CB_PRESERVE: + printf(" SQL_CB_PRESERVE\n") ; + break ; + default: + printf(" undefined\n") ; + break ; + } + + printf( "-------------------------------------------\n" ) ; + + return retcode ; + +} + + + +/************************************************* +Function: ArithOp() +*************************************************/ + +int ArithOp(char* szTable, int nTotalCols, float* pValue, attr_type attrType, arth_op op){ + + SQLRETURN retcode = SQL_ERROR ; + int nVerRet = -1 ; + SQLCHAR szStmt[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szEndBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + + void* pBuffer = NULL ; + SQLINTEGER BindInt = 0, IntResult = 0, RefIntResult = 0 ; + SQLFLOAT BindFloat = 0, FloatResult = 0, RefFloatResult = 0 ; + SQLDOUBLE BindDouble = 0, DoubleResult = 0, RefDoubleResult = 0 ; + SQLINTEGER cbSize = 0 ; + SQLINTEGER cbLen = 0 ; + SQLSMALLINT cbTarget = 0 ; + + GetHandles(&stHandles, GET, 0) ; + + for(int c = 0 ; c < nTotalCols ; ++c){ + + sprintf((char*)szStmt, "SELECT COL%d, (COL%d", c, c) ; + switch(op){ + case MINUS: + strcat((char*)szStmt, " - ") ; + break ; + case PLUS: + strcat((char*)szStmt, " + ") ; + break ; + case MULTI: + strcat((char*)szStmt, " * ") ; + break ; + case DIVIDE: + strcat((char*)szStmt, " / ") ; + break ; + case MODULO: + //strcat((char*)szStmt, " % ") ; Not implemented + GetHandles(&stHandles, FREE, 0) ; + return -1 ; //Close handles and return + break ; + default: + break ; + } + + sprintf((char*)(szAuxBuffer),"%.9f) ", *((float*)(pValue))) ; + strcat((char*)szStmt, (char*)szAuxBuffer) ; + sprintf((char*)szEndBuffer, "FROM %s", szTable) ; + strcat((char*)szStmt, (char*)szEndBuffer) ; + + ODBC_FN(SQLExecDirect(stHandles.hstmt, (SQLCHAR*)szStmt, SQL_NTS), retcode) ; + if(retcode == SQL_ERROR){ + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + printf("\n%s\n", szStmt) ; + } + + SQLSMALLINT cbNameLen = 0, cbSqlType = 0, cbNullable = 0, cbColScale = 0 ; + SQLINTEGER cbColSize = 0 ; + SQLDescribeCol(stHandles.hstmt, 2, szColBuffer, MAX_COL_NAME-1, &cbNameLen, &cbSqlType, (unsigned long*)&cbColSize, &cbColScale, &cbNullable) ; + + switch(cbSqlType){ + case SQL_NUMERIC: + pBuffer = &IntResult ; + cbSize = sizeof(SQLINTEGER) ; + cbTarget = SQL_C_ULONG ; + case SQL_INTEGER: + pBuffer = &IntResult ; + cbSize = sizeof(SQLINTEGER) ; + cbTarget = SQL_C_LONG ; + break ; + case SQL_FLOAT: + pBuffer = &FloatResult ; + cbSize = sizeof(SQLFLOAT) ; + cbTarget = SQL_C_FLOAT ; + break ; + case SQL_DOUBLE: + pBuffer = &DoubleResult ; + cbSize = sizeof(SQLDOUBLE) ; + cbTarget = SQL_C_DOUBLE ; + break ; + default: + printf("\nUndefined result type: %d\n", cbSqlType) ; + break ; + } + + switch(attrType){ + case T_INT: + ODBC_FN(SQLBindCol(stHandles.hstmt, 1, SQL_C_SLONG, (void*)&BindInt, sizeof(SQLINTEGER), &cbLen), retcode) ; + break ; + case T_FLOAT: + ODBC_FN(SQLBindCol(stHandles.hstmt, 1, SQL_C_FLOAT, (void*)&BindFloat, sizeof(SQLFLOAT), &cbLen), retcode) ; + break ; + /* case T_DOUBLE: + ODBC_FN(SQLBindCol(stHandles.hstmt, 1, SQL_C_DOUBLE, (void*)&BindDouble, sizeof(SQLDOUBLE), &cbLen), retcode) ; + break ; + */ + default: + break ; + } + + ODBC_FN(SQLBindCol(stHandles.hstmt, 2, cbTarget, pBuffer, cbSize, &cbLen), retcode) ; + + retcode = SQLFetch(stHandles.hstmt) ; + + if (SQL_SUCCESS == retcode || SQL_SUCCESS_WITH_INFO == retcode){ + switch(attrType){ + case T_INT: + switch(cbSqlType){ + case SQL_INTEGER: + nVerRet = VerifyArthOp((int*)&BindInt, pValue, (int*)pBuffer, op) ; + break ; + case SQL_FLOAT: + nVerRet = VerifyArthOp((int*)&BindInt, pValue, (float*)pBuffer, op) ; + break ; + case SQL_DOUBLE: + nVerRet = VerifyArthOp((int*)&BindInt, pValue, (double*)pBuffer, op) ; + break ; + case SQL_NUMERIC: + nVerRet = VerifyArthOp((int*)&BindInt, pValue, (int*)pBuffer, op) ; + break ; + default: + break ; + } + break ; + + case T_FLOAT: + switch(cbSqlType){ + case SQL_INTEGER: + nVerRet = VerifyArthOp((float*)&BindFloat, pValue, (int*)pBuffer, op) ; + break ; + case SQL_FLOAT: + nVerRet = VerifyArthOp((float*)&BindFloat, pValue, (float*)pBuffer, op) ; + break ; + case SQL_DOUBLE: + nVerRet = VerifyArthOp((float*)&BindFloat, pValue, (double*)pBuffer, op) ; + break ; + default: + break ; + } + break ; + /* case T_DOUBLE: + switch(cbSqlType){ + case SQL_INTEGER: + nVerRet = VerifyArthOp((double*)&BindDouble, pValue, (int*)pBuffer, op) ; + break ; + case SQL_FLOAT: + nVerRet = VerifyArthOp((double*)&BindDouble, pValue, (float*)pBuffer, op) ; + break ; + case SQL_DOUBLE: + nVerRet = VerifyArthOp((double*)&BindDouble, pValue, (double*)pBuffer, op) ; + break ; + default: + break ; + } + break ; + */ + default: + break ; + } + if(-1 == nVerRet){ + printf("\nVerification failed.\n") ; + return nVerRet ; + }else if(SQL_NO_DATA == retcode){ + break ; + } + }else{ + + HandleError(stHandles.hstmt, SQL_HANDLE_STMT) ; + } + + SQLCloseCursor(stHandles.hstmt) ; + } + + GetHandles(&stHandles, FREE, 0) ; + + return nVerRet ; +} + + + + +/************************************************* +Function: Join() +*************************************************/ +SQLRETURN Join(char* szTable, int nTables, int nCol, join_type joinType){ + + SQLRETURN retcode = SQL_ERROR ; + SQLCHAR szStmt[MAX_SQL_STMT] = { 0 } ; + SQLCHAR szEndBuffer[MAX_STR_LEN] = { 0 } ; + SQLCHAR szColBuffer[MAX_COL_NAME] = { 0 } ; + SQLCHAR szAuxBuffer[MAX_STR_LEN] = { 0 } ; + + ODBC_HANDLES stHandles ; + memset(&stHandles, 0, sizeof(ODBC_HANDLES)) ; + + int c = 0, t = 0 ; + + GetHandles(&stHandles, GET, 0) ; + + for(c = 0 ; c < nCol ; ++c) { + + switch(joinType){ + case ITSELF: + sprintf((char*)szStmt, "SELECT * FROM %s, %s", (char*)szTable, (char*)szTable) ; + break ; + case EQUI: + break ; + case NON_EQUI: + break ; + case INNER: + break ; + case OUTTER: + break ; + default: + break ; + } + } + +GetHandles(&stHandles, FREE, 0) ; + +return retcode ; + +} + + + +SQLRETURN GetResults(SQLHSTMT){ + + SQLRETURN retcode = SQL_ERROR ; + + return retcode ; +} + +/* + +int createTables(char* szTableName, int nTables){ + + for (int i = 0; i < nNoOfCol; i++){ + snprintf(attrName[i], MAXSTRLEN, "COL%d", i) ; + } + + for (int i = 0; i < nTables; i++){ + snprintf(tableName[i], MAXSTRLEN, "TAB%d", i) ; + } + + for(unsigned i = 0; i < nTables; i++){ + + ndbout << "Creating " << szTableName[i] << "... " ; + + NDBT_Table tmpTable(szTableName[i]) ; + + tmpTable.setStoredTable(!theTempTable) ; + + tmpTable.addAttribute(NDBT_Attribute(attrName[0], + UnSigned, + 4, // 4 Bytes + TupleKey)); + } + + + for (int j = 1 ; j < nNoOfCol ; j++) + tmpTable.addAttribute(NDBT_Attribute(attrName[j], UnSigned, 4*tAttributeSize)) ; + + if(tmpTable.createTableInDb(pMyNdb) == -1){ + return -1 ; + } + + ndbout << "done" << endl ; + + return 0; +} +*/ + +/************************************************* +Function: createTables() +Uses NDB API to create tables for the tests +*************************************************/ + +int createTables(char* szTableName, int nTables){ + + Ndb * pNdb = new Ndb("TEST_DB") ; + pNdb->init(); + + ndbout << "Waiting for ndb to become ready..." <<endl; + if (pNdb->waitUntilReady(10000) != 0){ + ndbout << "NDB is not ready" << endl; + ndbout << "Benchmark failed!" << endl; + delete pNdb ; + return -1 ; + } + + NdbSchemaCon *MySchemaTransaction = NULL ; + NdbSchemaOp *MySchemaOp = NULL ; + int check = -1 ; + char szColNameBuffer[MAX_COL_NAME] = { 0 } ; + int tLoadFactor = 80 ; + + for(int i=0 ; i < nTables ; ++i) { + + ndbout << "Creating " << (char*)(szTableName+MAX_TABLE_NAME*i) << "..." << endl ; + + MySchemaTransaction = pNdb->startSchemaTransaction() ; + //printf("MySchemaTransaction - OK\n") ; + if(MySchemaTransaction == NULL){ + printf("MySchemaTransaction is NULL\n") ; + delete pNdb ; + return -1 ; + } + + MySchemaOp = MySchemaTransaction->getNdbSchemaOp(); + //printf("MySchemaTransaction->getNdb... - OK\n") ; + if(MySchemaOp == NULL){ + printf("MySchemaOp is NULL\n") ; + delete pNdb ; + return -1 ; + } + + check = MySchemaOp->createTable( (const char*)(szTableName+MAX_TABLE_NAME*i) + ,8 // Table Size + ,TupleKey // Key Type + ,40 // Nr of Pages + ,All + ,6 + ,(tLoadFactor - 5) + ,(tLoadFactor) + ,1 + ,0 + ); + + if (check == -1){ + printf("MySchemaOp->createTable failed\n") ; + delete pNdb ; + return -1 ; + } + + snprintf(szColNameBuffer, MAX_COL_NAME, "COL%d", 0) ; + check = MySchemaOp->createAttribute( szColNameBuffer, + TupleKey, + 32, + PKSIZE, + UnSigned, + MMBased, + NotNullAttribute ); + + if (check == -1){ + printf("MySchemaOp->createAttribute() #1 failed\n") ; + delete pNdb ; + return -1 ; + } + + for (int j = 1; j < nNoOfCol ; j++){ + snprintf(szColNameBuffer, MAX_COL_NAME, "COL%d", j) ; + check = MySchemaOp->createAttribute(szColNameBuffer, + NoKey, + 32, + tAttributeSize, + UnSigned, + MMBased, + NotNullAttribute ); + + if (check == -1){ + printf("MySchemaOp->createAttribute() #2 failed\n") ; + delete pNdb ; + return -1; + } + } + + if (MySchemaTransaction->execute() == -1){ + printf("MySchemaTransaction->execute() failed\n") ; + printf("%s\n", MySchemaTransaction->getNdbError().message) ; + return -1 ; + delete pNdb ; + } + + pNdb->closeSchemaTransaction(MySchemaTransaction); + } + + return 0; +} + + + diff --git a/ndb/test/odbc/SQL99_test/SQL99_test.h b/ndb/test/odbc/SQL99_test/SQL99_test.h new file mode 100644 index 00000000000..1c49f4a9a51 --- /dev/null +++ b/ndb/test/odbc/SQL99_test/SQL99_test.h @@ -0,0 +1,261 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include <ndb_types.h> +#include <NdbThread.h> +#include <NdbOut.hpp> +#include <NdbSleep.h> +#include <NDBT.hpp> +#include <sqlext.h> +#include <stdio.h> +//#include <stdlib.h> +#include <unistd.h> +//#include <windows.h> +//#include <process.h> + +#define MAX_STR_LEN 128 +#define MAX_TABLE_NAME 32 +#define MAX_COL_NAME 32 +#define MAX_SQL_STMT 2048 +#define MAX_VALUE_LEN 32 +#define MAX_CHAR_ATTR_LEN 24 +#define NUM_COL_ARITHM 2 +#define FLTDEV 0.0001 +//#define DBLDEV 0.000000001 + +#define REPORTERROR(fn, str) ReportError(fn, str, __FILE__, __LINE__) +#define REPORT(str) printf((str)) + +#define ATTR_TYPE_SWITCH(buffer, ptr, attr) switch(attr){ \ + case T_INT:\ + sprintf((char*)(buffer),"%d", (int)(ptr)) ;\ + break ;\ + case T_FLOAT:\ + sprintf((char*)(buffer),"%f", (float)(ptr)) ;\ + break ;\ + default:\ + break ;\ + } + +#define ATTR_TYPE_SWITCH_T(value, attr) switch(attr){ \ + case T_INT:\ + printf("%d \t", (int)(value)) ;\ + break ;\ + case T_FLOAT:\ + printf("%f \t", (float)(value)) ;\ + break ;\ + default:\ + break ;\ + } + +#define ATTR_TYPE_SWITCH_AGR(str, value_A, value_B, value_C, attr) switch(attr){ \ + case T_INT:\ + printf("%s\t%d %d\t\t\t%d\n\n", str, value_A, (int)value_B, (int)value_C) ; break ;\ + case T_FLOAT:\ + printf("%s\t%d %f\t\t\t%d\n\n", str, value_A, value_B, (int)value_C) ; break ;\ + default:\ + break ;\ + } + + +#define ODBC_FN(fn, rc) rc = ((((fn)))) ; if(SQL_SUCCESS == rc || SQL_SUCCESS_WITH_INFO == rc){;}else ReportError("ODBC function", "failed in ", __FILE__, __LINE__) + + +typedef enum attr_type_tag { + T_INT, + T_FLOAT, +// T_DOUBLE, + T_CHAR +} attr_type ; + +typedef enum aggr_fn_tag { + FN_COUNT, + FN_SUM, + FN_AVG, + FN_MAX, + FN_MIN, + FN_VARIANCE, + FN_STDDEV +} aggr_fn ; + +typedef enum join_type_tag { + ITSELF, + EQUI, + NON_EQUI, + INNER, + OUTTER +} join_type ; + +typedef enum arth_op_tag { + MINUS, + PLUS, + MULTI, + DIVIDE, + MODULO +} arth_op ; + +typedef struct ODBC_HANDLES_tag{ + SQLHENV henv ; + SQLHDBC hdbc ; + SQLHSTMT hstmt ; +} ODBC_HANDLES ; + +typedef enum handle_op_tag{ + GET, + FREE +} handle_op ; + +typedef enum test_case_tag { + NUMERIC_DATA_TYPES, + CHAR_DATA_TYPES, + IDENTIFIERS, + BASIC_QUERY, + PREDICATE_SEARCH, + DATA_MANIPULATION, + NULL_SUPPORT, + BASIC_CONSTRAINTS, + TRANSACTION, + SET_FUNCTIONS, + BASIC_SCHEMA, + JOINED_TABLE, + ALL +} test_case ; + +typedef enum status_tag{ + S_STOP, + S_IDLE, + S_STARTED, + S_GET_BUSY, + S_BUSY, + S_EXIT +} status ; + +typedef enum type_tag { + T_INSERT, + T_READ, + T_UPDATE, + T_DELETE, + T_READ_VERIFY, + T_DELETE_VERIFY, + T_WAIT +} type ; + +typedef struct PARAMS_tag { + int nThreadID ; + int nError ; + int nVerifyFlag ; + status thread_status ; + status report_status ; + type op_type ; + void* pThreadRef ; + char szTableName[MAX_TABLE_NAME] ; +} PARAMS ; + +typedef enum table_opt_tag { + CREATE, + DROP +} table_opt ; + +static char szANSI[] ="0123456789ABCEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ; + +void ReportError(char* szFn, char* szBuffer, char* szFile, int iLine) ; +void HandleError(void*, SQLSMALLINT) ; +SQLRETURN GetHandles(ODBC_HANDLES*, handle_op, bool) ; +SQLRETURN AggregateFn(aggr_fn, char*, int, double*, double*, attr_type) ; +SQLRETURN GetDriverAndSourceInfo(SQLHDBC) ; +SQLRETURN Join(char*, join_type) ; +SQLRETURN GetResults(SQLHSTMT) ; +int ArithOp(char*, int, float*, attr_type, arth_op) ; +void ParseArguments(int argc, const char** argv) ; +void* ThreadFnInt(void*) ; +void* ThreadFnFloat(void*) ; +//void* ThreadFnDouble(void*) ; +void* ThreadFnChar(void*) ; +inline void AssignTableNames(char* szBuffer, int nTables) ; +SQLRETURN CreateDemoTables(char*, int, table_opt) ; +inline void StartThreads(PARAMS*, void*, int, char*, attr_type, UintPtr*) ; +inline void SetThreadOperationType(PARAMS*, type) ; +inline int WaitForThreads(PARAMS*) ; +inline void StopThreads(PARAMS*, UintPtr*) ; +inline void PrintAll(char* szTableName, int, attr_type) ; +void AssignRefCharValues(char*, bool) ; + +template <class T, class V> +int VerifyArthOp(V* tValue, float* tOperand, T* tRes, arth_op op){ + + int nResult = 0 ; + int nValue = 0, nOperand = 0 ; + + switch(op){ + case MINUS: + if(FLTDEV < abs((*tValue - *tOperand) - *tRes)) + nResult = -1 ; + break ; + case PLUS: + if(FLTDEV < abs((*tValue + *tOperand) - *tRes)) + nResult = -1 ; + break ; + case MULTI: + if(FLTDEV < abs((*tValue * *tOperand) - *tRes)) + nResult = -1 ; + break ; + case DIVIDE: + if(FLTDEV < abs((*tValue / *tOperand) - *tRes)) + nResult = -1 ; + break ; + case MODULO: + nValue = *tValue ; + nOperand = *tOperand ; + if(*tRes != (nValue % nOperand)) + nResult = -1 ; + break ; + } + + return nResult ; +} + +template <class P> void AssignRefNumValues(P* pRef, attr_type attrType, bool bVerbose) { + + int count = 0, rows = 0, nThreadOffset = 0, nRowOffset = 0 ; + P* p = (P*)pRef ; + + float fRandomBase = (rand()*rand()) % 100; + for(int c = 0 ; c < nNoOfThreads ; ++c){ + nThreadOffset = nNoOfRows*nNoOfCol*c ; + for(int d = 0 ; d < nNoOfRows ; ++d){ + nRowOffset = nNoOfCol*d ; ++rows ; + for(int i = 0 ; i < nNoOfCol ; ++i){ + (p[nThreadOffset + nRowOffset + i]) = (fRandomBase*(c+1) + (d+3)*7 + i)/1.1034093201 ; + ++count ; + if(bVerbose){ + ATTR_TYPE_SWITCH_T(p[nThreadOffset + nRowOffset + i], AttributeType) ; + } + } + if(bVerbose) { printf("\n") ; NdbSleep_MilliSleep(10) ; + } + } + } + + if(bVerbose){ + printf("_____________________") ; + printf("\nRows: %d Values: %d\n\n", rows, count) ; + } + + return ; +} + + diff --git a/ndb/test/odbc/client/Makefile b/ndb/test/odbc/client/Makefile new file mode 100644 index 00000000000..4b962f5b65a --- /dev/null +++ b/ndb/test/odbc/client/Makefile @@ -0,0 +1,95 @@ +include .defs.mk + +TYPE := odbcclient +#TYPE := odbcdriver + +BIN_TARGET := testOdbcClient +#BIN_TARGET := testodbc2 + + +# Source files of non-templated classes (.C files) +SOURCES = main.cpp \ + SQLFetchTest.cpp \ + SQLDisconnectTest.cpp \ + SQLTablesTest.cpp \ + SQLGetInfoTest.cpp \ + SQLGetTypeInfoTest.cpp \ + SQLGetFunctionsTest.cpp \ + SQLGetDataTest.cpp \ + SQLCancelTest.cpp \ + SQLTransactTest.cpp \ + SQLGetCursorNameTest.cpp \ + SQLSetCursorNameTest.cpp \ + SQLRowCountTest.cpp \ + SQLNumResultColsTest.cpp \ + SQLDescribeColTest.cpp \ + SQLExecDirectTest.cpp \ + SQLColAttributeTest.cpp \ + SQLColAttributeTest1.cpp \ + SQLColAttributeTest2.cpp \ + SQLColAttributeTest3.cpp \ + SQLBindColTest.cpp \ + SQLDriverConnectTest.cpp \ + SQLPrepareTest.cpp \ + SQLGetDiagRecSimpleTest.cpp \ + SQLConnectTest.cpp + +XSOURCES = testodbc2.cpp +XSOURCES = \ + main.cpp \ + SQLDriverConnectTest.cpp \ + SQLPrepareTest.cpp \ + SQLMoreResultsTest.cpp \ + SQLGetStmtAttrTest.cpp \ + SQLGetEnvAttrTest.cpp \ + SQLGetConnectAttrTest.cpp \ + SQLExecuteTest.cpp \ + SQLExecDirectTest.cpp \ + SQLDisconnectTest.cpp \ + SQLCloseCursorTest.cpp \ + SQLCancelTest.cpp \ + SQLBindColTest.cpp \ + SQLDescribeColTest.cpp \ + SQLGetTypeInfoTest.cpp \ + SQLGetFunctionsTest.cpp \ + SQLNumResultColsTest.cpp \ + SQLSetDescFieldTest.cpp \ + SQLGetDescRecTest.cpp \ + SQLEndTranTest.cpp \ + SQLGetInfoTest.cpp \ + SQLConnectTest.cpp \ + SQLAllocHandleTest.cpp \ + SQLAllocEnvTest.cpp \ + SQLRowCountTest.cpp \ + SQLFetchScrollTest.cpp \ + SQLFetchTest.cpp \ + SQLGetDescFieldTest.cpp \ + SQLSetDescRecTest.cpp \ + SQLFreeHandleTest.cpp + +ifeq ($(TYPE),odbcdriver) +LIBS_SPEC += \ + -lodbcdriver_pic \ + -lodbchandles_pic \ + -lodbccodegen_pic \ + -lodbccompiler_pic \ + -lodbcexecutor_pic \ + -lodbccommon_pic \ + -lodbcdictionary_pic \ + -lNDBT \ + -lportlib +endif + +ifeq ($(TYPE),odbcclient) +LIBS_SPEC += \ + -lportlib \ + -lNDBT +endif + +CCFLAGS_LOC += -I/usr/local/include \ + -I$(NDB_TOP)/include/ndbapi \ + -I$(NDB_TOP)/test/include + +include $(NDB_TOP)/Epilogue.mk +#LIBS_LOC += -L/usr/local/opt/iODBC/lib +#LIBS_SPEC = -liodbc -lNDBT -lportlib diff --git a/ndb/test/odbc/client/NDBT_ALLOCHANDLE.cpp b/ndb/test/odbc/client/NDBT_ALLOCHANDLE.cpp new file mode 100644 index 00000000000..336f4a46554 --- /dev/null +++ b/ndb/test/odbc/client/NDBT_ALLOCHANDLE.cpp @@ -0,0 +1,53 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" +#include <NdbTest.hpp> +#include <NdbMain.h> + +SQLRETURN SQLHENV_check, SQLHENV_FREE_check; + +int NDBT_ALLOCHANDLE() +{ + /*****************************HENV Handle*****************************/ + + SQLHENV henv; + SQLHENV_check = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + + if (SQLHENV_check == -1) { + return(-1); + //return NDBT_ProgramExit(NDBT_FAILED); + } + + if (SQLHENV_check == 0) { + return 0; + } + + SQLHENV_FREE_check = SQLFreeHandle(SQL_HANDLE_ENV, henv); + + if (SQLHENV_FREE_check == -1) { + // Deallocate any allocated memory, if it exists + return(-1); + //return NDBT_ProgramExit(NDBT_FAILED); + } + + if (SQLHENV_FREE_check == 0) { + return 0; + } + + return 0; +} + diff --git a/ndb/test/odbc/client/NDBT_ALLOCHANDLE_HDBC.cpp b/ndb/test/odbc/client/NDBT_ALLOCHANDLE_HDBC.cpp new file mode 100644 index 00000000000..8477a71edbf --- /dev/null +++ b/ndb/test/odbc/client/NDBT_ALLOCHANDLE_HDBC.cpp @@ -0,0 +1,59 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" +#include <NdbTest.hpp> +#include <NdbMain.h> + +SQLRETURN SQLHENVFREE_check, SQLHDBC_check; + + +// NDB_COMMAND(SQLTest1, ......., 65535) +int NDBT_ALLOCHANDLE_HDBC() +{ + + SQLHENV henv; + SQLHDBC hdbc; + + /*****************************HDBC Handle*****************************/ + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + + SQLHDBC_check = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + + if (SQLHDBC_check == -1) { + return NDBT_ProgramExit(NDBT_FAILED); + } + + if (SQLHDBC_check == 0) { + return 0; + } + + SQLHENVFREE_check = SQLFreeHandle(SQL_HANDLE_ENV, henv); + + if (SQLHENVFREE_check == -1) { + // Deallocate any allocated memory, if it exists + return(-1); + //return NDBT_ProgramExit(NDBT_FAILED); + } + + if (SQLHENVFREE_check == 0) { + return 0; + } +} + + + + diff --git a/ndb/test/odbc/client/NDBT_SQLConnect.cpp b/ndb/test/odbc/client/NDBT_SQLConnect.cpp new file mode 100644 index 00000000000..da97ffebea4 --- /dev/null +++ b/ndb/test/odbc/client/NDBT_SQLConnect.cpp @@ -0,0 +1,82 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" +#include <NdbTest.hpp> +#include <NdbMain.h> + +SQLRETURN retcode, SQLSTATEs; +SQLHENV henv; +SQLHDBC hdbc; + +void NDBT_Connect_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int NDBT_SQLConnect() +{ + + /*****************************SQLConnect AutoTest*****************************/ + + // Allocate An Environment Handle + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + + // This part does not include in sqlcli.h, it is only in ODBC + // Set the ODBC application Version to 3.x + // SQLSetEnvattr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTERGER); + + // Allocate A Connection Handle + SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + + // Connect to NDB + retcode = SQLConnect(hdbc, + (SQLCHAR*) "Sales", + 5, + (SQLCHAR*) "JohnS", + 5, + (SQLCHAR*) "Sesame", + 6); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + else + { if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + NDBT_Connect_DisplayError(SQL_HANDLE_DBC, hdbc);} + + // Free the Connection Handle + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + + // Free the Environment Handle + SQLFreeHandle(SQL_HANDLE_ENV, henv); + + return 0; +} + + +void NDBT_Connect_DisplayError(SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + SQLRETURN Sqlstate; + int i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} diff --git a/ndb/test/odbc/client/NDBT_SQLPrepare.cpp b/ndb/test/odbc/client/NDBT_SQLPrepare.cpp new file mode 100644 index 00000000000..4aaff6a7df9 --- /dev/null +++ b/ndb/test/odbc/client/NDBT_SQLPrepare.cpp @@ -0,0 +1,109 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlext.h> +#include <stdio.h> + +#include <NdbTest.hpp> +#include <NdbMain.h> + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN SQLPrepare_retcode, SQLAllocHandl_retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void NDBT_SQLPrepare_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + + // Execute a statement to retrieve rows from the Customers table. We can + // create the table and inside rows into NDB by invoking SQLExecute() or + // another program called TestDirectSQL + +int NDBT_SQLPrepare() +{ + // Allocate An Environment Handle + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + + // Allocate A Connection Handle + SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + + // Allocate A Connection Handle + SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + + // Connecte to database + SQLConnect(hdbc, (SQLCHAR*) "Sales", 5, (SQLCHAR*) "JohnS", 5, (SQLCHAR*) "Sesame", 6); + + // Allocate A Statement Handle + SQLAllocHandl_retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); + + /* We can change the SQL statement in the SQLPrepare() function according to the requirement of Johnny. */ + /* The order of the SQL statement could be CREATE, INSERT, UPDATE, SELECT, DELETE or another special SQL */ + + if (SQLAllocHandl_retcode == SQL_SUCCESS){ + SQLPrepare_retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", 56); + + if (SQLPrepare_retcode == SQL_INVALID_HANDLE) +ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE and SQL_SUCCESS still appeared. Please check programm" << endl; + + if (SQLPrepare_retcode == SQL_ERROR || SQLPrepare_retcode == SQL_SUCCESS_WITH_INFO) + NDBT_SQLPrepare_DisplayError(SQL_HANDLE_STMT, hstmt); + + SQLExecute(hstmt); + + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + } + + // Disconnect from the database before free Connection Handle and Environment Handle + SQLDisconnect(hdbc); + + // Free the Connection Handle + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + + // Free the Environment Handle + SQLFreeHandle(SQL_HANDLE_ENV, henv); + + return 0; + + } + + +void NDBT_SQLPrepare_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLAllocEnvTest.cpp b/ndb/test/odbc/client/SQLAllocEnvTest.cpp new file mode 100644 index 00000000000..ce50c4b7ccd --- /dev/null +++ b/ndb/test/odbc/client/SQLAllocEnvTest.cpp @@ -0,0 +1,115 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHENV henv; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; + +void sqlallocenv_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle); +void sqlallocenv_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle); + +void DisplayError_HDBC_free(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle); +void DisplayError_HENV_free(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle); + + +int SQLAllocEnvTest() +{ + +/* Environment test for SQLAllocEnv() */ +ndbout << "Environment test for SQLAllocEnv()" << endl; +//SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + +sqlallocenv_deal_with_HENV(SQL_HANDLE_ENV, henv); + +//SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); +//SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); +sqlallocenv_deal_with_HDBC(SQL_HANDLE_DBC, hdbc); + +return 0; + +} + +void sqlallocenv_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + retcode = SQLAllocHandle(HandleType, henv, &InputHandle); + + ndbout << "the HandleType is : " << HandleType << endl; + ndbout << "the InputHandle is SQLHDBC:" << InputHandle << endl; + ndbout << "retcode = " << retcode << endl; + + /* *** + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HDBC_free(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + *** */ +} + +void sqlallocenv_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + retcode = SQLAllocEnv(&InputHandle); + + ndbout << "the HandleType is : " << HandleType << endl; + ndbout << "the InputHandle is SQLHENV:" << InputHandle << endl; + ndbout << "retcode = " << retcode << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HENV_free(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + */ + } + + +void DisplayError_HENV_free(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void DisplayError_HDBC_free(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + diff --git a/ndb/test/odbc/client/SQLAllocHandleTest.cpp b/ndb/test/odbc/client/SQLAllocHandleTest.cpp new file mode 100644 index 00000000000..0c51e2e46b7 --- /dev/null +++ b/ndb/test/odbc/client/SQLAllocHandleTest.cpp @@ -0,0 +1,314 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" + +using namespace std; + +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +long strangehandle; + +void handle_deal_with_HSTMT(SQLSMALLINT HandleType, SQLHSTMT InputHandle); +void handle_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle); +void handle_deal_with_HDESC(SQLSMALLINT HandleType, SQLHDESC InputHandle); +void handle_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle); +//void handle_deal_with_int(SQLSMALLINT HandleType, long InputHandle); + +void DisplayError_HDBC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle); +void DisplayError_HSTMT(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHSTMT InputHandle); +void DisplayError_HENV(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle); +void DisplayError_HDESC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDESC InputHandle); +//void DisplayError_int(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, int InputHandle); + +int SQLAllocHandleTest() +{ + +strangehandle = 6; + +/*Allocate environment handle */ + +//retcode = SQLFreeHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE); + +/* ENV */ +ndbout << endl; +ndbout << "The HandleType: Allocate Environment handle" << endl; +ndbout << endl; + +handle_deal_with_HENV(SQL_HANDLE_ENV, SQL_NULL_HANDLE); + +handle_deal_with_HENV(SQL_HANDLE_ENV, henv); + +handle_deal_with_HDBC(SQL_HANDLE_ENV, hdbc); + +handle_deal_with_HSTMT(SQL_HANDLE_ENV, hstmt); + +handle_deal_with_HDESC(SQL_HANDLE_ENV, hdesc); + +//handle_deal_with_int(SQL_HANDLE_ENV, strangehandle); + +/* DBC */ +ndbout << endl; +ndbout << "The HandleType: Allocate Connection handle" << endl; +ndbout << endl; + +handle_deal_with_HDBC(SQL_HANDLE_DBC, SQL_NULL_HANDLE); + +handle_deal_with_HENV(SQL_HANDLE_DBC, henv); + +handle_deal_with_HDBC(SQL_HANDLE_DBC, hdbc); + +handle_deal_with_HSTMT(SQL_HANDLE_DBC, hstmt); + +handle_deal_with_HDESC(SQL_HANDLE_DBC, hdesc); + +//handle_deal_with_int(SQL_HANDLE_DBC, strangehandle); + +/* STMT */ +ndbout << endl; +ndbout << "The HandleType: Allocate Statement handle" << endl; +ndbout << endl; + +handle_deal_with_HSTMT(SQL_HANDLE_STMT, SQL_NULL_HANDLE); + +handle_deal_with_HENV(SQL_HANDLE_STMT, henv); + +handle_deal_with_HDBC(SQL_HANDLE_STMT, hdbc); + +handle_deal_with_HSTMT(SQL_HANDLE_STMT, hstmt); + +handle_deal_with_HDESC(SQL_HANDLE_STMT, hdesc); + +//handle_deal_with_int(SQL_HANDLE_STMT, strangehandle); + + +/* DESC */ +ndbout << endl; +ndbout << "The HandType: Allocate Descriptor handle" << endl; +ndbout << endl; + +handle_deal_with_HDESC(SQL_HANDLE_DESC, SQL_NULL_HANDLE); + +handle_deal_with_HENV(SQL_HANDLE_DESC, henv); + +handle_deal_with_HDBC(SQL_HANDLE_DESC, hdbc); + +handle_deal_with_HSTMT(SQL_HANDLE_DESC, hstmt); + +handle_deal_with_HDESC(SQL_HANDLE_DESC, hdesc); + +//handle_deal_with_int(SQL_HANDLE_DESC, strangehandle); + + +/* strangehandle */ +ndbout << endl; +ndbout << "The HandType: strangehandle" << endl; +ndbout << endl; + +//handle_deal_with_int(strangehandle, SQL_NULL_HANDLE); + +handle_deal_with_HENV(strangehandle, henv); + +handle_deal_with_HDBC(strangehandle, hdbc); + +handle_deal_with_HSTMT(strangehandle, hstmt); + +handle_deal_with_HDESC(strangehandle, hdesc); + +// handle_deal_with_int(strangehandle, strangehandle); + +return 0; + +} + +void handle_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLAllocHandle(HandleType, InputHandle, &hdbc); + + ndbout << "the HandleType is : " << HandleType << endl; + + ndbout << "the InputHandle is SQLHDBC:" << InputHandle << endl; + + ndbout << "return &hdbc: " << (long)&hdbc << endl; + ndbout << "the retcode state is:" << retcode << endl; + ndbout << endl; + + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HDBC(Sqlstate, HandleType, InputHandle); + i ++; + } + } + */ + } + + +void handle_deal_with_HSTMT(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLAllocHandle(HandleType, InputHandle, &hstmt); + + ndbout << "the HandleType is : " << HandleType << endl; + + ndbout << "the InputHandle is SQLHSTMT:" << InputHandle << endl; + + ndbout << "return &hstmt: " << (long)&hstmt << endl; + ndbout << "the output retcode is:" << retcode << endl; + ndbout << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HSTMT(Sqlstate, HandleType, InputHandle); + i ++; + } + } + */ + } + +void handle_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLAllocHandle(HandleType, InputHandle, &henv); + + ndbout << "the HandleType is : " << HandleType << endl; + + ndbout << "the InputHandle is SQLHENV:" << InputHandle << endl; + + ndbout << "return &henv: " << (long)&henv << endl; + ndbout << "the output retcode is:" << retcode << endl; + ndbout << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HENV(Sqlstate, HandleType, InputHandle); + i ++; + } + } + */ + } + +void handle_deal_with_HDESC(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLAllocHandle(HandleType, InputHandle, &hdesc); + + ndbout << "the HandleType is : " << HandleType << endl; + + ndbout << "the InputHandle is SQLHDESC:" << InputHandle << endl; + + ndbout << "return &hdesc: " << (long)&hdesc << endl; + ndbout << "the output retcode is:" << retcode << endl; + ndbout << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HDESC(Sqlstate, HandleType, InputHandle); + i ++; + } + } + */ + } + + +//void handle_deal_with_int(SQLSMALLINT HandleType, long InputHandle) +//{ +// SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +// retcode = SQLAllocHandle(HandleType, InputHandle, &InputHandle); +// +// ndbout << "the HandleType is: " << HandleType << endl; +// +// ndbout << "the InputHandle is stranghandle:" << InputHandle << endl; +// +// ndbout << "return &InputHandle: " << (long)&InputHandle << endl; +// ndbout << "the output retcode is:" << retcode << endl; +// ndbout << endl; +// /* +// if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { +// i = 1; +// while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, +// Sqlstate, &NativeError, Msg, sizeof(Msg), +// &MsgLen)) != SQL_NO_DATA) { +// +// DisplayError_int(Sqlstate, HandleType, InputHandle); +// +// i ++; +// } +// } +// */ +// } + + +void DisplayError_HENV(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + + +void DisplayError_HDBC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void DisplayError_HSTMT(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void DisplayError_HDESC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +//void DisplayError_int(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, int InputHandle) +//{ +// ndbout << "the HandleType is:" << HandleType << endl; +// ndbout << "the InputHandle is :" << InputHandle << endl; +// ndbout << "the output state is:" << (char *)Sqlstate << endl; +//} diff --git a/ndb/test/odbc/client/SQLAllocHandleTest_bf.cpp b/ndb/test/odbc/client/SQLAllocHandleTest_bf.cpp new file mode 100644 index 00000000000..7786675243a --- /dev/null +++ b/ndb/test/odbc/client/SQLAllocHandleTest_bf.cpp @@ -0,0 +1,259 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include sqlcli.h; +#include stdio.h; + +#define SQL_MAX_MESSAGE_LENGTH 200; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR SqlState[6], SQLStmt[100], Msg[SQL_MAX_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; + +struct handle_set +{ +SQLHDBC hdbc_varible; +SQLHSTMT hstmt_varible; +SQLHENV henv_varible; +SQLHDESC hdesc_varible; +INTEGER strangehandle; +} + +static int +check( + SQLSMALLINT HandleType, + SQLHANDLE inputhandle, + SQLHANDLE *outputhandle, + SQLRETURN wantret, + char *wantSqlstate) +{ + SQLRETURN ret; + SQLCHAR Sqlstate[20]; + + ret = SQLAllocHandle(handletype, inputhandle, outputhandle); + if (ret != wantret) { + // report error + return -1; + } + if (ret == SQL_INVALID_HANDLE) { + // cannot get diag + return 0; + } + // TODO + ret = SQLGetDiagRec(HandleType, InputHandle, 1, Sqlstate, &NativeError, Msg, sizeof(Msg), &MsgLen); + if (strcmp(Sqlstate, wantSqlstate) != 0) { + // report error; + return -1; + } + return 0; +} + +int +Test_SQLAllocHandle() +{ + SQLRETURN ret; + SQLHENV henv; + SQLDBC dbc; + int i; + + // env + check(SQL_HANDLE_ENV, SQL_NULL_HANDLE, 0, SQL_ERROR, "HY009"); + for (i = 0; i < 1000; i++) { + if (i != SQL_NULL_HANDLE) + check(SQL_HANDLE_ENV, i, &henv, SQL_INVALID_HANDLE, 0); + } + if (check(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv, SQL_SUCCESS, "00000") < 0) + return -1; + + // dbc + check(SQL_HANDLE_DBC, henv, 0, SQL_ERROR, "HY009"); + for (i = 0; i < 1000; i++) { + if (i != henv) + check(SQL_HANDLE_DBC, i, &dbc, SQL_INVALID_HANDLE, 0); + } + if (check(SQL_HANDLE_DBC, henv, &dbc, SQL_SUCCESS, "00000") < 0) + return -1; + + //?? + check(SQL_HANDLE_ENV, dbc, 0, SQL_ERROR, "HY092"); + + // TODO + // stmt + + return 0; +} + + +handle_set handlevalue; + +handlevalue.hdbc_varible = hdbc; +handlevalue.hstmt_varible = hstmt; +handlevalue.henv_varible = henv; +handlevalue.hdesc_varible = hdesc; +handlevalue.stranghandle = 67; + + /*Allocate environment handle */ +//retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + +while (int j = 0; j++; j < 6) { + if ( j = 0 ) + handle_deal_with(SQL_HANDLE_ENV, SQL_NULL_HANDLE, ); + + else if ( j = 1 ) + handle_deal_with(SQL_HANDLE_ENV, handlevalue.henv_varible, ); + + else if ( j = 2 ) + handle_deal_with(SQL_HANDLE_ENV, handlevalue.hdbc_varible, ); + + else if ( j = 3 ) + handle_deal_with(SQL_HANDLE_ENV, handlevalue.hstmt_varible, ); + + else if ( j = 4 ) + handle_deal_with(SQL_HANDLE_ENV, handlevalue.hdesc_varible, ); + + else + handle_deal_with(SQL_HANDLE_ENV, handlevalue.stranghandle, ); + + } + + while (int j = 0; j++; j < 6) { + if ( j = 0 ) + handle_deal_with(SQL_HANDLE_DBC, SQL_NULL_HANDLE, ); + + else if ( j = 1 ) + handle_deal_with(SQL_HANDLE_DBC, handlevalue.henv_varible, ); + + else if ( j = 2 ) + handle_deal_with(SQL_HANDLE_DBC, handlevalue.hdbc_varible, ); + + else if ( j = 3 ) + handle_deal_with(SQL_HANDLE_DBC, handlevalue.hstmt_varible, ); + + else if ( j = 4 ) + handle_deal_with(SQL_HANDLE_DBC, handlevalue.hdesc_varible, ); + + else + handle_deal_with(SQL_HANDLE_DBC, handlevalue.stranghandle, ); + + } + + + while (int j = 0; j++; j < 6) { + if ( j = 0 ) + handle_deal_with(SQL_HANDLE_STMT, SQL_NULL_HANDLE, ); + + else if ( j = 1 ) + handle_deal_with(SQL_HANDLE_STMT, handlevalue.henv_varible, ); + + else if ( j = 2 ) + handle_deal_with(SQL_HANDLE_STMT, handlevalue.hdbc_varible, ); + + else if ( j = 3 ) + handle_deal_with(SQL_HANDLE_STMT, handlevalue.hstmt_varible, ); + + else if ( j = 4 ) + handle_deal_with(SQL_HANDLE_STMT, handlevalue.hdesc_varible, ); + + else + handle_deal_with(SQL_HANDLE_STMT, handlevalue.stranghandle, ); + + } + + + + while (int j = 0; j++; j < 6) { + if ( j = 0 ) + handle_deal_with(SQL_HANDLE_DESC, SQL_NULL_HANDLE, ); + + else if ( j = 1 ) + handle_deal_with(SQL_HANDLE_DESC, handlevalue.henv_varible, ); + + else if ( j = 2 ) + handle_deal_with(SQL_HANDLE_DESC, handlevalue.hdbc_varible, ); + + else if ( j = 3 ) + handle_deal_with(SQL_HANDLE_DESC, handlevalue.hstmt_varible, ); + + else if ( j = 4 ) + handle_deal_with(SQL_HANDLE_DESC, handlevalue.hdesc_varible, ); + + else + handle_deal_with(SQL_HANDLE_DESC, handlevalue.stranghandle, ); + + } + + while (int j = 0; j++; j < 6) { + if ( j = 0 ) + handle_deal_with(handlevalue.stranghandle, SQL_NULL_HANDLE, ); + + else if ( j = 1 ) + handle_deal_with(handlevalue.stranghandle, handlevalue.henv_varible, ); + + else if ( j = 2 ) + handle_deal_with(handlevalue.stranghandle, handlevalue.hdbc_varible, ); + + else if ( j = 3 ) + handle_deal_with(handlevalue.stranghandle, handlevalue.hstmt_varible, ); + + else if ( j = 4 ) + handle_deal_with(handlevalue.stranghandle handlevalue.hdesc_varible, ); + + else + handle_deal_with(handlevalue.stranghandle, handlevalue.stranghandle, ); + + } + + +} + + +void DisplayError(SQLCHAR SqlState[6], string SQLSTATE, string flag, SQLSMALLINT HandleType, SQLHANDLE InputHandle) +{ +cout << "the operation is: " << flag << endl; +cout << "the HandleType is:" << HandleType << endl; +cout << "the InputHandle is :"<< InputHandle <<endl; +cout << "the correct state is:" << SQLSTATE << endl; +cout << "the output state is:" << Sqlstate << endl; +} + +} + + +void handle_deal_with(SQLSMALLINT HandleType, SQLHANDLE InputHandle, string SQLSTATE) +{ + retcode = SQLAllocHandle(HandleType, InputHandle, OutputHandlePtr); + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATE) { + + if (SQLSTATE = Sqlstate ) + DisplayError(SqlState, SQLSTATE, 'OK'); + + else + DisplayError(SqlState, SQLSTATE, 'failure'); + + i ++; + } + } + } diff --git a/ndb/test/odbc/client/SQLBindColTest.cpp b/ndb/test/odbc/client/SQLBindColTest.cpp new file mode 100644 index 00000000000..e2cd4ce73d1 --- /dev/null +++ b/ndb/test/odbc/client/SQLBindColTest.cpp @@ -0,0 +1,537 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLBindColTest.cpp + */ +#include <common.hpp> +using namespace std; + +#define BindCol_NAME_LEN 10 +#define BindCol_PHONE_LEN 10 +#define BindCol_ADDRESS_LEN 10 +#define BindCol_Price_LEN 10 +#define BindCol_Weight_LEN 10 +#define BindCol_Tax_LEN 10 + +#define BindCol_SQL_MAXIMUM_MESSAGE_LENGTH 200 + +//SQLHDBC BindCol_hdbc; +//SQLHSTMT BindCol_hstmt; +//SQLHENV BindCol_henv; +//SQLHDESC BindCol_hdesc; +//SQLRETURN BCret; + +//SQLCHAR BindCol_Name[BindCol_NAME_LEN], BindCol_Phone[BindCol_PHONE_LEN]; +//SQLCHAR BindCol_Address[BindCol_ADDRESS_LEN]; +//SQLINTEGER NativeError; +//unsigned long BindCol_CustID; + +void BindCol_DisplayError(SQLSMALLINT BindCol_HandleType, + SQLHSTMT BindCol_InputHandle); + +/** + * Test setting column to bind + * for a column in a result + * + * -# Bind columns 1 + * -# Bind columns 2 + * -# Bind columns 3 + * -# Bind columns 4 + * -# Bind columns 5 + * -# Bind columns 6 + * -# Bind columns 7 + * @return Zero, if test succeeded + */ + +int SQLBindColTest() +{ + + SQLHDBC BindCol_hdbc; + SQLHSTMT BindCol_hstmt; + SQLHENV BindCol_henv; + SQLHDESC BindCol_hdesc; + + SQLCHAR SQLStmt1 [240]; + SQLCHAR SQLStmt2 [240]; + SQLCHAR SQLStmt3 [120]; + + SQLRETURN BCret; + + unsigned long BindCol_CustID; + SQLCHAR BindCol_Name[BindCol_NAME_LEN]; + short BindCol_Account; + unsigned short BindCol_Phone; + long BindCol_Price; + float BindCol_Weight; + double BindCol_Tax; + + ndbout << endl << "Start SQLBindCol Testing" << endl; + + //******************************************************************* + //** hstmt + //** Execute a statement to retrieve rows from the Customers table ** + //** We can create the table and insert rows into Customers ** + //******************************************************************* + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + BCret = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &BindCol_henv); + +if (BCret == SQL_SUCCESS || BCret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + BCret = SQLSetEnvAttr(BindCol_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + +if (BCret == SQL_SUCCESS || BCret == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + +//********************************** +//** Allocate A Connection Handle ** +//********************************** + + BCret = SQLAllocHandle(SQL_HANDLE_DBC, + BindCol_henv, + &BindCol_hdbc); + + if (BCret == SQL_SUCCESS || BCret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + BCret = SQLConnect(BindCol_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (BCret == SQL_SUCCESS || BCret == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + BCret = SQLAllocHandle(SQL_HANDLE_STMT, + BindCol_hdbc, + &BindCol_hstmt); + if(BCret == SQL_SUCCESS || BCret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + /* Primary key is Integer and Char */ + strcpy((char *) SQLStmt1, "CREATE TABLE Customer1(CustID Integer, Name Char(12), Account Char(12), Phone Char(12), Price Char(6), Weight Char(6), Tax Char(6), Primary Key(CustID, Name))"); + + strcpy((char *) SQLStmt2, "INSERT INTO Customer1 (CustID, Name, Account, Phone, Price, Weight, Tax) VALUES(588, 'peter','6808','7190890', '5.68', '1.58', '0.88')"); + + strcpy((char *) SQLStmt3, "SELECT * FROM Customer1"); + + //************************************************ + //** Prepare and Execute CREATE TABLE statement ** + //************************************************ + ndbout << endl << "Prepare and Execute CREATE TABLE statement ......" << endl; + ndbout << ">>>>" << (char*)SQLStmt1 << "<<<<" << endl; + BCret = SQLExecDirect(BindCol_hstmt, + SQLStmt1, + SQL_NTS); + if (BCret == SQL_SUCCESS) + ndbout << "Prepare and Execute CREATE TABLE statement OK!" + << endl<< endl; + + if (BCret == SQL_ERROR || BCret == SQL_SUCCESS_WITH_INFO) + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + + if (BCret == -2) + { + ndbout << "BCret = SQLExexDirect()=" << BCret << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + + //******************************************************* + //** Prepare and Execute INSERT statement with prepare ** + //******************************************************* + ndbout << "Prepare and Execute INSERT statement ......" << endl; + ndbout << ">>>>" << (char*)SQLStmt2 << "<<<<" << endl; + BCret = SQLExecDirect(BindCol_hstmt, + SQLStmt2, + SQL_NTS); + + if (BCret == SQL_SUCCESS) + ndbout << "Prepare and Execute INSERT statement OK!" + << endl << endl; + + if (BCret == SQL_ERROR || BCret == SQL_SUCCESS_WITH_INFO) + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + + if (BCret == -2) + { + ndbout << "BCret = SQLExexDirect()=" << BCret << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + + //****************************************** + //** Prepare and EXECUTE SELECT statement ** + //****************************************** + ndbout << "Prepare and Execute SELECT statement ......" << endl; + ndbout << ">>>>" << (char*)SQLStmt3 << "<<<<" << endl; + BCret = SQLExecDirect(BindCol_hstmt, + SQLStmt3, + SQL_NTS); + + if (BCret == SQL_SUCCESS) + ndbout << "Prepare and Execute SELECT statement OK!" + << endl << endl; + + if (BCret == SQL_ERROR || BCret == SQL_SUCCESS_WITH_INFO) + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + + if (BCret == -2) + { + ndbout << "BCret = SQLExexDirect()=" << BCret << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + + //******************************* + //** Execute SELECT statement ** + //******************************* + // BCret = SQLExecute(BindCol_hstmt); + // if (BCret == SQL_ERROR || BCret == SQL_SUCCESS_WITH_INFO) + // { + // ndbout << "BCret = " << BCret << endl; + // BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + // } + // else + // { + + if (BCret == SQL_SUCCESS) + ndbout << "Execute INSERT statement OK!" << endl; + + //********************* + //** Test1 ** + //** Bind columns 1 ** + //********************* + + BCret =SQLBindCol(BindCol_hstmt, + 1, + SQL_C_ULONG, + &BindCol_CustID, + sizeof(BindCol_CustID), + NULL); + + if (BCret == SQL_SUCCESS) + { + ndbout << endl << "Bind col 1 OK!" << endl; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 1 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 1 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else + ndbout << endl; + + //********************* + //** Test2 ** + //** Bind columns 2 ** + //********************* + + BCret =SQLBindCol(BindCol_hstmt, + 2, + SQL_C_CHAR, + &BindCol_Name, + BindCol_NAME_LEN, + NULL); + + if (BCret == SQL_SUCCESS) + { + ndbout << "Bind col 2 OK!" << endl; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 2 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 2 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else + ndbout << endl; + + //********************* + //** Test3 ** + //** Bind columns 3 ** + //********************* + + BCret = SQLBindCol(BindCol_hstmt, + 3, + SQL_C_USHORT, + &BindCol_Account, + sizeof(BindCol_Account), + NULL); + + if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 3 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 3 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_SUCCESS) + { + ndbout << "Bind col 3 OK!" << endl; + } + else + ndbout << endl; + + //********************* + //** Test4 ** + //** Bind columns 4 ** + //********************* + + BCret = SQLBindCol(BindCol_hstmt, + 4, + SQL_C_USHORT, + &BindCol_Phone, + sizeof(BindCol_Phone), + NULL); + + if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 4 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 4 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_SUCCESS) + { + ndbout << "Bind col 4 OK!" << endl; + } + else + ndbout << endl; + + //********************* + //** Test5 ** + //** Bind columns 5 ** + //********************* + + BCret = SQLBindCol(BindCol_hstmt, + 5, + SQL_C_SLONG, + &BindCol_Price, + sizeof(BindCol_Price), + NULL); + + if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 5 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 5 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_SUCCESS) + { + ndbout << "Bind col 5 OK!" << endl; + } + else + ndbout << endl; + + //********************* + //** Test6 ** + //** Bind columns 6 ** + //********************* + + BCret = SQLBindCol(BindCol_hstmt, + 6, + SQL_C_FLOAT, + &BindCol_Weight, + sizeof(BindCol_Weight), + NULL); + + if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 6 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 6 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_SUCCESS) + { + ndbout << "Bind col 6 OK!" << endl; + } + else + ndbout << endl; + + //********************* + //** Test7 ** + //** Bind columns 7 ** + //********************* + + BCret = SQLBindCol(BindCol_hstmt, + 7, + SQL_C_DOUBLE, + &BindCol_Tax, + sizeof(BindCol_Tax), + NULL); + + if (BCret == SQL_ERROR) + { + ndbout << "Bind Col 7 Failed!" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; + } + else if (BCret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Bind Col 7 OK but with INFO" << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + } + else if (BCret == SQL_SUCCESS) + { + ndbout << "Bind col 7 OK!" << endl; + } + else + ndbout << endl; + + //} + +//***************************************** +//* Fetch and print each row of data. On ** +//* an error, display a message and exit ** +//***************************************** + +BCret = SQLFetch(BindCol_hstmt); + + ndbout << endl << "BCret = SQLFetch(BindCol_hstmt) = " + << BCret << endl; + +if (BCret == SQL_ERROR) +{ + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); + return NDBT_FAILED; +} +else if (BCret == SQL_SUCCESS_WITH_INFO) +{ + ndbout << "CustID = " << (int)BindCol_CustID << endl; + ndbout << "Name = " << (char *)BindCol_Name << endl; + ndbout << "Account = " << (int)BindCol_Account << endl; + ndbout << "Phone = " << (int)BindCol_Phone << endl; + ndbout << "Price = " << (int)BindCol_Price << endl; + ndbout << "Weight = " << (int)BindCol_Weight << endl; + ndbout << "Tax = " << (int)BindCol_Tax << endl; + BindCol_DisplayError(SQL_HANDLE_STMT, BindCol_hstmt); +} +else +{ + ndbout << "CustID = " << (int)BindCol_CustID << endl; + ndbout << "Name = " << (char *)BindCol_Name << endl; + ndbout << "Account = " << (int)BindCol_Account << endl; + ndbout << "Phone = " << (int)BindCol_Phone << endl; + ndbout << "Price = " << (int)BindCol_Price << endl; + ndbout << "Weight = " << (int)BindCol_Weight << endl; + ndbout << "Tax = " << (int)BindCol_Tax << endl; +} + +// ********************************* +// ** Disconnect and Free Handles ** +// ********************************* +SQLDisconnect(BindCol_hdbc); +SQLFreeHandle(SQL_HANDLE_STMT, BindCol_hstmt); +SQLFreeHandle(SQL_HANDLE_DBC, BindCol_hdbc); +SQLFreeHandle(SQL_HANDLE_ENV, BindCol_henv); + +return NDBT_OK; + +} + +void BindCol_DisplayError(SQLSMALLINT BindCol_HandleType, + SQLHSTMT BindCol_InputHandle) +{ + SQLSMALLINT BindCol_i = 1; + SQLRETURN BindCol__SQLSTATEs; + SQLCHAR BindCol_Sqlstate[5]; + SQLCHAR BindCol_Msg[BindCol_SQL_MAXIMUM_MESSAGE_LENGTH]; + SQLSMALLINT BindCol_MsgLen; + SQLINTEGER NativeError; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((BindCol__SQLSTATEs = SQLGetDiagRec(BindCol_HandleType, + BindCol_InputHandle, + BindCol_i, + BindCol_Sqlstate, + &NativeError, + BindCol_Msg, + sizeof(BindCol_Msg), + &BindCol_MsgLen) + ) != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << BindCol_HandleType << endl; + ndbout << "the InputHandle is :" << (long)BindCol_InputHandle << endl; + ndbout << "the BindCol_Msg is: " << (char *) BindCol_Msg << endl; + ndbout << "the output state is:" << (char *)BindCol_Sqlstate << endl; + + BindCol_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + diff --git a/ndb/test/odbc/client/SQLBindParameterTest.cpp b/ndb/test/odbc/client/SQLBindParameterTest.cpp new file mode 100644 index 00000000000..2ffd2892064 --- /dev/null +++ b/ndb/test/odbc/client/SQLBindParameterTest.cpp @@ -0,0 +1,219 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 + +SQLHSTMT hstmt; + +SQLSMALLINT sOrderID; +SQLSMALLINT sCustID; +DATE_STRUCT dsOpenDate; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR szStatus[STATUS_LEN],Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER cbOrderID = 0, cbCustID = 0, cbOpenDate = 0, cbSalesPerson = SQL_NTS, cbStatus = SQL_NTS, NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLSMALLINT i, MsgLen; + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLBindParameterTest () +{ + + /* hstmt */ + //** Execute a statement to retrieve rows from the Customers table. + //** We can create the table and inside rows in + //** NDB by another program TestDirectSQL. + //** In this test program(SQLBindParameterTest),we only have three rows in + //** table ORDERS + + //************************ + //** Define a statement ** + //************************ + strcpy( (char *) SQLStmt, + "INSERT INTO Customers (CUSTID, Name, Address, Phone) VALUES (2, 'paul, 'Alzato', '468719989'); + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, SQLStmt, SQL_NTS); + +/* Specify data types and buffers for OrderID, CustID, OpenDate, SalesPerson, */ +/* Status parameter data. */ + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + /* ParameterNumber is less than 1 */ +retcode = SQLBindParameter(hstmt, + 0, + SQL_PARAM_INPUT, + SQL_C_SSHORT, + SQL_INTEGER, + 0, + 0, + &sOrderID, + 0, + &cbOrderID); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + + /* InputOutputMode is not one of the code values in Table 11 */ +retcode = SQLBindParameter(hstmt, + 1, + 3, + SQL_C_SSHORT, + SQL_INTEGER, + 0, + 0, + &sOrderID, + 0, + &cbOrderID); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + + /* ParameterType is not one of the code values in Table 37 */ +retcode = SQLBindParameter(hstmt, + 1, + 3, + SQL_C_SSHORT, + 114, + 0, + 0, + &sOrderID, + 0, + &cbOrderID); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + +SQLBindParameter(hstmt, + 1, + SQL_PARAM_INPUT, + SQL_C_SSHORT, + SQL_INTEGER, + 0, + 0, + &sOrderID, + 0, + &cbOrderID); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + + +SQLBindParameter(hstmt, + 2, + SQL_PARAM_INPUT, + SQL_C_SSHORT, + SQL_INTEGER, + 0, + 0, + &sCustID, + 0, + &cbCustID); + +SQLBindParameter(hstmt, + 3, + SQL_PARAM_INPUT, + SQL_C_TYPE_DATE, + SQL_TYPE_DATE, + 0, + 0, + &dsOpenDate, + 0, + &cbOpenDate); + +SQLBindParameter(hstmt, + 4, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + SALES_PERSON_LEN, + 0, + szSalesPerson, + 0, + &cbSalesPerson); + +SQLBindParameter(hstmt, + 5, + SQL_PARAM_INPUT, + SQL_C_CHAR, + SQL_CHAR, + STATUS_LEN, + 0, + szStatus, + 0, + &cbStatus); + +/* + +/* Specify first row of parameter data. */ +sOrderID = 1001; +sCustID = 298; +dsOpenDate.year = 1996; +dsOpenDate.month = 3; +dsOpenDate.day = 8; +strcpy(szSalesPerson, "Johnson"); +strcpy(szStatus, "Closed"); + +/* Execute statement with first row. */ +retcode = SQLExecute(hstmt); + +/* Specify second row of parameter data. */ +sOrderID = 1002; +sCustID = 501; +dsOpenDate.year = 1996; +dsOpenDate.month = 3; +dsOpenDate.day = 9; +strcpy(szSalesPerson, "Bailey"); +strcpy(szStatus, "Open"); + +/* Execute statement with second row. */ +retcode = SQLExecute(hstmt); + +*/ + +} + + return 0; + + } + + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLCancelTest.cpp b/ndb/test/odbc/client/SQLCancelTest.cpp new file mode 100644 index 00000000000..904ffab6979 --- /dev/null +++ b/ndb/test/odbc/client/SQLCancelTest.cpp @@ -0,0 +1,254 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLCancelTest.cpp + */ + +#include <common.hpp> +#define Cancel_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC CC_hdbc; +SQLHSTMT CC_hstmt; +SQLHENV CC_henv; +SQLHDESC CC_hdesc; + +void Cancel_DisplayError(SQLSMALLINT Cancel_HandleType, + SQLHSTMT Cancel_InputHandle); +/** + * Test to terminate SQL statement precessing + * + * Tests: + * -# normal case test with correct hstmt handle + * -# SQL_STILL_EXECUTING case test with hstmt handle + * -# abnormal case test with incorrect hdbc, henv and hdesc handle + * @return Zero, if test succeeded + */ + +int SQLCancelTest() +{ + + SQLRETURN retcode; + SQLCHAR SQLStmt [120]; + + ndbout << endl << "Start SQLCancel Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &CC_henv); + + if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(CC_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + retcode = SQLAllocHandle(SQL_HANDLE_DBC, CC_henv, &CC_hdbc); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(CC_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + ndbout << "Failure to Connect DB!" << endl; + + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, CC_hdbc, &CC_hstmt); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + strcpy((char *) SQLStmt, + "select * FROM Customers"); + + //************************* + //** Prepare a statement ** + //************************* + + retcode = SQLPrepare(CC_hstmt, + SQLStmt, + SQL_NTS); + + //*********************** + //** Execute statement ** + //*********************** + + retcode = SQLExecute(CC_hstmt); + + //************************************************ + //** Test 1 ** + //** Input correct hstmt handle for normal test ** + //************************************************ + + retcode = SQLCancel(CC_hstmt); + + if (retcode == SQL_INVALID_HANDLE) + { + ndbout << "Test 1" << endl; + ndbout << "Handle Type is SQL_HANDLE_STMT, but SQL_INVALID_HANDLE" + << "still appeared. Please check program" << endl; + } + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Test 1" << endl; + Cancel_DisplayError(SQL_HANDLE_STMT, CC_hstmt); + } + //************************************************ + //** Test 2 ** + //** SQL_STILL_EXECUTING is not defined ** + //************************************************ + + if (retcode == SQL_STILL_EXECUTING) + { + ndbout << "Test 2" << endl; + ndbout << "The function is still processing." << endl; + } + + if (retcode == SQL_ERROR) + { + ndbout << "Test 2" << endl; + ndbout << "The Asynchronous processing was successfully canceled!" + << endl; + } + //********************************* + //** Test 3 ** + //** Input incorrect henv handle ** + //********************************* + + retcode = SQLCancel(CC_henv); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + { + ndbout << "Test 3" << endl; + ndbout << "Handle Type is SQL_HANDLE_ENV, but SQL_SUCCESS_WITH_INFO" + << " still appeared. Please check program" << endl; + Cancel_DisplayError(SQL_HANDLE_ENV, CC_henv); + } + + //********************************* + //** Test 4 ** + //** Input incorrect hdbc handle ** + //********************************* + + retcode = SQLCancel(CC_hdbc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + { + ndbout << "Test 4" << endl; + ndbout << "Handle Type is SQL_HANDLE_DBC, but SQL_SUCCESS_WITH_INFO" + << "still appeared. Please check programm" << endl; + Cancel_DisplayError(SQL_HANDLE_DBC, CC_hdbc); + } + + //********************************** + //** Test 5 ** + //** Input incorrect handle hdesc ** + //********************************** + + retcode = SQLCancel(CC_hdesc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + { + ndbout << endl + << "Handle Type is SQL_HANDLE_DESC, but SQL_SUCCESS_WITH_INFO" + << "still appeared. Please check program" << endl; + ndbout << "Test 5" << endl; + Cancel_DisplayError(SQL_HANDLE_DESC, CC_hdesc); + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(CC_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, CC_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, CC_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, CC_henv); + + return NDBT_OK; + + } + +void Cancel_DisplayError(SQLSMALLINT Cancel_HandleType, + SQLHSTMT Cancel_InputHandle) +{ + SQLCHAR Sqlstate[5]; + SQLRETURN SQLSTATEs; + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + SQLCHAR Msg[Cancel_MESSAGE_LENGTH]; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(Cancel_HandleType, + Cancel_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << Cancel_HandleType << endl; + ndbout << "the InputHandle is :" << (long)Cancel_InputHandle << endl; + ndbout << "the Msg is: " << (char *) Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLCloseCursorTest.cpp b/ndb/test/odbc/client/SQLCloseCursorTest.cpp new file mode 100644 index 00000000000..35f125df59d --- /dev/null +++ b/ndb/test/odbc/client/SQLCloseCursorTest.cpp @@ -0,0 +1,92 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void CloseCursor_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLCloseCursorTest() +{ + /* "If there is no open cursor associated with S, then an exception is raised: invalid cursor state" How to test this case */ + + /* hstmt */ + retcode = SQLCloseCursor(hstmt); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + CloseCursor_DisplayError(SQL_HANDLE_STMT, hstmt); + + /* henv */ + retcode = SQLCloseCursor(henv); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_SUCCESS_WITH_INFO still appeared. Please check programm" << endl; + // CloseCursor_DisplayError(SQL_HANDLE_ENV, henv); + + /* hdbc */ + retcode = SQLCloseCursor(hdbc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_SUCCESS_WITH_INFO still appeared. Please check programm" << endl; + // CloseCursor_DisplayError(SQL_HANDLE_DBC, hdbc); + + /* hdesc */ + retcode = SQLCloseCursor(hdesc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_DESC, but string SQL_SUCCESS_WITH_INFO still appeared. Please check programm" << endl; + // CloseCursor_DisplayError(SQL_HANDLE_DESC, hdesc); + + return 0; + + } + + +void CloseCursor_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLColAttributeTest.cpp b/ndb/test/odbc/client/SQLColAttributeTest.cpp new file mode 100644 index 00000000000..4c067c21d7d --- /dev/null +++ b/ndb/test/odbc/client/SQLColAttributeTest.cpp @@ -0,0 +1,328 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * @file SQLColAttributeTest.cpp + */ + +#include <common.hpp> +using namespace std; + +#define MAXIMUM_MESSAGE_LENGTH_Test 200 +#define BufferLengthTest 156 + +SQLHSTMT ColAtt_hstmt; +SQLHSTMT ColAtt_hdbc; +SQLHENV ColAtt_henv; +SQLHDESC ColAtt_hdesc; + +SQLCHAR CharacterAttributePtr; +SQLINTEGER NumericAttributePtr; +SQLSMALLINT StringLengthPtr; + +SQLRETURN ColAtt_ret; + +void ColAtt_DisplayError(SQLSMALLINT ColAtt_HandleType, + SQLHSTMT ColAtt_InputHandle); + +/** + * Test returning descriptor information + * + * Tests: + * -# Call SQLColAttribute, without preceeding SQLPrepare + * -# ??? + * + * @return Zero, if test succeeded + */ +int SQLColAttributeTest() +{ + ndbout << endl << "Start SQLColAttribute Testing" << endl; + + SQLCHAR SQLStmt [120]; + + /******************************************************************** + ** Test 1: ** + ** ** + ** Checks to execute SQLColAttribute, when there is no ** + ** prepared or executed statement associated with StatementHandle ** + ** ** + ** Intended result: SQL_ERROR ??? ** + ********************************************************************/ + ColAtt_ret = SQLColAttribute(ColAtt_hstmt, + 1, + SQL_DESC_AUTO_UNIQUE_VALUE, + &CharacterAttributePtr, + BufferLengthTest, + &StringLengthPtr, + &NumericAttributePtr); + + if (ColAtt_ret == SQL_ERROR) + { + ndbout << "ColAtt_ret = " << ColAtt_ret << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + else if (ColAtt_ret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "ColAtt_ret = " << ColAtt_ret << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + else if (ColAtt_ret == SQL_SUCCESS) + { + ndbout << "ColAtt_ret = " << ColAtt_ret << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + else if (ColAtt_ret == -2) + { + ndbout << "ColAtt_ret = " << ColAtt_ret << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + else + { + ndbout << "ColAtt_ret = " << ColAtt_ret << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + + //******************************************************************* + //** Test 2: ** + //** ** + //** hstmt ** + //** Execute a statement to retrieve rows from the Customers table ** + //** We can create the table and insert rows into Mysql ** + //** ** + //** Intended result: ??? ** + //******************************************************************* + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + ColAtt_ret = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &ColAtt_henv); + + if (ColAtt_ret == SQL_SUCCESS || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 2.x ** + //********************************************* + ColAtt_ret = SQLSetEnvAttr(ColAtt_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC2, + SQL_IS_UINTEGER); + + if (ColAtt_ret == SQL_SUCCESS || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 2.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + ColAtt_ret = SQLAllocHandle(SQL_HANDLE_DBC, + ColAtt_henv, + &ColAtt_hdbc); + + if (ColAtt_ret == SQL_SUCCESS || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + ColAtt_ret = SQLConnect(ColAtt_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (ColAtt_ret == SQL_SUCCESS || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + //******************************* + //** Allocate statement handle ** + //******************************* + + ColAtt_ret = SQLAllocHandle(SQL_HANDLE_STMT, + ColAtt_hdbc, + &ColAtt_hstmt); + if(ColAtt_ret == SQL_SUCCESS || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + /* + strcpy((char *) SQLStmt, + "DELETE FROM Customers WHERE CustID = 6"); + */ + + strcpy((char *) SQLStmt, + "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (6, 'Jan', 'LM vag 8', '969696')"); + + /* + strcpy((char *) SQLStmt, + "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (?, ?, ?, ?)"); + */ + + //******************************** + //** Prepare SQL statement ** + //******************************** + ColAtt_ret = SQLPrepare(ColAtt_hstmt, + SQLStmt, + SQL_NTS); + + if (ColAtt_ret == SQL_SUCCESS || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + { + //************************************************************** + //** FieldIdentifer is not one of the code valuess in Table 20, + //** "Codes used for descriptor fields" + //************************************************************** + ColAtt_ret = SQLColAttribute(ColAtt_hstmt, + 2, + 9999, + &CharacterAttributePtr, + BufferLengthTest, + &StringLengthPtr, + &NumericAttributePtr); + + if (ColAtt_ret == SQL_ERROR || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "FieldIdentifer is not one of the" << endl; + ndbout << "code valuess in Table 20, Codes used for" << endl; + ndbout << "descriptor fields" <<endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + + //**************************************************************** + //** Let TYPE is 'ITEM' in Table 20, ColumnNumber is less than one + //**************************************************************** + ColAtt_ret = SQLColAttribute(ColAtt_hstmt, + -1, + SQL_DESC_BASE_COLUMN_NAME, + &CharacterAttributePtr, + BufferLengthTest, + &StringLengthPtr, + &NumericAttributePtr); + + if (ColAtt_ret == SQL_ERROR || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Let TYPE is 'ITEM' in Table 20,ColumnNumber" + << "is less than one" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + + //********************************************************* + //** Let TYPE is 'ITEM' in Table 20, FieldIdentifer is zero + //********************************************************* + ColAtt_ret = SQLColAttribute(ColAtt_hstmt, + 1018, + 0, + &CharacterAttributePtr, + BufferLengthTest, + &StringLengthPtr, + &NumericAttributePtr); + + if (ColAtt_ret == SQL_ERROR || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Let TYPE is 'ITEM' in Table 20, FieldIdentifer" + << " is zero" <<endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + + //********************************************************** + //** Let TYPE is 'ITEM' in Table 20, ColumnNumber is greater + //** than TOP_LEVEL_COUNT(1044) + //********************************************************* + ColAtt_ret = SQLColAttribute(ColAtt_hstmt, + 1045, + SQL_DESC_BASE_COLUMN_NAME, + &CharacterAttributePtr, + BufferLengthTest, + &StringLengthPtr, + &NumericAttributePtr); + + if (ColAtt_ret == SQL_ERROR || ColAtt_ret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Let TYPE is 'ITEM' in Table 20, ColumnNumber" << endl + << "is greater than TOP_LEVEL_COUNT(1044)" << endl; + ColAtt_DisplayError(SQL_HANDLE_STMT, ColAtt_hstmt); + } + + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(ColAtt_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, ColAtt_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, ColAtt_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, ColAtt_henv); + + return NDBT_OK; +} + +void ColAtt_DisplayError(SQLSMALLINT ColAtt_HandleType, + SQLHSTMT ColAtt_InputHandle) +{ + SQLSMALLINT ColAtt_i = 1; + SQLRETURN ColAtt_SQLSTATEs; + SQLCHAR ColAtt_Sqlstate[5]; + SQLCHAR ColAtt_Msg[MAXIMUM_MESSAGE_LENGTH_Test]; + SQLSMALLINT ColAtt_MsgLen; + SQLINTEGER ColAtt_NativeError; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((ColAtt_SQLSTATEs = SQLGetDiagRec(ColAtt_HandleType, + ColAtt_InputHandle, + ColAtt_i, + ColAtt_Sqlstate, + &ColAtt_NativeError, + ColAtt_Msg, + sizeof(ColAtt_Msg), + &ColAtt_MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << ColAtt_HandleType << endl; + ndbout << "the InputHandle is :" << (long)ColAtt_InputHandle << endl; + ndbout << "the ColAtt_Msg is: " << (char *) ColAtt_Msg << endl; + ndbout << "the output state is:" << (char *)ColAtt_Sqlstate << endl; + + ColAtt_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLColAttributeTest1.cpp b/ndb/test/odbc/client/SQLColAttributeTest1.cpp new file mode 100644 index 00000000000..322a21eefc1 --- /dev/null +++ b/ndb/test/odbc/client/SQLColAttributeTest1.cpp @@ -0,0 +1,143 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * @file SQLColAttributeTest1.cpp + */ + +#include <common.hpp> +using namespace std; + +#define MAXIMUM_MESSAGE_LENGTH_Test1 200 +#define BufferLenghTest1 156 + +SQLHSTMT ColAtt_hstmtTest1; +SQLHSTMT ColAtt_hdbcTest1; +SQLHENV ColAtt_henvTest1; +SQLHDESC ColAtt_hdescTest1; + +SQLCHAR CharacterAttributePtrTest1; +SQLINTEGER NumericAttributePtrTest1; +SQLSMALLINT StringLengthPtrTest1; + +SQLRETURN ColAtt_retTest1; + +void ColAtt_DisplayErrorTest1(SQLSMALLINT ColAtt_HandleType, + SQLHSTMT ColAtt_InputHandle); + +/** + * Test returning descriptor information + * + * Tests: + * -# Execute SQLColAttribute without prepared or executed statement + * + * @return Zero, if test succeeded + */ +int SQLColAttributeTest1() +{ + ndbout << endl << "Start SQLColAttribute Testing1" << endl; + /******************************************************************** + ** Test : ** + ** ** + ** Checks to execute SQLColAttribute, when there is no ** + ** prepared or executed statement associated with StatementHandle ** + ** ** + ** Intended result:CLI-specific condition-function sequence error ** + ********************************************************************/ + ColAtt_retTest1 = SQLColAttribute(ColAtt_hstmtTest1, + 1, + SQL_DESC_AUTO_UNIQUE_VALUE, + &CharacterAttributePtrTest1, + BufferLenghTest1, + &StringLengthPtrTest1, + &NumericAttributePtrTest1); + + if (ColAtt_retTest1 == SQL_ERROR) + { + ndbout << "ColAtt_ret = " << ColAtt_retTest1 << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayErrorTest1(SQL_HANDLE_STMT, ColAtt_hstmtTest1); + } + else if (ColAtt_retTest1 == SQL_SUCCESS_WITH_INFO) + { + ndbout << "ColAtt_ret = " << ColAtt_retTest1 << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayErrorTest1(SQL_HANDLE_STMT, ColAtt_hstmtTest1); + } + else if (ColAtt_retTest1 == SQL_SUCCESS) + { + ndbout << "ColAtt_ret = " << ColAtt_retTest1 << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayErrorTest1(SQL_HANDLE_STMT, ColAtt_hstmtTest1); + } + else if (ColAtt_retTest1 == -2) + { + ndbout << "ColAtt_ret = " << ColAtt_retTest1 << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayErrorTest1(SQL_HANDLE_STMT, ColAtt_hstmtTest1); + } + else + { + ndbout << "ColAtt_ret = " << ColAtt_retTest1 << endl; + ndbout << endl << "There is no prepared or executed" << endl + << " statement associated with StatementHandle" << endl; + ColAtt_DisplayErrorTest1(SQL_HANDLE_STMT, ColAtt_hstmtTest1); + } + + return NDBT_OK; +} + +void ColAtt_DisplayErrorTest1(SQLSMALLINT ColAtt_HandleType, + SQLHSTMT ColAtt_InputHandle) +{ + SQLSMALLINT ColAtt_i = 1; + SQLRETURN ColAtt_SQLSTATEs; + SQLCHAR ColAtt_Sqlstate[5]; + SQLCHAR ColAtt_Msg[MAXIMUM_MESSAGE_LENGTH_Test1]; + SQLSMALLINT ColAtt_MsgLen; + SQLINTEGER ColAtt_NativeError; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((ColAtt_SQLSTATEs = SQLGetDiagRec(ColAtt_HandleType, + ColAtt_InputHandle, + ColAtt_i, + ColAtt_Sqlstate, + &ColAtt_NativeError, + ColAtt_Msg, + sizeof(ColAtt_Msg), + &ColAtt_MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << ColAtt_HandleType << endl; + ndbout << "the InputHandle is :" << (long)ColAtt_InputHandle << endl; + ndbout << "the ColAtt_Msg is: " << (char *) ColAtt_Msg << endl; + ndbout << "the output state is:" << (char *)ColAtt_Sqlstate << endl; + + ColAtt_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLColAttributeTest2.cpp b/ndb/test/odbc/client/SQLColAttributeTest2.cpp new file mode 100644 index 00000000000..18cffae76c1 --- /dev/null +++ b/ndb/test/odbc/client/SQLColAttributeTest2.cpp @@ -0,0 +1,277 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLColAttributeTest2.cpp + */ + +#include <common.hpp> +using namespace std; + +#define MAXIMUM_MESSAGE_LENGTH_Test2 200 +#define BufferLengthTest2 156 + +SQLHSTMT ColAtt_hstmtTest2; +SQLHSTMT ColAtt_hdbcTest2; +SQLHENV ColAtt_henvTest2; +SQLHDESC ColAtt_hdescTest2; + +SQLCHAR CharacterAttributePtrTest2; +SQLINTEGER NumericAttributePtrTest2; +SQLSMALLINT StringLengthPtrTest2; + +SQLRETURN ColAtt_retTest2; + +void ColAtt_DisplayErrorTest2(SQLSMALLINT ColAttTest2_HandleType, + SQLHSTMT ColAttTest2_InputHandle); + +/** + * Test returning descriptor information + * + * Test: + * -# Call SQLColAttribute without preceeding SQLExecute + * -# Let TYPE is 'ITEM' in Table 20, FieldIdentifer is zero + * -# Let TYPE is 'ITEM' in Table 20, ColumnNumber is less than one + * -# FieldIdentifer is not one of the code valuess in Table 20 + * -# Let TYPE is 'ITEM' in Table 20, ColumnNumber is greater than 1044 + * + * @return Zero, if test succeeded + */ +int SQLColAttributeTest2() +{ + ndbout << endl << "Start SQLColAttribute Testing2" << endl; + + SQLCHAR SQLStmt [120]; + + //******************************************************************* + //** Test ** + //** ** + //** hstmt ** + //** Prepare a statement without executing the statement ** + //** ** + //** Intended result: table Customer should not have new row ** + //******************************************************************* + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + ColAtt_retTest2 = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &ColAtt_henvTest2); + + if (ColAtt_retTest2 == SQL_SUCCESS || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + ColAtt_retTest2 = SQLSetEnvAttr(ColAtt_henvTest2, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (ColAtt_retTest2 == SQL_SUCCESS || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 2.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + ColAtt_retTest2 = SQLAllocHandle(SQL_HANDLE_DBC, + ColAtt_henvTest2, + &ColAtt_hdbcTest2); + + if (ColAtt_retTest2 == SQL_SUCCESS || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + ColAtt_retTest2 = SQLConnect(ColAtt_hdbcTest2, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (ColAtt_retTest2 == SQL_SUCCESS || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + ColAtt_retTest2 = SQLAllocHandle(SQL_HANDLE_STMT, + ColAtt_hdbcTest2, + &ColAtt_hstmtTest2); + if(ColAtt_retTest2 == SQL_SUCCESS || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + /* + strcpy((char *) SQLStmt, + "DELETE FROM Customers WHERE CustID = 6"); + */ + + strcpy((char *) SQLStmt, + "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (6, 'Jan', 'LM vag 8', '969696')"); + + /* + strcpy((char *) SQLStmt, + "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (?, ?, ?, ?)"); + */ + + //******************************** + //** Prepare SQL statement ** + //******************************** + ColAtt_retTest2 = SQLPrepare(ColAtt_hstmtTest2, + SQLStmt, + SQL_NTS); + + if (ColAtt_retTest2 == SQL_SUCCESS || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + { + //************************************************************** + //** FieldIdentifer is not one of the code valuess in Table 20, + //** "Codes used for descriptor fields" + //************************************************************** + ColAtt_retTest2 = SQLColAttribute(ColAtt_hstmtTest2, + 2, + 9999, + &CharacterAttributePtrTest2, + BufferLengthTest2, + &StringLengthPtrTest2, + &NumericAttributePtrTest2); + + if (ColAtt_retTest2 == SQL_ERROR || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "FieldIdentifer is not one of the" << endl; + ndbout << "code valuess in Table 20, Codes used for" << endl; + ndbout << "descriptor fields" <<endl; + ColAtt_DisplayErrorTest2(SQL_HANDLE_STMT, ColAtt_hstmtTest2); + } + + //**************************************************************** + //** Let TYPE is 'ITEM' in Table 20, ColumnNumber is less than one + //**************************************************************** + ColAtt_retTest2 = SQLColAttribute(ColAtt_hstmtTest2, + -1, + SQL_DESC_BASE_COLUMN_NAME, + &CharacterAttributePtrTest2, + BufferLengthTest2, + &StringLengthPtrTest2, + &NumericAttributePtrTest2); + + if (ColAtt_retTest2 == SQL_ERROR || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Let TYPE is 'ITEM' in Table 20,ColumnNumber" + << "is less than one" << endl; + ColAtt_DisplayErrorTest2(SQL_HANDLE_STMT, ColAtt_hstmtTest2); + } + + //********************************************************* + //** Let TYPE is 'ITEM' in Table 20, FieldIdentifer is zero + //********************************************************* + ColAtt_retTest2 = SQLColAttribute(ColAtt_hstmtTest2, + 1018, + 0, + &CharacterAttributePtrTest2, + BufferLengthTest2, + &StringLengthPtrTest2, + &NumericAttributePtrTest2); + + if (ColAtt_retTest2 == SQL_ERROR || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Let TYPE is 'ITEM' in Table 20, FieldIdentifer" + << " is zero" <<endl; + ColAtt_DisplayErrorTest2(SQL_HANDLE_STMT, ColAtt_hstmtTest2); + } + + //********************************************************** + //** Let TYPE is 'ITEM' in Table 20, ColumnNumber is greater + //** than TOP_LEVEL_COUNT(1044) + //********************************************************* + ColAtt_retTest2 = SQLColAttribute(ColAtt_hstmtTest2, + 1045, + SQL_DESC_BASE_COLUMN_NAME, + &CharacterAttributePtrTest2, + BufferLengthTest2, + &StringLengthPtrTest2, + &NumericAttributePtrTest2); + + if (ColAtt_retTest2 == SQL_ERROR || ColAtt_retTest2 == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Let TYPE is 'ITEM' in Table 20, ColumnNumber" << endl + << "is greater than TOP_LEVEL_COUNT(1044)" << endl; + ColAtt_DisplayErrorTest2(SQL_HANDLE_STMT, ColAtt_hstmtTest2); + } + + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(ColAtt_hdbcTest2); + SQLFreeHandle(SQL_HANDLE_STMT, ColAtt_hstmtTest2); + SQLFreeHandle(SQL_HANDLE_DBC, ColAtt_hdbcTest2); + SQLFreeHandle(SQL_HANDLE_ENV, ColAtt_henvTest2); + + return NDBT_OK; +} + + +void ColAtt_DisplayErrorTest2(SQLSMALLINT ColAttTest2_HandleType, + SQLHSTMT ColAttTest2_InputHandle) +{ + SQLSMALLINT ColAtt_i = 1; + SQLRETURN ColAtt_SQLSTATEs; + SQLCHAR ColAtt_Sqlstate[5]; + SQLCHAR ColAtt_Msg[MAXIMUM_MESSAGE_LENGTH_Test2]; + SQLSMALLINT ColAtt_MsgLen; + SQLINTEGER ColAtt_NativeError; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((ColAtt_SQLSTATEs = SQLGetDiagRec(ColAttTest2_HandleType, + ColAttTest2_InputHandle, + ColAtt_i, + ColAtt_Sqlstate, + &ColAtt_NativeError, + ColAtt_Msg, + sizeof(ColAtt_Msg), + &ColAtt_MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << ColAttTest2_HandleType << endl; + ndbout << "the InputHandle is :" << (long)ColAttTest2_InputHandle << endl; + ndbout << "the ColAtt_Msg is: " << (char *) ColAtt_Msg << endl; + ndbout << "the output state is:" << (char *)ColAtt_Sqlstate << endl; + + ColAtt_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} diff --git a/ndb/test/odbc/client/SQLColAttributeTest3.cpp b/ndb/test/odbc/client/SQLColAttributeTest3.cpp new file mode 100644 index 00000000000..f8817565711 --- /dev/null +++ b/ndb/test/odbc/client/SQLColAttributeTest3.cpp @@ -0,0 +1,275 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLColAttributeTest3.cpp + */ + +#include <common.hpp> +using namespace std; + +#define MAXIMUM_MESSAGE_LENGTH_Test3 200 +#define BufferLengthTest3 156 + +SQLHSTMT ColAtt_hstmtTest3; +SQLHSTMT ColAtt_hdbcTest3; +SQLHENV ColAtt_henvTest3; +SQLHDESC ColAtt_hdescTest3; + +SQLCHAR TypeName[18]; +SQLSMALLINT TypeNameLen; + +SQLRETURN ColAtt_retTest3; + +void ColAtt_DisplayErrorTest3(SQLSMALLINT ColAttTest3_HandleType, + SQLHSTMT ColAttTest3_InputHandle); + +/** + * Test returning descriptor information + * + * Test: + * -# Print out column name without executing statement + * + * @return Zero, if test succeeded + */ + +int SQLColAttributeTest3() +{ + ndbout << endl << "Start SQLColAttribute Testing3" << endl; + + SQLCHAR SQLStmt [120]; + + //******************************************************************** + //** Test 3: ** + //** ** + //** Prepare a statement without executing the statement ** + //** We want to print out the Type Name of each column in the table ** + //** Customers ** + //** ** + //** Intended result: Only display column name, but there is no new ** + //** row in table Customers ** + //******************************************************************** + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + ColAtt_retTest3 = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &ColAtt_henvTest3); + + if (ColAtt_retTest3 == SQL_SUCCESS || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + ColAtt_retTest3 = SQLSetEnvAttr(ColAtt_henvTest3, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (ColAtt_retTest3 == SQL_SUCCESS || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + ColAtt_retTest3 = SQLAllocHandle(SQL_HANDLE_DBC, + ColAtt_henvTest3, + &ColAtt_hdbcTest3); + + if (ColAtt_retTest3 == SQL_SUCCESS || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + ColAtt_retTest3 = SQLConnect(ColAtt_hdbcTest3, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (ColAtt_retTest3 == SQL_SUCCESS || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + ColAtt_retTest3 = SQLAllocHandle(SQL_HANDLE_STMT, + ColAtt_hdbcTest3, + &ColAtt_hstmtTest3); + if(ColAtt_retTest3 == SQL_SUCCESS || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + /* + strcpy((char *) SQLStmt, + "DELETE FROM Customers WHERE CustID = 6"); + */ + + strcpy((char *) SQLStmt, + "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (6, 'Jan', 'LM vag 8', '969696')"); + + /* + strcpy((char *) SQLStmt, + "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (?, ?, ?, ?)"); + */ + + //***************************** + //** Prepare SQL statement ** + //***************************** + ColAtt_retTest3 = SQLPrepare(ColAtt_hstmtTest3, + SQLStmt, + SQL_NTS); + + if (ColAtt_retTest3 == SQL_SUCCESS || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + { + //************************************ + //** Display the name of column one ** + //************************************ + ColAtt_retTest3 = SQLColAttribute(ColAtt_hstmtTest3, + 1, + SQL_COLUMN_TYPE_NAME, + TypeName, + sizeof(TypeName), + &TypeNameLen, + NULL); + + if (ColAtt_retTest3 == SQL_ERROR || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "ColAtt_retTest3 = " << ColAtt_retTest3 << endl; + ndbout << endl << "Name of column 1 is:" + << (char *)TypeName <<endl; + ColAtt_DisplayErrorTest3(SQL_HANDLE_STMT, ColAtt_hstmtTest3); + } + + //************************************ + //** Display the name of column two ** + //************************************ + ColAtt_retTest3 = SQLColAttribute(ColAtt_hstmtTest3, + 2, + SQL_DESC_BASE_COLUMN_NAME, + TypeName, + sizeof(TypeName), + &TypeNameLen, + NULL); + + if (ColAtt_retTest3 == SQL_ERROR || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "ColAtt_retTest3 = " << ColAtt_retTest3 << endl; + ndbout << endl << "Name of column 2 is:" + << (char *)TypeName <<endl; + ColAtt_DisplayErrorTest3(SQL_HANDLE_STMT, ColAtt_hstmtTest3); + } + + //*************************************** + //** Display the name of column three ** + //*************************************** + ColAtt_retTest3 = SQLColAttribute(ColAtt_hstmtTest3, + 3, + SQL_DESC_BASE_COLUMN_NAME, + TypeName, + sizeof(TypeName), + &TypeNameLen, + NULL); + + if (ColAtt_retTest3 == SQL_ERROR || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + { + ndbout << "ColAtt_retTest3 = " << ColAtt_retTest3 << endl; + ndbout << endl << "Name of column 3 is:" + << (char *)TypeName <<endl; + ColAtt_DisplayErrorTest3(SQL_HANDLE_STMT, ColAtt_hstmtTest3); + } + + //************************************** + //** Display the name of column four ** + //************************************** + ColAtt_retTest3 = SQLColAttribute(ColAtt_hstmtTest3, + 4, + SQL_DESC_BASE_COLUMN_NAME, + TypeName, + sizeof(TypeName), + &TypeNameLen, + NULL); + + if (ColAtt_retTest3 == SQL_ERROR || ColAtt_retTest3 == SQL_SUCCESS_WITH_INFO) + { + ndbout << "ColAtt_retTest3 = " << ColAtt_retTest3 << endl; + ndbout << endl << "Name of column 4 is:" + << (char *)TypeName <<endl; + ColAtt_DisplayErrorTest3(SQL_HANDLE_STMT, ColAtt_hstmtTest3); + } + + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(ColAtt_hdbcTest3); + SQLFreeHandle(SQL_HANDLE_STMT, ColAtt_hstmtTest3); + SQLFreeHandle(SQL_HANDLE_DBC, ColAtt_hdbcTest3); + SQLFreeHandle(SQL_HANDLE_ENV, ColAtt_henvTest3); + + return NDBT_OK; +} + +void ColAtt_DisplayErrorTest3(SQLSMALLINT ColAttTest3_HandleType, + SQLHSTMT ColAttTest3_InputHandle) +{ + SQLSMALLINT ColAtt_i = 1; + SQLRETURN ColAtt_SQLSTATEs; + SQLCHAR ColAtt_Sqlstate[5]; + SQLCHAR ColAtt_Msg[MAXIMUM_MESSAGE_LENGTH_Test3]; + SQLSMALLINT ColAtt_MsgLen; + SQLINTEGER ColAtt_NativeError; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((ColAtt_SQLSTATEs = SQLGetDiagRec(ColAttTest3_HandleType, + ColAttTest3_InputHandle, + ColAtt_i, + ColAtt_Sqlstate, + &ColAtt_NativeError, + ColAtt_Msg, + sizeof(ColAtt_Msg), + &ColAtt_MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << ColAttTest3_HandleType << endl; + ndbout << "the InputHandle is :" << (long)ColAttTest3_InputHandle << endl; + ndbout << "the ColAtt_Msg is: " << (char *) ColAtt_Msg << endl; + ndbout << "the output state is:" << (char *)ColAtt_Sqlstate << endl; + + ColAtt_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} diff --git a/ndb/test/odbc/client/SQLConnectTest.cpp b/ndb/test/odbc/client/SQLConnectTest.cpp new file mode 100644 index 00000000000..552fc8640fe --- /dev/null +++ b/ndb/test/odbc/client/SQLConnectTest.cpp @@ -0,0 +1,165 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLConnectTest.cpp + */ +#include <common.hpp> +using namespace std; + +SQLHDBC conn_hdbc; +SQLHSTMT conn_hstmt; +SQLHENV conn_henv; +SQLHDESC conn_hdesc; +SQLRETURN conn_retcode; + +#define conn_SQL_MAXIMUM_MESSAGE_LENGTH 200 +SQLCHAR conn_Sqlstate[5]; + +SQLINTEGER conn_NativeError; +SQLSMALLINT conn_MsgLen; +SQLCHAR conn_Msg[conn_SQL_MAXIMUM_MESSAGE_LENGTH]; + +void SQLConnectTest_DisplayError_HDBC(SQLSMALLINT conn_HandleType, + SQLHDBC conn_InputHandle); + +/** + * -# Test to make a connection to an ODBC data source + * + * @return Zero, if test succeeded + */ +int SQLConnectTest() +{ + ndbout << endl << "Start SQLConnect Testing" << endl; + + // ************************************ + // ** Allocate an environment handle ** + // ************************************ + conn_retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &conn_henv); + //conn_retcode = SQLAllocEnv(&conn_henv); + if(conn_retcode == SQL_SUCCESS || conn_retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Allocated an environment handle!" << endl; + } + else + { + ndbout << "Failed to allocate environment handle!" << endl; + return NDBT_FAILED; + } + + // ********************************************* + // ** Set the ODBC application Version to 3.x ** + // ********************************************* + conn_retcode = SQLSetEnvAttr(conn_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + if (conn_retcode == SQL_SUCCESS || conn_retcode == SQL_SUCCESS_WITH_INFO) { + ndbout << "Set ODBC application version to 3.x" << endl; + } else { + ndbout << "Failed to set application version!" << endl; + return NDBT_FAILED; + } + + // ********************************** + // ** Allocate a connection handle ** + // ********************************** + conn_retcode = SQLAllocHandle(SQL_HANDLE_DBC, conn_henv, &conn_hdbc); + // retcode = SQLAllocConnect(conn_henv, &conn_hdbc); + if (conn_retcode == SQL_SUCCESS || conn_retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Allocated a connection handle!" << endl; + } + else + { + ndbout << "Failed to allocate connection handle!" << endl; + return NDBT_FAILED; + } + + // ******************* + // ** Connect to DB ** + // ******************* + conn_retcode = SQLConnect(conn_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + ndbout << "conn_retcode = " << conn_retcode << endl; + if (conn_retcode == SQL_SUCCESS) + { + ndbout << "Connected to DB!" << endl; + } + else if (conn_retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Connected to DB, but SQL_SUCCESS_WITH_INFO!" << endl; + SQLConnectTest_DisplayError_HDBC(SQL_HANDLE_DBC, conn_hdbc); + } + else if (conn_retcode == SQL_INVALID_HANDLE) + { + ndbout << "SQL_INVALID_HANDLE appeared. Please check program." << endl; + return NDBT_FAILED; + } + else if (conn_retcode == SQL_ERROR) + { + ndbout << "Failed to connect!" << endl; + SQLConnectTest_DisplayError_HDBC(SQL_HANDLE_DBC, conn_hdbc); + return NDBT_FAILED; + } + else + ; + + // ****************** + // ** Free Handles ** + // ****************** + SQLDisconnect(conn_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, conn_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, conn_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, conn_henv); + return NDBT_OK; +} + + +void SQLConnectTest_DisplayError_HDBC(SQLSMALLINT conn_HandleType, + SQLHDBC conn_InputHandle) { + SQLSMALLINT conn_i = 1; + SQLRETURN conn_SQLSTATE; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((conn_SQLSTATE = SQLGetDiagRec(conn_HandleType, + conn_InputHandle, + conn_i, + conn_Sqlstate, + &conn_NativeError, + conn_Msg, + sizeof(conn_Msg), + &conn_MsgLen) + ) != SQL_NO_DATA) + { + ndbout << "SQLSTATE = " << conn_SQLSTATE << endl; + ndbout << "the HandleType is: " << conn_HandleType << endl; + ndbout << "the InputHandle is :" << (long)conn_InputHandle << endl; + ndbout << "the conn_Msg is: " << (char *) conn_Msg << endl; + ndbout << "the output state is:" << (char *)conn_Sqlstate << endl; + + conn_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} diff --git a/ndb/test/odbc/client/SQLCopyDescTest.cpp b/ndb/test/odbc/client/SQLCopyDescTest.cpp new file mode 100644 index 00000000000..4a3742f97ae --- /dev/null +++ b/ndb/test/odbc/client/SQLCopyDescTest.cpp @@ -0,0 +1,140 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 + +#define ROWS 100 +#define DESC_LEN 50 + + +// Template for a row +typedef struct { + SQLINTEGER sPartID; + SQLINTEGER cbPartID; + SQLUCHAR szDescription[DESC_LENGTH]; + SQLINTEGER cbDescription; + REAL sPrice; + SQLINTEGER cbPrice; +} PartsSource; + +PartsSource rget[ROWS]; // rowset buffer +SQLUSMALLINT sts_ptr[ROWS]; // status pointer +SQLHSTMT hstmt0, hstmt1; +SQLHDESC hArd0, hIrd0, hApd1, hIpd1; + + +SQLHSTMT hstmt; +SQLHDESC hdesc; + +SQLSMALLINT RecNumber; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLINTEGER ValuePtr1; +SQLCHAR ValuePtr2; +SQLSMALLINT ValuePtr3; + + +SQLINTEGER StringLengthPtr; + +SQLSMALLINT i, MsgLen; + +void DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLCopyDescTest () +{ + + + // We can create the table and insert rows in NDB by program TestDirectSQL. + // In this test program(SQLGetCopyRecTest),we only have three rows in table ORDERS + + +// ARD and IRD of hstmt0 +SQLGetStmtAttr(hstmt0, SQL_ATTR_APP_ROW_DESC, &hArd0, 0, NULL); +SQLGetStmtAttr(hstmt0, SQL_ATTR_IMP_ROW_DESC, &hIrd0, 0, NULL); + +// APD and IPD of hstmt1 +SQLGetStmtAttr(hstmt1, SQL_ATTR_APP_PARAM_DESC, &hApd1, 0, NULL); +SQLGetStmtAttr(hstmt1, SQL_ATTR_IMP_PARAM_DESC, &hIpd1, 0, NULL); + +// Use row-wise binding on hstmt0 to fetch rows +SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) sizeof(PartsSource), 0); + +// Set rowset size for hstmt0 +SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0); + +// Execute a select statement +SQLExecDirect(hstmt0, "SELECT PARTID, DESCRIPTION, PRICE FROM PARTS ORDER BY 3, 1, 2"", + SQL_NTS); + +// Bind +SQLBindCol(hstmt0, 1, SQL_C_SLONG, rget[0].sPartID, 0, + &rget[0].cbPartID); +SQLBindCol(hstmt0, 2, SQL_C_CHAR, &rget[0].szDescription, DESC_LEN, + &rget[0].cbDescription); +SQLBindCol(hstmt0, 3, SQL_C_FLOAT, rget[0].sPrice, + 0, &rget[0].cbPrice); + + // Perform parameter bindings on hstmt1. + /* If SourceDeschandle does not identify an allocated CLI descriptor area */ + retcode1 = SQLCopyDesc(hArd0, hApd1); + retcode2 = SQLCopyDesc(hIrd0, hIpd1); + +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_DESC, hdesc); + + + /* If TargetDeschandle does not identify an allocated CLI descriptor area */ + retcode = SQLCopyDesc(hdesc, ); + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_DESC, hdesc); + + + return 0; + + } + + +void DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLDescribeColTest.cpp b/ndb/test/odbc/client/SQLDescribeColTest.cpp new file mode 100644 index 00000000000..9f55c6a1cfe --- /dev/null +++ b/ndb/test/odbc/client/SQLDescribeColTest.cpp @@ -0,0 +1,260 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLDescribeColTest.cpp + */ +#include <common.hpp> + +using namespace std; + +#define DC_Column_NAME_LEN 50 +#define DC_MESSAGE_LENGTH 200 + +SQLHSTMT DC_hstmt; +SQLHDBC DC_hdbc; +SQLHENV DC_henv; +SQLHDESC DC_hdesc; + +void DescribeCol_DisplayError(SQLSMALLINT DC_HandleType, + SQLHSTMT DC_InputHandle); + +/** + * Test to retrieve basic result data set metadata information + * (specifically, column name, SQL data type, column size, decimal + * precision, and nullability) for a specified column in a result + * data set + * -# No prepared or executed statement when executing + * -# ColumnNumber is less than 1 + * -# ColumnNumber is greater than the value of the TOP_LEVEL_COUNT field of IRD + * @return Zero, if test succeeded + */ + +int SQLDescribeColTest() +{ + SQLCHAR SQLStmt [120]; + SQLRETURN retcode; + SQLCHAR ColumnName[DC_Column_NAME_LEN]; + SQLSMALLINT NameLength, DataTypePtr, DecimalDigitsPtr, NullablePtr; + SQLUINTEGER ColumnSizePtr; + + ndbout << "Start SQLDescribeCol Test " << endl; + //****************************************************************** + //** Test1 ** + //** There is no prepared or executed statement associated with ** + //** StatementHandle ** + //****************************************************************** + + retcode = SQLDescribeCol(DC_hstmt, + (SQLUSMALLINT)1, + ColumnName, + sizeof(ColumnName), + &NameLength, + &DataTypePtr, + &ColumnSizePtr, + &DecimalDigitsPtr, + &NullablePtr); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DescribeCol_DisplayError(SQL_HANDLE_STMT, DC_hstmt); + + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &DC_henv); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(DC_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + DC_henv, + &DC_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(DC_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + DC_hdbc, + &DC_hstmt); + if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + strcpy((char *) SQLStmt, + "SELECT * FROM Customers"); + + //*********************************************** + //** Prepare and Execute the SQL statement ** + //*********************************************** + + retcode = SQLExecDirect(DC_hstmt, + SQLStmt, + SQL_NTS); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + //********************************* + //** ColumnNumber is from 1 to 4 ** + //********************************* + ndbout << endl << "ColumnNumber is from 1 to 4" << endl; + + for (int ii = 1; ii <= 4; ii++) + { + retcode = SQLDescribeCol(DC_hstmt, + ii, + ColumnName, + sizeof(ColumnName), + &NameLength, + &DataTypePtr, + &ColumnSizePtr, + &DecimalDigitsPtr, + &NullablePtr); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Column Name = " << (char *)ColumnName << endl; + + } + + //********************************* + //** Test2 ** + //** ColumnNumber is less than 1 ** + //********************************* + + retcode = SQLDescribeCol(DC_hstmt, + (SQLUSMALLINT)-1, + ColumnName, + sizeof(ColumnName), + &NameLength, + &DataTypePtr, + &ColumnSizePtr, + &DecimalDigitsPtr, + &NullablePtr); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << endl << "ColumnNumber is less than 1" << endl; + DescribeCol_DisplayError(SQL_HANDLE_STMT, DC_hstmt); + + //********************************************************************* + //** Test3 ** + //** ColumnNumber is greater than N(the value of the TOP_LEVEL_COUNT ** + //** field of IRD) ** + //********************************************************************* + + ndbout << endl <<"ColumnNumber is greater than N(the value" + << "of the TOP_LEVEL_COUNTfield of IRD)" << endl; + + retcode = SQLDescribeCol(DC_hstmt, + (SQLUSMALLINT)1045, + ColumnName, + sizeof(ColumnName), + &NameLength, + &DataTypePtr, + &ColumnSizePtr, + &DecimalDigitsPtr, + &NullablePtr); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DescribeCol_DisplayError(SQL_HANDLE_STMT, DC_hstmt); + +} + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(DC_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, DC_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, DC_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, DC_henv); + + return NDBT_OK; +} + +void DescribeCol_DisplayError(SQLSMALLINT DC_HandleType, + SQLHSTMT DC_InputHandle) +{ + SQLCHAR Sqlstate[5], Msg[DC_MESSAGE_LENGTH]; + SQLINTEGER NativeError; + SQLSMALLINT DC_i, MsgLen; + SQLRETURN SQLSTATEs; + + DC_i = 1; + + while ((SQLSTATEs = SQLGetDiagRec(DC_HandleType, + DC_InputHandle, + DC_i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << DC_HandleType << endl; + ndbout << "the InputHandle is :" << (long)DC_InputHandle << endl; + ndbout << "the return message is:" << (char *)Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + DC_i ++; + break; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLDisconnectTest.cpp b/ndb/test/odbc/client/SQLDisconnectTest.cpp new file mode 100644 index 00000000000..823b446ab84 --- /dev/null +++ b/ndb/test/odbc/client/SQLDisconnectTest.cpp @@ -0,0 +1,155 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLDisconnectTest.cpp + */ + +#include <common.hpp> +#define disc_SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC disc_hdbc; +SQLHSTMT disc_hstmt; +SQLHENV disc_henv; +SQLHDESC disc_hdesc; + +void Disconnect_DisplayError_HDBC(SQLSMALLINT disc_HandleType, + SQLHDBC disc_InputHandle); +/** + * Test to close the data source connection associated with + * a specific connection handle + * + * -# Normal case testing + * @return Zero, if test succeeded + */ + +int SQLDisconnectTest() +{ + SQLRETURN disc_retcode; + ndbout << endl << "Start SQLDisconnect Testing" << endl; + + // ************************************ + // ** Allocate an environment handle ** + // ************************************ + disc_retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &disc_henv); + + if(disc_retcode == SQL_SUCCESS || disc_retcode == SQL_SUCCESS_WITH_INFO) { + ndbout << "Allocated an environment handle!" << endl; + } else { + ndbout << "Failed to allocate environment handle!" << endl; + return NDBT_FAILED; + } + + // ********************************************* + // ** Set the ODBC application Version to 3.x ** + // ********************************************* + disc_retcode = SQLSetEnvAttr(disc_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + if (disc_retcode == SQL_SUCCESS || disc_retcode == SQL_SUCCESS_WITH_INFO) { + ndbout << "Set ODBC application version to 3.x" << endl; + } else { + ndbout << "Failed to set application version!" << endl; + return NDBT_FAILED; + } + + // ********************************** + // ** Allocate a connection handle ** + // ********************************** + disc_retcode = SQLAllocHandle(SQL_HANDLE_DBC, disc_henv, &disc_hdbc); + + if (disc_retcode == SQL_SUCCESS || disc_retcode == SQL_SUCCESS_WITH_INFO) { + ndbout << "Allocated a connection handle!" << endl; + } else { + ndbout << "Failed to allocate connection handle!" << endl; + return NDBT_FAILED; + } + + // ******************* + // ** connect to DB ** + // ******************* + disc_retcode = SQLConnect(disc_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + // ********************** + // ** Disconnect to DB ** + // ********************** + disc_retcode = SQLDisconnect(disc_hdbc); + + if (disc_retcode == SQL_INVALID_HANDLE) +{ + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE" + << " still appeared. Please check program" << endl; + Disconnect_DisplayError_HDBC(SQL_HANDLE_DBC, disc_hdbc); +} + + if (disc_retcode == SQL_ERROR || disc_retcode == SQL_SUCCESS_WITH_INFO) +{ + ndbout << "disconnect retcode = " << disc_retcode << endl; + Disconnect_DisplayError_HDBC(SQL_HANDLE_DBC, disc_hdbc); +} + // ****************** + // ** Free Handles ** + // ****************** + SQLFreeHandle(SQL_HANDLE_STMT, disc_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, disc_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, disc_henv); + + return NDBT_OK; + + } + +void Disconnect_DisplayError_HDBC(SQLSMALLINT disc_HandleType, + SQLHDBC disc_InputHandle) +{ + SQLCHAR disc_Msg[disc_SQL_MAXIMUM_MESSAGE_LENGTH]; + SQLSMALLINT disc_i, disc_MsgLen; + SQLINTEGER disc_NativeError; + SQLRETURN disc_SQLSTATEs; + disc_i = 1; + SQLCHAR disc_Sqlstate[5]; + + while ((disc_SQLSTATEs = SQLGetDiagRec(disc_HandleType, + disc_InputHandle, + disc_i, + disc_Sqlstate, + &disc_NativeError, + disc_Msg, + sizeof(disc_Msg), + &disc_MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << disc_HandleType << endl; + ndbout << "the InputHandle is :" <<(long)disc_InputHandle << endl; + ndbout << "the output state is:" << (char *)disc_Sqlstate << endl; + + disc_i ++; + break; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLDriverConnectTest.cpp b/ndb/test/odbc/client/SQLDriverConnectTest.cpp new file mode 100644 index 00000000000..fc3b1d10f91 --- /dev/null +++ b/ndb/test/odbc/client/SQLDriverConnectTest.cpp @@ -0,0 +1,96 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.hpp> +#include <string.h> + +using namespace std; + +SQLHDBC driconn_hdbc; +SQLHSTMT driconn_hstmt; +SQLHENV driconn_henv; +SQLHDESC driconn_hdesc; +SQLRETURN driconn_retcode, driconn_SQLSTATEs; + +#define driconn_SQL_MAXIMUM_MESSAGE_LENGTH 200 +SQLCHAR driconn_Sqlstate[5]; + +SQLINTEGER driconn_NativeError; +SQLSMALLINT driconn_i, driconn_MsgLen; +SQLCHAR driconn_Msg[driconn_SQL_MAXIMUM_MESSAGE_LENGTH], driconn_ConnectIn[30]; + +void SQLDriverConnectTest_DisplayError_HDBC(SQLSMALLINT driconn_HandleType, SQLHDBC driconn_InputHandle); + +int SQLDriverConnectTest() +{ + ndbout << endl << "Start SQLDriverConnect Testing" << endl; + // Allocate An Environment Handle + driconn_retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &driconn_henv); + + // Set the ODBC application Version to 3.x + driconn_retcode = SQLSetEnvAttr(driconn_henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER); + + if (driconn_retcode == SQL_SUCCESS || driconn_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x" << endl; + + // Allocate A Connection Handle + driconn_retcode = SQLAllocHandle(SQL_HANDLE_DBC, driconn_henv, &driconn_hdbc); + + if (driconn_retcode == SQL_SUCCESS || driconn_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocation A Connection Handle" << endl; + + // Build A Connection String + strcpy((char*) driconn_ConnectIn, "DSN=ndb;UID=x;PWD=y"); + + // Connect to NDB + driconn_retcode = SQLDriverConnect(driconn_hdbc, NULL, driconn_ConnectIn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT); + ndbout << "retcode = " << driconn_retcode << endl; + ndbout << "Before pringing out information about connection, we print out retcode = " << driconn_retcode << endl; + + if (driconn_retcode == SQL_SUCCESS || driconn_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to NDB" << endl; + + if (driconn_retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + else + { if (driconn_retcode == SQL_ERROR || driconn_retcode == SQL_SUCCESS_WITH_INFO) + SQLDriverConnectTest_DisplayError_HDBC(SQL_HANDLE_DBC, driconn_hdbc);} + + // Free the Connection Handle + SQLFreeHandle(SQL_HANDLE_DBC, driconn_hdbc); + + // Free the Environment Handle + SQLFreeHandle(SQL_HANDLE_ENV, driconn_henv); + + return 0; + } + +void SQLDriverConnectTest_DisplayError_HDBC(SQLSMALLINT driconn_HandleType, SQLHDBC driconn_InputHandle) +{ + driconn_i = 1; + while ((driconn_SQLSTATEs = SQLGetDiagRec(driconn_HandleType, driconn_InputHandle, driconn_i, + driconn_Sqlstate, &driconn_NativeError, driconn_Msg, sizeof(driconn_Msg), + &driconn_MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << driconn_HandleType << endl; + ndbout << "the InputHandle is :" << (long)driconn_InputHandle << endl; + ndbout << "the output state is:" << (char *)driconn_Sqlstate << endl; + + driconn_i ++; + } + +} diff --git a/ndb/test/odbc/client/SQLEndTranTest.cpp b/ndb/test/odbc/client/SQLEndTranTest.cpp new file mode 100644 index 00000000000..06c497954fd --- /dev/null +++ b/ndb/test/odbc/client/SQLEndTranTest.cpp @@ -0,0 +1,108 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> + +using namespace std; + +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLINTEGER strangehandle; +SQLRETURN retcode, retcodeprepare, SQLSTATEs; +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLSMALLINT Not_In_Table13; + +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + + +void SQLEndTran_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLEndTranTest() +{ + + strangehandle = 67; + /* hstmt */ + // Execute a statement to retrieve rows from the Customers table. We can create the table and + // inside rows into NDB by program TestDirectSQL + // retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", 56); + + retcodeprepare = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcodeprepare == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + retcode = SQLExecute(hstmt); + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + + /* HandleType is not in Table 13 */ + Not_In_Table13 = 67; + SQLSTATEs = SQLEndTran(Not_In_Table13, (void*)strangehandle , SQL_COMMIT); + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(67, 67, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:67" << endl; + ndbout << "the InputHandle is :67" << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + + } + + /* HandleType is STATEMENT HANDLE, if the value of Handle does not identity an allocated SQL_statement */ + SQLSTATEs = SQLEndTran(SQL_HANDLE_STMT, hdbc, SQL_COMMIT); + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLEndTran_DisplayError(SQL_HANDLE_STMT, hstmt); + + /* The value of CompletionType is not in Table 14 */ + SQLSTATEs = SQLEndTran(SQL_HANDLE_STMT, hstmt, 8888); + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLEndTran_DisplayError(SQL_HANDLE_STMT, hstmt); + + } + + } + return 0; + + } + + +void SQLEndTran_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLErrorTest.cpp b/ndb/test/odbc/client/SQLErrorTest.cpp new file mode 100644 index 00000000000..5220e7b5eed --- /dev/null +++ b/ndb/test/odbc/client/SQLErrorTest.cpp @@ -0,0 +1,107 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#if 0 + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +SQLCHAR szName[NAME_LEN], szPhone[PHONE_LEN]; +SQLINTEGER sCustID, cbName, cbCustID, cbPhone, NativeError; + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLBindColTest () +{ + + /* hstmt */ + // Execute a statement to retrieve rows from the Customers table. We can create the table and inside rows in + // NDB by another program TestDirectSQL. In this test program(SQLBindColTest),we only have three rows in + // table CUSTOMERS + +retcode = SQLExecDirect(hstmt, (SQLCHAR*)"SELECT CUSTID, NAME, PHONE FROM CUSTOMERS ORDER BY 2, 1, 3", SQL_NTS); +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + +SQLBindCol(hstmt, 0, SQL_C_ULONG, &sCustID, 0, &cbCustID); +while (TRUE) { +retcode = SQLFetch(hstmt); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + + } + + +SQLBindCol(hstmt, 4, SQL_C_ULONG, &sCustID, 0, &cbCustID); +while (TRUE) { +retcode = SQLFetch(hstmt); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + + } + +/* Bind columns 1, 2, and 3 */ +SQLBindCol(hstmt, 1, SQL_C_ULONG, &sCustID, 0, &cbCustID); +SQLBindCol(hstmt, 2, SQL_C_CHAR, szName, NAME_LEN, &cbName); +SQLBindCol(hstmt, 3, SQL_C_CHAR, szPhone, PHONE_LEN, &cbPhone); +/* Fetch and print each row of data. On */ +/* an error, display a message and exit. */ +while (TRUE) { +retcode = SQLFetch(hstmt); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + DisplayError(SQL_HANDLE_STMT, hstmt); + + } + } + + return 0; + + } + + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + +#endif diff --git a/ndb/test/odbc/client/SQLExecDirectTest.cpp b/ndb/test/odbc/client/SQLExecDirectTest.cpp new file mode 100644 index 00000000000..b9b4e770412 --- /dev/null +++ b/ndb/test/odbc/client/SQLExecDirectTest.cpp @@ -0,0 +1,353 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLExecDirectTest.cpp + */ +#include <common.hpp> +#define EXD_MESSAGE_LENGTH 200 +#define EXD_NAME_LEN 10 +#define EXD_PHONE_LEN 10 +#define EXD_ADDRESS_LEN 10 +using namespace std; + +SQLHDBC EXD_hdbc; +SQLHSTMT EXD_hstmt; +SQLHENV EXD_henv; +SQLHDESC EXD_hdesc; +SQLRETURN EXD_ret, SQLSTATEs; + +void ExecDirect_DisplayError(SQLSMALLINT EXD_HandleType, + SQLHSTMT EXD_InputHandle); + +int EXD_Display_Result(SQLHSTMT EXDR_InputHandle); + +/** + * Test to execute a prepared ststement + * + * -# Normal case: Prepare and Execute a prepared statement + * -# Prepare and Execute an empty statement + * -# Prepare and Execute a statement with wrong henv handle + * -# Prepare and Execute a statement with wrong hdbc handle + * -# Prepare and Execute a statement with wrong hdesc handle + * @return Zero, if test succeeded + */ + +int SQLExecDirectTest() +{ + ndbout << endl << "Start ExecDirect Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + EXD_ret = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &EXD_henv); + +if (EXD_ret == SQL_SUCCESS || EXD_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + EXD_ret = SQLSetEnvAttr(EXD_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + +if (EXD_ret == SQL_SUCCESS || EXD_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + EXD_ret = SQLAllocHandle(SQL_HANDLE_DBC, + EXD_henv, + &EXD_hdbc); + +if (EXD_ret == SQL_SUCCESS || EXD_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + EXD_ret = SQLConnect(EXD_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + +if (EXD_ret == SQL_SUCCESS || EXD_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + EXD_ret = SQLAllocHandle(SQL_HANDLE_STMT, + EXD_hdbc, + &EXD_hstmt); +if(EXD_ret == SQL_SUCCESS || EXD_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //********************************************** + //** Test1 ** + //** Prepare and Execute a prepared statement ** + //********************************************** + EXD_ret = SQLExecDirect(EXD_hstmt, + (SQLCHAR*)"SELECT * FROM Customers", + SQL_NTS); + + if (EXD_ret == SQL_INVALID_HANDLE) + { + ndbout << "Handle Type is SQL_HANDLE_STMT, but SQL_INVALID_HANDLE" << endl; + ndbout << "still appeared. Please check program" << endl; + } + + if (EXD_ret == SQL_ERROR || EXD_ret == SQL_SUCCESS_WITH_INFO) + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXD_hstmt); + + //************************* + //** Display the results ** + //************************* + + EXD_Display_Result(EXD_hstmt); + + //******************************************* + //** Test2 ** + //** Prepare and Execute an empty statement** + //** in order to see what will happen ** + //******************************************* + EXD_ret = SQLExecDirect(EXD_hstmt, + (SQLCHAR*)" ", + SQL_NTS); + + if (EXD_ret == SQL_ERROR || EXD_ret == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Prepare and Execute an empty statement," << endl; + ndbout << "The following case happened!" << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXD_hstmt); + } + + //*************************************************************** + //** Test3 ** + //** Prepare and Execute a statement with wrong henv handle ** + //** in order to see what will happen ** + //*************************************************************** + EXD_ret = SQLExecDirect(EXD_henv, + (SQLCHAR*)"SELECT * FROM Customers", + SQL_NTS); + + if (EXD_ret == SQL_SUCCESS_WITH_INFO || EXD_ret == SQL_SUCCESS) + { ndbout << "Handle Type is SQL_HANDLE_HENV, but SQL_INVALID_HANDLE" << endl; + ndbout << "still appeared. Please check programm" << endl; + ExecDirect_DisplayError(SQL_HANDLE_ENV, EXD_henv); + } + + //****************************************************************** + //** Test4 ** + //** Prepare and Execute a statement with wrong hdbc handle ** + //** in order to see what will happen ** + //****************************************************************** + + EXD_ret = SQLExecDirect(EXD_hdbc, + (SQLCHAR*)"SELECT * FROM Customers", + SQL_NTS); + + if (EXD_ret == SQL_SUCCESS_WITH_INFO || EXD_ret == SQL_SUCCESS) + ExecDirect_DisplayError(SQL_HANDLE_DBC, EXD_hdbc); + + //******************************************************************* + //** Test5 ** + //** Prepare and Execute a statement with wrong hdesc handle ** + //** in order to see what will happen ** + //******************************************************************* + + EXD_ret = SQLExecDirect(EXD_hdesc, + (SQLCHAR*)"SELECT * FROM Customers", + SQL_NTS); + + if (EXD_ret == SQL_SUCCESS_WITH_INFO || EXD_ret == SQL_SUCCESS) + { + ndbout << "Handle Type is SQL_HANDLE_DESC, but SQL_SUCCESS_WITH_INFO" <<endl; + ndbout << "appeared. Please check program" << endl; + ExecDirect_DisplayError(SQL_HANDLE_DESC, EXD_hdesc); + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(EXD_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, EXD_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, EXD_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, EXD_henv); + + return NDBT_OK; + + } + + +void ExecDirect_DisplayError(SQLSMALLINT EXD_HandleType, + SQLHSTMT EXD_InputHandle) +{ + SQLCHAR EXD_Sqlstate[5]; + SQLINTEGER EXD_NativeError; + SQLSMALLINT EXD_i, EXD_MsgLen; + SQLCHAR EXD_Msg[EXD_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + EXD_i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(EXD_HandleType, + EXD_InputHandle, + EXD_i, + EXD_Sqlstate, + &EXD_NativeError, + EXD_Msg, + sizeof(EXD_Msg), + &EXD_MsgLen)) + != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << EXD_HandleType << endl; + ndbout << "the InputHandle is :" << (long)EXD_InputHandle << endl; + ndbout << "the ColAtt_Msg is: " << (char *) EXD_Msg << endl; + ndbout << "the output state is:" << (char *)EXD_Sqlstate << endl; + + EXD_i ++; + // break; + } + ndbout << "-------------------------------------------------" << endl; +} + +int EXD_Display_Result(SQLHSTMT EXDR_InputHandle) +{ + SQLRETURN EXD_retcode; + unsigned long EXD_CustID; + SQLCHAR EXD_Name[EXD_NAME_LEN], EXD_Phone[EXD_PHONE_LEN]; + SQLCHAR EXD_Address[EXD_ADDRESS_LEN]; + + //********************* + //** Bind columns 1 ** + //********************* + EXD_retcode =SQLBindCol(EXDR_InputHandle, + 1, + SQL_C_ULONG, + &EXD_CustID, + sizeof(EXD_CustID), + NULL); + if (EXD_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXDR_InputHandle); + return NDBT_FAILED; + } + //********************* + //** Bind columns 2 ** + //********************* + + EXD_retcode =SQLBindCol(EXDR_InputHandle, + 2, + SQL_C_CHAR, + &EXD_Name, + EXD_NAME_LEN, + NULL); + if (EXD_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXDR_InputHandle); + return NDBT_FAILED; + } + + //********************* + //** Bind columns 3 ** + //********************* + + EXD_retcode = SQLBindCol(EXDR_InputHandle, + 3, + SQL_C_CHAR, + &EXD_Address, + EXD_ADDRESS_LEN, + NULL); + + if (EXD_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXDR_InputHandle); + return NDBT_FAILED; + } + + //********************* + //** Bind columns 4 ** + //********************* + + EXD_retcode = SQLBindCol(EXDR_InputHandle, + 4, + SQL_C_CHAR, + &EXD_Phone, + EXD_PHONE_LEN, + NULL); + + if (EXD_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXDR_InputHandle); + return NDBT_FAILED; + } + + //***************************************** + //* Fetch and print each row of data. On ** + //* an error, display a message and exit ** + //***************************************** + + if (EXD_retcode != SQL_ERROR) + EXD_retcode = SQLFetch(EXDR_InputHandle); + + ndbout << endl << "EXD_retcode = SQLFetch(EXDR_InputHandle) = " + << EXD_retcode << endl; + + if (EXD_retcode == SQL_ERROR) + { + ndbout << "Executing SQLFetch, SQL_ERROR happened!" << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXDR_InputHandle); + return NDBT_FAILED; + } + else if (EXD_retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "CustID = " << (int)EXD_CustID << endl; + ndbout << "Name = " << (char *)EXD_Name << endl; + ndbout << "Address = " << (char *)EXD_Address << endl; + ndbout << "Phone = " << (char *)EXD_Phone << endl; + ExecDirect_DisplayError(SQL_HANDLE_STMT, EXDR_InputHandle); + } + else + { + ndbout << "CustID = " << (int)EXD_CustID << endl; + ndbout << "Name = " << (char *)EXD_Name << endl; + ndbout << "Address = " << (char *)EXD_Address << endl; + ndbout << "Phone = " << (char *)EXD_Phone << endl; + } + return 0; +} diff --git a/ndb/test/odbc/client/SQLExecuteTest.cpp b/ndb/test/odbc/client/SQLExecuteTest.cpp new file mode 100644 index 00000000000..5f6bdb5d4bf --- /dev/null +++ b/ndb/test/odbc/client/SQLExecuteTest.cpp @@ -0,0 +1,122 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLExecuteTest.cpp + */ + +#include <common.hpp> +#define ESQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC Ehdbc; +SQLHSTMT Ehstmt; +SQLHENV Ehenv; +SQLHDESC Ehdesc; + +void Execute_DisplayError(SQLSMALLINT EHandleType, + SQLHSTMT EInputHandle); + +/** + * Test to execute a SQL statement in a data result set + * + * Tests: + * -# Test1 There is no executed statement + * @return Zero, if test succeeded + */ +int SQLExecuteTest() +{ + + SQLRETURN retcode; + /* hstmt */ + retcode = SQLExecute(Ehstmt); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but SQL_INVALID_HANDLE" << endl; + ndbout << "still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + Execute_DisplayError(SQL_HANDLE_STMT, Ehstmt); + + /* henv */ + retcode = SQLExecute(Ehenv); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_ENV, but SQL_SUCCESS_WITH_INFO" + << "still appeared. Please check programm" << endl; + // Execute_DisplayError(SQL_HANDLE_ENV, Ehenv); + + /* hdbc */ + retcode = SQLExecute(Ehdbc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_DBC, but SQL_SUCCESS_WITH_INFO" + <<"still appeared. Please check programm" << endl; + // Execute_DisplayError(SQL_HANDLE_DBC, Ehdbc); + + /* hdesc */ + retcode = SQLExecute(Ehdesc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_DESC, but SQL_SUCCESS_WITH_INFO" + << "still appeared. Please check programm" << endl; + // Execute_DisplayError(SQL_HANDLE_DESC, Ehdesc); + + return NDBT_OK; + + } + + +void Execute_DisplayError(SQLSMALLINT EHandleType, + SQLHSTMT EInputHandle) +{ + SQLCHAR Sqlstate[5]; + + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + SQLCHAR Msg[ESQL_MAXIMUM_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(EHandleType, + EInputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << EHandleType << endl; + ndbout << "the InputHandle is :" << EInputHandle << endl; + ndbout << "the Msg is :" << (char *)Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; + + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLFetchScrollTest.cpp b/ndb/test/odbc/client/SQLFetchScrollTest.cpp new file mode 100644 index 00000000000..4a11ccd143e --- /dev/null +++ b/ndb/test/odbc/client/SQLFetchScrollTest.cpp @@ -0,0 +1,82 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <stdio.h> +#include <sqlext.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHSTMT hstmt; +SQLSMALLINT RecNumber; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLINTEGER ValuePtr1; +SQLCHAR ValuePtr2; +SQLSMALLINT ValuePtr3; +SQLSMALLINT i, MsgLen; + +void SFCT_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLFetchScrollTest () +{ + + // FetchScroll a statement to retrieve rows from the Customers table. We can + // create the table and insert rows in NDB by program TestDirectSQL + + /* There is no executed statement associated with the allocated SQL-statement identified by StatementHandle */ +retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 1); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SFCT_DisplayError(SQL_HANDLE_DESC, hstmt); + + /* FetchOrientation is not one of the code values in Table24 */ +retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 8); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SFCT_DisplayError(SQL_HANDLE_DESC, hstmt); + + return 0; + + } + + +void SFCT_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLFetchTest.cpp b/ndb/test/odbc/client/SQLFetchTest.cpp new file mode 100644 index 00000000000..bd62fcb2f04 --- /dev/null +++ b/ndb/test/odbc/client/SQLFetchTest.cpp @@ -0,0 +1,438 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLFetchTest.cpp + */ + +#include <common.hpp> +#define F_MESSAGE_LENGTH 200 +using namespace std; + +#define F_NAME_LEN 20 +#define F_PHONE_LEN 20 +#define F_ADDRESS_LEN 20 + +SQLHSTMT F_hstmt; +SQLHDESC F_hdbc; +SQLHENV F_henv; +SQLHDESC F_hdesc; + +void SQLFetchTest_DisplayError(SQLSMALLINT F_HandleType, + SQLHDESC F_InputHandle); + +/** + * Test to advance a cursor to the next row of data in a data result set + * and to retrieve data from any bound columns that exist for that row + * into their associated application variables + * + * Tests: + * _# Test1 Execute statements and display the results + * -# Test2 There is no executed statement + * @return Zero, if test succeeded + */ +int SQLFetchTest() +{ + SQLRETURN retcode; + SQLCHAR SQLStmt[120]; + SQLCHAR SQLStmt1[120]; + SQLCHAR SQLStmt2[120]; + SQLCHAR SQLStmt3[120]; + SQLCHAR SQLStmt4[120]; + + SQLCHAR F_CustID[20]; + SQLCHAR F_Name[F_NAME_LEN], F_Phone[F_PHONE_LEN]; + SQLCHAR F_Address[F_ADDRESS_LEN]; + + ndbout << "Start SQLFetch Testing!" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &F_henv); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(F_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + F_henv, + &F_hdbc); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(F_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + F_hdbc, + &F_hstmt); +if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + /* *** CustID is Integer *** */ + strcpy((char *) SQLStmt1, "CREATE TABLE Customers (CustID Integer, Name Char(12), Address Char(12), Phone Char(12), Primary Key(CustID, Name))"); + + /* *** the primary key is alone *** */ +// strcpy((char *) SQLStmt1, "CREATE TABLE Customers (CustID Integer, Name Char(12), Address Char(12), Phone Char(12), Primary Key(CustID))"); + + strcpy((char *) SQLStmt2, "INSERT INTO Customers (CustID, Name, Address,Phone) VALUES(188, 'peter','LM Vag8','7190890')"); + + /* *** CustID is Float *** */ +// strcpy((char *) SQLStmt1, +// "CREATE TABLE Customers (CustID float, Name Char(12), Address Char(12), Phone Char(12), Primary Key(CustID))"); +// strcpy((char *) SQLStmt2, "INSERT INTO Customers (CustID, Name, Address,Phone) VALUES(1.1516, 'peter','LM Vag8','7190890')"); + + /* *** CustID is Char *** */ + // strcpy((char *) SQLStmt1, "CREATE TABLE Customers (CustID char(6), Name Char(12), Address Char(12), Phone Char(12), Primary Key(CustID))"); + + // strcpy((char *) SQLStmt2, "INSERT INTO Customers (CustID, Name, Address,Phone) VALUES('000001', 'peter','LM Vag8','7190890')"); + + /* The UPDATE statements */ + // strcpy((char *) SQLStmt3, "UPDATE Customers SET Phone = '98998' WHERE CustID = 1.1516"); + + // strcpy((char *) SQLStmt3, "UPDATE Customers SET Phone = '98998' WHERE CustID = '000001'"); + + // strcpy((char *) SQLStmt3, "UPDATE Customers SET Phone = '98998' WHERE CustID = 188"); + + strcpy((char *) SQLStmt3, "UPDATE Customers SET Phone = '98998' WHERE CustID = 188 AND Name = 'peter'"); + + // DELETE statements + + // DELETE all records + // strcpy((char *) SQLStmt4, "DELETE FROM Customers"); + + // DELETE One record + // strcpy((char *) SQLStmt4, "DELETE FROM Customers WHERE CustID = 1.1516"); + // strcpy((char *) SQLStmt4, "DELETE FROM Customers WHERE CustID = '000001'"); + // strcpy((char *) SQLStmt4, "DELETE FROM Customers WHERE CustID = 188 AND Name = 'peter'"); + // strcpy((char *) SQLStmt4, "DELETE FROM Customers WHERE CustID = 188"); + + strcpy((char *) SQLStmt4, "DELETE FROM Customers WHERE CustID = 188 AND Name = 'peter'"); + + //SELECT statements + strcpy((char *) SQLStmt, "SELECT * FROM Customers"); + + //******************************** + //** Prepare CREATE statements ** + //******************************** + + ndbout << ">>>>" << (char*)SQLStmt1 << "<<<<" << endl; + retcode = SQLPrepare(F_hstmt, + SQLStmt1, + SQL_NTS); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //****************************************************************** + //** There is no executed statement associated with the allocated ** + //** SQL-statement identified by StatementHandle ** + //****************************************************************** + + //This function is correct after testing. We don't test again. + /* + retcode = SQLFetch(F_hstmt); + ndbout << endl << "retcode = SQLFetch(F_hstmt) = " << retcode << endl; + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "There is no executed statement associated with" << endl; + ndbout << "the allocated SQL-statement" << endl; + SQLFetchTest_DisplayError(SQL_HANDLE_DESC, F_hstmt); + + } + */ + + //******************************* + //** Execute CREATE statement ** + //******************************* + + retcode = SQLExecute(F_hstmt); + + if (retcode == 0) + ndbout << endl << "Execute CREATE TABLE Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //******************************** + //** Prepare INSERT statements ** + //******************************** + + ndbout << ">>>>" << (char*)SQLStmt2 << "<<<<" << endl; + retcode = SQLPrepare(F_hstmt, + SQLStmt2, + SQL_NTS); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + + //****************************** + //** Execute INSERT statement ** + //****************************** + retcode = SQLExecute(F_hstmt); + + if (retcode == 0) + ndbout << endl <<"Execute INSERT Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //******************************** + //** Prepare UPDATE statements ** + //******************************** + + ndbout << ">>>>" << (char*)SQLStmt3 << "<<<<" << endl; + retcode = SQLPrepare(F_hstmt, + SQLStmt3, + SQL_NTS); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //****************************** + //** Execute UPDATE statement ** + //****************************** + retcode = SQLExecute(F_hstmt); + + if (retcode == 0) + ndbout << endl <<"Execute UPDATE Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //******************************** + //** Prepare DELETE statements ** + //******************************** + ndbout << ">>>>" << (char*)SQLStmt4 << "<<<<" << endl; + retcode = SQLPrepare(F_hstmt, + SQLStmt4, + SQL_NTS); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "Preparing DELETE Statement failure!" << endl; + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + } + + //****************************** + //** Execute DELETE statement ** + //****************************** + + retcode = SQLExecute(F_hstmt); + + if (retcode == 0) + ndbout << endl <<"Execute DELETE Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "DELETE Statement executing failure!" << endl; + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + } + //******************************** + //** Prepare SELECT statements ** + //******************************** + ndbout << ">>>>" << (char*)SQLStmt << "<<<<" << endl; + retcode = SQLPrepare(F_hstmt, + SQLStmt, + SQL_NTS); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + /* + //****************************** + //** Execute SELECT statement ** + //****************************** + + retcode = SQLExecute(F_hstmt); + + if (retcode == 0) + ndbout << endl <<"Execute SELECT Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + */ + + //******************** + //** Bind columns ** + //******************** + + retcode =SQLBindCol(F_hstmt, + 1, + SQL_C_CHAR, + F_CustID, + sizeof(F_CustID), + NULL); + ndbout << endl << "Bind Col1 retcode = " << retcode << " OK!" << endl; + + retcode =SQLBindCol(F_hstmt, + 2, + SQL_C_CHAR, + F_Name, + F_NAME_LEN, + NULL); + + ndbout << "Bind Col2 retcode = " << retcode << " OK!" << endl; + + retcode = SQLBindCol(F_hstmt, + 3, + SQL_C_CHAR, + F_Address, + F_ADDRESS_LEN, + NULL); + + ndbout << "Bind Col3 retcode = " << retcode << " OK!" << endl; + + retcode = SQLBindCol(F_hstmt, + 4, + SQL_C_CHAR, + F_Phone, + F_PHONE_LEN, + NULL); + + ndbout << "Bind Col4 retcode = " << retcode << " OK!" << endl; + + //****************************** + //** Execute SELECT statement ** + //****************************** + + retcode = SQLExecute(F_hstmt); + + if (retcode == 0) + ndbout << endl <<"Execute SELECT Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //*************** + //* Fetch data ** + //*************** + ndbout << endl <<"Executing Fetch SELECT Statement ......" << endl; + + retcode = SQLFetch(F_hstmt); + + if (retcode == 100) + ndbout << endl <<"Execute Fetch SELECT Statement, But No DATA!" << endl; + + if (retcode == 0) + ndbout << endl <<"Execute Fetch SELECT Statement OK!" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLFetchTest_DisplayError(SQL_HANDLE_STMT, F_hstmt); + + //******************* + //* Display result ** + //******************* + ndbout << endl << "The results is : " << endl; + ndbout << "CustID = " << (char *)F_CustID << endl; + ndbout << "Name = " << (char *)F_Name << endl; + ndbout << "Address = " << (char *)F_Address << endl; + ndbout << "Phone = " << (char *)F_Phone << endl; + + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(F_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, F_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, F_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, F_henv); + + return NDBT_OK; + + } + + +void SQLFetchTest_DisplayError(SQLSMALLINT F_HandleType, + SQLHSTMT F_InputHandle) +{ + SQLCHAR Sqlstate[50], Msg[F_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + Msg[0] = 0; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(F_HandleType, + F_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) +{ + + ndbout << "the HandleType is:" << F_HandleType << endl; + ndbout << "the InputHandle is :" <<(long)F_InputHandle << endl; + ndbout << "the Msg is :" << (char *)Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; +} + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLFreeHandleTest.cpp b/ndb/test/odbc/client/SQLFreeHandleTest.cpp new file mode 100644 index 00000000000..3a7241dbe68 --- /dev/null +++ b/ndb/test/odbc/client/SQLFreeHandleTest.cpp @@ -0,0 +1,195 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; +int strangehandle; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; + + +void freehandle_deal_with_HSTMT(SQLSMALLINT HandleType, SQLHSTMT InputHandle); +void freehandle_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle); +void freehandle_deal_with_HDESC(SQLSMALLINT HandleType, SQLHDESC InputHandle); +void freehandle_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle); + +void freehandle_DisplayError_HDBC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle); +void freehandle_DisplayError_HSTMT(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHSTMT InputHandle); +void freehandle_DisplayError_HENV(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle); +void freehandle_DisplayError_HDESC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLFreeHandleTest () +{ + +strangehandle = 67; + +/* ENV */ +ndbout << "Environment Handle" << endl; +SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); +freehandle_deal_with_HENV(SQL_HANDLE_ENV, henv); + +/* DBC */ +ndbout << "Connection Handle" << endl; +SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); +SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); +freehandle_deal_with_HDBC(SQL_HANDLE_DBC, hdbc); + +/* STMT */ +ndbout << "Statement Handle" << endl; +SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); +SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); +freehandle_deal_with_HSTMT(SQL_HANDLE_STMT, hstmt); + +/* DESC */ +ndbout << "Descriptor Handle" << endl; +SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc); +freehandle_deal_with_HDESC(SQL_HANDLE_DESC, hdesc); + +return 0; + +} + + +void freehandle_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + ndbout << "the HandleType is : " << HandleType << endl; + ndbout << "the InputHandle is SQLHDBC:" << InputHandle << endl; + ndbout << "retcode = " << retcode << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HDBC_free(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + */ + } + + +void freehandle_deal_with_HSTMT(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + ndbout << "the HandleType is : " << HandleType << endl; + ndbout << "the InputHandle is SQLHSTMT:" << InputHandle << endl; + ndbout << "retcode = " << retcode << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HSTMT_free(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + */ + } + +void freehandle_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + ndbout << "the HandleType is : " << HandleType << endl; + ndbout << "the InputHandle is SQLHENV:" << InputHandle << endl; + ndbout << "retcode = " << retcode << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HENV_free(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + */ + } + +void freehandle_deal_with_HDESC(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + ndbout << "the HandleType is : " << HandleType << endl; + ndbout << "the InputHandle is SQLHDESC:" << InputHandle << endl; + ndbout << "retcode = " << retcode << endl; + /* + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HDESC_free(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + */ + } + + +void freehandle_DisplayError_HENV(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void freehandle_DisplayError_HDBC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void freehandle_DisplayError_HSTMT(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void freehandle_DisplayError_HDESC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} diff --git a/ndb/test/odbc/client/SQLFreeStmtTest.cpp b/ndb/test/odbc/client/SQLFreeStmtTest.cpp new file mode 100644 index 00000000000..e636b3063de --- /dev/null +++ b/ndb/test/odbc/client/SQLFreeStmtTest.cpp @@ -0,0 +1,182 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; +int strange_handle; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; + +struct handle_set +{ +SQLHDBC hdbc_varible; +SQLHSTMT hstmt_varible; +SQLHENV henv_varible; +SQLHDESC hdesc_varible; +int strangehandle; +}; +handle_set handlevalue; + +void handle_deal_with_HSTMT(SQLSMALLINT HandleType, SQLHSTMT InputHandle); +void handle_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle); +void handle_deal_with_HDESC(SQLSMALLINT HandleType, SQLHDESC InputHandle); +void handle_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle); + +void DisplayError_HDBC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle); +void DisplayError_HSTMT(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHSTMT InputHandle); +void DisplayError_HENV(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle); +void DisplayError_HDESC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLFreeStmtTest () +{ + +handlevalue.hdbc_varible = hdbc; +handlevalue.hstmt_varible = hstmt; +handlevalue.henv_varible = henv; +handlevalue.hdesc_varible = hdesc; +handlevalue.strangehandle = 67; + + +/* ENV */ +handle_deal_with_HENV(SQL_HANDLE_ENV, SQL_NULL_HANDLE); + +/* DBC */ +handle_deal_with_HDBC(SQL_HANDLE_DBC, SQL_NULL_HANDLE); + +/* STMT */ +handle_deal_with_HSTMT(SQL_HANDLE_STMT, SQL_NULL_HANDLE); + +/* DESC */ +handle_deal_with_HDESC(SQL_HANDLE_DESC, SQL_NULL_HANDLE); + +return 0; + +} + + +void handle_deal_with_HDBC(SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HDBC(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + } + + +void handle_deal_with_HSTMT(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + DisplayError_HSTMT(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + } + +void handle_deal_with_HENV(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HENV(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + } + +void handle_deal_with_HDESC(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + retcode = SQLFreeHandle(HandleType, InputHandle); + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + DisplayError_HDESC(Sqlstate, HandleType, InputHandle); + + i ++; + } + } + } + + +void DisplayError_HENV(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + + +void DisplayError_HDBC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDBC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void DisplayError_HSTMT(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + +void DisplayError_HDESC(SQLCHAR Sqlstate[6], SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; +} + + diff --git a/ndb/test/odbc/client/SQLGetConnectAttrTest.cpp b/ndb/test/odbc/client/SQLGetConnectAttrTest.cpp new file mode 100644 index 00000000000..8d5a5c0dbbb --- /dev/null +++ b/ndb/test/odbc/client/SQLGetConnectAttrTest.cpp @@ -0,0 +1,131 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLPOINTER ValuePtr; +SQLINTEGER GetConnectAttr_StringLengthPtr; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void GetConnectAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle); + +int SQLGetConnectAttrTest() +{ + /* SQL/CLI attributes */ + // char PtrValue1[2] = {'SQL_TRUE', 'SQL_FALSE'}; + // for (i=0; i < 2; i++) { + retcode = SQLGetConnectAttr(hdbc, SQL_ATTR_AUTO_IPD, ValuePtr, 36, &GetConnectAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc); // } + + /* ODBC attributes */ + /* + char PtrValue1[3] = {'SQL_MODE_READ_ONLY', 'SQL_MODE_READ_WRITE'}; + for (i=0; i < 3; i++) { + retcode = SQLGetConnectAttr(hdbc, SQL_ATTR_ACCESS_MODE, (void*)PtrValue1[i], sizeof(PtrValue1[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + + char PtrValue2[2] = {'SQL_ASYNC_ENABLE_OFF', 'SQL_ASYNC_ENABLE_ON'}; + for (i=0; i < 2; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_ASYNC_ENABLE, (void*)PtrValue2[i], sizeof(PtrValue2[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + + char PtrValue4[2] = {'SQL_AUTOCOMMIT_OFF', 'SQL_AUTOCOMMIT_ON'}; + for (i=0; i < 2; i++) { + retcode = SQLGetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (void*)PtrValue4[i], sizeof(PtrValue4[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + char PtrValue5[2] = {'SQL_CD_TRUE', 'SQL_CD_FALSE'}; + for (i=0; i < 2; i++) { + retcode = SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_DEAD, (void*)PtrValue4[i], sizeof(PtrValue5[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + + char PtrValue5[2] = {'SQL_CD_TRUE', 'SQL_CD_FALSE'}; + for (i=0; i < 2; i++) { + retcode = SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_TIMEOUT, (void*)PtrValue4[i], sizeof(PtrValue5[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + */ + + return 0; + + } + + +void GetConnectAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetCursorNameTest.cpp b/ndb/test/odbc/client/SQLGetCursorNameTest.cpp new file mode 100644 index 00000000000..1e3ed9f557e --- /dev/null +++ b/ndb/test/odbc/client/SQLGetCursorNameTest.cpp @@ -0,0 +1,221 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLGetCursorNameTest.cpp + */ + +#include <common.hpp> +using namespace std; + +#define GCN_MESSAGE_LENGTH 50 + +SQLHSTMT GCN_hstmt; +SQLHDESC GCN_hdesc; +SQLHENV GCN_henv; +SQLHDBC GCN_hdbc; + +void GCN_DisplayError(SQLSMALLINT GCN_HandleType, + SQLHDESC GCN_InputHandle); + +/** + * Test to assign a user-defined name to a cursor that is + * associated with an active SQL statement handle + * + * Tests: + * -# if there is no user-defined cursor name, then try to + * get user-definedcursor name + * -# get cursor name in normal case + * + * @return Zero, if test succeeded + */ + +int SQLGetCursorNameTest() +{ + SQLRETURN retcode; + SQLCHAR SQLStmt [120]; + SQLCHAR CursorName [80]; + SQLSMALLINT CNameSize; + + ndbout << endl << "Start SQLGetCursorName Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &GCN_henv); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(GCN_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + GCN_henv, + &GCN_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(GCN_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + GCN_hdbc, + &GCN_hstmt); + + if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + strcpy((char *) SQLStmt, + "SELECT * FROM Customers WHERE Address = 'LM Vag 8'"); + + //************************* + //** Prepare a statement ** + //************************* + + retcode = SQLPrepare(GCN_hstmt, + SQLStmt, + SQL_NTS); + + //************************************************************************* + //** if there is no user-defined cursor name, try to get the cursor name ** + //************************************************************************* + retcode = SQLGetCursorName(GCN_hstmt, + CursorName, + sizeof(CursorName), + &CNameSize); + + if (retcode != SQL_SUCCESS) + { + ndbout << endl << "retcode =" << retcode << endl; + GCN_DisplayError(SQL_HANDLE_STMT, GCN_hstmt); + } + else + ndbout << endl << "The cursor name is : " << (char *) CursorName << endl; + + //************************* + //** Set the cursor name ** + //************************* + retcode = SQLSetCursorName(GCN_hstmt, + (char *)"Customer_CURSOR", + SQL_NTS); + + //*************************** + //** Execute the statement ** + //*************************** + retcode = SQLExecute(GCN_hstmt); + + //********************************************** + //** retrieve and display the new cursor name ** + //********************************************** + retcode = SQLGetCursorName(GCN_hstmt, + CursorName, + sizeof(CursorName), + &CNameSize); + + if (retcode != SQL_SUCCESS) + { + ndbout << endl << "retcode =" << retcode << endl; + GCN_DisplayError(SQL_HANDLE_STMT, GCN_hstmt); + } + else + ndbout << endl << "The cursor name is : " << (char *) CursorName << endl; + + //**************** + // Free Handles ** + //**************** + SQLDisconnect(GCN_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, GCN_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, GCN_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, GCN_henv); + + return NDBT_OK; + + } + + +void GCN_DisplayError(SQLSMALLINT GCN_HandleType, SQLHDESC GCN_InputHandle) +{ + + SQLINTEGER NativeError; + SQLCHAR Sqlstate[5], Msg[GCN_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + SQLSMALLINT i, MsgLen; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(GCN_HandleType, + GCN_InputHandle, i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << GCN_HandleType << endl; + ndbout << "the InputHandle is :" << (long)GCN_InputHandle << endl; + ndbout << "the Msg is: " << (char *) Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLGetDataTest.cpp b/ndb/test/odbc/client/SQLGetDataTest.cpp new file mode 100644 index 00000000000..9d958c6c953 --- /dev/null +++ b/ndb/test/odbc/client/SQLGetDataTest.cpp @@ -0,0 +1,358 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLGetDataTest.cpp + */ + +#include <common.hpp> +using namespace std; + +#define GD_MESSAGE_LENGTH 200 + +SQLHSTMT GD_hstmt; +SQLHENV GD_henv; +SQLHDBC GD_hdbc; +SQLHDESC GD_hdesc; + +void GetData_DisplayError(SQLSMALLINT GD_HandleType, SQLHSTMT GD_InputHandle); + +/** + * Test to retrieve data for a single unbound column + * in the current row of a result data set + * + * Tests: + * -# Test1 There is no fetched rowset associated with S + * -# Test2 column number is less than zero + * -# Test3 fetched rowset is empty + * @return Zero, if test succeeded + */ + +int SQLGetDataTest() +{ + SQLRETURN retcode; + SQLCHAR ColumnName; + SQLINTEGER CustID; + // SQLCHAR Name, Address, Phone; + SQLCHAR SQLStmt [120]; + SQLCHAR SQLStmt1 [120]; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &GD_henv); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(GD_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.X!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + GD_henv, + &GD_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(GD_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + GD_hdbc, + &GD_hstmt); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //***************************** + //** Define SELECT statement ** + //***************************** + + strcpy((char *) SQLStmt, "SELECT * FROM Customers"); + + + //*********************************** + //** Prepare SELECT SQL statement ** + //*********************************** + + retcode = SQLPrepare(GD_hstmt, + SQLStmt, + SQL_NTS); + ndbout << endl << "Preparing SELECT, retcode = SQLprepare()= " + << retcode << endl; + + //********************************* + //** Execute prepared statement ** + //********************************* + + // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + //{ + + retcode = SQLExecute(GD_hstmt); + + ndbout << "Exexuting SELECT, retcode = SQLExecute()= " + << retcode << endl; + + // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + // { + + //***************************************************************** + //** Test1 ** + //** There is no fetched rowset associated with S(SQL-statement) ** + //***************************************************************** + + retcode = SQLGetData(GD_hstmt, + 1, + SQL_C_SLONG, + &CustID, + sizeof(CustID), + NULL); + ndbout << "retcode = SQLGetData()= " << retcode << endl; + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "Test 1:" << endl; + ndbout << "There is no fetched rowset associated with SQL" + << " statement. But system reported SUCCESS or" + << " SUCCESS_WITH_INFO. Please check the function!" << endl; + GetData_DisplayError(SQL_HANDLE_STMT, GD_hstmt); + } + else if (retcode == SQL_ERROR) + { + ndbout << endl << "Test 1:" << endl; + ndbout << "There is no fetched rowset associated with SQL" + << " statement. The system reported ERROR " + << " The function is OK!" << endl; + } + else + ndbout << endl; + + //******************************* + //** Fetch Data from database ** + //******************************* + + retcode = SQLFetch(GD_hstmt); + + ndbout << endl + << "Fetching after Executing SELECT, retcode = SQLFetch()= " + << retcode << endl; + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + + //************************************** + //** Test2 ** + //** column number is less than zero ** + //************************************** + + retcode = SQLGetData(GD_hstmt, + 0, + SQL_C_ULONG, + &CustID, + sizeof(CustID), + NULL); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Test 2:" <<"Column number is less than zero" + << " The system reported SUCCESS or SUCCESS_WITH_INFO." + << " Check the function, please!" <<endl; + GetData_DisplayError(SQL_HANDLE_STMT, GD_hstmt); + } + else if (retcode == SQL_ERROR) + { + ndbout << "Test 2:" << "Column number is less than zero." + << " The system reported SQL_ERROR." + << " The function is OK!" << endl; + } + else + ndbout << endl; + } + // } + + // } + + //***************************** + //** Define DELETE statement ** + //***************************** + + // strcpy((char *) SQLStmt1, "DELETE FROM Customers"); + strcpy((char *) SQLStmt1, "DELETE FROM Customers WHERE CustID = 568 AND Name = 'Hans Peter'"); + + //*********************************** + //** Prepare DELETE SQL statement ** + //*********************************** + + retcode = SQLPrepare(GD_hstmt, + SQLStmt1, + SQL_NTS); + ndbout << endl << "Preparing DELETE, retcode = SQLPrepare()= " + << retcode << endl; + + //**************************************** + //** Execute prepared DELETE statement ** + //**************************************** + + // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + // { + + retcode = SQLExecute(GD_hstmt); + + ndbout << "Executing DELETE, retcode = SQLExecute()= " + << retcode << endl; + + // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + // { + + retcode = SQLFetch(GD_hstmt); + + ndbout << "Fetching after Executing DELETE, retcode = SQLExecute()= " + << retcode << endl; + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + + //****************************************************** + //** Test3 ** + //** If the fetched rowset associated with ** + //** Statement is empty, condition is raised: NO DATA ** + //** We can delete all rows in table Customers for ** + //** this case ** + //****************************************************** + + retcode = SQLGetData(GD_hstmt, + 1, + SQL_C_ULONG, + &CustID, + sizeof(CustID), + NULL); + + if (retcode == SQL_ERROR) + { + ndbout << "Test 3:" << endl; + ndbout << "The fetched rowset associated" + << "with Statementhandle is empty. The system" + << " reported SQL_ERROR. Check the function!" << endl; + GetData_DisplayError(SQL_HANDLE_STMT, GD_hstmt); + } + else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Test 3:" << endl; + ndbout << "The fetched rowset associated" + << "with Statementhandle is empty. The system" + << " reported SUCCESS. Check the function!" << endl; + GetData_DisplayError(SQL_HANDLE_STMT, GD_hstmt); + } + else if (retcode == 100) + { + ndbout << "Test 3:" << endl; + ndbout << "The fetched rowset associated" + << "with Statementhandle is empty. The system" + << " reported SQL_NO_DATA. The function is OK!" << endl; + } + } + else if (retcode == SQL_ERROR) + { + ndbout << "Test 3 falied!" << endl; + GetData_DisplayError(SQL_HANDLE_STMT, GD_hstmt); + } + else + ndbout << " " << endl; + + // } + // } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(GD_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, GD_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, GD_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, GD_henv); + + return NDBT_OK; +} + +void GetData_DisplayError(SQLSMALLINT GD_HandleType, SQLHSTMT GD_InputHandle) +{ + + SQLSMALLINT i, MsgLen; + SQLRETURN SQLSTATEs; + SQLCHAR Sqlstate[5], Msg[GD_MESSAGE_LENGTH]; + SQLINTEGER NativeError; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(GD_HandleType, + GD_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << GD_HandleType << endl; + ndbout << "the InputHandle is :" << (long)GD_InputHandle << endl; + ndbout << "Phone = " << (char *)Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLGetDescFieldTest.cpp b/ndb/test/odbc/client/SQLGetDescFieldTest.cpp new file mode 100644 index 00000000000..b789ed75378 --- /dev/null +++ b/ndb/test/odbc/client/SQLGetDescFieldTest.cpp @@ -0,0 +1,113 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlext.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHSTMT hstmt; +SQLHDESC hdesc; + +SQLSMALLINT RecNumber; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLINTEGER ValuePtr1; +SQLCHAR ValuePtr2; +SQLSMALLINT ValuePtr3; + + + +SQLINTEGER StringLengthPtr; + +SQLSMALLINT i, MsgLen; + +void SQLGetDescFieldTest_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLGetDescFieldTest() +{ + + /* If MBR is 'PS' and there is no prepared or execute statement associated with S*/ +retcode = SQLGetDescField(hdesc, 1, SQL_DESC_ARRAY_SIZE, &ValuePtr1, 128, &StringLengthPtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLGetDescFieldTest_DisplayError(SQL_HANDLE_DESC, hdesc); + + /* hstmt */ + // SQLPrepare a statement to select rows from the ORDERS Table. We can create the + // table and inside rows in NDB by another program TestDirectSQL. In this test + // program(SQLGetDescRecTest),we only have three rows in table ORDERS + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, (SQLCHAR *)"SELECT ORDERID, CUSTID, OPENDATE, SALESPERSON, STATUS FROM ORDERS)", SQL_NTS); + +/* SELECT OrderID, CustID, OpenDate, SalesPerson from Table ORDERS */ + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + + /* If FI(FieldIdentifer) is not one of the code values in Table 20 */ +retcode = SQLGetDescField(hdesc, 1, 9999, &ValuePtr1, 128, &StringLengthPtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLGetDescFieldTest_DisplayError(SQL_HANDLE_DESC, hdesc); + + + /* RecoderNumber is less than 1 */ +retcode = SQLGetDescField(hdesc, -1, SQL_DESC_ARRAY_SIZE, &ValuePtr1, 128, &StringLengthPtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLGetDescFieldTest_DisplayError(SQL_HANDLE_DESC, hdesc); + + /* RecoderNumber is greater than N, N be the value of the COUNT field of D, D be the allocated CLI */ + /* descriptor area identified by DescriptorHandle */ +retcode = SQLGetDescField(hdesc, 4, SQL_DESC_ARRAY_SIZE, &ValuePtr1, 128, &StringLengthPtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLGetDescFieldTest_DisplayError(SQL_HANDLE_DESC, hdesc); + +} + + return 0; + + } + + +void SQLGetDescFieldTest_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetDescRecTest.cpp b/ndb/test/odbc/client/SQLGetDescRecTest.cpp new file mode 100644 index 00000000000..5944f393a71 --- /dev/null +++ b/ndb/test/odbc/client/SQLGetDescRecTest.cpp @@ -0,0 +1,95 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHSTMT hstmt; +SQLHDESC hdesc; + +SQLSMALLINT RecNumber; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Name; +SQLINTEGER LengthPtr; +SQLSMALLINT SGDR_StringLengthPtr, TypePtr, SubTypePtr, PrecisionPtr, ScalePtr, NullablePtr; + +SQLSMALLINT i, MsgLen; + +void SQLGetDescRec_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLGetDescRecTest() +{ + + /* hstmt */ + // SQLPrepare a statement to select rows from the ORDERS Table. We can create the table and inside rows in + // NDB by another program TestDirectSQL. In this test program(SQLGetDescRecTest),we only have three rows in + // table ORDERS + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, (SQLCHAR *)"SELECT ORDERID, CUSTID, OPENDATE, SALESPERSON, STATUS FROM ORDERS)", SQL_NTS); + +/* SELECT OrderID, CustID, OpenDate, SalesPerson from Table ORDERS */ + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + /* RecoderNumber is less than 1 */ +retcode = SQLGetDescRec(hdesc, -1, &Name, sizeof(Name), &SGDR_StringLengthPtr, &TypePtr, &SubTypePtr, &LengthPtr, &PrecisionPtr, &ScalePtr, &NullablePtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLGetDescRec_DisplayError(SQL_HANDLE_DESC, hdesc); + + /* RecoderNumber is greater than N, N be the value of the COUNT field of D, D be the allocated CLI */ + /* descriptor area identified by DescriptorHandle */ +retcode = SQLGetDescRec(hdesc, 4, &Name, sizeof(Name), &SGDR_StringLengthPtr, &TypePtr, &SubTypePtr, &LengthPtr, &PrecisionPtr, &ScalePtr, &NullablePtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLGetDescRec_DisplayError(SQL_HANDLE_DESC, hdesc); + +} + + return 0; + + } + + +void SQLGetDescRec_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetDiagFieldTest.cpp b/ndb/test/odbc/client/SQLGetDiagFieldTest.cpp new file mode 100644 index 00000000000..ef9bc3eb3fc --- /dev/null +++ b/ndb/test/odbc/client/SQLGetDiagFieldTest.cpp @@ -0,0 +1,236 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLINTEGER strangehandle; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +SQLSMALLINT StringLengthPtr; +SQLINTEGER DiagInfoPtr1; +SQLCHAR DiagInfoPtr2; +SQLRETURN DiagInfoPtr3; + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLGetDiagFieldTest () +{ + + strangehandle = 67; + /* hstmt */ + // Execute a statement to retrieve rows from the Customers table. We can create the table and inside rows in + // NDB by another program TestDirectSQL + // const SQLCHAR *StatementText = "SELECT CustID, Name, Address, Phone FROM Customers"; + // retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", 56); + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; +while ((SQLSTATEs = SQLGetDiagField(67, 67, i, SQL_DIAG_CURSOR_ROW_COUNT, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + /* HandleType indicates ENVIRNMENT HANDLE and Handle does not identify an allocated SQL_environment */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; +while ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_ENV, hdbc, i, SQL_DIAG_CURSOR_ROW_COUNT, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + /* HandleType indicates CONNECTION HANDLE and Handle does not identify an allocated SQL_connection */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; +while ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_DBC, henv, i, SQL_DIAG_CURSOR_ROW_COUNT, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + /* HandleType indicates STATEMENT HANDLE and Handle does not identify an allocated SQL_statement */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; +while ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_STMT, hdbc, i, SQL_DIAG_CURSOR_ROW_COUNT, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + /* HandleType indicates DESCRIPTOR HANDLE and Handle does not identify an allocated SQL_descriptor */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; +while ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_DESC, hdbc, i, SQL_DIAG_CURSOR_ROW_COUNT, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + /* DiagIdentifer is not one of the code values in Table12 */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + +where ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_DBC, hdbc, -1, 99, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + /* If TYPE is 'STATUS' and RN is greater than N */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + +where ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_DBC, hdbc, 9999, 8, &DiagInfoPtr2, 128, &StringLengthPtr)) != SQL_NO_DATA) { + + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + /* If TYPE is 'STATUS' and RN is less than 1 */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + + where ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_DBC, hdbc, -1, 8, &DiagInfoPtr2, 128, &StringLengthPtr)) != SQL_NO_DATA) { + + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + /* If DI indicates ROW_COUNT and R is neither Execute nor ExecDirect, then an exception condition is raised */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + +where ((SQLSTATEs = SQLGetDiagField(SQL_HANDLE_DBC, hdbc, i, SQL_DIAG_ROW_COUNT, &DiagInfoPtr1, 128, &StringLengthPtr)) != SQL_NO_DATA) { + + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + return 0; + + } + + + + + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetDiagRecSimpleTest.cpp b/ndb/test/odbc/client/SQLGetDiagRecSimpleTest.cpp new file mode 100644 index 00000000000..8fa4a2b3dbb --- /dev/null +++ b/ndb/test/odbc/client/SQLGetDiagRecSimpleTest.cpp @@ -0,0 +1,167 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLGetDiagRecSimpleTest.cpp + */ +#include <common.hpp> +#include <string.h> + +using namespace std; + +SQLHDBC GDS_hdbc; +SQLHSTMT GDS_hstmt; +SQLHENV GDS_henv; +SQLHDESC GDS_hdesc; +SQLRETURN GDS_retcode, GDS_RETURN; + +#define GDS_SQL_MAXIMUM_MESSAGE_LENGTH 255 +SQLCHAR GDS_Sqlstate[5]; + +SQLINTEGER GDS_NativeError; +SQLSMALLINT GDS_i = 1, GDS_MsgLen; +SQLCHAR GDS_Msg[GDS_SQL_MAXIMUM_MESSAGE_LENGTH], GDS_ConnectIn[30]; + +/** + * Test SQLGetDiagRec return value + * + * -#Simply test Msg when return is SQL_NO_DATA + * -#Simply test Msg when return is SQL_SUCCESS + * -#Simply test Msg when return is SQL_SUCCESS_WITH_INFO + * -#Simply test Msg when return is SQL_INVALID_HANDLE + * -#Simply test Msg when return is SQL_ERROR + * + * @return Zero, if test succeeded + */ + +int SQLGetDiagRecSimpleTest() +{ + ndbout << endl << "Start SQLGetDiagRec Simple Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + + GDS_retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &GDS_henv); + if (GDS_retcode == SQL_SUCCESS || GDS_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated An Environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + + GDS_retcode = SQLSetEnvAttr(GDS_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (GDS_retcode == SQL_SUCCESS || GDS_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + GDS_retcode = SQLAllocHandle(SQL_HANDLE_DBC, GDS_henv, &GDS_hdbc); + + if (GDS_retcode == SQL_SUCCESS || GDS_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated A Connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + + GDS_retcode = SQLConnect(GDS_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (GDS_retcode == SQL_SUCCESS || GDS_retcode == SQL_SUCCESS_WITH_INFO){ + ndbout << "Success connection to DB!" << endl; + ndbout << "GDS_retcode = " << GDS_retcode << endl; + ndbout << "SQL_SUCCESS = " << SQL_SUCCESS << endl; + ndbout << "SQL_SUCCESS_WITH_INFO = " << SQL_SUCCESS_WITH_INFO << endl;} + + ndbout << endl; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + if (GDS_retcode != SQL_SUCCESS || GDS_retcode != SQL_SUCCESS_WITH_INFO){ + ndbout << "GDS_retcode = " << GDS_retcode << endl; + ndbout << "SQL_SUCCESS = " << SQL_SUCCESS << endl; + ndbout << "SQL_SUCCESS_WITH_INFO = " << SQL_SUCCESS_WITH_INFO << endl; + + GDS_RETURN = SQLGetDiagRec(SQL_HANDLE_DBC, + GDS_hdbc, + GDS_i, + GDS_Sqlstate, + &GDS_NativeError, + GDS_Msg, + sizeof(GDS_Msg), + &GDS_MsgLen); + + if (GDS_RETURN == SQL_NO_DATA){ + ndbout << "GDS_SQLSTATES = SQL_NO_DATA" << endl; + ndbout << "the HandleType is:" << SQL_HANDLE_DBC << endl; + ndbout << "the Handle is :" << (long)GDS_hdbc << endl; + ndbout << "the GDS_Msg is :" << (char *)GDS_Msg << endl; + ndbout << "the sqlstate is:" << (char *)GDS_Sqlstate << endl;} + + else if (GDS_RETURN == SQL_SUCCESS){ + ndbout << "GDS_SQLSTATES = SQL_SUCCESS" << endl; + ndbout << "the HandleType is:" << SQL_HANDLE_DBC << endl; + ndbout << "the Handle is :" << (long)GDS_hdbc << endl; + ndbout << "the GDS_Msg is :" << (char *)GDS_Msg << endl; + ndbout << "the sqlstate is:" << (char *)GDS_Sqlstate << endl;} + + else if (GDS_RETURN == SQL_SUCCESS_WITH_INFO){ + ndbout << "GDS_SQLSTATES = SQL_SUCCESS_WITH_INFO" << endl; + ndbout << "the HandleType is:" << SQL_HANDLE_DBC << endl; + ndbout << "the Handle is :" << (long)GDS_hdbc << endl; + ndbout << "the GDS_Msg is :" << (char *)GDS_Msg << endl; + ndbout << "the sqlstate is:" << (char *)GDS_Sqlstate << endl;} + + else if (GDS_RETURN == SQL_INVALID_HANDLE){ + ndbout << "GDS_SQLSTATES = SQL_INVALID_HANDLE" << endl; + ndbout << "the HandleType is:" << SQL_HANDLE_DBC << endl; + ndbout << "the Handle is :" << (long)GDS_hdbc << endl; + ndbout << "the GDS_Msg is :" << (char *)GDS_Msg << endl; + ndbout << "the sqlstate is:" << (char *)GDS_Sqlstate << endl;} + + else{ + ndbout << "GDS_RETURN = SQL_ERROR" << endl; + ndbout << "the HandleType is:" << SQL_HANDLE_DBC << endl; + ndbout << "the Handle is :" << (long)GDS_hdbc << endl; + ndbout << "the GDS_Msg is :" << (char *)GDS_Msg << endl; + ndbout << "the sqlstate is:" << (char *)GDS_Sqlstate << endl; + } + } + ndbout << "-------------------------------------------------" << endl; + + //****************** + //** Free Handles ** + //****************** + SQLDisconnect(GDS_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, GDS_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, GDS_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, GDS_henv); + return NDBT_OK; + } + diff --git a/ndb/test/odbc/client/SQLGetDiagRecTest.cpp b/ndb/test/odbc/client/SQLGetDiagRecTest.cpp new file mode 100644 index 00000000000..27c78edaa4d --- /dev/null +++ b/ndb/test/odbc/client/SQLGetDiagRecTest.cpp @@ -0,0 +1,207 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLINTEGER strangehandle; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLGetDiagRecTest() +{ + + strangehandle = 67; + /* hstmt */ + // Execute a statement to retrieve rows from the Customers table. We can create the table and inside rows in + // NDB by another program TestDirectSQL + // const SQLCHAR *StatementText = "SELECT CustID, Name, Address, Phone FROM Customers"; + + // retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", 56); + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(67, 67, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + /* HandleType indicates ENVIRNMENT HANDLE and Handle does not identify an allocated SQL_environment */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(SQL_HANDLE_ENV, hdbc, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + /* HandleType indicates CONNECTION HANDLE and Handle does not identify an allocated SQL_connection */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(SQL_HANDLE_DBC, henv, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + /* HandleType indicates STATEMENT HANDLE and Handle does not identify an allocated SQL_statement */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(SQL_HANDLE_STMT, hdbc, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + /* HandleType indicates DESCRIPTOR HANDLE and Handle does not identify an allocated SQL_descriptor */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(SQL_HANDLE_DESC, hdbc, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + /* RecordNumber is less than one */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + + where ((SQLSTATEs = SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, -1, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + /* RecordNumber is greater than N */ + + retcode = SQLPrepare(hstmt, (SQLCHAR*)"SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) { + + where ((SQLSTATEs = SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 9999, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + if (SQLSTATEs == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + } + i ++; + } + } + + + return 0; + + } + + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetEnvAttrTest.cpp b/ndb/test/odbc/client/SQLGetEnvAttrTest.cpp new file mode 100644 index 00000000000..efc8117d6d2 --- /dev/null +++ b/ndb/test/odbc/client/SQLGetEnvAttrTest.cpp @@ -0,0 +1,110 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLPOINTER ValuePtr; +SQLINTEGER GetEnvAttr_StringLengthPtr; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void GetEnvAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle); + +int SQLGetEnvAttrTest() +{ + /* ODBC attributres */ + + /* + // char PtrValue1[3] = {'SQL_CP_OFF', 'SQL_CP_ONE_DRIVER', 'SQL_CP_ONE_PER_HENV'}; + // for (i=0; i < 3; i++) { + retcode = SQLGetEnvAttr(henv, SQL_ATTR_CONNECTION_POOLING, ValuePtr, 36, &GetEnvAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv); // } + + + // char PtrValue2[2] = {'SQL_CP_STRICT_MATCH', 'SQL_CP_RELAXED_MATCH'}; + // for (i=0; i < 2; i++) { + retcode = SQLGetEnvAttr(henv, SQL_ATTR_CP_MATCH, ValuePtr, 36, &GetEnvAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv); // } + + + // char PtrValue3[2] = {'SQL_OV_ODBC3', 'SQL_OV_ODBC2'}; + // for (i=0; i < 2; i++) { + retcode = SQLGetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, ValuePtr, 36, &GetEnvAttr_StringLengthPtr ); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv); // } + + */ + + // char PtrValue4[2] = {'SQL_TRUE', 'SQL_FALSE'}; + // for (i=0; i < 2; i++) { + retcode = SQLGetEnvAttr(henv, SQL_ATTR_OUTPUT_NTS, ValuePtr, 36, &GetEnvAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv); // } + + return 0; + + } + + +void GetEnvAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetFunctionsTest.cpp b/ndb/test/odbc/client/SQLGetFunctionsTest.cpp new file mode 100644 index 00000000000..c6feb8ec033 --- /dev/null +++ b/ndb/test/odbc/client/SQLGetFunctionsTest.cpp @@ -0,0 +1,284 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLGetFunctionsTest.cpp + */ + + +#include <common.hpp> +#define GF_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC GF_hdbc; +SQLHSTMT GF_hstmt; +SQLHENV GF_henv; + +void SQLGetFunctions_DisplayError(SQLSMALLINT GF_HandleType, + SQLHDBC GF_InputHandle); + +/** + * Test whether a specific ODBC API function is supported by + * the driver an application is currently connected to. + * + * In this test program, we can change ODBC function values in order to + * know different which fuction is supported by ODBC drivers + * Tests: + * -# Test1 There is no established SQL-connection + * -# Test2 ConnectionHandle does not identify an allocated SQL-connection + * -# Test3 The value of FunctionId is not in table 27 + * -# Test4 Normal case test + * @return Zero, if test succeeded + */ + +int SQLGetFunctionsTest() +{ + SQLUSMALLINT TableExists, Supported; + SQLCHAR SQLStmt [120]; + SQLRETURN retcode; + + ndbout << endl << "Start SQLGetFunctions Testing" << endl; + + //********************************************************** + //** Test 1 ** + //** If there is no established SQL-connection associated ** + //** with allocated SQL-connection ** + //********************************************************** + + retcode = SQLGetFunctions(GF_hdbc, SQL_API_SQLTABLES, &TableExists); + if (retcode == -2) +{ + ndbout << endl << "Test 1" << endl; + ndbout << "retcode = " << retcode << endl; + ndbout << endl << "There is no established SQL-connection" << endl; + ndbout << "associated with allocated SQL_connection" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) +{ + ndbout << endl << "Test 1" << endl; + ndbout << "retcode = " << retcode << endl; + ndbout << endl << "There is no established SQL-connection" << endl; + ndbout << "associated with allocated SQL_connection" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + else +{ + ndbout << endl << "Test 1" << endl; + ndbout << "retcode = " << retcode << endl; + ndbout << endl << "There is no established SQL-connection" << endl; + ndbout << "associated with allocated SQL_connection" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &GF_henv); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(GF_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.X!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + GF_henv, + &GF_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(GF_hdbc, + (SQLCHAR*) connectString(), + SQL_NTS, + (SQLCHAR*) "", + SQL_NTS, + (SQLCHAR*) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) +{ + + //************************************************************* + //** Test 2 ** + //** If ConnectionHandle does not identify an allocated ** + //** SQL-connection, then an exception condition is raised ** + //************************************************************* + retcode = SQLGetFunctions(GF_hdbc, SQL_API_SQLTABLES, &TableExists); + if (retcode == -2) +{ + ndbout << endl << "Test 2" << endl; + ndbout << "retcode = " << retcode << endl; + ndbout << "If ConnectionHandle does not identify an allocated" << endl; + ndbout << "SQL-connection,an exception condition is raised" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) +{ + ndbout << endl << "Test 2" << endl; + ndbout << "retcode = " << retcode << endl; + ndbout << "If ConnectionHandle does not identify an allocated" << endl; + ndbout << "SQL-connection,an exception condition is raised" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + else +{ + ndbout << endl << "Test 2 :" << endl; + ndbout << "retcode = " << retcode << endl; + ndbout << "If ConnectionHandle does not identify an allocated" << endl; + ndbout << "SQL-connection,an exception condition is raised" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + + //************************************************************* + //** Test 3 ** + //** If the value of FunctionId is not in table 27, "Codes ** + //** used to identify SQL/CLI routines" ** + //************************************************************* + + retcode = SQLGetFunctions(GF_hdbc, 88888, &TableExists); + ndbout<< "TableExists = " << TableExists << endl; + if (retcode == -2) +{ + ndbout << "retcode = " << retcode << endl; + ndbout << "Test 3 : The value of FunctionId is not in table 27" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + else if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) +{ + ndbout << "retcode = " << retcode << endl; + ndbout << "Test 3 : The value of FunctionId is not in table 27" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + else +{ + ndbout << "retcode = " << retcode << endl; + ndbout << "Test 3 : The value of FunctionId is not in table 27" << endl; + SQLGetFunctions_DisplayError(SQL_HANDLE_STMT, GF_hstmt); +} + + //****************** + //** Test 4 ** + //** Normal case ** + //****************** + ndbout << "Test 4:" << endl; + retcode = SQLGetFunctions(GF_hdbc, SQL_API_SQLBROWSECONNECT, &Supported); + ndbout << "retcode = " << retcode << endl; + if (Supported == TRUE) +{ + ndbout << "Supported = " << Supported << endl; + ndbout << "SQLBrowseConnect is supported by the current data source" + << endl; +} + else +{ + ndbout << "Supported = " << Supported << endl; + ndbout << "SQLBrowseConnect isn't supported by the current data source" + << endl; +} + + + //****************** + //** Test 5 ** + //** Normal case ** + //****************** + ndbout << endl << "Test 5:" << endl; + retcode = SQLGetFunctions(GF_hdbc, SQL_API_SQLFETCH, &Supported); + ndbout << "retcode = " << retcode << endl; + if (Supported == TRUE) +{ + ndbout << "Supported = " << Supported << endl; + ndbout << "SQLFETCH is supported by the current data source" << endl; +} + else +{ + ndbout << "Supported = " << Supported << endl; + ndbout << "SQLFETCH isn't supported by the current data source" << endl; +} + +} + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(GF_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, GF_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, GF_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, GF_henv); + + return NDBT_OK; + +} + + +void SQLGetFunctions_DisplayError(SQLSMALLINT GF_HandleType, + SQLHDBC GF_InputHandle) +{ + SQLRETURN SQLSTATEs; + SQLCHAR Sqlstate[50]; + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + SQLCHAR Msg[GF_MESSAGE_LENGTH]; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + Msg[0] = 0; + while ((SQLSTATEs = SQLGetDiagRec(GF_HandleType, + GF_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << GF_HandleType << endl; + ndbout << "the InputHandle is :" << (long)GF_InputHandle << endl; + ndbout << "the Msg is :" << (char *) Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + Msg[0] = 0; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLGetInfoTest.cpp b/ndb/test/odbc/client/SQLGetInfoTest.cpp new file mode 100644 index 00000000000..95f7562dafe --- /dev/null +++ b/ndb/test/odbc/client/SQLGetInfoTest.cpp @@ -0,0 +1,215 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLGetInfoTest.cpp + */ + +#include <common.hpp> + +using namespace std; + +SQLHDBC GI_hdbc; +SQLHSTMT GI_hstmt; +SQLHENV GI_henv; + +#define GI_MESSAGE_LENGTH 200 + +SQLCHAR Msg[GI_MESSAGE_LENGTH]; + +void SQLGetInfoTest_DisplayError(SQLSMALLINT GI_HandleType, + SQLHDBC GI_InputHandle); + +/** + * Test to retrieve general information about the driver and + * the data source an application is currently connected to. + * + * Tests: + * -# Test The value of FunctionId is not in table 27 + * @return Zero, if test succeeded + */ + +int SQLGetInfoTest() +{ + SQLRETURN retcode; + SQLINTEGER InfoValuePtr; + SQLSMALLINT SLPStringLengthPtr; + + ndbout << endl << "Start SQLGetInfo Testing" << endl; + + //****************************************************** + //** The value of FunctionId is not in Table 27, then ** + //** an exception condition is raised ** + //****************************************************** + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &GI_henv); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(GI_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + GI_henv, + &GI_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(GI_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + + // ********************** + // ** GET INFO FROM DB ** + // ********************* + + retcode = SQLGetInfo(GI_hdbc, + SQL_DATABASE_NAME, + &InfoValuePtr, + sizeof(InfoValuePtr), + &SLPStringLengthPtr); + + if (retcode == SQL_SUCCESS) + ndbout << endl << "Database Name:" << InfoValuePtr << endl; + else + { + ndbout << endl << "retcode = SQLGetInfo() = " << retcode <<endl; + SQLGetInfoTest_DisplayError(SQL_HANDLE_STMT, GI_hstmt); + } + + retcode = SQLGetInfo(GI_hdbc, + SQL_DRIVER_NAME, + &InfoValuePtr, + sizeof(InfoValuePtr), + &SLPStringLengthPtr); + + if (retcode == SQL_SUCCESS) + ndbout << endl << "Driver Name:" << InfoValuePtr << endl; + else + { + ndbout << endl << "retcode = SQLGetInfo() = " << retcode <<endl; + SQLGetInfoTest_DisplayError(SQL_HANDLE_STMT, GI_hstmt); + } + + // ************************** + // ** INPUT WRONG InfoType ** + // ************************** + retcode = SQLGetInfo(GI_hdbc, + 8888, + &InfoValuePtr, + sizeof(InfoValuePtr), + &SLPStringLengthPtr); + if (retcode == -2) + { + ndbout << endl <<"retcode = " << retcode << endl; + ndbout << "System reported -2. Please check your test programme" + << " about the connectionhandle." << endl; + SQLGetInfoTest_DisplayError(SQL_HANDLE_STMT, GI_hstmt); + } + else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "retcode = " << retcode << endl; + ndbout << "The information of InfoType is not in Table 28," + << " but SQLGetInfo() executeed succeddfully." + << " Check the function!" <<endl; + SQLGetInfoTest_DisplayError(SQL_HANDLE_STMT, GI_hstmt); + } + else if (retcode == SQL_ERROR) + { + ndbout << endl << "retcode = " << retcode << endl; + ndbout << "Input a wrong InfoType. The system found the" + << " information of InfoType is not in Table 28." + << " Test successful!" << endl; + } + else + ndbout << endl; + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(GI_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, GI_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, GI_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, GI_henv); + + return NDBT_OK; + + } + + +void SQLGetInfoTest_DisplayError(SQLSMALLINT GI_HandleType, + SQLHDBC GI_InputHandle) +{ + SQLRETURN SQLSTATEs; + SQLINTEGER NativeError; + SQLCHAR Sqlstate[50]; + SQLSMALLINT i, MsgLen; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + + while ((SQLSTATEs = SQLGetDiagRec(GI_HandleType, + GI_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) +{ + + ndbout << "the GI_HandleType is:" << GI_HandleType << endl; + ndbout << "the GI_InputHandle is :" << (long)GI_InputHandle << endl; + ndbout << "the Msg is :" << (char *) Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLGetStmtAttrTest.cpp b/ndb/test/odbc/client/SQLGetStmtAttrTest.cpp new file mode 100644 index 00000000000..2052af60ee0 --- /dev/null +++ b/ndb/test/odbc/client/SQLGetStmtAttrTest.cpp @@ -0,0 +1,155 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLPOINTER ValuePtr; +SQLINTEGER GetStmtAttr_StringLengthPtr; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void GetStmtAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle); + +int SQLGetStmtAttrTest() +{ + /* SQL/CLI attributes */ + /* SQL_ATTR_APP_PARAM_DESC */ + // char PtrValue1[1] = {'SQL_NULL_DESC'}; + // for (i=0; i < 1; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_PARAM_DESC, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + /* SQL_ATTR_APP_ROW_DESC */ + // char PtrValue2[1] = {'SQL_NULL_DESC'}; /* ? */ + // for (i=0; i < 2; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + /* SQL_ATTR_CURSOR_SCROLLABLE */ + // char PtrValue3[2] = {'SQL_NONSCROLLABLE', 'SQL_SCROLLABLE'}; /* ? */ + // for (i=0; i < 2; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_CURSOR_SCROLLABLE, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + /* SQL_ATTR_CURSOR_SENSITIVITY */ + // char PtrValue4[3] = {'SQL_UNSPECIFIED', 'SQL_INSENSITIVE', 'SQL_SENSITIVE'}; /* ? */ + // for (i=0; i < 3; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_CURSOR_SENSITIVITY, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + /* SQL_ATTR_METADATA_ID */ + // char PtrValue5[2] = {'SQL_TRUE', 'SQL_FALSE'}; /* ? */ + // for (i=0; i < 2; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_METADATA_ID, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + /* SQL_ATTR_IMP_ROW_DESC */ + // char PtrValue6[2] = {'TRUE', 'FALSE'}; /* ? */ + // for (i=0; i < 2; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_ROW_DESC, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + + /* SQL_ATTR_IMP_PARAM_DESC */ + // char PtrValue6[2] = {'TRUE', 'FALSE'}; /* ? */ + // for (i=0; i < 2; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + + /* SQL_ATTR_METADATA_ID */ + // char PtrValue6[2] = {'TRUE', 'FALSE'}; /* ? */ + // for (i=0; i < 2; i++) { + retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_METADATA_ID, ValuePtr, 36, &GetStmtAttr_StringLengthPtr); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + GetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);//} + + return 0; + + + } + + +void GetStmtAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLGetTypeInfoTest.cpp b/ndb/test/odbc/client/SQLGetTypeInfoTest.cpp new file mode 100644 index 00000000000..5925d1cc1ae --- /dev/null +++ b/ndb/test/odbc/client/SQLGetTypeInfoTest.cpp @@ -0,0 +1,202 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLGetTypeInfoTest.cpp + */ + +#include <common.hpp> +#define GT_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC GT_hdbc; +SQLHSTMT GT_hstmt; +SQLHENV GT_henv; + +void SQLGetTypeInfoTest_DisplayError(SQLSMALLINT GT_HandleType, + SQLHDBC GT_InputHandle); + +/** + * Test to retrieve general information about the data types + * supported by the data source an application is currently connected to. + * + * Tests: + * -# Test The value of FunctionId is not in table 37 + * @return Zero, if test succeeded + */ +int SQLGetTypeInfoTest() +{ + SQLRETURN retcode; + SQLSMALLINT ColumnSize; + unsigned long TypeName; + // SQLCHAR TypeName[128]; + + ndbout << endl << "Start SQLGetTypeInfo Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + >_henv); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(GT_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.X!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + GT_henv, + >_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(GT_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + GT_hdbc, + >_hstmt); + + + //*********************************************** + //** Get DataType From the Current Application ** + //*********************************************** + retcode = SQLGetTypeInfo(GT_hstmt, SQL_CHAR); + ndbout << "retcode =SQLGetTypeInfo()= " << retcode << endl; + if (retcode == SQL_SUCCESS) + { + retcode =SQLBindCol(GT_hstmt, + 2, + SQL_C_ULONG, + TypeName, + sizeof(TypeName), + NULL); + ndbout << "retcode = SQLBindCol()= " << retcode << endl; + + // retcode =SQLBindCol(GT_hstmt, + // 1, + // SQL_C_DEFAULT, + // ColumnSize, + // sizeof(ColumnSize), + // NULL); + + retcode = SQLFetch(GT_hstmt); + ndbout << "retcode = SQLFETCH()=" << retcode << endl; + ndbout << "DataType = " << TypeName << endl; + + } + + //******************************************************* + //** If the Value of DataType is not in Table 37, then ** + //** an exception condition is raised ** + //******************************************************* + retcode = SQLGetTypeInfo(GT_hstmt, 8888888); + if (retcode == -2) + { + ndbout << "retcode = " << retcode << endl; + ndbout << "The value of DataType is not in table 37" << endl; + SQLGetTypeInfoTest_DisplayError(SQL_HANDLE_STMT, GT_hstmt); + } + else if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "retcode = " << retcode << endl; + ndbout << endl << "The value of DataType is not in Table 37" << endl; + SQLGetTypeInfoTest_DisplayError(SQL_HANDLE_STMT, GT_hstmt); + } + else + { + ndbout << "retcode = " << retcode << endl; + ndbout << endl << "The value of DataType is not in Table 37" << endl; + SQLGetTypeInfoTest_DisplayError(SQL_HANDLE_STMT, GT_hstmt); + } + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(GT_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, GT_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, GT_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, GT_henv); + + return NDBT_OK; + + } + +void SQLGetTypeInfoTest_DisplayError(SQLSMALLINT GT_HandleType, + SQLHDBC GT_InputHandle) +{ + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + SQLCHAR Msg[GT_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + SQLCHAR Sqlstate[50]; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(GT_HandleType, + GT_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) +{ + + ndbout << "the HandleType is:" << GT_HandleType << endl; + ndbout << "the InputHandle is :" << (long)GT_InputHandle << endl; + ndbout << "the Msg is :" << (char *) Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLMoreResultsTest.cpp b/ndb/test/odbc/client/SQLMoreResultsTest.cpp new file mode 100644 index 00000000000..cba8b0dc53e --- /dev/null +++ b/ndb/test/odbc/client/SQLMoreResultsTest.cpp @@ -0,0 +1,91 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void SQLMoreResults_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLMoreResultsTest() +{ + + /* hstmt */ + retcode = SQLMoreResults(hstmt); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLMoreResults_DisplayError(SQL_HANDLE_STMT, hstmt); + + /* henv */ + retcode = SQLMoreResults(henv); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_SUCCESS_WITH_INFO still appeared. Please check programm" << endl; + // SQLMoreResults_DisplayError(SQL_HANDLE_ENV, henv); + + /* hdbc */ + retcode = SQLMoreResults(hdbc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_SUCCESS_WITH_INFO still appeared. Please check programm" << endl; + // SQLMoreResults_DisplayError(SQL_HANDLE_DBC, hdbc); + + /* hdesc */ + retcode = SQLMoreResults(hdesc); + + if (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_SUCCESS) + ndbout << "Handle Type is SQL_HANDLE_DESC, but string SQL_SUCCESS_WITH_INFO still appeared. Please check programm" << endl; + // SQLMoreResults_DisplayError(SQL_HANDLE_DESC, hdesc); + + return 0; + + } + + +void SQLMoreResults_DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLNumResultColsTest.cpp b/ndb/test/odbc/client/SQLNumResultColsTest.cpp new file mode 100644 index 00000000000..8f0c1dba94c --- /dev/null +++ b/ndb/test/odbc/client/SQLNumResultColsTest.cpp @@ -0,0 +1,202 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLNumResultColsTest.cpp + */ +#include <common.hpp> +using namespace std; + +#define NRC_MESSAGE_LENGTH 200 + +SQLHSTMT NRC_hstmt; +SQLHSTMT NRC_hdbc; +SQLHENV NRC_henv; +SQLHDESC NRC_hdesc; + +void SQLNumResultColsTest_DisplayError(SQLSMALLINT NRC_HandleType, + SQLHSTMT NRC_InputHandle); + +/** + * Test returning descriptor information + * + * Tests: + * -# Testing how many columns exist in the result data set + * + * @return Zero, if test succeeded + */ + +int SQLNumResultColsTest() +{ + SQLRETURN retcode; + SQLSMALLINT NumColumns; + SQLCHAR SQLStmt[NRC_MESSAGE_LENGTH]; + + ndbout << endl << "Start SQLNumResultCols Testing" << endl << endl; + + //************************************************************** + //** If there is no prepared or executed statement associated ** + //** with SQL-statement ** + //************************************************************** + + retcode = SQLNumResultCols(NRC_hstmt, &NumColumns); + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + { + + SQLNumResultColsTest_DisplayError(SQL_HANDLE_STMT, NRC_hstmt); + } + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &NRC_henv); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(NRC_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + NRC_henv, + &NRC_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(NRC_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + NRC_hdbc, + &NRC_hstmt); + if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + strcpy((char *) SQLStmt, "SELECT * FROM Customers"); + + // strcpy((char *) SQLStmt, + // "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES (7, 'pet', 'LM vag 8', '88888')"); + + //******************************************* + //** Prepare and Execute the SQL statement ** + //******************************************* + + retcode = SQLExecDirect(NRC_hstmt, + SQLStmt, + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + //***************************************************** + //** Only general error test. It is not in test rule ** + //***************************************************** + + retcode = SQLNumResultCols(NRC_hstmt, &NumColumns); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << endl << "Number of columns in the result data set" << endl; + ndbout << NumColumns << endl; + } + else + SQLNumResultColsTest_DisplayError(SQL_HANDLE_STMT, NRC_hstmt); + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(NRC_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, NRC_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, NRC_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, NRC_henv); + + return NDBT_OK; + +} + +void SQLNumResultColsTest_DisplayError(SQLSMALLINT NRC_HandleType, + SQLHSTMT NRC_InputHandle) +{ + SQLRETURN SQLSTATEs; + SQLINTEGER NativeError; + SQLSMALLINT i, MsgLen; + SQLCHAR Msg[NRC_MESSAGE_LENGTH],Sqlstate[5]; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(NRC_HandleType, + NRC_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << NRC_HandleType << endl; + ndbout << "the InputHandle is :" << (long)NRC_InputHandle << endl; + ndbout << "the Msg is: " << (char *)Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLParamDataTest.cpp b/ndb/test/odbc/client/SQLParamDataTest.cpp new file mode 100644 index 00000000000..92d491dfaf5 --- /dev/null +++ b/ndb/test/odbc/client/SQLParamDataTest.cpp @@ -0,0 +1,105 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 + +#define NAME_LEN 50 +#define PHONE_LEN 50 + +SQLCHAR szName[NAME_LEN], szPhone[PHONE_LEN]; +SQLINTEGER sCustID, cbName, cbAge, cbBirthday; + +SQLHSTMT hstmt; +SQLHENV henv; + +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR szStatus[STATUS_LEN], Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER cbOrderID = 0, cbCustID = 0, cbOpenDate = 0, cbSalesPerson = SQL_NTS, cbStatus = SQL_NTS, NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLSMALLINT sOrderID; + +SQLSMALLINT i, MsgLen; + +SQLCHAR ColumnName; +SQLSMALLINT TargetValuePtr; +SQLINTEGER StrLen_or_IndPtr; +SQLPOINTER ValuePtrPtr; + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLParamDataTest() +{ + + /* hstmt */ + // We can create the table ORDERS and insert rows into ORDERS + // NDB by program TestDirectSQL. In this test program, We only have three rows in table ORDERS + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, (SQLCHAR *)"SELECT ORDERID, CUSTID, OPENDATE, SALESPERSON, STATUS FROM ORDERS", SQL_NTS); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + retcode = SQLExecute(hstmt); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 16, 0, &sOrderID, 16, &cbOrderID); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + +while (retcode == SQL_NEED_DATA) { + retcode = SQLParamData(hstmt, &ValuePtrPtr); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){ + DisplayError(SQL_HANDLE_STMT, hstmt); + } + } + + + } +} +} + return 0; + + } + + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLPrepareTest.cpp b/ndb/test/odbc/client/SQLPrepareTest.cpp new file mode 100644 index 00000000000..2ebbc224b85 --- /dev/null +++ b/ndb/test/odbc/client/SQLPrepareTest.cpp @@ -0,0 +1,285 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLprepareTest.cpp + */ +#include <common.hpp> +#define pare_SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC pare_hdbc; +SQLHSTMT pare_hstmt; +SQLHENV pare_henv; +SQLHDESC pare_hdesc; +SQLRETURN pare_retcode, pare_SQLSTATEs; + +SQLCHAR pare_Sqlstate[5]; + +SQLINTEGER pare_NativeError; +SQLSMALLINT pare_i, pare_MsgLen; +SQLCHAR pare_Msg[pare_SQL_MAXIMUM_MESSAGE_LENGTH]; + +void Prepare_DisplayError(SQLSMALLINT pare_HandleType, + SQLHSTMT pare_InputHandle); + +/** + * Test to prepare a statement with different handles + * + * -# Input correct hstmt handle + * -# Input incorrect henv handle + * -# Input incorrect hdbc handle + * -# Input incorrect handle hdesc + * + * @return Zero, if test succeeded + */ +int SQLPrepareTest() +{ + SQLCHAR SQLStmt [120]; + ndbout << endl << "Start SQLPrepare Testing" << endl; + ndbout << endl << "Test 1" << endl; + //********************************* + //** Test1 ** + //** Input correct hstmt handle ** + //********************************* + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + pare_retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &pare_henv); + + if(pare_retcode == SQL_SUCCESS || pare_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + pare_retcode = SQLSetEnvAttr(pare_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (pare_retcode == SQL_SUCCESS || pare_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + pare_retcode = SQLAllocHandle(SQL_HANDLE_DBC, pare_henv, &pare_hdbc); + if (pare_retcode == SQL_SUCCESS || pare_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + pare_retcode = SQLConnect(pare_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (pare_retcode == SQL_SUCCESS || pare_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + ndbout << "Failure to Connect DB!" << endl; + + //******************************* + //** Allocate statement handle ** + //******************************* + pare_retcode = SQLAllocHandle(SQL_HANDLE_STMT, pare_hdbc, &pare_hstmt); + if (pare_retcode == SQL_SUCCESS || pare_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + strcpy( (char *) SQLStmt, "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES(2, 'Hans Peter', 'LM Vag8', '468719000')"); + + pare_retcode = SQLPrepare(pare_hstmt, + SQLStmt, + SQL_NTS); + + if (pare_retcode == SQL_INVALID_HANDLE) + { + ndbout << "pare_retcode = " << pare_retcode << endl; + ndbout << "HandleType is SQL_HANDLE_STMT, but SQL_INVALID_HANDLE" + << endl; + ndbout << "appeared. Please check program!" << endl; + } + else if (pare_retcode == SQL_ERROR || pare_retcode == SQL_SUCCESS_WITH_INFO) + { + Prepare_DisplayError(SQL_HANDLE_STMT, pare_hstmt); + } + else + { + //*********************** + //** Execute statement ** + //*********************** + pare_retcode = SQLExecute(pare_hstmt); + if (pare_retcode != SQL_SUCCESS) + { + ndbout << "pare_retcode = " << pare_retcode << endl; + Prepare_DisplayError(SQL_HANDLE_STMT, pare_hstmt); + } + else + ndbout << endl << "Test 1:Input correct HSTMT handle. OK!" << endl; + } + + //********************************* + //** Test2 ** + //** Input incorrect henv handle ** + //********************************* + + strcpy( (char *) SQLStmt, "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES(3, 'Hans', 'LM8', '51888')"); + + pare_retcode = SQLPrepare(pare_henv, + SQLStmt, + SQL_NTS); + + ndbout << endl << "Test 2" << endl; + if (pare_retcode == SQL_SUCCESS_WITH_INFO || pare_retcode == SQL_SUCCESS) + { + FAILURE("Wrong SQL_HANDLE_HENV, but success returned. Check it!"); + } + else if (pare_retcode == SQL_INVALID_HANDLE) + { + ndbout << "Wrong SQL_HANDLE_HENV input and -2 appeared. OK!" << endl ; + } + else + ; + /* + { + ndbout << "Input wrong SQL_HANDLE_ENV, but SQL_SUCCESS_W_I" << endl; + ndbout << "and SQL_SUCCESS appeared. Please check program!" << endl; + return NDBT_FAILED; + } + */ + + //********************************* + //** Test3 ** + //** Input incorrect hdbc handle ** + //********************************* + + strcpy( (char *) SQLStmt, "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES(4, 'HP', 'VÄG8', '90888')"); + + pare_retcode = SQLPrepare(pare_hdbc, + SQLStmt, + SQL_NTS); + + ndbout << endl << "Test 3" << endl; + if (pare_retcode == SQL_SUCCESS_WITH_INFO || pare_retcode == SQL_SUCCESS) + { + FAILURE("Wrong SQL_HANDLE_HDBC, but success returned. Check it!"); + } + else if (pare_retcode == SQL_INVALID_HANDLE) + { + ndbout << "Wrong SQL_HANDLE_HDBC input and -2 appeared. OK!" << endl ; + } + else + ; + + /* + { + ndbout << "Input wrong statement handle SQL_HANDLE_DBC" << endl; + ndbout << "but SQL_SUCCESS_WITH_INFO" << endl; + ndbout << "and SQL_SUCCESS still appeared. Please check program" << endl; + return NDBT_FAILED; + } + + */ + //********************************** + //** Test4 ** + //** Input incorrect handle hdesc ** + //********************************** + + strcpy( (char *) SQLStmt, "INSERT INTO Customers (CustID, Name, Address, Phone) VALUES(5, 'Richard', 'VÄG8', '56888')"); + + pare_retcode = SQLPrepare(pare_hdesc, + SQLStmt, + SQL_NTS); + + ndbout << endl << "Test 4" << endl; + if (pare_retcode == SQL_SUCCESS_WITH_INFO || pare_retcode == SQL_SUCCESS) + { + FAILURE("Wrong SQL_HANDLE_DESC, but success returned"); + } + else if (pare_retcode == SQL_INVALID_HANDLE) + { + ndbout << "Wrong SQL_HANDLE_DESC input and -2 appeared. OK!" << endl ; + } + else + ndbout << endl; + + /* + { + ndbout << "TEST FAILURE: Input wrong SQL_HANDLE_DESC, " + << "but SQL_SUCCESS_WITH_INFO or SQL_SUCCESS was returned." + << endl; + return NDBT_FAILED; + } + */ + + //**************** + // Free Handles ** + //**************** + SQLDisconnect(pare_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, pare_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, pare_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, pare_henv); + + return NDBT_OK; + +} + +void Prepare_DisplayError(SQLSMALLINT pare_HandleType, + SQLHSTMT pare_InputHandle) +{ + SQLSMALLINT pare_i = 1; + SQLRETURN pare_SQLSTATEs; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((pare_SQLSTATEs = SQLGetDiagRec(pare_HandleType, + pare_InputHandle, + pare_i, + pare_Sqlstate, + &pare_NativeError, + pare_Msg, + sizeof(pare_Msg), + &pare_MsgLen) + ) != SQL_NO_DATA) + { + ndbout << "SQLSTATE = " << pare_SQLSTATEs << endl; + ndbout << "the HandleType is:" << pare_HandleType << endl; + ndbout << "the Handle is :" << (long)pare_InputHandle << endl; + ndbout << "the conn_Msg is: " << (char *) pare_Msg << endl; + ndbout << "the output state is:" << (char *)pare_Sqlstate << endl; + + pare_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLPutDataTest.cpp b/ndb/test/odbc/client/SQLPutDataTest.cpp new file mode 100644 index 00000000000..38a8458fec4 --- /dev/null +++ b/ndb/test/odbc/client/SQLPutDataTest.cpp @@ -0,0 +1,108 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlcli.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 + +#define NAME_LEN 50 +#define PHONE_LEN 50 + +SQLCHAR szName[NAME_LEN], szPhone[PHONE_LEN]; +SQLINTEGER sCustID, cbName, cbAge, cbBirthday; + +SQLHSTMT hstmt; +SQLHENV henv; + +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR szStatus[STATUS_LEN], Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER cbOrderID = 0, cbCustID = 0, cbOpenDate = 0, cbSalesPerson = SQL_NTS, cbStatus = SQL_NTS, NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLSMALLINT sOrderID; + +SQLSMALLINT i, MsgLen; + +SQLCHAR ColumnName; +SQLSMALLINT TargetValuePtr; +SQLINTEGER StrLen_or_Ind, DataPtr; +SQLPOINTER ValuePtrPtr; + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle); + +int SQLPutDataTest() +{ + + /* hstmt */ + // We can create the table ORDERS and insert rows into ORDERS + // NDB by program TestDirectSQL. In this test program, We only have three rows in table ORDERS + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, (SQLCHAR *)"SELECT ORDERID, CUSTID, OPENDATE, SALESPERSON, STATUS FROM ORDERS", SQL_NTS); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + retcode = SQLExecute(hstmt); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 16, 0, &sOrderID, 16, &cbOrderID); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + +while (retcode == SQL_NEED_DATA) { + retcode = SQLParamData(hstmt, &ValuePtrPtr); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){ + retcode = SQLPutData(hstmt, &DataPtr, StrLen_or_Ind); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){ + DisplayError(SQL_HANDLE_STMT, hstmt); + } + } + } + + + } +} +} + return 0; + + } + + +void DisplayError(SQLSMALLINT HandleType, SQLHSTMT InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLRowCountTest.cpp b/ndb/test/odbc/client/SQLRowCountTest.cpp new file mode 100644 index 00000000000..f298017c519 --- /dev/null +++ b/ndb/test/odbc/client/SQLRowCountTest.cpp @@ -0,0 +1,203 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLRowCountTest.cpp + */ + +#include <common.hpp> +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 +#define RC_MESSAGE_LENGTH 200 + +SQLHSTMT RC_hstmt; +SQLHDBC RC_hdbc; +SQLHENV RC_henv; +SQLHDESC RC_hdesc; + +void SQLRowCountTest_DisplayError(SQLSMALLINT RC_HandleType, + SQLHSTMT RC_InputHandle); + +/** + * Test to obtain a count of the number of rows + * in a table + * + * -# Call SQLRowCount without executed statement + * -# Call SQLRowCount with normal case + * + * @return Zero, if test succeeded + */ + +int SQLRowCountTest() +{ + SQLRETURN retcode; + unsigned long RowCount; + SQLCHAR SQLStmt [120]; + + ndbout << endl << "Start SQLRowCount Testing" << endl; + + //************************************************************************ + //* If there is no executed statement, an execption condotion is raised ** + //************************************************************************ + + retcode = SQLRowCount(RC_hstmt, &RowCount); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + + SQLRowCountTest_DisplayError(SQL_HANDLE_STMT, RC_hstmt); + } + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &RC_henv); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(RC_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + RC_henv, + &RC_hdbc); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(RC_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + RC_hdbc, + &RC_hstmt); + if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + strcpy((char *) SQLStmt, "INSERT INTO Customers (CustID, Name, Address,Phone) VALUES(588, 'HeYong','LM888','919888')"); + + //******************************* + //* Prepare the SQL statement ** + //******************************* + + retcode = SQLPrepare(RC_hstmt, + SQLStmt, + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + //****************************** + //* Execute the SQL statement ** + //****************************** + retcode = SQLExecute(RC_hstmt); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + //*************** + // Normal test ** + //*************** + retcode = SQLRowCount(RC_hstmt, &RowCount); + if (retcode == SQL_ERROR ) + SQLRowCountTest_DisplayError(SQL_HANDLE_STMT, RC_hstmt); + else + ndbout << endl << "Number of the rows in the table Customers: " + << (int)RowCount << endl; + } + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(RC_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, RC_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, RC_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, RC_henv); + + return NDBT_OK; + +} + +void SQLRowCountTest_DisplayError(SQLSMALLINT RC_HandleType, + SQLHSTMT RC_InputHandle) +{ + SQLRETURN SQLSTATEs; + SQLSMALLINT i, MsgLen; + SQLCHAR Sqlstate[5], Msg[RC_MESSAGE_LENGTH]; + SQLINTEGER NativeError; + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(RC_HandleType, + RC_InputHandle, + i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) +{ + + ndbout << "the HandleType is:" << RC_HandleType << endl; + ndbout << "the InputHandle is :" << (long)RC_InputHandle << endl; + ndbout << "the Msg:" << (char *)Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; +} + +} + + + diff --git a/ndb/test/odbc/client/SQLSetConnectAttrTest.cpp b/ndb/test/odbc/client/SQLSetConnectAttrTest.cpp new file mode 100644 index 00000000000..c41ef885521 --- /dev/null +++ b/ndb/test/odbc/client/SQLSetConnectAttrTest.cpp @@ -0,0 +1,131 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLPOINTER ValuePtr; +//SQLINTEGER StringLength; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void SetConnectAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle); + +int SQLSetConnectAttrTest () +{ + /* SQL/CLI attributes */ + char PtrValue1[2] = {'SQL_TRUE', 'SQL_FALSE'}; + for (i=0; i < 2; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTO_IPD, (void*)PtrValue1[i], sizeof(PtrValue1[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + /* ODBC attributes */ + /* + char PtrValue1[3] = {'SQL_MODE_READ_ONLY', 'SQL_MODE_READ_WRITE'}; + for (i=0; i < 3; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_ACCESS_MODE, (void*)PtrValue1[i], sizeof(PtrValue1[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + + char PtrValue2[2] = {'SQL_ASYNC_ENABLE_OFF', 'SQL_ASYNC_ENABLE_ON'}; + for (i=0; i < 2; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_ASYNC_ENABLE, (void*)PtrValue2[i], sizeof(PtrValue2[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + + char PtrValue4[2] = {'SQL_AUTOCOMMIT_OFF', 'SQL_AUTOCOMMIT_ON'}; + for (i=0; i < 2; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (void*)PtrValue4[i], sizeof(PtrValue4[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + char PtrValue5[2] = {'SQL_CD_TRUE', 'SQL_CD_FALSE'}; + for (i=0; i < 2; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_CONNECTION_DEAD, (void*)PtrValue4[i], sizeof(PtrValue5[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + + char PtrValue5[2] = {'SQL_CD_TRUE', 'SQL_CD_FALSE'}; + for (i=0; i < 2; i++) { + retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_CONNECTION_TIMEOUT, (void*)PtrValue4[i], sizeof(PtrValue5[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_DBC, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetConnectAttr_DisplayError(SQL_HANDLE_DBC, hdbc);} + + */ + + return 0; + + } + + +void SetConnectAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLSetCursorNameTest.cpp b/ndb/test/odbc/client/SQLSetCursorNameTest.cpp new file mode 100644 index 00000000000..b35cf9fefc2 --- /dev/null +++ b/ndb/test/odbc/client/SQLSetCursorNameTest.cpp @@ -0,0 +1,215 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLSetCursorNameTest.cpp + */ +#include <common.hpp> +using namespace std; + +#define SCN_MESSAGE_LENGTH 50 + +SQLHSTMT SCN_hstmt; +SQLHDESC SCN_hdesc; +SQLHENV SCN_henv; +SQLHDBC SCN_hdbc; + +void SCN_DisplayError(SQLSMALLINT SCN_HandleType, + SQLHDESC SCN_InputHandle); + +/** + * Test to assign a user-defined name to a cursor that is + * associated with an active SQL statement handle + * + * Tests: + * -# set user-defined cursor name to zero + * -# set user-defined cursor name in normal case + * + * @return Zero, if test succeeded + */ + +int SQLSetCursorNameTest() +{ + SQLRETURN retcode; + SQLCHAR SQLStmt [120]; + SQLCHAR CursorName [80]; + SQLSMALLINT CNameSize; + + ndbout << endl << "Start SQLSetCursorName Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &SCN_henv); + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + retcode = SQLSetEnvAttr(SCN_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + retcode = SQLAllocHandle(SQL_HANDLE_DBC, + SCN_henv, + &SCN_hdbc); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + retcode = SQLConnect(SCN_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + //******************************* + //** Allocate statement handle ** + //******************************* + + retcode = SQLAllocHandle(SQL_HANDLE_STMT, + SCN_hdbc, + &SCN_hstmt); + + if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************ + //** Define a statement ** + //************************ + + strcpy((char *) SQLStmt, + "SELECT * FROM Customers WHERE Address = 'LM Vag 8'"); + + //************************* + //** Prepare a statement ** + //************************* + + retcode = SQLPrepare(SCN_hstmt, + SQLStmt, + SQL_NTS); + + //********************************** + //** Set the cursor name with zero** + //********************************** + retcode = SQLSetCursorName(SCN_hstmt, + (char *)"", + SQL_NTS); + + if (retcode != SQL_SUCCESS) + { + ndbout << endl << "retcode =" << retcode << endl; + SCN_DisplayError(SQL_HANDLE_STMT, SCN_hstmt); + } + + //************************* + //** Set the cursor name ** + //************************* + retcode = SQLSetCursorName(SCN_hstmt, + (char *)"Customer_CURSOR", + SQL_NTS); + + if (retcode != SQL_SUCCESS) + { + ndbout << endl << "retcode =" << retcode << endl; + SCN_DisplayError(SQL_HANDLE_STMT, SCN_hstmt); + } + //*************************** + //** Execute the statement ** + //*************************** + retcode = SQLExecute(SCN_hstmt); + + //********************************************** + //** retrieve and display the new cursor name ** + //********************************************** + retcode = SQLGetCursorName(SCN_hstmt, + CursorName, + sizeof(CursorName), + &CNameSize); + + ndbout << endl << "The cursor name is : " << (char *) CursorName << endl; + + //**************** + // Free Handles ** + //**************** + SQLDisconnect(SCN_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, SCN_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, SCN_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, SCN_henv); + + return NDBT_OK; + + } + + +void SCN_DisplayError(SQLSMALLINT SCN_HandleType, SQLHDESC SCN_InputHandle) +{ + + SQLINTEGER NativeError; + SQLCHAR Sqlstate[5], Msg[SCN_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + SQLSMALLINT i, MsgLen; + i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(SCN_HandleType, + SCN_InputHandle, i, + Sqlstate, + &NativeError, + Msg, + sizeof(Msg), + &MsgLen)) + != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << SCN_HandleType << endl; + ndbout << "the InputHandle is :" << (long)SCN_InputHandle << endl; + ndbout << "the Msg is: " << (char *) Msg << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + ndbout << "-------------------------------------------------" << endl; +} + + + diff --git a/ndb/test/odbc/client/SQLSetDescFieldTest.cpp b/ndb/test/odbc/client/SQLSetDescFieldTest.cpp new file mode 100644 index 00000000000..798622e0f75 --- /dev/null +++ b/ndb/test/odbc/client/SQLSetDescFieldTest.cpp @@ -0,0 +1,100 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHSTMT hstmt; +SQLHDESC hdesc; + +SQLSMALLINT RecNumber; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLINTEGER ValuePtr1; +SQLCHAR ValuePtr2; +SQLSMALLINT ValuePtr3; + +SQLSMALLINT i, MsgLen; + +void SQLSetDescFieldTest_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLSetDescFieldTest() +{ + + /* hstmt */ + // SQLPrepare a statement to select rows from the ORDERS Table. We can create the table and inside rows in + // NDB by another program TestDirectSQL. In this test program(SQLGetDescRecTest),we only have three rows in + // table ORDERS + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, (SQLCHAR *)"SELECT ORDERID, CUSTID, OPENDATE, SALESPERSON, STATUS FROM ORDERS)", SQL_NTS); + +/* SELECT OrderID, CustID, OpenDate, SalesPerson from Table ORDERS */ + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + retcode = SQLExecute(hstmt); +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + /* If FI(FieldIdentifer) is not one of the code values in Table 20 */ +retcode = SQLSetDescField(hdesc, 1, 9999, &ValuePtr1, 128); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLSetDescFieldTest_DisplayError(SQL_HANDLE_DESC, hdesc); + + + /* RecoderNumber is less than 1 and the value of the Type column in the Table is ITEM */ +retcode = SQLSetDescField(hdesc, -1, SQL_DESC_LENGTH, &ValuePtr1, 128); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLSetDescFieldTest_DisplayError(SQL_HANDLE_DESC, hdesc); + + +} + +} + + return 0; + + } + + +void SQLSetDescFieldTest_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLSetDescRecTest.cpp b/ndb/test/odbc/client/SQLSetDescRecTest.cpp new file mode 100644 index 00000000000..d97af576cb0 --- /dev/null +++ b/ndb/test/odbc/client/SQLSetDescRecTest.cpp @@ -0,0 +1,99 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <sqlext.h> +#include <stdio.h> + +using namespace std; + +#define NAME_LEN 50 +#define PHONE_LEN 10 +#define SALES_PERSON_LEN 10 +#define STATUS_LEN 6 +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHSTMT hstmt; +SQLHDESC hdesc; + +SQLSMALLINT RecNumber; +SQLCHAR szSalesPerson[SALES_PERSON_LEN]; + +SQLCHAR Sqlstate[5], Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; +SQLINTEGER NativeError; +SQLRETURN retcode, SQLSTATEs; + +SQLCHAR Name; +SQLINTEGER LengthPtr; + +SQLSMALLINT i, MsgLen; + +SQLINTEGER StringLengthPtr, IndicatorPtr; +SQLPOINTER DataPtr; + +void SQLSetDescRecTest_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle); + +int SQLSetDescRecTest() +{ + + /* hstmt */ + // SQLPrepare a statement to select rows from the ORDERS Table. We can create the table and inside rows in + // NDB by program TestDirectSQL. In this test program(SQLSetDescRecTest),we only have three rows in + // table ORDERS + +/* Prepare the SQL statement with parameter markers. */ +retcode = SQLPrepare(hstmt, (SQLCHAR *)"SELECT ORDERID, CUSTID, OPENDATE, SALESPERSON, STATUS FROM ORDERS)", SQL_NTS); + +/* SELECT OrderID, CustID, OpenDate, SalesPerson from Table ORDERS */ + +if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { + + /* RecoderNumber is less than 1 */ +retcode = SQLSetDescRec(hdesc, -1, 1002, 1007, 1013, 1005, 1006, (void *)DataPtr, &StringLengthPtr, &IndicatorPtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLSetDescRecTest_DisplayError(SQL_HANDLE_DESC, hdesc); + + /* RecoderNumber is greater than N, N be the value of the COUNT field of D, D be the allocated CLI */ + /* descriptor area identified by DescriptorHandle */ +retcode = SQLSetDescRec(hdesc, 4, 1002, 1007, 1013, 1005, 1006, (void *)DataPtr, &StringLengthPtr, &IndicatorPtr); +if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SQLSetDescRecTest_DisplayError(SQL_HANDLE_DESC, hdesc); + +} + + return 0; + + } + + +void SQLSetDescRecTest_DisplayError(SQLSMALLINT HandleType, SQLHDESC InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLSetEnvAttrTest.cpp b/ndb/test/odbc/client/SQLSetEnvAttrTest.cpp new file mode 100644 index 00000000000..16ae5671ca3 --- /dev/null +++ b/ndb/test/odbc/client/SQLSetEnvAttrTest.cpp @@ -0,0 +1,108 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLPOINTER ValuePtr; +SQLINTEGER SetEnvAttr_StringLength; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void SetEnvAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle); + +int SQLSetEnvAttrTest() +{ + /* ODBC attributes */ + /* + char PtrValue1[3] = {'SQL_CP_OFF', 'SQL_CP_ONE_DRIVER', 'SQL_CP_ONE_PER_HENV'}; + for (i=0; i < 3; i++) { + retcode = SQLSetEnvAttr(henv, SQL_ATTR_CONNECTION_POOLING, (void*)PtrValue1[i], sizeof(PtrValue1[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv);} + + + char PtrValue2[2] = {'SQL_CP_STRICT_MATCH', 'SQL_CP_RELAXED_MATCH'}; + for (i=0; i < 2; i++) { + retcode = SQLSetEnvAttr(henv, SQL_ATTR_CP_MATCH, (void*)PtrValue2[i], sizeof(PtrValue2[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv);} + + + char PtrValue3[2] = {'SQL_OV_ODBC3', 'SQL_OV_ODBC2'}; + for (i=0; i < 2; i++) { + retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)PtrValue3[i], sizeof(PtrValue3[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv);} + */ + + char PtrValue4[2] = {'SQL_TRUE', 'SQL_FALSE'}; + for (i=0; i < 2; i++) { + retcode = SQLSetEnvAttr(henv, SQL_ATTR_OUTPUT_NTS, (void*)PtrValue4[i], sizeof(PtrValue4[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_ENV, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetEnvAttr_DisplayError(SQL_HANDLE_ENV, henv);} + + return 0; + + } + + +void SetEnvAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLSetStmtAttrTest.cpp b/ndb/test/odbc/client/SQLSetStmtAttrTest.cpp new file mode 100644 index 00000000000..646f82cd306 --- /dev/null +++ b/ndb/test/odbc/client/SQLSetStmtAttrTest.cpp @@ -0,0 +1,108 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <common.h> +#define SQL_MAXIMUM_MESSAGE_LENGTH 200 + +using namespace std; + +SQLHDBC hdbc; +SQLHSTMT hstmt; +SQLHENV henv; +SQLHDESC hdesc; +SQLRETURN retcode, SQLSTATEs; + +SQLPOINTER ValuePtr; +//SQLINTEGER StringLength; + +SQLCHAR Sqlstate[5]; + +SQLINTEGER NativeError; +SQLSMALLINT i, MsgLen; +SQLCHAR Msg[SQL_MAXIMUM_MESSAGE_LENGTH]; + +void SetStmtAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle); + +int SQLSetStmtAttrTest() +{ + /* SQL/CLI attributes */ + /* SQL_ATTR_APP_PARAM_DESC */ + char PtrValue1[13] = {'SQL_NULL_DESC'}; + for (i=0; i < 1; i++) { + retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_APP_PARAM_DESC, (void*)PtrValue1[i], sizeof(PtrValue1[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);} + + /* SQL_ATTR_APP_ROW_DESC */ + char PtrValue2[1] = {'SQL_NULL_DESC'}; /* ? */ + for (i=0; i < 2; i++) { + retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, (void*)PtrValue2[i], sizeof(PtrValue2[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);} + + /* SQL_ATTR_CURSOR_SCROLLABLE */ + char PtrValue3[2] = {'SQL_NONSCROLLABLE', 'SQL_SCROLLABLE'}; /* ? */ + for (i=0; i < 2; i++) { + retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_SCROLLABLE, (void*)PtrValue3[i], sizeof(PtrValue3[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);} + + /* SQL_ATTR_CURSOR_SENSITIVITY */ + char PtrValue4[3] = {'SQL_UNSPECIFIED', 'SQL_INSENSITIVE', 'SQL_SENSITIVE'}; /* ? */ + for (i=0; i < 3; i++) { + retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_SENSITIVITY, (void*)PtrValue4[i], sizeof(PtrValue4[i])); + + if (retcode == SQL_INVALID_HANDLE) + ndbout << "Handle Type is SQL_HANDLE_STMT, but string SQL_INVALID_HANDLE still appeared. Please check programm" << endl; + + if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) + SetStmtAttr_DisplayError(SQL_HANDLE_STMT, hstmt);} + + return 0; + + } + + +void SetStmtAttr_DisplayError(SQLSMALLINT HandleType, SQLHENV InputHandle) +{ + i = 1; + while ((SQLSTATEs = SQLGetDiagRec(HandleType, InputHandle, i, + Sqlstate, &NativeError, Msg, sizeof(Msg), + &MsgLen)) != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << HandleType << endl; + ndbout << "the InputHandle is :" << InputHandle << endl; + ndbout << "the output state is:" << (char *)Sqlstate << endl; + + i ++; + } + +} + + + diff --git a/ndb/test/odbc/client/SQLTablesTest.cpp b/ndb/test/odbc/client/SQLTablesTest.cpp new file mode 100644 index 00000000000..735efd81e9c --- /dev/null +++ b/ndb/test/odbc/client/SQLTablesTest.cpp @@ -0,0 +1,227 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLTablesTest.cpp + */ +#include <common.hpp> +using namespace std; + +#define Tables_NAME_LEN 12 +#define Tables_PHONE_LEN 12 +#define Tables_ADDRESS_LEN 12 +#define Tables_SQL_MAXIMUM_MESSAGE_LENGTH 200 + +SQLHDBC Tables_hdbc; +SQLHSTMT Tables_hstmt; +SQLHENV Tables_henv; +SQLHDESC Tables_hdesc; + +void Tables_DisplayError(SQLSMALLINT Tables_HandleType, + SQLHSTMT Tables_InputHandle); + +/** + * Test to retrieve a list of table names stored in aspecified + * data source's system + * + * -# Normal case test: print out the table name in the data result set + * @return Zero, if test succeeded + */ + +int SQLTablesTest() +{ + SQLRETURN Tables_retcode; + SQLCHAR Tables_Name[Tables_NAME_LEN], Tables_Phone[Tables_PHONE_LEN]; + SQLCHAR Tables_Address[Tables_ADDRESS_LEN]; + SQLINTEGER Tables_CustID; + + ndbout << endl << "Start SQLTables Testing" << endl; + + //******************************************************************* + //** hstmt + //** Execute a statement to retrieve rows from the Customers table ** + //** We can create the table and insert rows into Customers ** + //******************************************************************* + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + Tables_retcode = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &Tables_henv); + +if (Tables_retcode == SQL_SUCCESS || Tables_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + Tables_retcode = SQLSetEnvAttr(Tables_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + +if (Tables_retcode == SQL_SUCCESS || Tables_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + Tables_retcode = SQLAllocHandle(SQL_HANDLE_DBC, + Tables_henv, + &Tables_hdbc); + +if (Tables_retcode == SQL_SUCCESS || Tables_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + Tables_retcode = SQLConnect(Tables_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + +if (Tables_retcode == SQL_SUCCESS || Tables_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + Tables_retcode = SQLAllocHandle(SQL_HANDLE_STMT, + Tables_hdbc, + &Tables_hstmt); + +if (Tables_retcode == SQL_SUCCESS || Tables_retcode == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //************************************************************** + //** Retrieve information about the tables in the data source ** + //************************************************************** + Tables_retcode = SQLTables(Tables_hstmt, + NULL, + 0, + NULL, + 0, + (SQLCHAR *)"%", + 128, + (SQLCHAR *)"TABLES", + 128); + + ndbout <<"Tables_retcode = SQLTables() =" << Tables_retcode; + + if (Tables_retcode == SQL_ERROR) + Tables_DisplayError(SQL_HANDLE_STMT, Tables_hstmt); + //******************************************* + //** Bind columns 3 in the result data set ** + //******************************************* + + Tables_retcode = SQLBindCol(Tables_hstmt, + 3, + SQL_C_CHAR, + &Tables_Name, + Tables_NAME_LEN, + NULL); + + ndbout <<"Tables_retcode = SQLBindCol() =" << Tables_retcode; + + //********************************************** + //* Fetch and print out data in the result On ** + //* an error, display a message and exit ** + //********************************************** + + Tables_retcode = SQLFetch(Tables_hstmt); + + + ndbout <<"Tables_retcode = SQLFetch() =" << Tables_retcode; + + ndbout << endl << "Tables_retcode = SQLFetch(Tables_hstmt) = " + << Tables_retcode << endl; + + if (Tables_retcode == SQL_ERROR) + { + Tables_DisplayError(SQL_HANDLE_STMT, Tables_hstmt); + return NDBT_FAILED; + } + else if (Tables_retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "Table Name = " << (char *)Tables_Name << endl; + Tables_DisplayError(SQL_HANDLE_STMT, Tables_hstmt); + } + else if (Tables_retcode == SQL_NO_DATA) + Tables_DisplayError(SQL_HANDLE_STMT, Tables_hstmt); + else + { + ndbout << "TableName = " << (char *)Tables_Name << endl; + Tables_DisplayError(SQL_HANDLE_STMT, Tables_hstmt); + } + + // ********************************* + // ** Disconnect and Free Handles ** + // ********************************* + SQLDisconnect(Tables_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, Tables_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, Tables_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, Tables_henv); + + return NDBT_OK; +} + +void Tables_DisplayError(SQLSMALLINT Tables_HandleType, + SQLHSTMT Tables_InputHandle) +{ + SQLINTEGER NativeError; + SQLSMALLINT Tables_i = 1; + SQLRETURN Tables__SQLSTATEs; + SQLCHAR Tables_Sqlstate[5]; + SQLCHAR Tables_Msg[Tables_SQL_MAXIMUM_MESSAGE_LENGTH]; + SQLSMALLINT Tables_MsgLen; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((Tables__SQLSTATEs = SQLGetDiagRec(Tables_HandleType, + Tables_InputHandle, + Tables_i, + Tables_Sqlstate, + &NativeError, + Tables_Msg, + sizeof(Tables_Msg), + &Tables_MsgLen) + ) != SQL_NO_DATA) + { + + ndbout << "the HandleType is:" << Tables_HandleType << endl; + ndbout << "the InputHandle is :" << (long)Tables_InputHandle << endl; + ndbout << "the Tables_Msg is: " << (char *) Tables_Msg << endl; + ndbout << "the output state is:" << (char *)Tables_Sqlstate << endl; + + Tables_i ++; + break; + } + ndbout << "-------------------------------------------------" << endl; +} + diff --git a/ndb/test/odbc/client/SQLTransactTest.cpp b/ndb/test/odbc/client/SQLTransactTest.cpp new file mode 100644 index 00000000000..e9abe42129d --- /dev/null +++ b/ndb/test/odbc/client/SQLTransactTest.cpp @@ -0,0 +1,305 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file SQLTransactTest.cpp + */ +#include <common.hpp> +#define STR_MESSAGE_LENGTH 200 +#define STR_NAME_LEN 20 +#define STR_PHONE_LEN 20 +#define STR_ADDRESS_LEN 20 +using namespace std; + +SQLHDBC STR_hdbc; +SQLHSTMT STR_hstmt; +SQLHENV STR_henv; +SQLHDESC STR_hdesc; + +void Transact_DisplayError(SQLSMALLINT STR_HandleType, + SQLHSTMT STR_InputHandle); + +int STR_Display_Result(SQLHSTMT EXDR_InputHandle); + +/** + * Test: + * -#Test to request a commit or a rollback operation for + * all active transactions associated with a specific + * environment or connection handle + * + * @return Zero, if test succeeded + */ + +int SQLTransactTest() +{ + SQLRETURN STR_ret; + + ndbout << endl << "Start SQLTransact Testing" << endl; + + //************************************ + //** Allocate An Environment Handle ** + //************************************ + STR_ret = SQLAllocHandle(SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &STR_henv); + + if (STR_ret == SQL_SUCCESS || STR_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated an environment Handle!" << endl; + + //********************************************* + //** Set the ODBC application Version to 3.x ** + //********************************************* + STR_ret = SQLSetEnvAttr(STR_henv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + SQL_IS_UINTEGER); + + if (STR_ret == SQL_SUCCESS || STR_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Set the ODBC application Version to 3.x!" << endl; + + //********************************** + //** Allocate A Connection Handle ** + //********************************** + + STR_ret = SQLAllocHandle(SQL_HANDLE_DBC, + STR_henv, + &STR_hdbc); + + if (STR_ret == SQL_SUCCESS || STR_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a connection Handle!" << endl; + + // ******************* + // ** Connect to DB ** + // ******************* + STR_ret = SQLConnect(STR_hdbc, + (SQLCHAR *) connectString(), + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS, + (SQLCHAR *) "", + SQL_NTS); + + if (STR_ret == SQL_SUCCESS || STR_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Connected to DB : OK!" << endl; + else + { + ndbout << "Failure to Connect DB!" << endl; + return NDBT_FAILED; + } + + //******************************* + //** Allocate statement handle ** + //******************************* + + STR_ret = SQLAllocHandle(SQL_HANDLE_STMT, + STR_hdbc, + &STR_hstmt); + if(STR_ret == SQL_SUCCESS || STR_ret == SQL_SUCCESS_WITH_INFO) + ndbout << "Allocated a statement handle!" << endl; + + //******************************** + //** Turn Manual-Commit Mode On ** + //******************************** + STR_ret = SQLSetConnectOption(STR_hdbc, + SQL_AUTOCOMMIT, + (UDWORD) SQL_AUTOCOMMIT_OFF); + + //********************************************** + //** Prepare and Execute a prepared statement ** + //********************************************** + STR_ret = SQLExecDirect(STR_hstmt, + (SQLCHAR*)"SELECT * FROM Customers", + SQL_NTS); + + if (STR_ret == SQL_INVALID_HANDLE) + { + ndbout << "Handle Type is SQL_HANDLE_STMT, but SQL_INVALID_HANDLE" + << endl; + ndbout << "still appeared. Please check program" << endl; + } + + if (STR_ret == SQL_ERROR || STR_ret == SQL_SUCCESS_WITH_INFO) + Transact_DisplayError(SQL_HANDLE_STMT, STR_hstmt); + + //************************* + //** Display the results ** + //************************* + + STR_Display_Result(STR_hstmt); + + //**************************** + //** Commit the transaction ** + //**************************** + STR_ret = SQLTransact(STR_henv, + STR_hdbc, + SQL_COMMIT); + + //**************** + // Free Handles ** + //**************** + SQLDisconnect(STR_hdbc); + SQLFreeHandle(SQL_HANDLE_STMT, STR_hstmt); + SQLFreeHandle(SQL_HANDLE_DBC, STR_hdbc); + SQLFreeHandle(SQL_HANDLE_ENV, STR_henv); + + return NDBT_OK; + + } + +void Transact_DisplayError(SQLSMALLINT STR_HandleType, + SQLHSTMT STR_InputHandle) +{ + SQLCHAR STR_Sqlstate[5]; + SQLINTEGER STR_NativeError; + SQLSMALLINT STR_i, STR_MsgLen; + SQLCHAR STR_Msg[STR_MESSAGE_LENGTH]; + SQLRETURN SQLSTATEs; + STR_i = 1; + + ndbout << "-------------------------------------------------" << endl; + ndbout << "Error diagnostics:" << endl; + + while ((SQLSTATEs = SQLGetDiagRec(STR_HandleType, + STR_InputHandle, + STR_i, + STR_Sqlstate, + &STR_NativeError, + STR_Msg, + sizeof(STR_Msg), + &STR_MsgLen)) + != SQL_NO_DATA) { + + ndbout << "the HandleType is:" << STR_HandleType << endl; + ndbout << "the InputHandle is :" << (long)STR_InputHandle << endl; + ndbout << "the STR_Msg is: " << (char *) STR_Msg << endl; + ndbout << "the output state is:" << (char *)STR_Sqlstate << endl; + + STR_i ++; + // break; + } + ndbout << "-------------------------------------------------" << endl; +} + +int STR_Display_Result(SQLHSTMT STR_InputHandle) +{ + SQLRETURN STR_retcode; + unsigned long STR_CustID; + SQLCHAR STR_Name[STR_NAME_LEN], STR_Phone[STR_PHONE_LEN]; + SQLCHAR STR_Address[STR_ADDRESS_LEN]; + + //********************* + //** Bind columns 1 ** + //********************* + STR_retcode =SQLBindCol(STR_InputHandle, + 1, + SQL_C_ULONG, + &STR_CustID, + sizeof(STR_CustID), + NULL); + if (STR_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + Transact_DisplayError(SQL_HANDLE_STMT, STR_InputHandle); + return NDBT_FAILED; + } + + //********************* + //** Bind columns 2 ** + //********************* + + STR_retcode =SQLBindCol(STR_InputHandle, + 2, + SQL_C_CHAR, + &STR_Name, + STR_NAME_LEN, + NULL); + if (STR_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + Transact_DisplayError(SQL_HANDLE_STMT, STR_InputHandle); + return NDBT_FAILED; + } + + //********************* + //** Bind columns 3 ** + //********************* + + STR_retcode = SQLBindCol(STR_InputHandle, + 3, + SQL_C_CHAR, + &STR_Address, + STR_ADDRESS_LEN, + NULL); + + if (STR_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + Transact_DisplayError(SQL_HANDLE_STMT, STR_InputHandle); + return NDBT_FAILED; + } + + //********************* + //** Bind columns 4 ** + //********************* + + STR_retcode = SQLBindCol(STR_InputHandle, + 4, + SQL_C_CHAR, + &STR_Phone, + STR_PHONE_LEN, + NULL); + + if (STR_retcode == SQL_ERROR) + { + ndbout << "Executing SQLBindCol, SQL_ERROR happened!" << endl; + Transact_DisplayError(SQL_HANDLE_STMT, STR_InputHandle); + return NDBT_FAILED; + } + + //***************************************** + //* Fetch and print each row of data. On ** + //* an error, display a message and exit ** + //***************************************** + + if (STR_retcode != SQL_ERROR) + STR_retcode = SQLFetch(STR_InputHandle); + + ndbout << endl << "STR_retcode = SQLFetch(STR_InputHandle) = " + << STR_retcode << endl; + + if (STR_retcode == SQL_ERROR) + { + ndbout << "Executing SQLFetch, SQL_ERROR happened!" << endl; + Transact_DisplayError(SQL_HANDLE_STMT, STR_InputHandle); + return NDBT_FAILED; + } + else if (STR_retcode == SQL_SUCCESS_WITH_INFO) + { + ndbout << "CustID = " << (int)STR_CustID << endl; + ndbout << "Name = " << (char *)STR_Name << endl; + ndbout << "Address = " << (char *)STR_Address << endl; + ndbout << "Phone = " << (char *)STR_Phone << endl; + Transact_DisplayError(SQL_HANDLE_STMT, STR_InputHandle); + } + else + { + ndbout << "CustID = " << (int)STR_CustID << endl; + ndbout << "Name = " << (char *)STR_Name << endl; + ndbout << "Address = " << (char *)STR_Address << endl; + ndbout << "Phone = " << (char *)STR_Phone << endl; + } + return 0; +} diff --git a/ndb/test/odbc/client/common.hpp b/ndb/test/odbc/client/common.hpp new file mode 100644 index 00000000000..236decf1b95 --- /dev/null +++ b/ndb/test/odbc/client/common.hpp @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <NdbOut.hpp> +#include <NDBT.hpp> +#include <sqlext.h> +#include <stdio.h> +#include <string.h> +#define FAILURE(msg) { ndbout << "TEST FAILURE: " << msg << endl \ + << "-- File: " << __FILE__ << ", Line: " << __LINE__ << endl; \ + return NDBT_FAILED; } + +char* connectString(); + +int SQLFetchTest(); +int SQLDisconnectTest(); +int SQLTablesTest(); +int SQLBindColTest(); +int SQLGetInfoTest(); +int SQLGetTypeInfoTest(); +int SQLGetDataTest(); +int SQLGetFunctionsTest(); +int SQLColAttributeTest(); +int SQLColAttributeTest1(); +int SQLColAttributeTest2(); +int SQLColAttributeTest3(); +int SQLGetDiagRecSimpleTest(); +int SQLDriverConnectTest(); +int SQLAllocEnvTest(); +int SQLFreeHandleTest(); +int SQLFetchScrollTest(); +int SQLFetchTest(); +int SQLGetDescRecTest(); +int SQLSetDescFieldTest(); +int SQLGetDescFieldTest(); +int SQLSetDescRecTest(); +int SQLSetCursorNameTest(); +int SQLGetCursorNameTest(); +int SQLRowCountTest(); +int SQLGetInfoTest(); +int SQLTransactTest(); +int SQLEndTranTest(); +int SQLNumResultColsTest(); +int SQLGetTypeInfoTest(); +int SQLGetFunctionsTest(); +int SQLDescribeColTest(); +int SQLAllocHandleTest(); +int SQLCancelTest(); +int SQLCloseCursorTest(); +int SQLConnectTest(); +int SQLDisconnectTest(); +int SQLExecDirectTest(); +int SQLExecuteTest(); +int SQLFreeHandleTest(); +int SQLFreeStmtTest(); +int SQLGetConnectAttrTest(); +int SQLGetEnvAttrTest(); +int SQLGetStmtAttrTest(); +int SQLMoreResultsTest(); +int SQLPrepareTest(); +int SQLSetConnectAttrTest(); +int SQLSetEnvAttrTest(); +int SQLSetStmtAttrTest(); + +// int NDBT_ALLOCHANDLE(); +// int NDBT_ALLOCHANDLE_HDBC(); +// int NDBT_SQLPrepare(); +// int NDBT_SQLConnect(); diff --git a/ndb/test/odbc/client/main.cpp b/ndb/test/odbc/client/main.cpp new file mode 100644 index 00000000000..b202b6de111 --- /dev/null +++ b/ndb/test/odbc/client/main.cpp @@ -0,0 +1,158 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + /** + * @file main.cpp + */ + +#include <common.hpp> + +/** + * main ODBC Tests + * + * Tests main ODBC functions. + */ + +#include <common.hpp> + +int check = NDBT_OK; +static char* myConnectString; + +char* connectString() +{ + return myConnectString; +} + +int main(int argc, char** argv) +{ + + if (argc != 3) { + return NDBT_ProgramExit(NDBT_WRONGARGS); + } + myConnectString = argv[1]; + + if ( strcmp(argv[2], "help") == 0 ) + { + ndbout << "Number of Testing Program " << " Name of Testing Program" << endl; + ndbout << " 1 SQLGetDataTest()" << endl; + ndbout << " 2 SQLTablesTest()" << endl; + ndbout << " 3 SQLGetFunctionsTest()" << endl; + ndbout << " 4 SQLGetInfoTest()" << endl; + ndbout << " 5 SQLGetTypeInfoTest()" << endl; + ndbout << " 6 SQLDisconnectTest()" << endl; + ndbout << " 7 SQLFetchTest()" << endl; + ndbout << " 8 SQLRowCountTest()" << endl; + ndbout << " 9 SQLGetCursorNameTest()" << endl; + ndbout << " 10 SQLCancelTest()" << endl; + ndbout << " 11 SQLTransactTest()" << endl; + ndbout << " 12 SQLSetCursorNameTest()" << endl; + ndbout << " 13 SQLNumResultColsTest()" << endl; + ndbout << " 14 SQLDescribeColTest()" << endl; + ndbout << " 15 SQLExecDirectTest()" << endl; + ndbout << " 16 SQLColAttributeTest3()" << endl; + ndbout << " 17 SQLColAttributeTest2()" << endl; + ndbout << " 18 SQLColAttributeTest1()" << endl; + ndbout << " 19 SQLColAttributeTest()" << endl; + ndbout << " 20 SQLBindColTest()" << endl; + ndbout << " 21 SQLGetDiagRecSimpleTest()" << endl; + ndbout << " 22 SQLConnectTest()" << endl; + ndbout << " 23 SQLPrepareTest()" << endl; + } + else + { + + ndbout << endl << "Executing Files Name = " << argv[0] << endl; + ndbout << "The Number of testing program = " << argv[2] << endl; + + int i = atoi(argv[2]); + switch (i) { + case 1: + if (check == NDBT_OK) check = SQLGetDataTest(); + break; + case 2: + if (check == NDBT_OK) check = SQLTablesTest(); + break; + case 3: + if (check == NDBT_OK) check = SQLGetFunctionsTest(); + break; + case 4: + if (check == NDBT_OK) check = SQLGetInfoTest(); + break; + case 5: + if (check == NDBT_OK) check = SQLGetTypeInfoTest(); + break; + case 6: + if (check == NDBT_OK) check = SQLDisconnectTest(); + break; + case 7: + if (check == NDBT_OK) check = SQLFetchTest(); + break; + case 8: + if (check == NDBT_OK) check = SQLRowCountTest(); + break; + case 9: + if (check == NDBT_OK) check = SQLGetCursorNameTest(); + break; + case 10: + if (check == NDBT_OK) check = SQLCancelTest(); + break; + case 11: + if (check == NDBT_OK) check = SQLTransactTest(); + break; + case 12: + if (check == NDBT_OK) check = SQLSetCursorNameTest(); + break; + case 13: + if (check == NDBT_OK) check = SQLNumResultColsTest(); + break; + case 14: + if (check == NDBT_OK) check = SQLDescribeColTest(); + break; + case 15: + if (check == NDBT_OK) check = SQLExecDirectTest(); + break; + case 16: + if (check == NDBT_OK) check = SQLColAttributeTest3(); + break; + case 17: + if (check == NDBT_OK) check = SQLColAttributeTest2(); + break; + case 18: + if (check == NDBT_OK) check = SQLColAttributeTest1(); + break; + case 19: + if (check == NDBT_OK) check = SQLColAttributeTest(); + break; + case 20: + if (check == NDBT_OK) check = SQLBindColTest(); + break; + case 21: + if (check == NDBT_OK) check = SQLGetDiagRecSimpleTest(); + break; + case 22: + if (check == NDBT_OK) check = SQLConnectTest(); + break; + case 23: + if (check == NDBT_OK) check = SQLPrepareTest(); + break; + } + } + + return NDBT_ProgramExit(check); +} + + + diff --git a/ndb/test/odbc/dm-iodbc/Makefile b/ndb/test/odbc/dm-iodbc/Makefile new file mode 100644 index 00000000000..ad0f0d39f5f --- /dev/null +++ b/ndb/test/odbc/dm-iodbc/Makefile @@ -0,0 +1,38 @@ +include .defs.mk + +TYPE = * + +BIN_TARGET = testOdbcDMi + +SOURCES = testOdbcDMi.cpp + +CCFLAGS_LOC += \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/include/ndbapi \ + -I$(NDB_TOP)/include/portlib \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/test/include + +CCFLAGS_WARNINGS += -Wno-unused -Wno-sign-compare + +CCFLAGS_TOP += -DHAVE_LONG_LONG -DiODBC + +BIN_TARGET_LIBS = NDBT general portlib + +ifeq ($(NDB_OS),SOLARIS) +CCFLAGS_TOP += -DDMALLOC +LIBS_LOC += -L/usr/local/opt/iODBC/lib +LIBS_LOC += -R/usr/local/opt/iODBC/lib +BIN_TARGET_LIBS += iodbc +BIN_TARGET_LIBS += dmallocthcxx +endif + +ifeq ($(NDB_OS),LINUX) +BIN_TARGET_LIBS_DIRS += /usr/local/opt/iODBC/lib +BIN_TARGET_LIBS += iodbc +endif + +include $(NDB_TOP)/Epilogue.mk + +testOdbcDMi.cpp: + ln -s ../driver/testOdbcDriver.cpp $@ diff --git a/ndb/test/odbc/dm-unixodbc/Makefile b/ndb/test/odbc/dm-unixodbc/Makefile new file mode 100644 index 00000000000..50d8e3b5e05 --- /dev/null +++ b/ndb/test/odbc/dm-unixodbc/Makefile @@ -0,0 +1,39 @@ +include .defs.mk + +TYPE = * + +BIN_TARGET = testOdbcDMu + +SOURCES = testOdbcDMu.cpp + +CCFLAGS_LOC += \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/include/ndbapi \ + -I$(NDB_TOP)/include/portlib \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/test/include + +CCFLAGS_WARNINGS += -Wno-unused -Wno-sign-compare + +CCFLAGS_TOP += -DHAVE_LONG_LONG -DunixODBC + +BIN_TARGET_LIBS = NDBT general portlib + +ifeq ($(NDB_OS),SOLARIS) +CCFLAGS_TOP += -DDMALLOC +LIBS_LOC += -L/usr/local/lib +BIN_TARGET_LIBS += odbc odbcinst +BIN_TARGET_LIBS += dmallocthcxx +endif + +ifeq ($(NDB_OS),LINUX) +BIN_TARGET_LIBS += odbc odbcinst +BIN_TARGET_LIBS_DIRS += . +dummy := $(shell [ ! -f /usr/lib/libodbc.so ] || ln -sf /usr/lib/libodbc.so.1 libodbc.so) +dummy := $(shell [ ! -f /usr/lib/libodbcinst.so ] || ln -sf /usr/lib/libodbcinst.so.1 libodbcinst.so) +endif + +include $(NDB_TOP)/Epilogue.mk + +testOdbcDMu.cpp: + ln -s ../driver/testOdbcDriver.cpp $@ diff --git a/ndb/test/odbc/driver/Makefile b/ndb/test/odbc/driver/Makefile new file mode 100644 index 00000000000..5cf83d73106 --- /dev/null +++ b/ndb/test/odbc/driver/Makefile @@ -0,0 +1,30 @@ +include .defs.mk + +TYPE = * + +BIN_TARGET = testOdbcDriver + +SOURCES = testOdbcDriver.cpp + +CCFLAGS_LOC += \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/include/ndbapi \ + -I$(NDB_TOP)/include/portlib \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/test/include \ + -I/usr/local/include + +CCFLAGS_WARNINGS += -Wno-unused -Wno-sign-compare -Wformat + +CCFLAGS_TOP += -DHAVE_LONG_LONG -DndbODBC + +BIN_TARGET_LIBS = NDBT NDB_ODBC + +ifeq ($(NDB_OS),SOLARIS) +BIN_TARGET_LIBS += dmallocthcxx +CCFLAGS_TOP += -DDMALLOC +endif + +include $(NDB_TOP)/Epilogue.mk + +$(BIN_DIR)$(BIN_TARGET): Makefile diff --git a/ndb/test/odbc/driver/testOdbcDriver.cpp b/ndb/test/odbc/driver/testOdbcDriver.cpp new file mode 100644 index 00000000000..9731c00eeaf --- /dev/null +++ b/ndb/test/odbc/driver/testOdbcDriver.cpp @@ -0,0 +1,4969 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + * testOdbcDriver + * + * Test of ODBC and SQL using a fixed set of tables. + */ + +#include <new> +#include <NdbUnistd.h> +#include <stdlib.h> +#include <NdbString.h> +#include <stdarg.h> +#include <NdbStdio.h> +#include <ndb_version.h> +#include <kernel/ndb_limits.h> +#include <Bitmask.hpp> +#include <kernel/AttributeList.hpp> +#ifdef ndbODBC +#include <NdbApi.hpp> +#endif +#include <math.h> +#include <sqlext.h> +#include <assert.h> + +#undef BOOL + +#include <NdbMain.h> +#include <NdbOut.hpp> +#include <NdbThread.h> +#include <NdbMutex.h> +#include <NdbCondition.h> +#include <NdbTick.h> +#include <NdbSleep.h> + +#ifdef ndbODBC +#include <NdbTest.hpp> +#else +#define NDBT_OK 0 +#define NDBT_FAILED 1 +#define NDBT_WRONGARGS 2 +static int +NDBT_ProgramExit(int rcode) +{ + const char* rtext = "Unknown"; + switch (rcode) { + case NDBT_OK: + rtext = "OK"; + break; + case NDBT_FAILED: + rtext = "Failed"; + break; + case NDBT_WRONGARGS: + rtext = "Wrong arguments"; + break; + }; + ndbout_c("\nNDBT_ProgramExit: %d - %s\n", rcode, rtext); + return rcode; +} +#endif + +#ifdef DMALLOC +#include <dmalloc.h> +#endif + +#define arraySize(x) (sizeof(x)/sizeof(x[0])) + +#define SQL_ATTR_NDB_TUPLES_FETCHED 66601 + +// options + +#define MAX_THR 128 // max threads + +struct Opt { + const char* m_name[100]; + unsigned m_namecnt; + bool m_core; + unsigned m_depth; + const char* m_dsn; + unsigned m_errs; + const char* m_fragtype; + unsigned m_frob; + const char* m_home; + unsigned m_loop; + bool m_nogetd; + bool m_noputd; + bool m_nosort; + unsigned m_scale; + bool m_serial; + const char* m_skip[100]; + unsigned m_skipcnt; + unsigned m_subloop; + const char* m_table; + unsigned m_threads; + unsigned m_trace; + unsigned m_v; + Opt() : + m_namecnt(0), + m_core(false), + m_depth(5), + m_dsn("NDB"), + m_errs(0), + m_fragtype(0), + m_frob(0), + m_home(0), + m_loop(1), + m_nogetd(false), + m_noputd(false), + m_nosort(false), + m_scale(100), + m_serial(false), + m_skipcnt(0), + m_subloop(1), + m_table(0), + m_threads(1), + m_trace(0), + m_v(1) { + for (unsigned i = 0; i < arraySize(m_name); i++) + m_name[i] = 0; + for (unsigned i = 0; i < arraySize(m_skip); i++) + m_skip[i] = 0; + } +}; + +static Opt opt; + +static void listCases(); +static void listTables(); +static void printusage() +{ + Opt d; + ndbout + << "usage: testOdbcDriver [options]" << endl + << "-case name run only named tests (substring match - can be repeated)" << endl + << "-core dump core on failure" << endl + << "-depth N join depth - default " << d.m_depth << endl + << "-dsn string data source name - default " << d.m_dsn << endl + << "-errs N allow N errors before quitting - default " << d.m_errs << endl + << "-fragtype t fragment type single/small/medium/large" << d.m_errs << endl + << "-frob X case-dependent tweak (number)" << endl + << "-home dir set NDB_HOME (contains Ndb.cfg)" << endl + << "-loop N loop N times (0 = forever) - default " << d.m_loop << endl + << "-nogetd do not use SQLGetData - default " << d.m_nogetd << endl + << "-noputd do not use SQLPutData - default " << d.m_noputd << endl + << "-nosort no order-by in verify scan (checks non-Pk values only)" << endl + << "-scale N row count etc - default " << d.m_scale << endl + << "-serial run multi-threaded test cases one at a time" << endl + << "-skip name skip named tests (substring match - can be repeated)" << endl + << "-subloop N loop count per case (same threads) - default " << d.m_subloop << endl + << "-table T do only table T (table name on built-in list)" << endl + << "-threads N number of threads (max " << MAX_THR << ") - default " << d.m_threads << endl + << "-trace N trace in NDB ODBC driver - default " << d.m_trace << endl + << "-v N verbosity - default " << d.m_v << endl + ; + listCases(); + listTables(); +} + +static void +fatal(const char* fmt, ...) +{ + va_list ap; + char buf[200]; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + ndbout << buf << endl; + if (opt.m_errs != 0) { + opt.m_errs--; + return; + } + if (opt.m_core) + abort(); + NDBT_ProgramExit(NDBT_FAILED); + exit(1); +} + +static void +cleanprint(const char* s, unsigned n) +{ + for (unsigned i = 0; i < n; i++) { + char b[10]; + if (0x20 < s[i] && s[i] <= 0x7e) + sprintf(b, "%c", s[i]); + else + sprintf(b, "\\%02x", (unsigned)s[i]); + ndbout << b; + } +} + +// global mutex +static NdbMutex my_mutex = NDB_MUTEX_INITIALIZER; +static void lock_mutex() { NdbMutex_Lock(&my_mutex); } +static void unlock_mutex() { NdbMutex_Unlock(&my_mutex); } + +// semaphore zeroed before each call to a test routine +static unsigned my_sema = 0; + +// print mutex +static NdbMutex out_mutex = NDB_MUTEX_INITIALIZER; +static NdbOut& lock(NdbOut& out) { NdbMutex_Lock(&out_mutex); return out; } +static NdbOut& unlock(NdbOut& out) { NdbMutex_Unlock(&out_mutex); return out; } + +static unsigned +urandom(unsigned n) +{ + assert(n != 0); + unsigned i = random(); + return i % n; +} + +// test cases + +struct Test; + +struct Case { + enum Mode { + Single = 1, // single thread + Serial = 2, // all threads but one at a time + Thread = 3 // all threads in parallel + }; + const char* m_name; + void (*m_func)(Test& test); + Mode m_mode; + unsigned m_stuff; + const char* m_desc; + Case(const char* name, void (*func)(Test& test), Mode mode, unsigned stuff, const char* desc) : + m_name(name), + m_func(func), + m_mode(mode), + m_stuff(stuff), + m_desc(desc) { + } + const char* modename() const { + const char* s = "?"; + if (m_mode == Case::Single) + return "Single"; + if (m_mode == Case::Serial) + return "Serial"; + if (m_mode == Case::Thread) + return "Thread"; + return "?"; + } + bool matchcase() const { + if (opt.m_namecnt == 0) + return ! skipcase(); + for (unsigned i = 0; i < opt.m_namecnt; i++) { + if (strstr(m_name, opt.m_name[i]) != 0) + return ! skipcase(); + } + return false; + } +private: + bool skipcase() const { + for (unsigned i = 0; i < opt.m_skipcnt; i++) { + if (strstr(m_name, opt.m_skip[i]) != 0) + return true; + } + return false; + } +}; + +// calculate values + +struct Calc { + enum { m_mul = 1000000 }; + unsigned m_no; + unsigned m_base; + unsigned m_salt; // modifies non-PK values + bool m_const; // base non-PK values on PK of row 0 + Calc(unsigned no) : + m_no(no), + m_salt(0), + m_const(false) { + m_base = m_no * m_mul; + } + void calcPk(unsigned rownum, char* v, unsigned n) const { + char b[10]; + sprintf(b, "%08x", m_base + rownum); + for (unsigned i = 0; i < n; i++) { + char c = i < n - 1 ? b[i % 8] : 0; + v[i] = c; + } + } + void calcPk(unsigned rownum, long* v) const { + *v = m_base + rownum; + } + void hashPk(unsigned* hash, const char* v, unsigned n) const { + for (unsigned i = 0; i < n; i++) { + *hash ^= (v[i] << i); + } + } + void hashPk(unsigned* hash, long v) const { + *hash ^= v; + } + void calcNk(unsigned hash, char* v, unsigned n, SQLINTEGER* ind, bool null) const { + unsigned m = hash % n; + for (unsigned i = 0; i < n; i++) { + char c = i < m ? 'a' + (hash + i) % ('z' - 'a' + 1) : i < n - 1 ? ' ' : 0; + v[i] = c; + } + *ind = null && hash % 9 == 0 ? SQL_NULL_DATA : SQL_NTS; + } + void calcNk(unsigned hash, long* v, SQLINTEGER* ind, bool null) const { + *v = long(hash); + *ind = null && hash % 7 == 0 ? SQL_NULL_DATA : 0; + } + void calcNk(unsigned hash, double* v, SQLINTEGER* ind, bool null) const { + *v = long(hash) / 1000.0; + *ind = null && hash % 5 == 0 ? SQL_NULL_DATA : 0; + } + bool verify(const char* v1, SQLINTEGER ind1, const char* v2, SQLINTEGER ind2, unsigned n) { + if (ind1 == SQL_NULL_DATA && ind2 == SQL_NULL_DATA) + return true; + if (ind1 != SQL_NULL_DATA && ind2 != SQL_NULL_DATA) + if (memcmp(v1, v2, n) == 0) + return true; + if (ind1 == SQL_NULL_DATA) + v1 = "NULL"; + if (ind2 == SQL_NULL_DATA) + v2 = "NULL"; + ndbout << "verify failed: got "; + if (ind1 == SQL_NULL_DATA) + ndbout << "NULL"; + else + cleanprint(v1, n); + ndbout << " != "; + if (ind2 == SQL_NULL_DATA) + ndbout << "NULL"; + else + cleanprint(v2, n); + ndbout << endl; + return false; + } + bool verify(long v1, SQLINTEGER ind1, long v2, SQLINTEGER ind2) { + char buf1[40], buf2[40]; + if (ind1 == SQL_NULL_DATA && ind2 == SQL_NULL_DATA) + return true; + if (ind1 != SQL_NULL_DATA && ind2 != SQL_NULL_DATA) + if (v1 == v2) + return true; + if (ind1 == SQL_NULL_DATA) + strcpy(buf1, "NULL"); + else + sprintf(buf1, "%ld", v1); + if (ind2 == SQL_NULL_DATA) + strcpy(buf2, "NULL"); + else + sprintf(buf2, "%ld", v2); + ndbout << "verify failed: got " << buf1 << " != " << buf2 << endl; + return false; + } + bool verify(double v1, SQLINTEGER ind1, double v2, SQLINTEGER ind2) { + char buf1[40], buf2[40]; + if (ind1 == SQL_NULL_DATA && ind2 == SQL_NULL_DATA) + return true; + if (ind1 != SQL_NULL_DATA && ind2 != SQL_NULL_DATA) + if (fabs(v1 - v2) < 1) // XXX + return true; + if (ind1 == SQL_NULL_DATA) + strcpy(buf1, "NULL"); + else + sprintf(buf1, "%.10f", v1); + if (ind2 == SQL_NULL_DATA) + strcpy(buf2, "NULL"); + else + sprintf(buf2, "%.10f", v2); + ndbout << "verify failed: got " << buf1 << " != " << buf2 << endl; + return false; + } +}; + +#if defined(NDB_SOLARIS) || defined(NDB_LINUX) || defined(NDB_MACOSX) +#define HAVE_SBRK +#else +#undef HAVE_SBRK +#endif + +struct Timer { + Timer() : + m_cnt(0), + m_calls(0), + m_on(0), + m_msec(0) +#ifndef NDB_WIN32 + , + m_brk(0), + m_incr(0) +#endif + { + } + void timerOn() { + m_cnt = 0; + m_calls = 0; + m_on = NdbTick_CurrentMillisecond(); +#ifdef HAVE_SBRK + m_brk = (int)sbrk(0); +#endif + } + void timerOff() { + m_msec = NdbTick_CurrentMillisecond() - m_on; + if (m_msec <= 0) + m_msec = 1; +#ifdef HAVE_SBRK + m_incr = (int)sbrk(0) - m_brk; + if (m_incr < 0) + m_incr = 0; +#endif + } + void timerCnt(unsigned cnt) { + m_cnt += cnt; + } + void timerCnt(const Timer& timer) { + m_cnt += timer.m_cnt; + m_calls += timer.m_calls; + } + friend NdbOut& operator<<(NdbOut& out, const Timer& timer) { + out << timer.m_cnt << " ( " << 1000 * timer.m_cnt / timer.m_msec << "/sec )"; +#ifdef HAVE_SBRK + out << " - " << timer.m_incr << " sbrk"; + if (opt.m_namecnt != 0) { // per case meaningless if many cases + if (timer.m_cnt > 0) + out << " ( " << timer.m_incr / timer.m_cnt << "/cnt )"; + } +#endif + out << " - " << timer.m_calls << " calls"; + return out; + } +protected: + unsigned m_cnt; // count rows or whatever + unsigned m_calls; // count ODBC function calls + NDB_TICKS m_on; + unsigned m_msec; +#ifdef HAVE_SBRK + int m_brk; + int m_incr; +#endif +}; + +#define MAX_MESSAGE 500 +#define MAX_DIAG 20 + +struct Diag { + char m_state[5+1]; + SQLINTEGER m_native; + char m_message[MAX_MESSAGE]; + unsigned m_flag; // temp use + Diag() { + strcpy(m_state, "00000"); + m_native = 0; + memset(m_message, 0, sizeof(m_message)); + m_flag = 0; + } + const char* text() { + snprintf(m_buf, sizeof(m_buf), "%s %d '%s'", m_state, (int)m_native, m_message); + return m_buf; + } + void getDiag(SQLSMALLINT type, SQLHANDLE handle, unsigned k, unsigned count) { + int ret; + SQLSMALLINT length = -1; + memset(m_message, 0, MAX_MESSAGE); + ret = SQLGetDiagRec(type, handle, k, (SQLCHAR*)m_state, &m_native, (SQLCHAR*)m_message, MAX_MESSAGE, &length); + if (k <= count && ret != SQL_SUCCESS) + fatal("SQLGetDiagRec %d of %d: return %d != SQL_SUCCESS", k, count, (int)ret); + if (k <= count && strlen(m_message) != length) + fatal("SQLGetDiagRec %d of %d: message length %d != %d", k, count, strlen(m_message), length); + if (k > count && ret != SQL_NO_DATA) + fatal("SQLGetDiagRec %d of %d: return %d != SQL_NO_DATA", k, count, (int)ret); + m_flag = 0; + } +private: + char m_buf[MAX_MESSAGE]; +}; + +struct Diags { + Diag m_diag[MAX_DIAG]; + SQLINTEGER m_diagCount; + SQLINTEGER m_rowCount; + SQLINTEGER m_functionCode; + void getDiags(SQLSMALLINT type, SQLHANDLE handle) { + int ret; + m_diagCount = -1; + ret = SQLGetDiagField(type, handle, 0, SQL_DIAG_NUMBER, &m_diagCount, SQL_IS_INTEGER, 0); + if (ret == SQL_INVALID_HANDLE) + return; + if (ret != SQL_SUCCESS) + fatal("SQLGetDiagField: return %d != SQL_SUCCESS", (int)ret); + if (m_diagCount < 0 || m_diagCount > MAX_DIAG) + fatal("SQLGetDiagField: count %d", (int)m_diagCount); + for (unsigned k = 0; k < MAX_DIAG; k++) { + m_diag[k].getDiag(type, handle, k + 1, m_diagCount); + if (k == m_diagCount + 1) + break; + } + m_rowCount = -1; + m_functionCode = SQL_DIAG_UNKNOWN_STATEMENT; + if (type == SQL_HANDLE_STMT) { + ret = SQLGetDiagField(type, handle, 0, SQL_DIAG_ROW_COUNT, &m_rowCount, SQL_IS_INTEGER, 0); +#ifndef iODBC + if (ret != SQL_SUCCESS) + fatal("SQLGetDiagField: return %d != SQL_SUCCESS", (int)ret); +#endif + ret = SQLGetDiagField(type, handle, 0, SQL_DIAG_DYNAMIC_FUNCTION_CODE, &m_functionCode, SQL_IS_INTEGER, 0); + } + } + void showDiags() { + for (unsigned k = 0; 0 <= m_diagCount && k < m_diagCount; k++) { + Diag& diag = m_diag[k]; + ndbout << "diag " << k + 1; + ndbout << (diag.m_flag ? " [*]" : " [ ]"); + ndbout << " " << diag.text() << endl; + if (k > 10) + abort(); + } + } +}; + +struct Exp { + int m_ret; + const char* m_state; + SQLINTEGER m_native; + Exp() : m_ret(SQL_SUCCESS), m_state(""), m_native(0) {} + Exp(int ret, const char* state) : m_ret(ret), m_state(state) {} +}; + +struct Test : Calc, Timer, Diags { + Test(unsigned no, unsigned loop) : + Calc(no), + m_loop(loop), + m_stuff(0), + m_perf(false), + ccp(0) { + exp(SQL_SUCCESS, 0, 0, true); + } + unsigned m_loop; // current loop + Exp m_expList[20]; // expected results + unsigned m_expCount; + int m_ret; // actual return code + int m_stuff; // the stuff of abuse + bool m_perf; // check no diags on success + const Case* ccp; // current case + void exp(int ret, const char* state, SQLINTEGER native, bool reset) { + if (reset) + m_expCount = 0; + unsigned i = m_expCount++; + assert(i < arraySize(m_expList) - 1); + m_expList[i].m_ret = ret; + m_expList[i].m_state = state == 0 ? "" : state; + m_expList[i].m_native = native; + } + void runCase(const Case& cc) { + ccp = &cc; + if (opt.m_v >= 3) + ndbout << cc.m_name << ": start" << endl; + m_rowCount = -1; + NDB_TICKS m_ms1 = NdbTick_CurrentMillisecond(); + m_salt = m_loop | (16 << cc.m_stuff); + m_const = cc.m_stuff == 0; + m_stuff = cc.m_stuff; + (*cc.m_func)(*this); + NDB_TICKS m_ms2 = NdbTick_CurrentMillisecond(); + } + void run(SQLSMALLINT type, SQLHANDLE handle, int line, int ret) { + m_calls++; + m_ret = ret; + if (m_perf && (m_ret == SQL_SUCCESS)) + return; + m_diagCount = 0; + if (handle != SQL_NULL_HANDLE) + getDiags(type, handle); + if (m_diagCount <= 0 && (ret != SQL_SUCCESS && ret != SQL_INVALID_HANDLE && ret != SQL_NEED_DATA && ret != SQL_NO_DATA)) { + fatal("%s: thr %d line %d: ret=%d but no diag records", ccp->m_name, m_no, line, ret); + } + for (unsigned k = 0; 0 <= m_diagCount && k < m_diagCount; k++) { + Diag& diag = m_diag[k]; + bool match = false; + for (unsigned i = 0; i < m_expCount; i++) { + if (strcmp(diag.m_state, m_expList[i].m_state) == 0 && (diag.m_native % 10000 == m_expList[i].m_native % 10000 || m_expList[i].m_native == -1)) { + match = true; + diag.m_flag = 0; + continue; + } + diag.m_flag = 1; // mark unexpected + } + if (! match) { + showDiags(); + fatal("%s: thr %d line %d: unexpected diag [*] ret=%d cnt=%d", ccp->m_name, m_no, line, (int)ret, (int)m_diagCount); + } + } + bool match = false; + for (unsigned i = 0; i < m_expCount; i++) { + if (ret == m_expList[i].m_ret) { + match = true; + break; + } + } + if (! match) { + showDiags(); + fatal("%s: thr %d line %d: ret=%d not expected", ccp->m_name, m_no, line, ret); + } + // reset expected to success + exp(SQL_SUCCESS, 0, 0, true); + } + void chk(SQLSMALLINT type, SQLHANDLE handle, int line, bool match, const char* fmt, ...) { + if (match) + return; + va_list ap; + va_start(ap, fmt); + char buf[500]; + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + fatal("%s: thr %d line %d: check failed - %s", ccp->m_name, m_no, line, buf); + } +}; + +#define HNull 0, SQL_NULL_HANDLE, __LINE__ +#define HEnv(h) SQL_HANDLE_ENV, h, __LINE__ +#define HDbc(h) SQL_HANDLE_DBC, h, __LINE__ +#define HStmt(h) SQL_HANDLE_STMT, h, __LINE__ +#define HDesc(h) SQL_HANDLE_DESC, h, __LINE__ + +// string support + +#define MAX_SQL 20000 + +static void +scopy(char*& ptr, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsprintf(ptr, fmt, ap); + va_end(ap); + ptr += strlen(ptr); +} + +static bool +blankeq(const char* s1, const char* s2, bool caseSensitive = false) +{ + unsigned n1 = strlen(s1); + unsigned n2 = strlen(s2); + unsigned i = 0; + char c1 = 0; + char c2 = 0; + while (i < n1 || i < n2) { + c1 = i < n1 ? s1[i] : 0x20; + if (! caseSensitive && 'a' <= c1 && c1 <= 'z') + c1 -= 'a' - 'A'; + c2 = i < n2 ? s2[i] : 0x20; + if (! caseSensitive && 'a' <= c2 && c2 <= 'z') + c2 -= 'a' - 'A'; + if (c1 != c2) + break; + i++; + } + return c1 == c2; +} + +// columns and tables + +struct Col { + enum Type { + Char = SQL_CHAR, + Varchar = SQL_VARCHAR, + Int = SQL_INTEGER, + Bigint = SQL_BIGINT, + Real = SQL_REAL, + Double = SQL_DOUBLE + }; + enum CType { + CChar = SQL_C_CHAR, + CLong = SQL_C_SLONG, + CDouble = SQL_C_DOUBLE + }; + enum Cons { + Null, // nullable + NotNull, // not nullable + Pk // part of primary key + }; + const char* m_name; + Type m_type; + unsigned m_length; + Cons m_cons; + CType m_ctype; + Col() : + m_type((Type)999) { + } + Col(const char* name, Type type, unsigned length, Cons cons, CType ctype) : + m_name(name), + m_type(type), + m_length(length), + m_cons(cons), + m_ctype(ctype) { + } + unsigned size() const { + switch (m_type) { + case Char: + case Varchar: + return m_length; + case Int: + return 4; + case Bigint: + return 8; + case Real: + return 4; + case Double: + return 8; + } + assert(false); + return 0; + } + unsigned csize() const { // size as char plus terminating null + switch (m_ctype) { + case CChar: + return m_length + 1; + case CLong: + return 12; + case CDouble: + return 24; + } + assert(false); + return 0; + } + void typespec(char*& ptr) const { + switch (m_type) { + case Char: + scopy(ptr, "char(%d)", m_length); + return; + case Varchar: + scopy(ptr, "varchar(%d)", m_length); + return; + case Int: + scopy(ptr, "int"); + return; + case Bigint: + scopy(ptr, "bigint"); + return; + case Real: + scopy(ptr, "real"); + return; + case Double: + scopy(ptr, "float"); + return; + } + assert(false); + } + SQLSMALLINT type() const { + return (SQLSMALLINT)m_type; + } + SQLSMALLINT ctype() const { + return (SQLSMALLINT)m_ctype; + } + void create(char*& ptr, bool pk) const { + scopy(ptr, "%s", m_name); + scopy(ptr, " "); + typespec(ptr); + if (m_cons == Pk && pk) { + scopy(ptr, " primary key"); + } + if (m_cons == NotNull) { + scopy(ptr, " not null"); + } + } +}; + +static Col ColUndef; + +struct Tab { + const char* m_name; + const Col* m_colList; + unsigned m_colCount; + unsigned m_pkCount; + unsigned* m_pkIndex; + unsigned m_nkCount; + unsigned* m_nkIndex; + char m_upperName[20]; + Tab(const char* name, const Col* colList, unsigned colCount) : + m_name(name), + m_colList(colList), + m_colCount(colCount) { + m_pkCount = 0; + m_nkCount = 0; + for (unsigned i = 0; i < m_colCount; i++) { + const Col& col = m_colList[i]; + if (col.m_cons == Col::Pk) + m_pkCount++; + else + m_nkCount++; + } + m_pkIndex = new unsigned[m_pkCount]; + m_nkIndex = new unsigned[m_nkCount]; + unsigned pk = 0; + unsigned nk = 0; + for (unsigned i = 0; i < m_colCount; i++) { + const Col& col = m_colList[i]; + if (col.m_cons == Col::Pk) + m_pkIndex[pk++] = i; + else + m_nkIndex[nk++] = i; + } + assert(pk == m_pkCount && nk == m_nkCount); + strcpy(m_upperName, m_name); + for (char* p = m_upperName; *p != 0; p++) { + if ('a' <= *p && *p <= 'z') + *p -= 'a' - 'A'; + } + } + ~Tab() { + delete[] m_pkIndex; + delete[] m_nkIndex; + } + void drop(char*& ptr) const { + scopy(ptr, "drop table %s", m_name); + } + void create(char*& ptr) const { + scopy(ptr, "create table %s (", m_name); + for (unsigned i = 0; i < m_colCount; i++) { + if (i > 0) + scopy(ptr, ", "); + const Col& col = m_colList[i]; + col.create(ptr, m_pkCount == 1); + } + if (m_pkCount != 1) { + scopy(ptr, ", primary key ("); + for (unsigned i = 0; i < m_pkCount; i++) { + const Col& col = m_colList[m_pkIndex[i]]; + if (i > 0) + scopy(ptr, ", "); + scopy(ptr, "%s", col.m_name); + } + scopy(ptr, ")"); + } + scopy(ptr, ")"); + } + void wherePk(char*& ptr) const { + scopy(ptr, " where"); + for (unsigned i = 0; i < m_pkCount; i++) { + const Col& col = m_colList[m_pkIndex[i]]; + if (i > 0) + scopy(ptr, " and"); + scopy(ptr, " %s = ?", col.m_name); + } + } + void whereRange(char*& ptr) const { + scopy(ptr, " where"); + for (unsigned i = 0; i < m_pkCount; i++) { + const Col& col = m_colList[m_pkIndex[i]]; + if (i > 0) + scopy(ptr, " and"); + scopy(ptr, " ? <= %s", col.m_name); + scopy(ptr, " and "); + scopy(ptr, "%s < ?", col.m_name); + } + } + void orderPk(char*& ptr) const { + scopy(ptr, " order by"); + for (unsigned i = 0; i < m_pkCount; i++) { + const Col& col = m_colList[m_pkIndex[i]]; + if (i > 0) + scopy(ptr, ", "); + else + scopy(ptr, " "); + scopy(ptr, "%s", col.m_name); + } + } + void selectPk(char*& ptr) const { + scopy(ptr, "select * from %s", m_name); + wherePk(ptr); + } + void selectAll(char*& ptr) const { + scopy(ptr, "select * from %s", m_name); + } + void selectRange(char*& ptr, bool sort) const { + selectAll(ptr); + whereRange(ptr); + if (sort) + orderPk(ptr); + } + void selectCount(char*& ptr) const { + scopy(ptr, "select count(*) from %s", m_name); + } + void insertAll(char*& ptr) const { + scopy(ptr, "insert into %s values (", m_name); + for (unsigned i = 0; i < m_colCount; i++) { + if (i > 0) + scopy(ptr, ", "); + scopy(ptr, "?"); + } + scopy(ptr, ")"); + } + void updatePk(char*& ptr) const { + scopy(ptr, "update %s set", m_name); + for (unsigned i = 0; i < m_nkCount; i++) { + const Col& col = m_colList[m_nkIndex[i]]; + if (i > 0) + scopy(ptr, ", "); + else + scopy(ptr, " "); + scopy(ptr, "%s = ?", col.m_name); + } + wherePk(ptr); + } + void updateRange(char*& ptr) const { + scopy(ptr, "update %s set", m_name); + for (unsigned i = 0; i < m_nkCount; i++) { + const Col& col = m_colList[m_nkIndex[i]]; + if (i > 0) + scopy(ptr, ", "); + else + scopy(ptr, " "); + scopy(ptr, "%s = ?", col.m_name); // XXX constant for now + } + whereRange(ptr); + } + void deleteAll(char*& ptr) const { + scopy(ptr, "delete from %s", m_name); + } + void deletePk(char*& ptr) const { + scopy(ptr, "delete from %s", m_name); + wherePk(ptr); + } + void deleteRange(char*& ptr) const { + scopy(ptr, "delete from %s", m_name); + whereRange(ptr); + } + // simple + void insertDirect(char*& ptr, unsigned n) const { + scopy(ptr, "insert into %s values (", m_name); + for (unsigned i = 0; i < m_colCount; i++) { + const Col& col = m_colList[i]; + if (i > 0) + scopy(ptr, ", "); + if (col.m_type == Col::Char || col.m_type == Col::Varchar) { + scopy(ptr, "'"); + for (unsigned i = 0; i <= n % col.m_length; i++) + scopy(ptr, "%c", 'a' + (n + i) % 26); + scopy(ptr, "'"); + } else if (col.m_type == Col::Int || col.m_type == Col::Bigint) { + scopy(ptr, "%u", n); + } else if (col.m_type == Col::Real || col.m_type == Col::Double) { + scopy(ptr, "%.3f", n * 0.001); + } else { + assert(false); + } + } + scopy(ptr, ")"); + } + void whereDirect(char*& ptr, unsigned n) const { + scopy(ptr, " where"); + for (unsigned i = 0; i < m_pkCount; i++) { + const Col& col = m_colList[m_pkIndex[i]]; + if (i > 0) + scopy(ptr, ", "); + else + scopy(ptr, " "); + scopy(ptr, "%s = ", col.m_name); + if (col.m_type == Col::Char || col.m_type == Col::Varchar) { + scopy(ptr, "'"); + for (unsigned i = 0; i <= n % col.m_length; i++) + scopy(ptr, "%c", 'a' + (n + i) % 26); + scopy(ptr, "'"); + } else if (col.m_type == Col::Int || col.m_type == Col::Bigint) { + scopy(ptr, "%u", n); + } else { + assert(false); + } + } + } + void countDirect(char*& ptr, unsigned n) const { + scopy(ptr, "select count(*) from %s", m_name); + whereDirect(ptr, n); + } + void deleteDirect(char*& ptr, unsigned n) const { + scopy(ptr, "delete from %s", m_name); + whereDirect(ptr, n); + } + // joins + void selectCart(char*& ptr, unsigned cnt) const { + scopy(ptr, "select count(*) from"); + for (unsigned j = 0; j < cnt; j++) { + if (j > 0) + scopy(ptr, ","); + scopy(ptr, " %s", m_name); + scopy(ptr, " t%u", j); + } + } + void selectJoin(char*& ptr, unsigned cnt) const { + scopy(ptr, "select * from"); + for (unsigned j = 0; j < cnt; j++) { + if (j > 0) + scopy(ptr, ","); + scopy(ptr, " %s", m_name); + scopy(ptr, " t%u", j); + } + for (unsigned i = 0; i < m_pkCount; i++) { + const Col& col = m_colList[m_pkIndex[i]]; + for (unsigned j = 0; j < cnt - 1; j++) { + if (i == 0 && j == 0) + scopy(ptr, " where"); + else + scopy(ptr, " and"); + scopy(ptr, " t%u.%s = t%u.%s", j, col.m_name, j + 1, col.m_name); + } + } + } + // check if selected on command line + bool optok() const { + return opt.m_table == 0 || strcasecmp(m_name, opt.m_table) == 0; + } +}; + +// the test tables + +static Col col0[] = { + Col( "a", Col::Bigint, 0, Col::Pk, Col::CLong ), + Col( "b", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c", Col::Char, 4, Col::NotNull, Col::CChar ), + Col( "d", Col::Double, 0, Col::Null, Col::CDouble ), + Col( "e", Col::Char, 40, Col::Null, Col::CChar ), + Col( "f", Col::Char, 10, Col::Null, Col::CChar ) +}; + +static Col col1[] = { + Col( "c0", Col::Int, 0, Col::Pk, Col::CLong ), + Col( "c1", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c2", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c3", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c4", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c5", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c6", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c7", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c8", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c9", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c10", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c11", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c12", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c13", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c14", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c15", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c16", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c17", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c18", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c19", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c20", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c21", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c22", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c23", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c24", Col::Int, 0, Col::NotNull, Col::CLong ), + Col( "c25", Col::Int, 0, Col::NotNull, Col::CLong ) +}; + +static Col col2[] = { + Col( "a", Col::Int, 0, Col::Pk, Col::CLong ), + Col( "c", Col::Char, 8000, Col::NotNull, Col::CChar ) +}; + +static Col col3[] = { + Col( "a", Col::Int, 0, Col::Pk, Col::CLong ), + Col( "c1", Col::Varchar, 1, Col::Null, Col::CChar ), + Col( "c2", Col::Varchar, 2, Col::Null, Col::CChar ), + Col( "c3", Col::Varchar, 3, Col::Null, Col::CChar ), + Col( "c4", Col::Varchar, 4, Col::Null, Col::CChar ), + Col( "c5", Col::Varchar, 10, Col::Null, Col::CChar ), + Col( "c6", Col::Varchar, 40, Col::Null, Col::CChar ), + Col( "c7", Col::Varchar, 255, Col::Null, Col::CChar ), + Col( "c8", Col::Varchar, 4000, Col::Null, Col::CChar ) +}; + +static Col col4[] = { + Col( "a", Col::Char, 8, Col::Pk, Col::CChar ), + Col( "b", Col::Char, 8, Col::NotNull, Col::CChar ), +}; + +static Tab tabList[] = { +#define colList(x) x, arraySize(x) + Tab( "tt00", colList(col0) ), + Tab( "tt01", colList(col1) ), // fläskbench special + Tab( "tt02", colList(col2) ), + Tab( "tt03", colList(col3) ), + Tab( "tt04", colList(col4) ) +#undef colList +}; + +static const unsigned tabCount = arraySize(tabList); +static const unsigned maxColCount = 100; // per table - keep up to date + +static bool +findTable() +{ + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (tab.optok()) + return true; + } + return false; +} + +static void +listTables() +{ + ndbout << "tables:" << endl; + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (i > 0) + ndbout << " "; + ndbout << tab.m_name; + } + ndbout << endl; +} + +// data fields and rows + +struct Fld { + const Col& m_col; + union { + char* m_char; + long m_long; + double m_double; + }; + SQLINTEGER m_ind; + SQLINTEGER m_need; // constant + Fld() : + m_col(ColUndef), + m_need(0) { + } + Fld(const Col& col) : + m_col(col), + m_need(SQL_LEN_DATA_AT_EXEC(0)) { + switch (m_col.m_ctype) { + case Col::CChar: + m_char = new char[m_col.csize()]; + memset(m_char, 0, m_col.csize()); + break; + case Col::CLong: + m_long = 0; + break; + case Col::CDouble: + m_double = 0.0; + break; + } + m_ind = -1; + } + ~Fld() { + switch (m_col.m_ctype) { + case Col::CChar: + delete[] m_char; + break; + case Col::CLong: + break; + case Col::CDouble: + break; + } + } + void zero() { + switch (m_col.m_ctype) { + case Col::CChar: + memset(m_char, 0x1f, m_col.csize()); + break; + case Col::CLong: + m_long = 0x1f1f1f1f; + break; + case Col::CDouble: + m_double = 1111111.1111111; + break; + } + m_ind = -1; + } + // copy values from another field + void copy(const Fld& fld) { + assert(&m_col == &fld.m_col); + switch (m_col.m_ctype) { + case Col::CChar: + memcpy(m_char, fld.m_char, m_col.csize()); + break; + case Col::CLong: + m_long = fld.m_long; + break; + case Col::CDouble: + m_double = fld.m_double; + break; + default: + assert(false); + break; + } + m_ind = fld.m_ind; + } + SQLPOINTER caddr() { + switch (m_col.m_ctype) { + case Col::CChar: + return (SQLPOINTER)m_char; + case Col::CLong: + return (SQLPOINTER)&m_long; + case Col::CDouble: + return (SQLPOINTER)&m_double; + } + assert(false); + return 0; + } + SQLINTEGER* ind() { + return &m_ind; + } + SQLINTEGER* need() { + m_need = SQL_LEN_DATA_AT_EXEC(0); + return &m_need; + } + void calcPk(const Test& test, unsigned rownum) { + switch (m_col.m_ctype) { + case Col::CChar: + test.calcPk(rownum, m_char, m_col.csize()); + m_ind = SQL_NTS; + return; + case Col::CLong: + test.calcPk(rownum, &m_long); + m_ind = 0; + return; + case Col::CDouble: + assert(false); + return; + } + assert(false); + } + void hashPk(const Test& test, unsigned* hash) const { + switch (m_col.m_ctype) { + case Col::CChar: + test.hashPk(hash, m_char, m_col.csize()); + return; + case Col::CLong: + test.hashPk(hash, m_long); + return; + case Col::CDouble: + assert(false); + return; + } + assert(false); + } + void calcNk(const Test& test, unsigned hash) { + bool null = m_col.m_cons == Col::Null; + switch (m_col.m_ctype) { + case Col::CChar: + test.calcNk(hash, m_char, m_col.csize(), &m_ind, null); + return; + case Col::CLong: + test.calcNk(hash, &m_long, &m_ind, null); + return; + case Col::CDouble: + test.calcNk(hash, &m_double, &m_ind, null); + return; + } + assert(false); + } + bool verify(Test& test, const Fld& fld) { + assert(&m_col == &fld.m_col); + switch (m_col.m_ctype) { + case Col::CChar: + return test.verify(m_char, m_ind, fld.m_char, fld.m_ind, m_col.csize()); + case Col::CLong: + return test.verify(m_long, m_ind, fld.m_long, fld.m_ind); + case Col::CDouble: + return test.verify(m_double, m_ind, fld.m_double, fld.m_ind); + } + assert(false); + } + // debug + void print() const { + if (m_ind == SQL_NULL_DATA) + ndbout << "NULL"; + else { + switch (m_col.m_ctype) { + case Col::CChar: + ndbout << m_char; + break; + case Col::CLong: + ndbout << (int)m_long; + break; + case Col::CDouble: + ndbout << m_double; + break; + } + } + } +}; + +struct Row { + const Tab& m_tab; + Fld* m_fldList; + Row(const Tab& tab) : + m_tab(tab) { + m_fldList = new Fld[m_tab.m_colCount]; + for (unsigned i = 0; i < m_tab.m_colCount; i++) { + const Col& col = m_tab.m_colList[i]; + void* place = &m_fldList[i]; + new (place) Fld(col); + } + } + ~Row() { + delete[] m_fldList; + } + // copy values from another row + void copy(const Row& row) { + assert(&m_tab == &row.m_tab); + for (unsigned i = 0; i < m_tab.m_colCount; i++) { + Fld& fld = m_fldList[i]; + fld.copy(row.m_fldList[i]); + } + } + // primary key value is determined by row number + void calcPk(Test& test, unsigned rownum) { + for (unsigned i = 0; i < m_tab.m_pkCount; i++) { + Fld& fld = m_fldList[m_tab.m_pkIndex[i]]; + fld.calcPk(test, rownum); + } + } + // other fields are determined by primary key value + void calcNk(Test& test) { + unsigned hash = test.m_salt; + for (unsigned i = 0; i < m_tab.m_pkCount; i++) { + Fld& fld = m_fldList[m_tab.m_pkIndex[i]]; + fld.hashPk(test, &hash); + } + for (unsigned i = 0; i < m_tab.m_colCount; i++) { + const Col& col = m_tab.m_colList[i]; + if (col.m_cons == Col::Pk) + continue; + Fld& fld = m_fldList[i]; + fld.calcNk(test, hash); + } + } + // verify against another row + bool verifyPk(Test& test, const Row& row) const { + assert(&m_tab == &row.m_tab); + for (unsigned i = 0; i < m_tab.m_pkCount; i++) { + Fld& fld = m_fldList[m_tab.m_pkIndex[i]]; + if (! fld.verify(test, row.m_fldList[m_tab.m_pkIndex[i]])) { + ndbout << "verify failed: tab=" << m_tab.m_name << " col=" << fld.m_col.m_name << endl; + return false; + } + } + return true; + } + bool verifyNk(Test& test, const Row& row) const { + assert(&m_tab == &row.m_tab); + for (unsigned i = 0; i < m_tab.m_nkCount; i++) { + Fld& fld = m_fldList[m_tab.m_nkIndex[i]]; + if (! fld.verify(test, row.m_fldList[m_tab.m_nkIndex[i]])) { + ndbout << "verify failed: tab=" << m_tab.m_name << " col=" << fld.m_col.m_name << endl; + return false; + } + } + return true; + } + bool verify(Test& test, const Row& row) const { + return verifyPk(test, row) && verifyNk(test, row); + } + // debug + void print() const { + ndbout << "row"; + for (unsigned i = 0; i < m_tab.m_colCount; i++) { + ndbout << " " << i << "="; + Fld& fld = m_fldList[i]; + fld.print(); + } + ndbout << endl; + } +}; + +// set ODBC version - required + +static void +setVersion(Test& test, SQLHANDLE hEnv) +{ + test.run(HEnv(hEnv), SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER)); +} + +// set autocommit + +static void +setAutocommit(Test& test, SQLHANDLE hDbc, bool on) +{ + SQLUINTEGER value = on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; + test.run(HDbc(hDbc), SQLSetConnectAttr(hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)value, SQL_IS_UINTEGER)); + SQLUINTEGER value2 = (SQLUINTEGER)-1; + test.run(HDbc(hDbc), SQLGetConnectAttr(hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)&value2, SQL_IS_UINTEGER, 0)); + test.chk(HDbc(hDbc), value2 == value, "got %u != %u", (unsigned)value2, (unsigned)value); +} + +// subroutines - migrate simple common routines here + +static void +allocEnv(Test& test, SQLHANDLE& hEnv) +{ + test.run(HNull, SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv)); + setVersion(test, hEnv); +} + +static void +allocDbc(Test& test, SQLHANDLE hEnv, SQLHANDLE& hDbc) +{ + test.run(HEnv(hEnv), SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc)); +} + +static void +allocConn(Test& test, SQLHANDLE hEnv, SQLHANDLE& hDbc) +{ + allocDbc(test, hEnv, hDbc); +#ifdef unixODBC + test.exp(SQL_SUCCESS_WITH_INFO, "IM003", 0, false); // unicode?? + test.exp(SQL_SUCCESS_WITH_INFO, "01000", 0, false); // version?? +#endif + test.run(HDbc(hDbc), SQLConnect(hDbc, (SQLCHAR*)opt.m_dsn, SQL_NTS, (SQLCHAR*)"user", SQL_NTS, (SQLCHAR*)"pass", SQL_NTS)); +} + +static void +allocStmt(Test& test, SQLHANDLE hDbc, SQLHANDLE& hStmt) +{ + test.run(HDbc(hDbc), SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt)); +} + +static void +allocAll(Test& test, SQLHANDLE& hEnv, SQLHANDLE& hDbc, SQLHANDLE& hStmt) +{ + allocEnv(test, hEnv); + allocConn(test, hEnv, hDbc); + allocStmt(test, hDbc, hStmt); +} + +static void +allocAll(Test& test, SQLHANDLE& hEnv, SQLHANDLE& hDbc, SQLHANDLE* hStmtList, unsigned nStmt) +{ + allocEnv(test, hEnv); + allocConn(test, hEnv, hDbc); + for (unsigned i = 0; i < nStmt; i++) + allocStmt(test, hDbc, hStmtList[i]); +} + +static void +freeEnv(Test& test, SQLHANDLE hEnv) +{ + test.run(HNull, SQLFreeHandle(SQL_HANDLE_ENV, hEnv)); +} + +static void +freeDbc(Test& test, SQLHANDLE hEnv, SQLHANDLE hDbc) +{ + test.run(HEnv(hEnv), SQLFreeHandle(SQL_HANDLE_DBC, hDbc)); +} + +static void +freeConn(Test& test, SQLHANDLE hEnv, SQLHANDLE hDbc) +{ + test.run(HDbc(hDbc), SQLDisconnect(hDbc)); + test.run(HEnv(hEnv), SQLFreeHandle(SQL_HANDLE_DBC, hDbc)); +} + +static void +freeStmt(Test& test, SQLHANDLE hDbc, SQLHANDLE hStmt) +{ + test.run(HDbc(hDbc), SQLFreeHandle(SQL_HANDLE_STMT, hStmt)); +} + +static void +freeAll(Test& test, SQLHANDLE hEnv, SQLHANDLE hDbc, SQLHANDLE hStmt) +{ + freeStmt(test, hDbc, hStmt); + freeConn(test, hEnv, hDbc); + freeEnv(test, hEnv); +} + +static void +freeAll(Test& test, SQLHANDLE hEnv, SQLHANDLE hDbc, SQLHANDLE* hStmtList, unsigned nStmt) +{ + for (unsigned i = 0; i < nStmt; i++) + freeStmt(test, hDbc, hStmtList[i]); + freeConn(test, hEnv, hDbc); + freeEnv(test, hEnv); +} + +#define chkTuplesFetched(/*Test&*/ _test, /*SQLHANDLE*/ _hStmt, /*SQLUINTEGER*/ _countExp) \ +do { \ + SQLUINTEGER _count = (SQLUINTEGER)-1; \ + getTuplesFetched(_test, _hStmt, &_count); \ + test.chk(HStmt(_hStmt), _count == _countExp, "tuples: got %ld != %ld", (long)_count, (long)_countExp); \ +} while (0) + +static void +getTuplesFetched(Test& test, SQLHANDLE hStmt, SQLUINTEGER* count) +{ + *count = (SQLUINTEGER)-1; + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_NDB_TUPLES_FETCHED, count, SQL_IS_POINTER, 0)); +} + +static void +selectCount(Test& test, SQLHANDLE hStmt, const char* sql, long* count) +{ + if (opt.m_v >= 3) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + SQLINTEGER ind; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_SLONG, count, 0, &ind)); + ind = -1; + *count = -1; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + unsigned k = 0; + while (1) { + if (k == 1) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (k == 1) + break; + k++; + } + test.chk(HStmt(hStmt), ind == sizeof(long), "got %d != %d", (int)ind, (int)sizeof(long)); + test.chk(HStmt(hStmt), *count >= 0, "got %ld < 0", *count); + chkTuplesFetched(test, hStmt, *count); +#ifndef iODBC + // + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); +#else + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_CLOSE)); +#endif +} + +static void +selectCount(Test& test, SQLHANDLE hStmt, const Tab& tab, long* count) +{ + static char sql[MAX_SQL], *sqlptr; // XXX static or core + tab.selectCount(sqlptr = sql); + selectCount(test, hStmt, sql, count); +} + +static void +verifyCount(Test& test, SQLHANDLE hStmt, const Tab& tab, long countExp) +{ + long count = -1; + selectCount(test, hStmt, tab, &count); + test.chk(HStmt(hStmt), count == countExp, "got %ld != %ld", count, countExp); +} + +#define chkRowCount(/*Test&*/ _test, /*SQLHANDLE*/ _hStmt, /*SQLINTEGER*/ _countExp) \ +do { \ + SQLINTEGER _count = -1; \ + getRowCount(_test, _hStmt, &_count); \ + test.chk(HStmt(_hStmt), _count == _countExp, "rowcount: got %ld != %ld", (long)_count, (long)_countExp); \ +} while (0) + +static void +getRowCount(Test& test, SQLHANDLE hStmt, SQLINTEGER* count) +{ + *count = -1; + test.run(HStmt(hStmt), SQLRowCount(hStmt, count)); +} + +// handle allocation + +static void +testAlloc(Test& test) +{ + const unsigned n1 = (opt.m_scale >> 8) & 0xf; // default 500 = 0x1f4 + const unsigned n2 = (opt.m_scale >> 4) & 0xf; + const unsigned n3 = (opt.m_scale >> 0) & 0xf; + const unsigned count = n1 + n1 * n2 + n1 * n2 * n3; + SQLHANDLE hEnvList[0xf]; + SQLHANDLE hDbcList[0xf][0xf]; + SQLHANDLE hStmtList[0xf][0xf][0xf]; + for (unsigned i1 = 0; i1 < n1; i1++) { + SQLHANDLE& hEnv = hEnvList[i1]; + test.run(HNull, SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv)); + test.run(HEnv(hEnv), SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER)); + for (unsigned i2 = 0; i2 < n2; i2++) { + SQLHANDLE& hDbc = hDbcList[i1][i2]; + test.run(HEnv(hEnv), SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc)); +#ifdef unixODBC + test.exp(SQL_SUCCESS_WITH_INFO, "IM003", 0, false); // unicode?? + test.exp(SQL_SUCCESS_WITH_INFO, "01000", 0, false); // version?? +#endif + test.run(HDbc(hDbc), SQLConnect(hDbc, (SQLCHAR*)opt.m_dsn, SQL_NTS, (SQLCHAR*)"user", SQL_NTS, (SQLCHAR*)"pass", SQL_NTS)); + // some attributes + test.exp(SQL_ERROR, "HY092", -1, true); // read-only attribute + test.run(HDbc(hDbc), SQLSetConnectAttr(hDbc, SQL_ATTR_AUTO_IPD, (SQLPOINTER)SQL_TRUE, SQL_IS_UINTEGER)); + test.exp(SQL_ERROR, "HYC00", -1, true); // not supported + test.run(HDbc(hDbc), SQLSetConnectAttr(hDbc, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)SQL_TXN_SERIALIZABLE, SQL_IS_UINTEGER)); + test.run(HDbc(hDbc), SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, (SQLPOINTER)"DEFAULT", strlen("DEFAULT"))); + for (unsigned i3 = 0; i3 < n3; i3++) { + SQLHANDLE& hStmt = hStmtList[i1][i2][i3]; + test.run(HDbc(hDbc), SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt)); + SQLHANDLE ipd0, ipd1; + SQLHANDLE ird0, ird1; + SQLHANDLE apd0, apd1, apd2; + SQLHANDLE ard0, ard1, ard2; + // get + ipd0 = ird0 = apd0 = ard0 = 0; + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_PARAM_DESC, &ipd0, SQL_IS_POINTER, 0)); + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_ROW_DESC, &ird0, SQL_IS_POINTER, 0)); + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_APP_PARAM_DESC, &apd0, SQL_IS_POINTER, 0)); + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_APP_ROW_DESC, &ard0, SQL_IS_POINTER, 0)); +#ifndef unixODBC + test.chk(HStmt(hStmt), ipd0 != 0, "got 0"); + test.chk(HStmt(hStmt), ird0 != 0, "got 0"); + test.chk(HStmt(hStmt), apd0 != 0, "got 0"); + test.chk(HStmt(hStmt), ard0 != 0, "got 0"); +#endif + // alloc + ipd1 = ird1 = apd1 = ard1 = 0; + test.run(HDbc(hDbc), SQLAllocHandle(SQL_HANDLE_DESC, hDbc, &ipd1)); + test.run(HDbc(hDbc), SQLAllocHandle(SQL_HANDLE_DESC, hDbc, &ird1)); + test.run(HDbc(hDbc), SQLAllocHandle(SQL_HANDLE_DESC, hDbc, &apd1)); + test.run(HDbc(hDbc), SQLAllocHandle(SQL_HANDLE_DESC, hDbc, &ard1)); + test.chk(HDbc(hDbc), ipd1 != 0 && ird1 != 0 && apd1 != 0 && ard1 != 0, "got null"); + // set + test.exp(SQL_ERROR, "HY092", -1, true); // read-only attribute + test.run(HStmt(hStmt), SQLSetStmtAttr(hStmt, SQL_ATTR_IMP_PARAM_DESC, ipd1, SQL_IS_POINTER)); + test.exp(SQL_ERROR, "HY092", -1, true); // read-only attribute + test.run(HStmt(hStmt), SQLSetStmtAttr(hStmt, SQL_ATTR_IMP_ROW_DESC, ird1, SQL_IS_POINTER)); + test.run(HStmt(hStmt), SQLSetStmtAttr(hStmt, SQL_ATTR_APP_PARAM_DESC, apd1, SQL_IS_POINTER)); + test.run(HStmt(hStmt), SQLSetStmtAttr(hStmt, SQL_ATTR_APP_ROW_DESC, ard1, SQL_IS_POINTER)); + // get + + apd2 = ard2 = 0; + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_APP_PARAM_DESC, &apd2, SQL_IS_POINTER, 0)); + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_APP_ROW_DESC, &ard2, SQL_IS_POINTER, 0)); + test.chk(HStmt(hStmt), apd2 == apd1, "got %x != %x", (unsigned)apd2, (unsigned)apd1); + test.chk(HStmt(hStmt), ard2 == ard1, "got %x != %x", (unsigned)ard2, (unsigned)ard1); + // free + test.run(HDbc(hDbc), SQLFreeHandle(SQL_HANDLE_DESC, ipd1)); + test.run(HDbc(hDbc), SQLFreeHandle(SQL_HANDLE_DESC, ird1)); + test.run(HDbc(hDbc), SQLFreeHandle(SQL_HANDLE_DESC, apd1)); + test.run(HDbc(hDbc), SQLFreeHandle(SQL_HANDLE_DESC, ard1)); + } + } + } + test.timerCnt(count); + if (opt.m_v >= 3) + ndbout << "allocated " << count << endl; + for (unsigned i1 = 0; i1 < n1; i1++) { + SQLHANDLE& hEnv = hEnvList[i1]; + for (unsigned i2 = 0; i2 < n2; i2++) { + SQLHANDLE& hDbc = hDbcList[i1][i2]; + if (i2 % 2 == 0) { + for (unsigned i3 = 0; i3 < n3; i3++) { + SQLHANDLE& hStmt = hStmtList[i1][i2][i3]; + test.run(HDbc(hDbc), SQLFreeHandle(SQL_HANDLE_STMT, hStmt)); + } + } else { + // cleaned up by SQLDisconnect + } + test.run(HDbc(hDbc), SQLDisconnect(hDbc)); + test.run(HEnv(hEnv), SQLFreeHandle(SQL_HANDLE_DBC, hDbc)); + } + test.run(HNull, SQLFreeHandle(SQL_HANDLE_ENV, hEnv)); + } + test.timerCnt(count); + if (opt.m_v >= 3) + ndbout << "freed " << count << endl; +} + +// create tables + +static void +testCreate(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // drop + tab.drop(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + test.exp(SQL_ERROR, "IM000", 2040709, false); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + if (test.m_ret == SQL_SUCCESS) + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_DROP_TABLE, "got %d != %d", test.m_functionCode, SQL_DIAG_DROP_TABLE); + if (test.m_ret == SQL_SUCCESS && opt.m_v >= 2) + ndbout << "table " << tab.m_name << " dropped" << endl; + if (test.m_ret != SQL_SUCCESS && opt.m_v >= 2) + ndbout << "table " << tab.m_name << " does not exist" << endl; + test.timerCnt(1); + // create + tab.create(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + test.exp(SQL_ERROR, "IM000", 2040721, false); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + if (test.m_ret == SQL_SUCCESS) + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_CREATE_TABLE, "got %d != %d", test.m_functionCode, SQL_DIAG_CREATE_TABLE); + if (test.m_ret == SQL_SUCCESS && opt.m_v >= 2) + ndbout << "table " << tab.m_name << " created" << endl; + if (test.m_ret != SQL_SUCCESS && opt.m_v >= 2) + ndbout << "table " << tab.m_name << " already exists" << endl; + test.timerCnt(1); + } + freeAll(test, hEnv, hDbc, hStmt); +} + +// prepare without execute + +static void +testPrepare(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + char sql[MAX_SQL], *sqlptr; + for (unsigned cnt = opt.m_depth; cnt <= opt.m_depth; cnt++) { + for (unsigned i = 0; i < tabCount; i++) { + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.selectJoin(sqlptr = sql, cnt); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + SQLSMALLINT colCount = -1; + SQLSMALLINT colExp = cnt * tab.m_colCount; + test.run(HStmt(hStmt), SQLNumResultCols(hStmt, &colCount)); + test.chk(HStmt(hStmt), colCount == colExp, "got %d != %d", (int)colCount, (int)colExp); + test.timerCnt(1); + } + } + freeAll(test, hEnv, hDbc, hStmt); +} + +// catalog functions + +static void +testCatalog(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + odbc_typeinfo: { + long type[] = { + SQL_CHAR, SQL_VARCHAR, SQL_SMALLINT, SQL_INTEGER, SQL_BIGINT, SQL_REAL, SQL_DOUBLE + }; + unsigned rows[] = { + 1, 1, 2, 2, 2, 1, 1 // 2 for signed and unsigned + }; + for (unsigned i = 0; i < arraySize(type); i++) { + test.run(HStmt(hStmt), SQLGetTypeInfo(hStmt, type[i])); + long dataType = 0; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 2, SQL_C_SLONG, &dataType, 0, 0)); + unsigned k = 0; + while (1) { + if (k == rows[i]) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (k == rows[i]) + break; + test.chk(HStmt(hStmt), dataType == type[i], "got %ld != %ld", dataType, type[i]); + test.timerCnt(1); + k++; + } +#ifndef iODBC + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); +#else + freeStmt(test, hDbc, hStmt); + allocStmt(test, hDbc, hStmt); +#endif + } + if (opt.m_v >= 2) + ndbout << "found " << (UintPtr)arraySize(type) << " data types" << endl; + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_UNBIND)); + } + odbc_tables: { + unsigned found[tabCount]; + for (unsigned i = 0; i < tabCount; i++) + found[i] = 0; + test.run(HStmt(hStmt), SQLTables(hStmt, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0)); + char tableName[200] = ""; + char tableType[200] = ""; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 3, SQL_C_CHAR, tableName, sizeof(tableName), 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 4, SQL_C_CHAR, tableType, sizeof(tableType), 0)); + unsigned cnt = 0; + while (1) { + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (test.m_ret == SQL_NO_DATA) + break; + test.timerCnt(1); + cnt++; + if (! blankeq(tableType, "TABLE")) + continue; + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + if (! blankeq(tab.m_name, tableName)) + continue; + test.chk(HStmt(hStmt), found[i] == 0, "duplicate table %s", tab.m_name); + found[i]++; + } + } +#ifndef iODBC + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); +#else + freeStmt(test, hDbc, hStmt); + allocStmt(test, hDbc, hStmt); +#endif + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + test.chk(HStmt(hStmt), found[i] == 1, "table %s not found", tab.m_name); + } + if (opt.m_v >= 2) + ndbout << "found " << cnt << " tables" << endl; + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_UNBIND)); + } + odbc_columns: { + unsigned found[tabCount][maxColCount]; + for (unsigned i = 0; i < tabCount; i++) { + for (unsigned j = 0; j < maxColCount; j++) + found[i][j] = 0; + } + test.run(HStmt(hStmt), SQLColumns(hStmt, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0)); + char tableName[200] = ""; + char columnName[200] = ""; + long dataType = 0; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 3, SQL_C_CHAR, tableName, sizeof(tableName), 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 4, SQL_C_CHAR, columnName, sizeof(columnName), 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 5, SQL_C_SLONG, &dataType, 0, 0)); + unsigned cnt = 0; + while (1) { + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (test.m_ret == SQL_NO_DATA) + break; + test.timerCnt(1); + cnt++; + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + if (! blankeq(tab.m_name, tableName)) + continue; + bool columnFound = false; + for (unsigned j = 0; j < tab.m_colCount; j++) { + const Col& col = tab.m_colList[j]; + if (! blankeq(col.m_name, columnName)) + continue; + test.chk(HStmt(hStmt), found[i][j] == 0, "duplicate column %s.%s", tableName, columnName); + found[i][j]++; + columnFound = true; + } + test.chk(HStmt(hStmt), columnFound, "unknown column %s.%s", tableName, columnName); + } + } +#ifndef iODBC + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); +#else + freeStmt(test, hDbc, hStmt); + allocStmt(test, hDbc, hStmt); +#endif + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + for (unsigned j = 0; j < tab.m_colCount; j++) { + const Col& col = tab.m_colList[j]; + test.chk(HStmt(hStmt), found[i][j] == 1, "column %s.%s not found", tab.m_name, col.m_name); + } + } + if (opt.m_v >= 2) + ndbout << "found " << cnt << " columns" << endl; + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_UNBIND)); + } + odbc_primarykeys: { + // table patterns are no allowed + for (unsigned i = 0; i < tabCount; i++) { + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + char tmp[200]; // p.i.t.a + strcpy(tmp, tab.m_name); + for (char* a = tmp; *a != 0; a++) { + if ('a' <= *a && *a <= 'z') + *a -= 'a' - 'A'; + } + test.run(HStmt(hStmt), SQLPrimaryKeys(hStmt, (SQLCHAR*)0, 0, (SQLCHAR*)0, 0, (SQLCHAR*)tmp, SQL_NTS)); + char tableName[200] = ""; + char columnName[200] = ""; + long keySeq = -1; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 3, SQL_C_CHAR, tableName, sizeof(tableName), 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 4, SQL_C_CHAR, columnName, sizeof(columnName), 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 5, SQL_C_SLONG, &keySeq, 0, 0)); + unsigned cnt = 0; + while (1) { + if (cnt == tab.m_pkCount) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (test.m_ret == SQL_NO_DATA) + break; + test.chk(HStmt(hStmt), keySeq == 1 + cnt, "got %ld != %u", keySeq, 1 + cnt); + const Col& col = tab.m_colList[tab.m_pkIndex[keySeq - 1]]; + test.chk(HStmt(hStmt), blankeq(columnName, col.m_name), "got %s != %s", columnName, col.m_name); + test.timerCnt(1); + cnt++; + } +#ifndef iODBC + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); +#else + freeStmt(test, hDbc, hStmt); + allocStmt(test, hDbc, hStmt); +#endif + } + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_UNBIND)); + } + freeAll(test, hEnv, hDbc, hStmt); +} + +// insert + +static void +testInsert(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // prepare + tab.insertAll(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + SQLSMALLINT parCount = -1; + test.run(HStmt(hStmt), SQLNumParams(hStmt, &parCount)); + test.chk(HStmt(hStmt), parCount == tab.m_colCount, "got %d != %d", (int)parCount, (int)tab.m_colCount); + // bind parameters + Row row(tab); + for (unsigned j = 0; j < tab.m_colCount; j++) { + Fld& fld = row.m_fldList[j]; + const Col& col = fld.m_col; + // every other at-exec + SQLPOINTER caddr; + SQLINTEGER* ind; + if (opt.m_noputd || j % 2 == 0) { + caddr = fld.caddr(); + ind = fld.ind(); + } else { + caddr = (SQLPOINTER)j; + ind = fld.need(); + } + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, caddr, col.csize(), ind)); + } + // bind columns (none) + SQLSMALLINT colCount = -1; + test.run(HStmt(hStmt), SQLNumResultCols(hStmt, &colCount)); + test.chk(HStmt(hStmt), colCount == 0, "got %d != 0", (int)colCount); + // execute + for (unsigned k = 0; k < opt.m_scale; k++) { + if (k % 5 == 0) { + // rebind + unsigned j = 0; + Fld& fld = row.m_fldList[j]; + const Col& col = fld.m_col; + // every other at-exec + SQLPOINTER caddr; + SQLINTEGER* ind; + if (opt.m_noputd || j % 2 == 0) { + caddr = fld.caddr(); + ind = fld.ind(); + } else { + caddr = (SQLPOINTER)j; + ind = fld.need(); + } + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, caddr, col.csize(), ind)); + } + row.calcPk(test, k); + row.calcNk(test); + unsigned needData = opt.m_noputd ? 0 : tab.m_colCount / 2; + if (needData) + test.exp(SQL_NEED_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_INSERT, "got %d != %d", test.m_functionCode, SQL_DIAG_INSERT); + if (needData) { + while (1) { + SQLPOINTER jPtr = (SQLPOINTER)999; + if (needData) + test.exp(SQL_NEED_DATA, 0, 0, true); + // completes SQLExecute on success + test.run(HStmt(hStmt), SQLParamData(hStmt, &jPtr)); + if (! needData) + break; + unsigned j = (unsigned)jPtr; + test.chk(HStmt(hStmt), j < tab.m_colCount && j % 2 != 0, "got %u 0x%x", j, j); + Fld& fld = row.m_fldList[j]; + const Col& col = fld.m_col; + SQLSMALLINT ctype = col.ctype(); + if (k % 2 == 0 || ctype != Col::CChar) + test.run(HStmt(hStmt), SQLPutData(hStmt, fld.caddr(), *fld.ind())); + else { + // put in pieces + unsigned size = col.csize() - 1; // omit null terminator + char* caddr = (char*)(fld.caddr()); + unsigned off = 0; + while (off < size) { + unsigned m = size / 7; // bytes to put + if (m == 0) + m = 1; + if (m > size - off) + m = size - off; + bool putNull = (*fld.ind() == SQL_NULL_DATA); + // no null terminator + SQLINTEGER len = putNull ? SQL_NULL_DATA : (int)m; + test.run(HStmt(hStmt), SQLPutData(hStmt, caddr + off, len)); + if (putNull) + break; + off += m; + } + } + needData--; + } + } + chkRowCount(test, hStmt, 1); + chkTuplesFetched(test, hStmt, 0); + } + test.timerCnt(opt.m_scale); + if (opt.m_v >= 3) + ndbout << "inserted " << opt.m_scale << " into " << tab.m_name << endl; + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +// count + +static void +testCount(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + long count = -1; + selectCount(test, hStmt, tab, &count); + test.chk(HStmt(hStmt), count == opt.m_scale * opt.m_threads, "got %ld != %u", count, opt.m_scale * opt.m_threads); + test.timerCnt(count); + if (opt.m_v >= 3) + ndbout << "counted " << (int)count << " rows in " << tab.m_name << endl; + } + // scan all at same time + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.selectAll(sqlptr = sql); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + unsigned k = 0; + while (1) { + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + if (k == opt.m_scale * opt.m_threads) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (k != opt.m_scale * opt.m_threads) { + chkTuplesFetched(test, hStmt, k + 1); + test.timerCnt(1); + } else { + chkTuplesFetched(test, hStmt, k); + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLMoreResults(hStmt)); + } + } + if (k == opt.m_scale * opt.m_threads) + break; + k++; + } + if (opt.m_v >= 3) + ndbout << "scanned " << opt.m_scale << " rows from each table" << endl; + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +// update + +static void +testUpdatePk(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // prepare + tab.updatePk(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // bind parameters + Row row(tab); + SQLSMALLINT parCount = -1; + test.run(HStmt(hStmt), SQLNumParams(hStmt, &parCount)); + test.chk(HStmt(hStmt), parCount == tab.m_colCount, "got %d != %d", (int)parCount, (int)tab.m_colCount); + for (unsigned j = 0; j < tab.m_nkCount; j++) { + Fld& fld = row.m_fldList[tab.m_nkIndex[j]]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + for (unsigned j = 0; j < tab.m_pkCount; j++) { + Fld& fld = row.m_fldList[tab.m_pkIndex[j]]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + tab.m_nkCount + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + // bind columns (none) + SQLSMALLINT colCount = -1; + test.run(HStmt(hStmt), SQLNumResultCols(hStmt, &colCount)); + test.chk(HStmt(hStmt), colCount == 0, "got %d != 0", (int)colCount); + // execute + for (unsigned k = 0; k < opt.m_scale; k++) { + if (k % 5 == 0) { + unsigned j = 0; + Fld& fld = row.m_fldList[tab.m_nkIndex[j]]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + row.calcPk(test, k); + row.calcNk(test); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_UPDATE_WHERE, "got %d != %d", test.m_functionCode, SQL_DIAG_UPDATE_WHERE); + chkRowCount(test, hStmt, 1); + // direct update, no read has been necessary + chkTuplesFetched(test, hStmt, 0); + } + test.timerCnt(opt.m_scale); + if (opt.m_v >= 3) + ndbout << "updated " << opt.m_scale << " in " << tab.m_name << endl; + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +static void +testUpdateScan(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // prepare + tab.updateRange(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // bind parameters + Row row(tab); // for set clause + Row rowlo(tab); // for pk ranges + Row rowhi(tab); + SQLSMALLINT parCount = -1; + test.run(HStmt(hStmt), SQLNumParams(hStmt, &parCount)); + test.chk(HStmt(hStmt), parCount == tab.m_nkCount + 2 * tab.m_pkCount, "got %d != %d", (int)parCount, (int)tab.m_nkCount + 2 * (int)tab.m_pkCount); + for (unsigned j = 0; j < tab.m_nkCount; j++) { + const Col& col = tab.m_colList[tab.m_nkIndex[j]]; + Fld& fld = row.m_fldList[tab.m_nkIndex[j]]; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + bool canInterp = true; + for (unsigned j = 0; j < tab.m_pkCount; j++) { + const Col& col = tab.m_colList[tab.m_pkIndex[j]]; + Fld& fldlo = rowlo.m_fldList[tab.m_pkIndex[j]]; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + tab.m_nkCount + 2 * j + 0, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fldlo.caddr(), col.csize(), fldlo.ind())); + Fld& fldhi = rowhi.m_fldList[tab.m_pkIndex[j]]; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + tab.m_nkCount + 2 * j + 1, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fldhi.caddr(), col.csize(), fldhi.ind())); + if (col.m_type != Col::Char) + canInterp = false; // XXX no unsigned yet + } + // execute + row.calcPk(test, 0); + row.calcNk(test); + rowlo.calcPk(test, 0); + rowhi.calcPk(test, test.m_mul); // sucks + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_UPDATE_WHERE, "got %d != %d", test.m_functionCode, SQL_DIAG_UPDATE_WHERE); + chkRowCount(test, hStmt, opt.m_scale); + chkTuplesFetched(test, hStmt, canInterp ? opt.m_scale : opt.m_scale * opt.m_threads); + test.timerCnt(opt.m_scale); + if (opt.m_v >= 3) + ndbout << "updated " << opt.m_scale << " in " << tab.m_name << endl; + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +// verify + +static void +testVerifyPk(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // prepare + tab.selectPk(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // use same row for input and output + Row row(tab); + // bind parameters + SQLSMALLINT parCount = -1; + test.run(HStmt(hStmt), SQLNumParams(hStmt, &parCount)); + test.chk(HStmt(hStmt), parCount == tab.m_pkCount, "got %d != %d", (int)parCount, (int)tab.m_pkCount); + for (unsigned j = 0; j < tab.m_pkCount; j++) { + Fld& fld = row.m_fldList[tab.m_pkIndex[j]]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + // bind columns + SQLSMALLINT colCount = -1; + test.run(HStmt(hStmt), SQLNumResultCols(hStmt, &colCount)); + test.chk(HStmt(hStmt), colCount == tab.m_colCount, "got %d != %d", (int)colCount, (int)tab.m_colCount); + for (unsigned j = 0; j < tab.m_colCount; j++) { + Fld& fld = row.m_fldList[j]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1 + j, col.ctype(), fld.caddr(), col.csize(), fld.ind())); + } + // row for SQLGetData + Row rowGet(tab); + // reference row + Row rowRef(tab); + // execute + for (unsigned k = 0; k < opt.m_scale; k++) { + if (k % 5 == 0) { + // rebind + unsigned j = 0; + Fld& fld = row.m_fldList[tab.m_pkIndex[j]]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + row.calcPk(test, k); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_SELECT_CURSOR, "got %d != %d", test.m_functionCode, SQL_DIAG_SELECT_CURSOR); + // fetch + for (unsigned k2 = 0; ; k2++) { + if (k2 == 1) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + chkTuplesFetched(test, hStmt, 1); + if (k2 == 1) + break; + rowRef.calcPk(test, k); + test.chk(HStmt(hStmt), row.verifyPk(test, rowRef), "verify row=%d", k); + if (test.m_const) + rowRef.calcPk(test, 0); + rowRef.calcNk(test); + test.chk(HStmt(hStmt), row.verifyNk(test, rowRef), "verify row=%d", k); + // SQLGetData is supported independent of SQLBindCol + if (opt.m_nogetd) + continue; + for (unsigned j = 0; j < tab.m_colCount; j++) { + Fld& fld = rowGet.m_fldList[j]; + fld.zero(); + const Col& col = fld.m_col; + // test both variants + SQLSMALLINT ctype = k % 2 == 0 ? col.ctype() : SQL_ARD_TYPE; + if (ctype != Col::CChar) + test.run(HStmt(hStmt), SQLGetData(hStmt, 1 + j, ctype, fld.caddr(), col.csize(), fld.ind())); + else { + // get in pieces + unsigned size = col.csize() - 1; // omit null terminator + char* caddr = (char*)(fld.caddr()); + unsigned off = 0; + while (off < size) { + unsigned m = size / 3; // bytes to get + if (m == 0) + m = 1; + if (m > size - off) + m = size - off; + bool getNull = (rowRef.m_fldList[j].m_ind == SQL_NULL_DATA); + if (off + m < size && ! getNull) + test.exp(SQL_SUCCESS_WITH_INFO, "01004", -1, true); + // include null terminator in buffer size + test.run(HStmt(hStmt), SQLGetData(hStmt, 1 + j, ctype, caddr + off, m + 1, fld.ind())); + int ind = *fld.ind(); + if (getNull) { + test.chk(HStmt(hStmt), ind == SQL_NULL_DATA, "got %d", ind); + break; + } + test.chk(HStmt(hStmt), ind == size - off, "got %d != %u", ind, size - off); + off += m; + } + } + } + rowRef.calcPk(test, k); + test.chk(HStmt(hStmt), rowGet.verifyPk(test, rowRef), "verify row=%d", k); + if (test.m_const) + rowRef.calcPk(test, 0); + rowRef.calcNk(test); + test.chk(HStmt(hStmt), rowGet.verifyNk(test, rowRef), "verify row=%d", k); + // SQLGetData again + for (unsigned j = 0; j < tab.m_colCount; j++) { + Fld& fld = rowGet.m_fldList[j]; + const Col& col = fld.m_col; + // test both variants + SQLSMALLINT ctype = k % 2 == 0 ? col.ctype() : SQL_ARD_TYPE; + // expect no more data + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLGetData(hStmt, 1 + j, ctype, fld.caddr(), col.csize(), fld.ind())); + } + } + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } + test.timerCnt(opt.m_scale); + if (opt.m_v >= 3) + ndbout << "verified " << opt.m_scale << " from " << tab.m_name << endl; + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +static void +testVerifyScan(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // prepare + tab.selectRange(sqlptr = sql, ! opt.m_nosort); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // bind parameters + Row rowlo(tab); // use available PK fields.. + Row rowhi(tab); // since we have no other way for now + SQLSMALLINT parCount = -1; + test.run(HStmt(hStmt), SQLNumParams(hStmt, &parCount)); + test.chk(HStmt(hStmt), parCount == 2 * tab.m_pkCount, "got %d != %d", (int)parCount, 2 * (int)tab.m_pkCount); + for (unsigned j = 0; j < tab.m_pkCount; j++) { + const Col& col = tab.m_colList[tab.m_pkIndex[j]]; + Fld& fldlo = rowlo.m_fldList[tab.m_pkIndex[j]]; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + 2 * j + 0, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fldlo.caddr(), col.csize(), fldlo.ind())); + Fld& fldhi = rowhi.m_fldList[tab.m_pkIndex[j]]; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + 2 * j + 1, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fldhi.caddr(), col.csize(), fldhi.ind())); + } + // bind columns + Row row(tab); + SQLSMALLINT colCount = -1; + test.run(HStmt(hStmt), SQLNumResultCols(hStmt, &colCount)); + test.chk(HStmt(hStmt), colCount == tab.m_colCount, "got %d != %d", (int)colCount, (int)tab.m_colCount); + for (unsigned j = 0; j < tab.m_colCount; j++) { + Fld& fld = row.m_fldList[j]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1 + j, col.ctype(), fld.caddr(), col.csize(), fld.ind())); + } + // execute + rowlo.calcPk(test, 0); + rowhi.calcPk(test, test.m_mul); // sucks + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_SELECT_CURSOR, "got %d != %d", test.m_functionCode, SQL_DIAG_SELECT_CURSOR); + // reference row + Row rowRef(tab); + // fetch + unsigned k = 0; + SQLUINTEGER rowCount1 = (SQLUINTEGER)-1; + test.run(HStmt(hStmt), SQLSetStmtAttr(hStmt, SQL_ATTR_ROWS_FETCHED_PTR, &rowCount1, SQL_IS_POINTER)); + while (1) { + unsigned countExp; + if (k == opt.m_scale) { + countExp = k; + test.exp(SQL_NO_DATA, 0, 0, true); + } else { + countExp = k + 1; + } + test.run(HStmt(hStmt), SQLFetch(hStmt)); + // let me count the ways.. + chkRowCount(test, hStmt, countExp); + test.chk(HStmt(hStmt), rowCount1 == countExp, "got %lu != %u", rowCount1, countExp); + SQLUINTEGER rowCount2 = (SQLUINTEGER)-1; + test.run(HStmt(hStmt), SQLGetStmtAttr(hStmt, SQL_ATTR_ROW_NUMBER, &rowCount2, SQL_IS_POINTER, 0)); + test.chk(HStmt(hStmt), rowCount2 == countExp, "got %lu != %u", rowCount2, countExp); + if (k == opt.m_scale) + break; + if (! opt.m_nosort) { + // expecting k-th row + rowRef.calcPk(test, k); + test.chk(HStmt(hStmt), row.verifyPk(test, rowRef), "verify row=%d", k); + if (test.m_const) + rowRef.calcPk(test, 0); + rowRef.calcNk(test); + test.chk(HStmt(hStmt), row.verifyNk(test, rowRef), "verify row=%d", k); + } else { + // expecting random row + rowRef.copy(row); + test.chk(HStmt(hStmt), row.verifyNk(test, rowRef), "verify row=%d", k); + } + k++; + } + test.timerCnt(opt.m_scale); + if (opt.m_v >= 3) + ndbout << "verified " << opt.m_scale << " from " << tab.m_name << endl; + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +// self-join (scan followed by pk lookups) + +static void +testJoin(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned cnt = opt.m_depth; cnt <= opt.m_depth; cnt++) { + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.selectJoin(sqlptr = sql, cnt); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + unsigned k = 0; + while (1) { + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + if (k == opt.m_scale * opt.m_threads) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (k == opt.m_scale * opt.m_threads) { + chkTuplesFetched(test, hStmt, k * opt.m_depth); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } else { + chkTuplesFetched(test, hStmt, (k + 1) * opt.m_depth); + test.timerCnt(1); + } + } + if (k == opt.m_scale * opt.m_threads) + break; + k++; + } + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +// cartesian join (multiple nested scans) + +static void +testCart(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned cnt = 2; cnt <= 2; cnt++) { + unsigned rows = 1; + //for (unsigned k = 0; k < opt.m_depth; k++) { + //rows *= opt.m_scale * opt.m_threads; + //} + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.selectCart(sqlptr = sql, cnt); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + unsigned k = 0; + while (1) { + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + if (k == rows) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (k == rows) { + //chkTuplesFetched(test, hStmt, k); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } else { + //chkTuplesFetched(test, hStmt, k + 1); + test.timerCnt(1); + } + } + if (k == rows) + break; + k++; + } + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +// delete + +static void +testDeleteAll(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + long count0 = -1; + selectCount(test, hStmt, tab, &count0); + tab.deleteAll(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + if (count0 == 0) + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLExecute(hStmt)); +#ifndef iODBC + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_DELETE_WHERE, "got %d != %d", test.m_functionCode, SQL_DIAG_DELETE_WHERE); +#endif + SQLINTEGER rowCount = -1; + getRowCount(test, hStmt, &rowCount); + test.timerCnt(rowCount); + test.chk(HStmt(hStmt), rowCount == count0, "got %d != %ld", (int)rowCount, count0); + chkTuplesFetched(test, hStmt, rowCount); + if (opt.m_v >= 3) + ndbout << "deleted " << (int)rowCount << " from " << tab.m_name << endl; + long count = -1; + selectCount(test, hStmt, tab, &count); + test.chk(HStmt(hStmt), count == 0, "got %ld != 0", count); + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +static void +testDeletePk(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // prepare + tab.deletePk(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // bind parameters + Row row(tab); + SQLSMALLINT parCount = -1; + test.run(HStmt(hStmt), SQLNumParams(hStmt, &parCount)); + test.chk(HStmt(hStmt), parCount == tab.m_pkCount, "got %d != %d", (int)parCount, (int)tab.m_colCount); + for (unsigned j = 0; j < tab.m_pkCount; j++) { + Fld& fld = row.m_fldList[tab.m_pkIndex[j]]; + const Col& col = fld.m_col; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, col.ctype(), col.type(), col.size(), 0, fld.caddr(), col.csize(), fld.ind())); + } + // bind columns (none) + SQLSMALLINT colCount = -1; + test.run(HStmt(hStmt), SQLNumResultCols(hStmt, &colCount)); + test.chk(HStmt(hStmt), colCount == 0, "got %d != 0", (int)colCount); + // execute + for (unsigned k = 0; k < opt.m_scale; k++) { + row.calcPk(test, k); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == SQL_DIAG_DELETE_WHERE, "got %d != %d", test.m_functionCode, SQL_DIAG_DELETE_WHERE); + chkRowCount(test, hStmt, 1); + // direct delete, no fetch required + chkTuplesFetched(test, hStmt, 0); + } + test.timerCnt(opt.m_scale); + if (opt.m_v >= 3) + ndbout << "updated " << opt.m_scale << " in " << tab.m_name << endl; + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +static void +testTrans(Test& test) +{ +#ifdef unixODBC + if (opt.m_v >= 1) + ndbout << "unixODBC does not support transactions - test skipped" << endl; +#else + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + // delete all + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.deleteAll(sqlptr = sql); + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + SQLINTEGER rowCount = -1; + getRowCount(test, hStmt, &rowCount); + if (opt.m_v >= 3) + ndbout << "deleted " << (int)rowCount << " from " << tab.m_name << endl; + } + setAutocommit(test, hDbc, false); + if (opt.m_v >= 2) + ndbout << "set autocommit OFF" << endl; + for (int commit = 0; commit < opt.m_scale; commit += 1) { + bool rollback = (commit % 2 == 0); + // XXX delete with no data leaves trans in error state for 2nd table + if (commit > 0 && rollback) { // previous case was commit + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.deleteDirect(sqlptr = sql, 0); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + test.run(HDbc(hDbc), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_COMMIT)); + } + // insert + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.insertDirect(sqlptr = sql, 0); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + if (opt.m_v >= 2) + ndbout << tab.m_name << ": inserted 1 row" << endl; + } + // count them via pk + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.countDirect(sqlptr = sql, 0); + long count = -1; + long countExp = 1; + selectCount(test, hStmt, sql, &count); + test.chk(HStmt(hStmt), count == countExp, "got %ld != %ld", count, countExp); + } + // count them via scan + for (unsigned i = 0; i < tabCount; i++) { + // XXX hupp no work + break; + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + long count = -1; + long countExp = 1; + selectCount(test, hStmt, tab, &count); + test.chk(HStmt(hStmt), count == countExp, "got %ld != %ld", count, countExp); + } + // rollback or commit + if (rollback) { + if (opt.m_v >= 2) + ndbout << "end trans ROLLBACK" << endl; + test.run(HDbc(hDbc), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_ROLLBACK)); + } else { + if (opt.m_v >= 2) + ndbout << "end trans COMMIT" << endl; + test.run(HDbc(hDbc), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_COMMIT)); + } + // count them via pk again + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + tab.countDirect(sqlptr = sql, 0); + long count = -1; + long countExp = rollback ? 0 : 1; + selectCount(test, hStmt, sql, &count); + test.chk(HStmt(hStmt), count == countExp, "got %ld != %ld", count, countExp); + } + // count them via scan again + for (unsigned i = 0; i < tabCount; i++) { + // XXX hupp no work + break; + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + long count = -1; + long countExp = rollback ? 0 : 1; + selectCount(test, hStmt, tab, &count); + test.chk(HStmt(hStmt), count == countExp, "got %ld != %ld", count, countExp); + } + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +#endif +} + +static void +testConcur(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmtList[tabCount]; + allocAll(test, hEnv, hDbc, hStmtList, tabCount); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + SQLHANDLE& hStmt = hStmtList[i]; + const Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + // delete all + tab.deleteAll(sqlptr = sql); + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // insert some + unsigned rowcount = 10; + for (unsigned n = 0; n < rowcount; n++) { + tab.insertDirect(sqlptr = sql, n); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + verifyCount(test, hStmt, tab, rowcount); + // start query scan followed by pk lookups + tab.selectJoin(sqlptr = sql, 2); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // start fetch + unsigned k = 0; + while (1) { + if (k > 0) + test.exp(SQL_ERROR, "24000", -1, true); // commit closed cursor + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (k > 0) + break; + // delete some random row + tab.deleteDirect(sqlptr = sql, k); + // try using same statement + test.exp(SQL_ERROR, "24000", -1, true); // cursor is open + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // try using different statement + SQLHANDLE hStmt2; + allocStmt(test, hDbc, hStmt2); + test.run(HStmt(hStmt2), SQLExecDirect(hStmt2, (SQLCHAR*)sql, SQL_NTS)); + k++; + } + test.exp(SQL_ERROR, "24000", -1, true); // cursor is not open + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + test.timerCnt(rowcount); + } + freeAll(test, hEnv, hDbc, hStmtList, tabCount); +} + +static void +testReadcom(Test& test) +{ + testDeleteAll(test); + testInsert(test); + const unsigned nc = 3; + SQLHANDLE hEnv[nc], hDbc[nc], hStmt[nc]; + char sql[MAX_SQL], *sqlptr; + for (unsigned j = 0; j < nc; j++) + allocAll(test, hEnv[j], hDbc[j], hStmt[j]); + for (unsigned i = 0; i < tabCount; i++) { + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + long count; + // check count + count = -1; + selectCount(test, hStmt[0], tab, &count); + test.chk(HStmt(hStmt[0]), count == opt.m_scale, "got %d != %d", (int)count, (int)opt.m_scale); + // scan delete uncommitted with handle 0 + setAutocommit(test, hDbc[0], false); + tab.deleteAll(sqlptr = sql); + if (opt.m_scale == 0) + test.exp(SQL_NO_DATA, 0, 0, false); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt[0]), SQLExecDirect(hStmt[0], (SQLCHAR*)sql, SQL_NTS)); + // scan via other tx should not hang and see all rows + for (unsigned j = 0; j < nc; j++) { + count = -1; + int want = j == 0 ? 0 : opt.m_scale; + selectCount(test, hStmt[j], tab, &count); + test.chk(HStmt(hStmt[j]), count == want, "tx %u: got %d != %d", j, (int)count, want); + if (opt.m_v >= 2) + ndbout << "tx " << j << " ok !" << endl; + } + // setting autocommit on commits the delete + setAutocommit(test, hDbc[0], true); + // check count + count = -1; + selectCount(test, hStmt[0], tab, &count); + test.chk(HStmt(hStmt[0]), count == 0, "got %d != 0", (int)count); + } + for (unsigned j = 0; j < nc; j++) + freeAll(test, hEnv[j], hDbc[j], hStmt[j]); +} + +static void +testPerf(Test& test) +{ + if (test.m_stuff == 0) { + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + char sql[MAX_SQL], *sqlptr; + for (unsigned i = 0; i < tabCount; i++) { + Tab& tab = tabList[i]; + if (! tab.optok()) + continue; + test.exp(SQL_NO_DATA, 0, 0, false); + tab.deleteAll(sqlptr = sql); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + long count0 = -1; + // XXX triggers SEGV somewhere + //selectCount(test, hStmt, tab, &count0); + //test.chk(HStmt(hStmt), count0 == 0, "got %d != 0", (int)count0); + } + freeAll(test, hEnv, hDbc, hStmt); + return; + } + assert(test.m_stuff == 1 || test.m_stuff == 2); + bool ndbapi = (test.m_stuff == 1); + tt01: { + const unsigned OFF = 1000000; + const unsigned N = 25; + Tab& tab = tabList[1]; + if (! tab.optok()) + goto out; + if (ndbapi) { +#ifndef ndbODBC + if (opt.m_v >= 1) + ndbout << "running via DM - test skipped" << endl; +#else + Ndb* ndb = new Ndb("TEST_DB"); + ndb->init(); + if (ndb->waitUntilReady() != 0) { + ndbout << ndb->getNdbError() << endl; + fatal("waitUntilReady"); + } + Uint32 val[1+N]; + // insert + for (unsigned k = 1; k <= opt.m_scale; k++) { + NdbConnection* con = ndb->startTransaction(); + if (con == 0) { + ndbout << ndb->getNdbError() << endl; + fatal("startTransaction"); + } + NdbOperation* op = con->getNdbOperation(tab.m_upperName); + if (op == 0) { + ndbout << con->getNdbError() << endl; + fatal("getNdbOperation"); + } + if (op->insertTuple() == -1) { + ndbout << op->getNdbError() << endl; + fatal("insertTuple"); + } + for (unsigned j = 0; j <= N; j++) { + val[j] = (j == 0 ? k + test.m_no * OFF : k * j); + if (j == 0) { + if (op->equal(j, val[j]) == -1) { + ndbout << op->getNdbError() << endl; + fatal("equal"); + } + } else { + if (op->setValue(j, val[j]) == -1) { + ndbout << op->getNdbError() << endl; + fatal("setValue"); + } + } + } + if (con->execute(Commit) == -1) { + ndbout << con->getNdbError() << endl; + fatal("execute"); + } + ndb->closeTransaction(con); + } + test.timerCnt(opt.m_scale); + // select PK + for (unsigned k = 1; k <= opt.m_scale; k++) { + NdbConnection* con = ndb->startTransaction(); + if (con == 0) { + ndbout << ndb->getNdbError() << endl; + fatal("startTransaction"); + } + NdbOperation* op = con->getNdbOperation(tab.m_upperName); + if (op == 0) { + ndbout << con->getNdbError() << endl; + fatal("getNdbOperation"); + } + if (op->readTuple() == -1) { + ndbout << op->getNdbError() << endl; + fatal("insertTuple"); + } + for (unsigned j = 0; j <= N; j++) { + val[j] = (j == 0 ? k + test.m_no * OFF : 0); + if (j == 0) { + if (op->equal(j, val[j]) == -1) { + ndbout << op->getNdbError() << endl; + fatal("equal"); + } + } else { + if (op->getValue(j, (char*)&val[j]) == 0) { + ndbout << op->getNdbError() << endl; + fatal("getValue"); + } + } + } + if (con->execute(Commit) == -1) { + ndbout << con->getNdbError() << endl; + fatal("execute"); + } + for (unsigned j = 1; j <= N; j++) { + assert(val[j] == k * j); + } + ndb->closeTransaction(con); + } + test.timerCnt(opt.m_scale); + // delete PK + for (unsigned k = 1; k <= opt.m_scale; k++) { + NdbConnection* con = ndb->startTransaction(); + if (con == 0) { + ndbout << ndb->getNdbError() << endl; + fatal("startTransaction"); + } + NdbOperation* op = con->getNdbOperation(tab.m_upperName); + if (op == 0) { + ndbout << con->getNdbError() << endl; + fatal("getNdbOperation"); + } + if (op->deleteTuple() == -1) { + ndbout << op->getNdbError() << endl; + fatal("deleteTuple"); + } + unsigned j = 0; + val[j] = k + test.m_no * OFF; + if (op->equal(j, val[j]) == -1) { + ndbout << op->getNdbError() << endl; + fatal("equal"); + } + if (con->execute(Commit) == -1) { + ndbout << con->getNdbError() << endl; + fatal("execute"); + } + ndb->closeTransaction(con); + } + test.timerCnt(opt.m_scale); + delete ndb; +#endif + } else { + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + long val[1+N]; + char sql[MAX_SQL], *sqlptr; + // insert + tab.insertAll(sqlptr = sql); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + for (unsigned j = 0; j <= N; j++) { + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &val[j], 0, 0)); + } + test.m_perf = true; + for (unsigned k = 1; k <= opt.m_scale; k++) { + for (unsigned j = 0; j <= N; j++) { + val[j] = (j == 0 ? k + test.m_no * OFF : k * j); + } + test.run(HStmt(hStmt), SQLExecute(hStmt)); + } + test.m_perf = false; + test.timerCnt(opt.m_scale); + // select PK + tab.selectPk(sqlptr = sql); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + for (unsigned j = 0; j <= N; j++) { + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1 + j, SQL_C_SLONG, &val[j], 0, 0)); + } + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + N + 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &val[0], 0, 0)); + test.m_perf = true; + for (unsigned k = 1; k <= opt.m_scale; k++) { + val[0] = k + test.m_no * OFF; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + for (unsigned j = 1; j <= N; j++) { + assert(val[j] == k * j); + } + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } + test.m_perf = false; + test.timerCnt(opt.m_scale); + // delete PK + tab.deletePk(sqlptr = sql); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + unsigned j = 0; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1 + j, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &val[j], 0, 0)); + test.m_perf = true; + for (unsigned k = 1; k <= opt.m_scale; k++) { + val[j] = k + test.m_no * OFF; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + } + test.m_perf = false; + test.timerCnt(opt.m_scale); + freeAll(test, hEnv, hDbc, hStmt); + } + out: + ; + } +} + +struct Sql { + const char* m_sql; + int m_functionCode; + int m_rowCount; + int m_tuplesFetched; + long m_lastValue; + unsigned long m_bindValue; + int m_ret; + const char* m_state; + SQLINTEGER m_native; + bool m_reset; + // run this function instead + typedef void (*TestFunc)(Test& test); + TestFunc m_testFunc; + Sql() : + m_sql(0) { + } + Sql(const char* do_cmd) : + m_sql(do_cmd) { + } + Sql(const char* sql, int functionCode, int rowCount, int tuplesFetched, long lastValue, long bindValue) : + m_sql(sql), + m_functionCode(functionCode), + m_rowCount(rowCount), + m_tuplesFetched(tuplesFetched), + m_lastValue(lastValue), + m_bindValue(bindValue), + m_ret(SQL_SUCCESS), + m_state(0), + m_native(0), + m_reset(true), + m_testFunc(0) { + } + // the 4 numbers after SQL_DIAG... rowCount tuplesFetched lastValue bindValue + Sql(const char* sql, int functionCode, int rowCount, int tuplesFetched, long lastValue, long bindValue, int ret, const char* state, SQLINTEGER native, bool reset) : + m_sql(sql), + m_functionCode(functionCode), + m_rowCount(rowCount), + m_tuplesFetched(tuplesFetched), + m_lastValue(lastValue), + m_bindValue(bindValue), + m_ret(ret), + m_state(state), + m_native(native), + m_reset(reset), + m_testFunc(0) { + } + Sql(const char* text, TestFunc testFunc) : + m_sql(text), + m_testFunc(testFunc) { + } + static const char* set_autocommit_on() { + return "set autocommit on"; + } + static const char* set_autocommit_off() { + return "set autocommit off"; + } + static const char* do_commit() { + return "commit"; + } + static const char* do_rollback() { + return "rollback"; + } +}; + +// 90 + +static const Sql +miscSql90[] = { + Sql("select * from dual", + SQL_DIAG_SELECT_CURSOR, 1, 0, -1, -1), + Sql("drop table tt90a", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt90a (a int, b int, c int, primary key(b, c)) storage(large) logging", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql() +}; + +// 91 + +static const Sql +miscSql91[] = { + Sql("drop table tt91a", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt91a (a bigint unsigned primary key, b bigint unsigned not null, c varchar(10))", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("insert into tt91a values (1, 111, 'aaa')", + SQL_DIAG_INSERT, 1, 0, -1, -1), + // fails + Sql("insert into tt91a values (2, null, 'ccc')", + SQL_DIAG_INSERT, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2014203, true), + Sql("update tt91a set b = 222 where a = 2", + SQL_DIAG_UPDATE_WHERE, 0, 0, -1, -1, + SQL_NO_DATA, 0, 0, true), + // two more + Sql("insert into tt91a values (2, 222, 'ccc')", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("insert into tt91a values (3, 333, 'bbb')", + SQL_DIAG_INSERT, 1, 0, -1, -1), + // direct update + Sql("update tt91a set b = 112 where a = 1", + SQL_DIAG_UPDATE_WHERE, 1, 0, -1, -1), + Sql("update tt91a set b = 113 where a = 1 and b > 111", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + // update and delete with interpreted scan + Sql("update tt91a set b = 114 where b < 114", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("delete from tt91a where b < 115", + SQL_DIAG_DELETE_WHERE, 1, 1, -1, -1), + Sql("insert into tt91a values (1, 111, 'aaa')", + SQL_DIAG_INSERT, 1, 0, -1, -1), + // check rows: 1,111,aaa + 2,222,ccc + 3,333,bbb + Sql("select * from tt91a order by c", + SQL_DIAG_SELECT_CURSOR, 3, 3, 2, -1), + Sql("select * from tt91a order by c desc", + SQL_DIAG_SELECT_CURSOR, 3, 3, 1, -1), + Sql("select * from tt91a where a = 2", + SQL_DIAG_SELECT_CURSOR, 1, 1, -1, -1), + Sql("select * from tt91a where a + b = 224", + SQL_DIAG_SELECT_CURSOR, 1, 3, -1, -1), + Sql("select * from tt91a where a = 4", + SQL_DIAG_SELECT_CURSOR, 0, 0, -1, -1), + Sql("select b-a from tt91a order by a-b", + SQL_DIAG_SELECT_CURSOR, 3, 3, 110, -1), + Sql("select sum(a+b) from tt91a", + SQL_DIAG_SELECT_CURSOR, 1, 3, 672, -1), + Sql("select x.b, y.b, z.b from tt91a x, tt91a y, tt91a z where x.b <= y.b and y.b < z.b order by x.b", + SQL_DIAG_SELECT_CURSOR, 4, 13, 222, -1), + Sql("select x.b, y.b, z.b from tt91a x, tt91a y, tt91a z where x.b + y.b = z.b order by x.b", + SQL_DIAG_SELECT_CURSOR, 3, 15, 222, -1), + // tmp index + Sql("create unique hash index xx91a on tt91a(b)", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + Sql("select x.b, y.b, z.b from tt91a x, tt91a y, tt91a z where x.b + y.b = z.b order by x.b", + SQL_DIAG_SELECT_CURSOR, 3, 15, 222, -1), + Sql("drop index xx91a on tt91a", + SQL_DIAG_DROP_INDEX, -1, -1, -1, -1), + // add some duplicates + Sql("insert into tt91a values (4, 222, 'ccc')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("insert into tt91a values (5, 333, 'bbb')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("insert into tt91a values (6, 333, 'bbb')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + // check rows: 1,111,aaa + 2 * 2,222,ccc + 3 * 3,333,bbb + Sql("select count(*) from tt91a", + SQL_DIAG_SELECT_CURSOR, 1, -1, 6, -1), + Sql("select a+b from tt91a where (b = 111 or b = 222 ) and (b = 222 or b = 333) and a > 1 and a < 3", + SQL_DIAG_SELECT_CURSOR, 1, -1, 224, -1), + Sql("select sum(a) from tt91a having min(a) = 1 and max(a) = 6", + SQL_DIAG_SELECT_CURSOR, 1, -1, 21, -1), + Sql("select sum(a) from tt91a where a = 2 or a = 4 having min(a) = 2 and max(a) = 4", + SQL_DIAG_SELECT_CURSOR, 1, -1, 6, -1), + Sql("select sum(a) from tt91a having min(a) = 1 and max(a) = 5", + SQL_DIAG_SELECT_CURSOR, 0, -1, -1, -1), + Sql("select sum(a), b from tt91a group by b order by b", + SQL_DIAG_SELECT_CURSOR, 3, -1, 14, -1), + Sql("select sum(a), b, c from tt91a group by b, c order by c", + SQL_DIAG_SELECT_CURSOR, 3, -1, 6, -1), + Sql("select b, sum(a) from tt91a group by b having b = 37 * sum(a)", + SQL_DIAG_SELECT_CURSOR, 1, -1, 222, -1), + // simple varchar vs interpreter test + Sql("select count(*) from tt91a where c = 'ccc'", + SQL_DIAG_SELECT_CURSOR, 1, 2, 2, -1), + Sql("select count(*) from tt91a where c like '%b%'", + SQL_DIAG_SELECT_CURSOR, 1, 3, 3, -1), + // interpreter limits (crashes in api on v211) +#if NDB_VERSION_MAJOR >= 3 + Sql("select count(*) from tt91a where a in (99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2)", + SQL_DIAG_SELECT_CURSOR, 1, 5, 5, -1), + Sql("select count(*) from tt91a where c in ('xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','bbb','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy','zzzzz','xxxxx','yyyyy')", + SQL_DIAG_SELECT_CURSOR, 1, 3, 3, -1), +#endif + // distinct + Sql("select distinct b from tt91a order by b", + SQL_DIAG_SELECT_CURSOR, 3, -1, 333, -1), + // some illegal groupings + Sql("select a from tt91a group by b", + -1, -1, -1, -1, -1, + SQL_ERROR, "IM000", -1, -1), + Sql("select sum(a) from tt91a group by b having a = 2", + -1, -1, -1, -1, -1, + SQL_ERROR, "IM000", -1, -1), + Sql("select sum(a) from tt91a group by b order by a", + -1, -1, -1, -1, -1, + SQL_ERROR, "IM000", -1, -1), + // string functions + Sql("insert into tt91a (c, b, a) values ('abcdef', 999, 9)", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("select count(*) from tt91a where left(c, 2) = 'ab' and substr(c, 3, 2) = 'cd' and right(c, 2) = 'ef'", + SQL_DIAG_SELECT_CURSOR, 1, -1, 1, -1), + // nulls + Sql("update tt91a set c = null where a > 8", + SQL_DIAG_UPDATE_WHERE, 1, -1, -1, -1), + Sql("select a from tt91a where c is null and b is not null order by a", + SQL_DIAG_SELECT_CURSOR, 1, -1, 9, -1), + Sql("select a from tt91a where not (c is not null or b is null) order by a", + SQL_DIAG_SELECT_CURSOR, 1, -1, 9, -1), + // null value guard in interpreter + Sql("select count(*) from tt91a where c < 'x' or c > 'x' or c != 'x' or c = 'x'", + SQL_DIAG_SELECT_CURSOR, 1, 6, 6, -1), + Sql("delete from tt91a where c is null", + SQL_DIAG_DELETE_WHERE, 1, -1, -1, -1), + // indexes + Sql("update tt91a set b = a + 5", + SQL_DIAG_UPDATE_WHERE, 6, 6, -1, -1), + Sql("create unique hash index xx91a on tt91a(b)", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + // scan y primary key x + Sql("select x.b from tt91a x, tt91a y where x.a = y.b + 0", + SQL_DIAG_SELECT_CURSOR, 1, 7, 11, -1), + // scan x index y + Sql("select x.b from tt91a x, tt91a y where x.a + 0 = y.b", + SQL_DIAG_SELECT_CURSOR, 1, -1, 11, -1), + // scan x scan y + Sql("select x.b from tt91a x, tt91a y where x.a + 0 = y.b + 0", + SQL_DIAG_SELECT_CURSOR, 1, -1, 11, -1), + // dml ops + Sql("delete from tt91a where b = 11 and a > 999", + SQL_DIAG_DELETE_WHERE, 0, 1, -1, -1, + SQL_NO_DATA, 0, 0, true), + Sql("delete from tt91a where b = 11", + SQL_DIAG_DELETE_WHERE, 1, 0, -1, -1), + Sql("delete from tt91a where b = 11", + SQL_DIAG_DELETE_WHERE, 0, 0, -1, -1, + SQL_NO_DATA, 0, 0, true), + Sql("update tt91a set b = 10*10 where b = 10", + SQL_DIAG_UPDATE_WHERE, 1, 0, -1, -1), + Sql("update tt91a set b = 10 where b = 10*10", + SQL_DIAG_UPDATE_WHERE, 1, 0, -1, -1), + Sql("update tt91a set b = 10*10 where b = 10 and b >= 10", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("update tt91a set b = 10 where b = 10*10 and b >= 10*10", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + // char vs varchar + Sql("drop table tt91b", + SQL_DIAG_DROP_TABLE, -1, -1, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt91b (a int primary key, b char(5), c varchar(5))", + SQL_DIAG_CREATE_TABLE, -1, -1, -1, -1), + Sql("insert into tt91b values (1, 'abc', 'abc')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("insert into tt91b values (2, 'xyz', 'xyz')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("insert into tt91b values (3, 'xyz', 'xyz ')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + // char = char strips blanks + Sql("select count(*) from tt91b x where (x.b = 'abc') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 1, -1), + Sql("select count(*) from tt91b x where (x.b = 'abc')", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("select count(*) from tt91b x where (x.b = 'abc ') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 1, -1), + Sql("select count(*) from tt91b x where (x.b = 'abc ')", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + // varchar = char + Sql("select count(*) from tt91b x where (x.c = 'abc') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 1, -1), + Sql("select count(*) from tt91b x where (x.c = 'abc')", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("select count(*) from tt91b x where (x.c = 'abc ') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 0, -1), + Sql("select count(*) from tt91b x where (x.c = 'abc ')", + SQL_DIAG_SELECT_CURSOR, 1, 0, 0, -1), + // char = varchar + Sql("select count(*) from tt91b x, tt91b y where (x.b = y.c) or x.a = x.a+1 or y.a = y.a+1", + SQL_DIAG_SELECT_CURSOR, 1, -1, 2, -1), + Sql("select count(*) from tt91b x, tt91b y where (x.b = y.c)", + SQL_DIAG_SELECT_CURSOR, 1, -1, 2, -1), + // varchar = varchar + Sql("select count(*) from tt91b x, tt91b y where (x.c = y.c) or x.a = x.a+1 or y.a = y.a+1", + SQL_DIAG_SELECT_CURSOR, 1, -1, 3, -1), + Sql("select count(*) from tt91b x, tt91b y where (x.c = y.c)", + SQL_DIAG_SELECT_CURSOR, 1, -1, 3, -1), + // less + Sql("select 10 * x.a + y.a from tt91b x, tt91b y where (x.b < y.b) or x.a = x.a+1 or y.a = y.a+1 order by x.a, y.a", + SQL_DIAG_SELECT_CURSOR, 2, -1, 13, -1), + Sql("select 10 * x.a + y.a from tt91b x, tt91b y where (x.b < y.b) order by x.a, y.a", + SQL_DIAG_SELECT_CURSOR, 2, -1, 13, -1), + Sql("select 10 * x.a + y.a from tt91b x, tt91b y where (x.c < y.c) or x.a = x.a+1 or y.a = y.a+1 order by x.a, y.a", + SQL_DIAG_SELECT_CURSOR, 3, -1, 23, -1), + Sql("select 10 * x.a + y.a from tt91b x, tt91b y where (x.c < y.c) order by x.a, y.a", + SQL_DIAG_SELECT_CURSOR, 3, -1, 23, -1), + // like + Sql("select count(*) from tt91b x where (x.b like 'a%') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 1, -1), + Sql("select count(*) from tt91b x where (x.b like 'a%')", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("select count(*) from tt91b x where (x.b like 'x%z') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 0, -1), + Sql("select count(*) from tt91b x where (x.b like 'x%z')", + SQL_DIAG_SELECT_CURSOR, 1, 0, 0, -1), + Sql("select count(*) from tt91b x where (x.a+0 = 2 and x.c like 'x%z') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 1, -1), + Sql("select count(*) from tt91b x where (x.a+0 = 2 and x.c like 'x%z')", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("select count(*) from tt91b x where (x.a+0 = 3 and x.c like 'x%z ') or x.a = x.a+1", + SQL_DIAG_SELECT_CURSOR, 1, 3, 1, -1), + Sql("select count(*) from tt91b x where (x.a+0 = 3 and x.c like 'x%z ')", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql() +}; + +// 92 + +static void +testMisc92a(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + char sql[MAX_SQL]; + char tname[20]; + sprintf(tname, "tt92%c", 0140 + test.m_no); + if (test.m_loop == 1) { + lock_mutex(); + sprintf(sql, "drop table %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.exp(SQL_ERROR, "IM000", 2040709, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + sprintf(sql, "create table %s (a int unsigned primary key, b int unsigned not null)", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + unlock_mutex(); + } else { + sprintf(sql, "delete from %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + test.run(HStmt(hStmt), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_COMMIT)); + } + for (int on = true; on >= false; on--) { + if (opt.m_v >= 2) + ndbout << "set autocommit " << (on ? "ON" : "OFF") << endl; + setAutocommit(test, hDbc, on); + // insert rows + if (opt.m_v >= 2) + ndbout << "SQL: insert into " << tname << " ..." << opt.m_scale << endl; + for (unsigned k = 0; k < opt.m_scale; k++) { + sprintf(sql, "insert into %s values (%u, %u)", tname, k, 10 * k); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + // commit always + test.run(HStmt(hStmt), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_COMMIT)); + // scan delete + sprintf(sql, "delete from %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // rollback or commit + test.run(HStmt(hStmt), SQLEndTran(SQL_HANDLE_DBC, hDbc, on ? SQL_COMMIT : SQL_ROLLBACK)); + // count + long count = -1; + sprintf(sql, "select count(*) from %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + selectCount(test, hStmt, sql, &count); + test.chk(HStmt(hStmt), count == on ? 0 : opt.m_scale, "%s: got %d != %d", tname, (int)count, (int)opt.m_scale); + } + freeAll(test, hEnv, hDbc, hStmt); +} + +static const Sql +miscSql92[] = { + // create in C func + Sql("testMisc92a", testMisc92a), + Sql() +}; + +// 93 + +static void +testMisc93a(Test& test) +{ + SQLHANDLE hEnv[2], hDbc[2], hStmt[2]; + allocAll(test, hEnv[0], hDbc[0], hStmt[0]); + allocAll(test, hEnv[1], hDbc[1], hStmt[1]); + char sql[MAX_SQL]; + // select via primary key + setAutocommit(test, hDbc[0], false); + sprintf(sql, "select c1 from tt93a where c0 = 1"); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt[0]), SQLExecDirect(hStmt[0], (SQLCHAR*)sql, SQL_NTS)); + // update via another trans must time out + sprintf(sql, "update tt93a set c1 = 'b' where c0 = 1"); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt[1]), SQLExecDirect(hStmt[1], (SQLCHAR*)sql, SQL_NTS)); + freeAll(test, hEnv[0], hDbc[0], hStmt[0]); + freeAll(test, hEnv[1], hDbc[1], hStmt[1]); +} + +static const Sql +miscSql93[] = { + // create in C func + Sql("drop table tt93a", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt93a (c0 int primary key, c1 char(10))", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("insert into tt93a values(1, 'a')", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("testMisc93a", testMisc93a), + Sql() +}; + +// 95 + +static const Sql +miscSql95[] = { + Sql("drop table tt95a", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt95a (a int not null, b char(10) not null, c int not null, d char(10), primary key(a, b)) storage(small)", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + // ordered index create and drop + Sql("create index xx95a on tt95a (c, d) nologging", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + Sql("drop index xx95a on tt95a", + SQL_DIAG_DROP_INDEX, -1, -1, -1, -1), + Sql("create index xx95a on tt95a (c) nologging", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + Sql("insert into tt95a values(1, 'a', 10, 'b')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("insert into tt95a values(2, 'a', 20, 'b')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("insert into tt95a values(3, 'a', 30, 'b')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("select a from tt95a where c = 20", + SQL_DIAG_SELECT_CURSOR, 1, 1, 2, -1), + Sql("delete from tt95a where c = 10", + SQL_DIAG_DELETE_WHERE, 1, 1, -1, -1), + Sql("update tt95a set c = 300 where c = 30", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("delete from tt95a where c = 300", + SQL_DIAG_DELETE_WHERE, 1, 1, -1, -1), + Sql("delete from tt95a", + SQL_DIAG_DELETE_WHERE, 1, 1, -1, -1), + // simple insert and rollback + Sql("-- simple insert and rollback"), + Sql(Sql::set_autocommit_off()), + Sql("insert into tt95a values(1, 'a', 10, 'b')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("select count(*) from tt95a", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("select count(*) from tt95a where c = 10", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql(Sql::do_rollback()), + Sql(Sql::set_autocommit_on()), + Sql("select count(*) from tt95a", + SQL_DIAG_SELECT_CURSOR, 1, 0, 0, -1), + // simple update and rollback + Sql("-- simple update and rollback"), + Sql("insert into tt95a values(1, 'a', 10, 'b')", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql(Sql::set_autocommit_off()), + Sql("update tt95a set c = 20 where c = 10", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("select count(*) from tt95a", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("select count(*) from tt95a where c = 20", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql(Sql::do_rollback()), + Sql(Sql::set_autocommit_on()), + Sql("select count(*) from tt95a where c = 10", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + // simple delete and rollback + Sql("-- simple delete and rollback"), + Sql(Sql::set_autocommit_off()), + Sql("delete from tt95a where c = 10", + SQL_DIAG_DELETE_WHERE, 1, 1, -1, -1), + Sql("select count(*) from tt95a", + SQL_DIAG_SELECT_CURSOR, 0, 0, 0, -1), + Sql("select count(*) from tt95a where c = 10", + SQL_DIAG_SELECT_CURSOR, 0, 0, 0, -1), + Sql(Sql::do_rollback()), + Sql(Sql::set_autocommit_on()), + Sql("select count(*) from tt95a where c = 10", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + // multiple update + Sql("-- multiple update and rollback"), + Sql(Sql::set_autocommit_off()), + Sql("update tt95a set c = 20 where c = 10", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("select count(*) from tt95a where c = 20", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("update tt95a set c = 30 where c = 20", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("select count(*) from tt95a where c = 30", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("update tt95a set c = 40 where c = 30", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("select count(*) from tt95a where c = 40", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql("update tt95a set c = 50 where c = 40", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + Sql("select count(*) from tt95a where c = 50", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + Sql(Sql::do_rollback()), + Sql(Sql::set_autocommit_on()), + Sql("select count(*) from tt95a where c = 10", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1, -1), + // another variant which found no tuple via index (aligment issue) + Sql("drop table tt95b", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt95b (a int primary key, b char(10) not null, c int not null)", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("create index xx95b on tt95b (b, c) nologging", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + Sql("insert into tt95b values(0,'0123456789',1)", + SQL_DIAG_INSERT, 1, -1, -1, -1), + Sql("select a from tt95b where b='0123456789'", + SQL_DIAG_SELECT_CURSOR, 1, 1, 0, -1), + // update index key to different value + Sql("update tt95b set b = '9876543210' where b = '0123456789'", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), + // same value goes nuts... + Sql("update tt95b set b = '9876543210'", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), +#if 0 + // ...if done via index key (variant of halloween problem) + Sql("update tt95b set b = '9876543210' where b = '9876543210'", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, -1), +#endif + Sql() +}; + +// 96 + +static void +testMisc96a(Test& test) +{ + // single thread + if (test.m_no != 1) + return; + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + char sql[MAX_SQL], *sqlptr; + char tname[20]; + strcpy(tname, "tt96a"); + // drop table + scopy(sqlptr = sql, "drop table %s", tname); + test.exp(SQL_ERROR, "IM000", 2040709, false); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // create table with many attributes + unsigned attrs = 1 + opt.m_scale; + if (attrs > MAX_ATTRIBUTES_IN_TABLE) + attrs = MAX_ATTRIBUTES_IN_TABLE; + if (attrs > 64) + attrs = 64; + scopy(sqlptr = sql, "create table %s (c0 int primary key", tname); + for (unsigned j = 1; j < attrs; j++) { + if (j % 2 == 0) + scopy(sqlptr, ", c%d int unsigned not null", j); + else + scopy(sqlptr, ", c%d char(10) not null", j); + } + scopy(sqlptr, ")"); + if (opt.m_fragtype != 0) + scopy(sqlptr, " storage(%s)", opt.m_fragtype); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // create or drop indexes + const unsigned seed = 1000037 * test.m_loop + 1000039 * opt.m_scale; + srandom(seed); + const unsigned imax = opt.m_scale < 20 ? opt.m_scale : 20; + AttributeMask* imasks = new AttributeMask[imax]; + unsigned ccnt = 0; + unsigned dcnt = 0; + for (unsigned n = 0; n < imax; n++) + imasks[n].clear(); + while (ccnt + dcnt < opt.m_scale) { + char iname[20]; + unsigned n = urandom(imax); + sprintf(iname, "xx96a%02d", n); + AttributeMask& imask = imasks[n]; + unsigned sel = urandom(10); + if (imask.isclear()) { + // create one + unsigned ncol = 0; + unsigned cols[MAX_ATTRIBUTES_IN_INDEX]; + unsigned cnum = urandom(attrs); + cols[ncol++] = cnum; + while (ncol < MAX_ATTRIBUTES_IN_INDEX) { + unsigned sel2 = urandom(10); + if (sel2 < 2) + break; + unsigned cnum2 = urandom(attrs); + if (sel2 < 9 && cnum2 == 0) + continue; + unsigned j; + for (j = 0; j < ncol; j++) { + if (cols[j] == cnum2) + break; + } + if (j == ncol) + cols[ncol++] = cnum2; + } + if (sel < 3) { + scopy(sqlptr = sql, "create unique hash index %s on %s (", iname, tname); + for (unsigned j = 0; j < ncol; j++) + scopy(sqlptr, "%sc%d", j == 0 ? "" : ", ", cols[j]); + scopy(sqlptr, ")"); + } else { + scopy(sqlptr = sql, "create index %s on %s (", iname, tname); + for (unsigned j = 0; j < ncol; j++) + scopy(sqlptr, "%sc%d", j == 0 ? "" : ", ", cols[j]); + scopy(sqlptr, ") nologging"); + } + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + for (unsigned j = 0; j < ncol; j++) + imask.set(cols[j]); + ccnt++; + } else if (sel < 5 && ccnt > dcnt + 1) { + scopy(sqlptr = sql, "drop index %s on %s", iname, tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + imask.clear(); + dcnt++; + } + } + // insert unique data + unsigned rows = opt.m_scale; + unsigned* uval = new unsigned[rows]; + for (unsigned i = 0; i < rows; i++) { + uval[i] = urandom(4); + scopy(sqlptr = sql, "insert into %s values(", tname); + for (unsigned j = 0; j < attrs; j++) { + if (j != 0) + scopy(sqlptr, ","); + unsigned v = (i << 10) | (j << 2) | uval[i]; + if (j == 0) + scopy(sqlptr, "%u", i); + else if (j % 2 == 0) + scopy(sqlptr, "%u", v); + else + scopy(sqlptr, "'%010u'", v); + } + scopy(sqlptr, ")"); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + // update each row via random index + for (unsigned i = 0; i < rows; i++) { + unsigned uold = uval[i]; + uval[i] = 3 - uval[i]; + AttributeMask imask; + do { + unsigned j = urandom(imax); + imask = imasks[j]; + } while (imask.isclear()); + scopy(sqlptr = sql, "update %s set", tname); + for (unsigned j = 1; j < attrs; j++) { + if (j != 1) + scopy(sqlptr, ","); + /* + * Equality update is just barely doable before savepoints + * provided we change value of keys in every index. + */ + unsigned v = (i << 10) | (j << 2) | uval[i]; + if (j == 0) + ; + else if (j % 2 == 0) + scopy(sqlptr, " c%d=%u", j, v); + else + scopy(sqlptr, " c%d='%010u'", j, v); + } + scopy(sqlptr, " where 1=1"); + while (! imask.isclear()) { + unsigned j = urandom(attrs); + if (imask.get(j)) { + unsigned v = (i << 10) | (j << 2) | uold; + scopy(sqlptr, " and c%d=", j); + if (j == 0) + scopy(sqlptr, "%u", i); + else if (j % 2 == 0) + scopy(sqlptr, "%u", v); + else + scopy(sqlptr, "'%010u'", v); + imask.clear(j); + } + } + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + chkRowCount(test, hStmt, 1); + } + // delete all + scopy(sqlptr = sql, "delete from %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // + if (opt.m_v >= 2) + ndbout << tname << ": creates " << ccnt << " drops " << dcnt << endl; + delete [] imasks; + delete [] uval; + freeAll(test, hEnv, hDbc, hStmt); +} + +static const Sql +miscSql96[] = { + Sql("testMisc96a", testMisc96a), + Sql() +}; + +// 97 + +static void +testMisc97a(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + const char* tname = "TT97A"; + const char* iname = "XX97A"; + char sql[MAX_SQL]; + // create in some thread + lock_mutex(); + if (my_sema == 0) { + if (opt.m_v >= 1) + ndbout << "thread " << test.m_no << " does setup" << endl; + sprintf(sql, "drop table %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL[" << test.m_no << "]: " << sql << endl; + test.exp(SQL_ERROR, "IM000", 2040709, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // a-pk b-index c-counter + sprintf(sql, "create table %s (a int primary key, b int, c int) storage(small)", tname); + if (opt.m_v >= 2) + ndbout << "SQL[" << test.m_no << "]: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + for (unsigned i = 0; i < opt.m_scale; i++) { + sprintf(sql, "insert into %s values (%d, %d, %d)", tname, i, 10 * i, 0); + if (opt.m_v >= 3) + ndbout << "SQL[" << test.m_no << "]: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + sprintf(sql, "create index %s on %s (b) nologging", iname, tname); + if (opt.m_v >= 2) + ndbout << "SQL[" << test.m_no << "]: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + my_sema = 1; + } + unlock_mutex(); + assert(my_sema == 1); + // parallel run - default rotating pk, ts, is + // frob: low 3 hex digits give alt sequence e.g. 0x311 = pk, pk, is + // frob: 4-th hex digit non-zero says use NDB API e.g. 0x1000 + unsigned typelist[3] = { 1, 2, 3 }; + for (unsigned i = 0; i < 3; i++) { + unsigned t = (opt.m_frob >> (i * 4)) & 0xf; + if (t != 0) + typelist[i] = t; + } + unsigned type = typelist[(test.m_no - 1) % 3]; + if ((opt.m_frob & 0xf000) == 0) { + for (unsigned i = 0; i < opt.m_scale; i++) { + if (type == 1) { + // pk update + sprintf(sql, "update %s set c = c + 1 where a = %d", tname, i % opt.m_scale); + if (opt.m_v >= 3) + ndbout << lock << "SQL[" << test.m_no << "]: " << sql << endl << unlock; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + if (type == 2) { + // table scan update + sprintf(sql, "update %s set c = c + 1 where b + 0 = %d", tname, 10 * i); + if (opt.m_v >= 3) + ndbout << lock << "SQL[" << test.m_no << "]: " << sql << endl << unlock; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + if (type == 3) { + // index scan update + sprintf(sql, "update %s set c = c + 1 where b = %d", tname, 10 * i); + if (opt.m_v >= 3) + ndbout << lock << "SQL[" << test.m_no << "]: " << sql << endl << unlock; + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + } + } + } else { +#ifdef ndbODBC +#define CHK(o, x) do { if (! (x)) { fatal("line %d: %d %s", __LINE__, o->getNdbError().code, o->getNdbError().message); } } while (0) + Ndb* ndb = new Ndb("TEST_DB"); + ndb->init(); + CHK(ndb, ndb->waitUntilReady() == 0); + Int32 a, b, c; + for (unsigned i = 0; i < opt.m_scale; i++) { + if (type == 1) { + // pk update with exclusive read + NdbConnection* con; + NdbOperation* op; + CHK(ndb, (con = ndb->startTransaction()) != 0); + a = i; + c = -1; + CHK(con, (op = con->getNdbOperation(tname)) != 0); + CHK(op, op->readTupleExclusive() == 0); + CHK(op, op->equal((unsigned)0, (char*)&a, 0) == 0); + CHK(op, op->getValue(2, (char*)&c) != 0); + CHK(con, con->execute(NoCommit) == 0); + c = c + 1; + CHK(con, (op = con->getNdbOperation(tname)) != 0); + CHK(op, op->updateTuple() == 0); + CHK(op, op->equal((unsigned)0, (char*)&a, 0) == 0); + CHK(op, op->setValue(2, (char*)&c) == 0); + CHK(con, con->execute(Commit) == 0); + ndb->closeTransaction(con); + if (opt.m_v >= 3) + ndbout << lock << "thr " << test.m_no << " pk a=" << i << " c=" << c << endl << unlock; + } + if (type == 2) { + // table scan update + NdbConnection* con; + NdbOperation* op; + CHK(ndb, (con = ndb->startTransaction()) != 0); + CHK(con, (op = con->getNdbOperation(tname)) != 0); + CHK(con, op->openScanExclusive(240) == 0); + CHK(op, op->getValue((unsigned)0, (char*)&a) != 0); + CHK(op, op->getValue(2, (char*)&c) != 0); + CHK(con, con->executeScan() == 0); + unsigned rows = 0; + unsigned updates = 0; + while (1) { + int ret; + a = -1; + c = -1; + CHK(con, (ret = con->nextScanResult()) == 0 || ret == 1); + if (ret == 1) + break; + rows++; + if (a == i) { + NdbConnection* con2; + NdbOperation* op2; + CHK(ndb, (con2 = ndb->startTransaction()) != 0); + CHK(op, (op2 = op->takeOverForUpdate(con2)) != 0); + c = c + 1; + CHK(op2, op2->setValue(2, (char*)&c) == 0); + CHK(con2, con2->execute(Commit) == 0); + ndb->closeTransaction(con2); + updates++; + if (opt.m_v >= 3) + ndbout << lock << "thr " << test.m_no << " ts rows=" << rows << " a=" << i << " c=" << c << endl << unlock; + // test stop scan too + CHK(con, con->stopScan() == 0); + break; + } + } + ndb->closeTransaction(con); + test.chk(HStmt(hStmt), updates == 1, "got %u != 1", updates); + } + if (type == 3) { + // index scan update + NdbConnection* con; + NdbOperation* op; + CHK(ndb, (con = ndb->startTransaction()) != 0); + CHK(con, (op = con->getNdbOperation(iname, tname)) != 0); + CHK(con, op->openScanExclusive(240) == 0); + b = 10 * i; + CHK(con, op->setBound((unsigned)0, 4, &b, sizeof(b)) == 0); + CHK(op, op->getValue((unsigned)0, (char*)&a) != 0); + CHK(op, op->getValue(2, (char*)&c) != 0); + CHK(con, con->executeScan() == 0); + unsigned rows = 0; + unsigned updates = 0; + while (1) { + int ret; + a = -1; + c = -1; + CHK(con, (ret = con->nextScanResult()) == 0 || ret == 1); + if (ret == 1) + break; + rows++; + if (a == i) { + NdbConnection* con2; + NdbOperation* op2; + CHK(ndb, (con2 = ndb->startTransaction()) != 0); + CHK(op, (op2 = op->takeOverForUpdate(con2)) != 0); + c = c + 1; + CHK(op2, op2->setValue(2, (char*)&c) == 0); + CHK(con2, con2->execute(Commit) == 0); + ndb->closeTransaction(con2); + updates++; + if (opt.m_v >= 3) + ndbout << lock << "thr " << test.m_no << " is rows=" << rows << " a=" << i << " c=" << c << endl << unlock; + // test stop scan too + CHK(con, con->stopScan() == 0); + break; + } + } + ndb->closeTransaction(con); + test.chk(HStmt(hStmt), rows == 1, "got %u != 1", rows); + test.chk(HStmt(hStmt), updates == 1, "got %u != 1", updates); + } + } + delete ndb; +#undef CHK +#endif + } + // verify result + lock_mutex(); + if (++my_sema == 1 + opt.m_threads) { + if (opt.m_v >= 1) + ndbout << "thread " << test.m_no << " does verification" << endl; + sprintf(sql, "select * from %s order by a", tname); + if (opt.m_v >= 2) + ndbout << "SQL[" << test.m_no << "]: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + long a, b, c; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_SLONG, &a, 0, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 2, SQL_C_SLONG, &b, 0, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 3, SQL_C_SLONG, &c, 0, 0)); + for (unsigned i = 0; i < opt.m_scale; i++) { + a = b = c = -1; + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.chk(HStmt(hStmt), a == i, "a: got %ld != %u", a, i); + test.chk(HStmt(hStmt), b == 10 * i, "b: got %ld != %u", b, 10 * i); + test.chk(HStmt(hStmt), c == opt.m_threads, "c: got %ld != %u", c, opt.m_threads); + if (opt.m_v >= 4) + ndbout << "verified " << i << endl; + } + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (opt.m_v >= 2) + ndbout << "thr " << test.m_no << " verified " << opt.m_scale << " rows" << endl; + my_sema = 0; + } + unlock_mutex(); + freeAll(test, hEnv, hDbc, hStmt); +} + +static const Sql +miscSql97[] = { + Sql("testMisc97a", testMisc97a), + Sql() +}; + +// 99 + +static void +testMisc99a(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + // bad + const char* sqlInsertBad = "insert into tt99a values(?, ?, ?, ?, ?)"; + test.exp(SQL_ERROR, "21S01", -1, true); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sqlInsertBad, SQL_NTS)); + // good + const char* sqlInsert = "insert into tt99a (col1, col2, col3, col4, col5) values(?, ?, ?, ?, ?)"; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sqlInsert, SQL_NTS)); + unsigned long value; + for (unsigned i = 1; i <= 5; i++) { + test.run(HStmt(hStmt), SQLBindParameter(hStmt, i, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &value, 0, 0)); + } + const unsigned long base = 1000000000; + const unsigned long scale = 10; + for (value = base; value < base + scale; value++) { + test.run(HStmt(hStmt), SQLExecute(hStmt)); + } + // bug1: re-analyze of converted expression... + const char* sqlSelect = "select col5 from tt99a where col2 + 0 = ?"; + unsigned long output; + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_ULONG, &output, 0, 0)); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sqlSelect, SQL_NTS)); + // bug2: previous bind must survive a new SQLPrepare + if (0) { + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &value, 0, 0)); + } + for (value = base; value < base + scale; value++) { + if (value > base + 4) { + // bug1: ...when IPD changed by JDBC + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &value, 0, 0)); + } + test.run(HStmt(hStmt), SQLExecute(hStmt)); + output = (unsigned long)-1; + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.chk(HStmt(hStmt), output == value, "got %lu != %lu", output, value); + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + test.timerCnt(1); + } + freeAll(test, hEnv, hDbc, hStmt); +} + +static void +testMisc99c(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + const char* sql = "select b from tt99c where a = ?"; + const unsigned long c1 = 2100000000U; + const unsigned long c2 = 4100000000U; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + unsigned long aval, bval; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &aval, 0, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_ULONG, &bval, 0, 0)); + // uno + for (unsigned i = 0; i < opt.m_scale; i++) { + aval = c1; + bval = (unsigned long)-1; + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << " [?=" << (Uint64)aval << "]" << endl; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.chk(HStmt(hStmt), bval == c2, "got %lu != %lu", bval, c2); + //test.exp(SQL_NO_DATA, 0, 0, true); + //test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } + // dos + for (unsigned i = 0; i < opt.m_scale; i++) { + break; // XXX not yet, hangs in NDB ?!? + aval = c2; + bval = (unsigned long)-1; + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << " [?=" << (Uint64)aval << "]" << endl; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.chk(HStmt(hStmt), bval == c1, "got %lu != %lu", bval, c2); + //test.exp(SQL_NO_DATA, 0, 0, true); + //test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } + freeAll(test, hEnv, hDbc, hStmt); +} + +static void +testMisc99d(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + const char* tname = "TT99D"; + char sql[MAX_SQL]; + sprintf(sql, "drop table %s", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.exp(SQL_ERROR, "IM000", 2040709, false); + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + sprintf(sql, "create table %s (a bigint unsigned, b bigint, primary key (a))", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLExecDirect(hStmt, (SQLCHAR*)sql, SQL_NTS)); + sprintf(sql, "insert into %s values (?, ?)", tname); + if (opt.m_v >= 2) + ndbout << "SQL: " << sql << endl; + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + // XXX replace by 100 when signed vs unsigned resolved + const unsigned num = 78; + SQLUBIGINT aval; + SQLBIGINT bval; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_BIGINT, 0, 0, &aval, 0, 0)); + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &bval, 0, 0)); + for (SQLBIGINT i = 0; i < num; i++) { + if (opt.m_v >= 3) + ndbout << "insert " << i << endl; + aval = i * i * i * i * i * i * i * i * i * i; // 10 + bval = -aval; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + } + sprintf(sql, "select a, b from tt99d where a = ?"); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql, SQL_NTS)); + SQLUBIGINT kval; + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_BIGINT, 0, 0, &kval, 0, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_UBIGINT, &aval, 0, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 2, SQL_C_SBIGINT, &bval, 0, 0)); + for (SQLBIGINT i = 0; i < num; i++) { + kval = i * i * i * i * i * i * i * i * i * i; // 10 + if (opt.m_v >= 3) + ndbout << "fetch " << i << " key " << kval << endl; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + aval = bval = 0; + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.chk(HStmt(hStmt), aval == kval && bval == -kval, "got %llu, %lld != %llu, %lld", aval, bval, kval, -kval); + test.exp(SQL_NO_DATA, 0, 0, true); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + } + freeAll(test, hEnv, hDbc, hStmt); +} + +static void +testMiscC2(Test& test) +{ + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); +#if 0 + { + char POP[255]; + char PORT[255]; + char ACCESSNODE[255]; + + const char* sqlSelect = "select PORT from AAA where POP=? and ACCESSNODE=?"; + + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sqlSelect, SQL_NTS)); + + for (int j=0; j<5; j++) { + printf("Loop %u\n", j); + printf("LINE %u\n", __LINE__); + + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, POP, 255, 0)); + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, ACCESSNODE, 255, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_CHAR, PORT, 255, 0)); + + sprintf(POP, "a"); + sprintf(ACCESSNODE, "b"); + + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + printf("got %s\n", PORT); + printf("LINE %u\n", __LINE__); + test.exp(SQL_NO_DATA, 0, 0, true); + printf("LINE %u\n", __LINE__); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + printf("LINE %u\n", __LINE__); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + printf("LINE %u\n", __LINE__); + } + } + return; +#endif + + char POP[255]; + char PORT[255]; + char ACCESSNODE[255]; + unsigned long VLAN = 0; + unsigned long SNMP_INDEX = 0; + unsigned long PORT_STATE = 0; + unsigned long STATIC_PORT = 0; + unsigned long COMMENT = 0; + + const char* sqlSelect = "select PORT, PORT_STATE from PORTS where POP=? and ACCESSNODE=?"; + + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sqlSelect, SQL_NTS)); + + for (int j=0; j<5; j++) { + printf("Loop %u\n", j); + printf("LINE %u\n", __LINE__); + + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, POP, 255, 0)); + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, ACCESSNODE, 255, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_CHAR, PORT, 255, 0)); + test.run(HStmt(hStmt), SQLBindCol(hStmt, 2, SQL_C_ULONG, &PORT_STATE, 0, 0)); + + sprintf(POP, "row%u.i%u.bredband.com", 2, 3); + sprintf(ACCESSNODE, "as%u", 2); + + test.run(HStmt(hStmt), SQLExecute(hStmt)); + for (int i=0; i < 3; i++) { + PORT_STATE=0; + sprintf(PORT, "XXXXXXXXXXXXXXXXXXXXX"); + + test.run(HStmt(hStmt), SQLFetch(hStmt)); + printf("got %s %lu\n", PORT, PORT_STATE); + // test.chk(HStmt(hStmt), false, "got %s != %s", "xxx", PORT); + } + printf("LINE %u\n", __LINE__); + test.exp(SQL_NO_DATA, 0, 0, true); + printf("LINE %u\n", __LINE__); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + printf("LINE %u\n", __LINE__); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + printf("LINE %u\n", __LINE__); + } +} + +static const Sql +miscSqlC2[] = { + Sql("drop table PORTS", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table PORTS (POP varchar(200) not null, ACCESSNODE varchar(200) not null, PORT varchar(200) not null, VLAN int unsigned, SNMP_INDEX int unsigned, PORT_STATE int unsigned, STATIC_PORT int unsigned, COMMENT int unsigned, primary key (POP,ACCESSNODE,PORT))", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("create index xxPORTS on PORTS (POP, ACCESSNODE) nologging", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + Sql("insert into PORTS values ('row2.i3.bredband.com','as2','Fa0/0',0,1,2,3,4)", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("insert into PORTS values ('row2.i3.bredband.com','as2','Fa0/1',1,2,3,4,5)", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("insert into PORTS values ('row2.i3.bredband.com','as2','Fa0/2',2,3,4,5,6)", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("select PORT, PORT_STATE from PORTS where POP='row2.i3.bredband.com' and ACCESSNODE='as2'", + SQL_DIAG_SELECT_CURSOR, 3, 3, -1, -1), + + Sql("drop table AAA", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table AAA (POP varchar(200), ACCESSNODE varchar(200) not null, PORT varchar(200) not null, primary key (POP,ACCESSNODE,PORT))", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("create index xxAAA on AAA (POP, ACCESSNODE) nologging", + SQL_DIAG_CREATE_INDEX, -1, -1, -1, -1), + Sql("insert into AAA values ('a','b','A')", + SQL_DIAG_INSERT, 1, 0, -1, -1), + + Sql("testMiscC2", testMiscC2), + Sql() +}; + +/* +> SELECT PORT, PORT_STATE FROM PORTS where pop=? and accessnode=? +> SELECT VLAN, SNMP_INDEX, PORT_STATE, STATIC_PORT, COMMENT FROM PORTS WHERE POP=? AND ACCESSNODE=? AND PORT=? +> select count(*) from ports +> select snmp_index from ports where pop='row2.i3.bredband.com' and accessnode='as2' and port='Fa0/2' + +> SELECT MAC, MAC_EXPIRE, IP, IP_EXPIRE, HOSTNAME, DETECTED, STATUS, STATIC_DNS, BLOCKED, NUM_REQUESTS, ACCESSTYPE, OS_TYPE, GATE_WAY, DIRTY_FLAG, LOCKED_IP FROM CLIENTS WHERE PORT=? AND ACCESSNODE=? AND POP=? +> SELECT SERVICES.ACCESSTYPE, SERVICES.NUM_IP, SERVICES.TEXPIRE, SERVICES.CUSTOMER_ID, SERVICES.LEASED_NUM_IP, SERVICES.PROVIDER, SERVICES.LOCKED_IP, SERVICES.STATIC_DNS, SERVICES.SUSPENDED_SERVICE FROM SERVICES , ACCESSTYPES WHERE SERVICES.PORT = ? AND SERVICES.ACCESSNODE = ? AND SERVICES.POP = ? AND SERVICES.ACCESSTYPE=ACCESSTYPES.ACCESSTYPE +*/ + +static const Sql +miscSql99[] = { + Sql("drop table tt99a", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt99a (col1 int unsigned primary key, col2 int unsigned, col3 int unsigned, col4 int unsigned, col5 int unsigned, col6 varchar(7) default 'abc123')", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + // inserts 10 rows, all same, start value 1000000000 + Sql("testMisc99a", testMisc99a), + // interpreted scan plus bind parameter + Sql("select col1 from tt99a where col2 = ?", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1000000004, 1000000004), + Sql("select col1 from tt99a where col2 = 1000000000 + ?", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1000000004, 4), + Sql("select col1 from tt99a where col2 = ? + 1000000000", + SQL_DIAG_SELECT_CURSOR, 1, 1, 1000000004, 4), + // same not interpreted, tuple count 10 + Sql("select col1 from tt99a where col2 + 0 = 1000000000 + ?", + SQL_DIAG_SELECT_CURSOR, 1, 10, 1000000004, 4), + // varchar variations + Sql("select count(*) from tt99a where col6 = 'abc123'", + SQL_DIAG_SELECT_CURSOR, 1, 10, 10, -1), + Sql("select count(*) from tt99a where left(col6, ?) = 'abc1'", + SQL_DIAG_SELECT_CURSOR, 1, 10, 10, 4), + Sql("select count(*) from tt99a where left(col6, ?) = 'abc1'", + SQL_DIAG_SELECT_CURSOR, 1, 10, 0, 3), + // tpc-b inspired, wrong optimization to direct update + Sql("drop table tt99b", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt99b(a int primary key, b int not null, c double precision)", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("insert into tt99b values(1, 10, 100.0)", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("insert into tt99b values(9, 90, 900.0)", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("create unique hash index tt99y on tt99b (b)", + SQL_DIAG_CREATE_INDEX, -1, 0, -1, -1), + // first scan update.. + Sql("update tt99b set c = c + ? where a+0 = 1", + SQL_DIAG_UPDATE_WHERE, 1, 2, -1, 10), + Sql("update tt99b set c = c + ? where b+0 = 10", + SQL_DIAG_UPDATE_WHERE, 1, 2, -1, 10), + // then optimized.. + Sql("update tt99b set c = c + ? where a = 1", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, 10), + Sql("update tt99b set c = c + ? where b = 10", + SQL_DIAG_UPDATE_WHERE, 1, 1, -1, 10), + // verify.. + Sql("select count(*) from tt99b where 100-1 < c and c < 140-1", + SQL_DIAG_SELECT_CURSOR, 1, 2, 0, -1), + Sql("select count(*) from tt99b where 140-.001 < c and c < 140+.001", + SQL_DIAG_SELECT_CURSOR, 1, 2, 1, -1), + // unsigned test + Sql("drop table tt99c", + SQL_DIAG_DROP_TABLE, -1, 0, -1, -1, + SQL_ERROR, "IM000", 2040709, false), + Sql("create table tt99c(a int unsigned primary key, b int unsigned)", + SQL_DIAG_CREATE_TABLE, -1, 0, -1, -1), + Sql("insert into tt99c values(2100000000, 4100000000)", + SQL_DIAG_INSERT, 1, 0, -1, -1), + Sql("insert into tt99c (a, b) select b, a from tt99c", + SQL_DIAG_INSERT, 1, 1, -1, -1), + Sql("testMisc99c", testMisc99c), + // new external type SQL_C_[SU]BIGINT + Sql("testMisc99d", testMisc99d), + Sql() +}; + +static const struct { const Sql* sql; int minscale; } +miscSql[11] = { + { miscSql90, 0 }, + { miscSql91, 0 }, + { miscSql92, 0 }, + { miscSql93, 0 }, + { 0, 0 }, // 94 + { miscSql95, 0 }, + { miscSql96, 0 }, + { miscSql97, 0 }, + { 0, 0 }, // 98 + { miscSql99, 0 }, + { miscSqlC2, 0 } +}; + +static void +testSql(Test& test) +{ + const unsigned salt = test.m_stuff; // mess + if (opt.m_scale < miscSql[salt].minscale) { + if (opt.m_v >= 1) + ndbout << "skip - requires scale >= " << miscSql[salt].minscale << endl; + return; + } + assert(0 <= salt && salt < 11 && miscSql[salt].sql != 0); + SQLHANDLE hEnv, hDbc, hStmt; + allocAll(test, hEnv, hDbc, hStmt); + for (unsigned i = 0; ; i++) { + const Sql& sql = miscSql[salt].sql[i]; + if (sql.m_sql == 0) + break; + if (opt.m_v >= 2) + ndbout << "SQL: " << sql.m_sql << endl; + if (sql.m_testFunc != 0) { + (*sql.m_testFunc)(test); + continue; + } + if (strncmp(sql.m_sql, "--", 2) == 0) { + continue; + } + if (strcmp(sql.m_sql, Sql::set_autocommit_on()) == 0) { + setAutocommit(test, hDbc, true); + continue; + } + if (strcmp(sql.m_sql, Sql::set_autocommit_off()) == 0) { + setAutocommit(test, hDbc, false); + continue; + } + if (strcmp(sql.m_sql, Sql::do_commit()) == 0) { + test.run(HDbc(hDbc), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_COMMIT)); + continue; + } + if (strcmp(sql.m_sql, Sql::do_rollback()) == 0) { + test.run(HDbc(hDbc), SQLEndTran(SQL_HANDLE_DBC, hDbc, SQL_ROLLBACK)); + continue; + } + if (opt.m_v >= 3) { + ndbout << "expect:"; + ndbout << " ret=" << sql.m_ret; + ndbout << " rows=" << sql.m_rowCount; + ndbout << " tuples=" << sql.m_tuplesFetched; + ndbout << endl; + } + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_UNBIND)); + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_RESET_PARAMS)); + // prep + test.exp(sql.m_ret, sql.m_state, sql.m_native, false); + test.run(HStmt(hStmt), SQLPrepare(hStmt, (SQLCHAR*)sql.m_sql, SQL_NTS)); + if (test.m_ret != SQL_SUCCESS) + continue; + // bind between prep and exec like JDBC + unsigned long bindValue = sql.m_bindValue; + for (int k = 0; k <= 1; k++) { + if (bindValue != -1) { + assert(strchr(sql.m_sql, '?') != 0); + test.run(HStmt(hStmt), SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &bindValue, 0, 0)); + } + if (k == 0) { + if (bindValue != -1) { + test.run(HStmt(hStmt), SQLFreeStmt(hStmt, SQL_RESET_PARAMS)); + // exec with unbound parameter + test.exp(SQL_ERROR, "HY010", -1, true); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == sql.m_functionCode || sql.m_functionCode == -1, "func: got %d != %d", (int)test.m_functionCode, (int)sql.m_functionCode); + } + } else { + // exec + test.exp(sql.m_ret, sql.m_state, sql.m_native, sql.m_reset); + test.run(HStmt(hStmt), SQLExecute(hStmt)); + test.chk(HStmt(hStmt), test.m_functionCode == sql.m_functionCode || sql.m_functionCode == -1, "func: got %d != %d", (int)test.m_functionCode, (int)sql.m_functionCode); + } + } + if (sql.m_rowCount != -1) { + if (sql.m_functionCode == SQL_DIAG_SELECT_CURSOR) { + long lastValue; + if (sql.m_lastValue != -1) + test.run(HStmt(hStmt), SQLBindCol(hStmt, 1, SQL_C_SLONG, &lastValue, 0, 0)); + unsigned k = 0; + do { + int rowCount = 0; + lastValue = -1; + while (1) { + test.exp(SQL_NO_DATA, 0, 0, false); + test.run(HStmt(hStmt), SQLFetch(hStmt)); + if (test.m_ret == SQL_NO_DATA) + break; + rowCount++; + } + test.chk(HStmt(hStmt), rowCount == sql.m_rowCount, "rowCount: got %d != %d", (int)rowCount, (int)sql.m_rowCount); + if (sql.m_tuplesFetched != -1) + chkTuplesFetched(test, hStmt, sql.m_tuplesFetched); + if (rowCount > 0 && sql.m_lastValue != -1) + test.chk(HStmt(hStmt), lastValue == sql.m_lastValue, "lastValue: got %ld != %ld", (long)lastValue, (long)sql.m_lastValue); + test.run(HStmt(hStmt), SQLCloseCursor(hStmt)); + if (++k >= opt.m_scale) + break; + test.run(HStmt(hStmt), SQLExecute(hStmt)); + } while (1); + test.timerCnt(opt.m_scale); + } else { + assert(sql.m_lastValue == -1); + chkRowCount(test, hStmt, sql.m_rowCount); + if (sql.m_tuplesFetched != -1) + chkTuplesFetched(test, hStmt, sql.m_tuplesFetched); + test.timerCnt(1); + } + } + } + freeAll(test, hEnv, hDbc, hStmt); +} + +// name, function, runmode, salt (0=const or n/a), description +static const Case caseList[] = { + Case( "00alloc", testAlloc, Case::Thread, 0, "allocate handles" ), + Case( "01create", testCreate, Case::Single, 0, "create tables for the test" ), + Case( "02prepare", testPrepare, Case::Thread, 0, "prepare without execute" ), + Case( "03catalog", testCatalog, Case::Thread, 0, "catalog functions" ), + Case( "10insert", testInsert, Case::Thread, 1, "insert computed rows" ), + Case( "11delall", testDeleteAll, Case::Single, 0, "delete all rows via scan" ), + Case( "12insert", testInsert, Case::Thread, 1, "insert computed rows again" ), + Case( "13count", testCount, Case::Single, 0, "count rows" ), + Case( "14verpk", testVerifyPk, Case::Thread, 1, "verify via primary key" ), + Case( "15verscan", testVerifyScan, Case::Serial, 1, "verify via range scans" ), + Case( "16join", testJoin, Case::Single, 0, "multiple self-join" ), + Case( "17cart", testCart, Case::Single, 0, "cartesian join" ), + Case( "20updpk", testUpdatePk, Case::Thread, 2, "update via primary key" ), + Case( "21verpk", testVerifyPk, Case::Thread, 2, "verify via primary key" ), + Case( "22verscan", testVerifyScan, Case::Serial, 2, "verify via range scans" ), + Case( "23updscan", testUpdateScan, Case::Serial, 0, "update via scan" ), + Case( "24verpk", testVerifyPk, Case::Thread, 0, "verify via primary key" ), + Case( "25verscan", testVerifyScan, Case::Serial, 0, "verify via range scans" ), + Case( "26delpk", testDeletePk, Case::Thread, 0, "delete via primary key" ), + Case( "30trans", testTrans, Case::Single, 3, "rollback and commit" ), + Case( "31concur", testConcur, Case::Single, 0, "commit across open cursor" ), + Case( "32readcom", testReadcom, Case::Single, 0, "read committed" ), + Case( "40perf", testPerf, Case::Single, 0, "perf test prepare" ), + Case( "41perf", testPerf, Case::Thread, 1, "perf test NDB API" ), + Case( "42perf", testPerf, Case::Thread, 2, "perf test NDB ODBC" ), + Case( "90sql", testSql, Case::Single, 0, "misc SQL: metadata" ), + Case( "91sql", testSql, Case::Single, 1, "misc SQL: misc" ), + Case( "92sql", testSql, Case::Thread, 2, "misc SQL: scan rollback" ), + Case( "93sql", testSql, Case::Single, 3, "misc SQL: locking" ), + Case( "95sql", testSql, Case::Single, 5, "misc SQL: indexes (simple)" ), + Case( "96sql", testSql, Case::Single, 6, "misc SQL: indexes" ), + Case( "97sql", testSql, Case::Thread, 7, "misc SQL: indexes" ), + Case( "99sql", testSql, Case::Single, 9, "misc SQL: bug du jour" ), + Case( "C2", testSql, Case::Single, 10, "misc SQL: C2" ) +}; + +static const unsigned caseCount = arraySize(caseList); + +static bool +findCase(const char* name) +{ + for (unsigned i = 0; i < caseCount; i++) { + const Case& cc = caseList[i]; + if (strstr(cc.m_name, name) != 0) + return true; + } + return false; +} + +static void +listCases() +{ + ndbout << "cases:" << endl; + unsigned m = 0; + for (unsigned i = 0; i < caseCount; i++) { + const Case& cc = caseList[i]; + if (m < strlen(cc.m_name)) + m = strlen(cc.m_name); + } + for (unsigned i = 0; i < caseCount; i++) { + const Case& cc = caseList[i]; + char buf[200]; + sprintf(buf, "%-*s [%-6s] %s", m, cc.m_name, cc.modename(), cc.m_desc); + ndbout << buf << endl; + } +} + +// threads + +extern "C" { static void* testThr(void* arg); } + +struct Thr { + enum State { + Wait = 1, // wait for test case + Run = 2, // run the test case + Done = 3, // done with the case + Exit = 4 // exit thread + }; + unsigned m_no; // thread number 1 .. max + NdbThread* m_thr; // thread id etc + const Case* m_case; // current case + State m_state; // condition variable + NdbMutex* m_mutex; // condition guard + NdbCondition* m_cond; + void* m_status; // exit status (not used) + Test m_test; // test runner + Thr(unsigned no, unsigned loop) : + m_no(no), + m_thr(0), + m_case(0), + m_state(Wait), + m_mutex(NdbMutex_Create()), + m_cond(NdbCondition_Create()), + m_status(0), + m_test(no, loop) { + } + ~Thr() { + destroy(); + NdbCondition_Destroy(m_cond); + NdbMutex_Destroy(m_mutex); + } + void create() { + assert(m_thr == 0); + m_thr = NdbThread_Create(testThr, (void**)this, 64*1024, "test", NDB_THREAD_PRIO_LOW); + } + void destroy() { + if (m_thr != 0) + NdbThread_Destroy(&m_thr); + m_thr = 0; + } + void lock() { + NdbMutex_Lock(m_mutex); + } + void unlock() { + NdbMutex_Unlock(m_mutex); + } + void wait() { + NdbCondition_Wait(m_cond, m_mutex); + } + void signal() { + NdbCondition_Signal(m_cond); + } + void join() { + NdbThread_WaitFor(m_thr, &m_status); + m_thr = 0; + } + // called from main + void mainStart(const Case& cc) { + lock(); + m_case = &cc; + m_state = Run; + signal(); + unlock(); + } + void mainStop() { + lock(); + while (m_state != Done) { + if (opt.m_v >= 4) + ndbout << ::lock << "thr " << m_no << " [main] wait state=" << m_state << endl << ::unlock; + wait(); + } + if (opt.m_v >= 4) + ndbout << ::lock << "thr " << m_no << " [main] done" << endl << ::unlock; + m_state = Wait; + unlock(); + } + // run in thread + void testSelf() { + while (1) { + lock(); + while (m_state != Run && m_state != Exit) { + if (opt.m_v >= 4) + ndbout << ::lock << "thr " << m_no << " [self] wait state=" << m_state << endl << ::unlock; + wait(); + } + if (m_state == Run) { + if (opt.m_v >= 4) + ndbout << ::lock << "thr " << m_no << " [self] run" << endl << ::unlock; + assert(m_case != 0); + m_test.timerOn(); + m_test.runCase(*m_case); + m_test.timerOff(); + m_state = Done; + if (opt.m_v >= 4) + ndbout << ::lock << "thr " << m_no << " [self] done" << endl << ::unlock; + signal(); + unlock(); + } else if (m_state == Exit) { + unlock(); + break; + } else { + assert(false); + } + } + if (opt.m_v >= 4) + ndbout << ::lock << "thr " << m_no << " [self] exit" << endl << ::unlock; + } +}; + +static void* +testThr(void* arg) +{ + Thr& thr = *(Thr*)arg; + thr.testSelf(); + return 0; +} + +#ifdef DMALLOC +extern "C" { + +static int malloc_bytes = 0; +static int free_bytes = 0; + +static void +malloc_track(const char *file, const unsigned int line, const int func_id, const DMALLOC_SIZE byte_size, const DMALLOC_SIZE alignment, const DMALLOC_PNT old_addr, const DMALLOC_PNT new_addr) +{ + if (func_id == DMALLOC_FUNC_MALLOC) { + malloc_bytes += byte_size; + return; + } + if (func_id == DMALLOC_FUNC_FREE) { + DMALLOC_SIZE size = 0; + dmalloc_examine(old_addr, &size, 0, 0, 0); + free_bytes += size; + // XXX useless - byte_size and size are 0 + return; + } +} + +} +#endif /* DMALLOC */ + +static void +testMain() +{ +#ifndef NDB_LINUX /* valgrind-1.0.3 does not support */ + NdbThread_SetConcurrencyLevel(opt.m_threads + 2); +#endif +#ifdef DMALLOC + dmalloc_track(malloc_track); +#endif + Test test(0, 0); +#ifdef ndbODBC + Ndb* ndb = 0; + if (1) { // pre-alloc one Ndb object + ndb = new Ndb("TEST_DB"); + ndb->init(); + if (ndb->waitUntilReady() != 0) { + ndbout << ndb->getNdbError() << endl; + fatal("waitUntilReady"); + } + } +#endif + for (unsigned loop = 1; opt.m_loop == 0 || loop <= opt.m_loop; loop++) { + if (opt.m_v >= 2) + ndbout << "loop " << loop << endl; + // create new set of threads in each loop + Thr** thrList = new Thr* [1 + opt.m_threads]; + for (unsigned n = 1; n <= opt.m_threads; n++) { + Thr& thr = *(thrList[n] = new Thr(n, loop)); + thr.create(); + if (opt.m_v >= 4) + ndbout << "thr " << n << " [main] created" << endl; + } +#ifdef DMALLOC + malloc_bytes = free_bytes = 0; +#endif + for (unsigned i = 0; i < caseCount; i++) { + const Case& cc = caseList[i]; + if (! cc.matchcase()) + continue; + if (opt.m_v >= 2) + ndbout << "RUN: " << cc.m_name << " - " << cc.m_desc << endl; + test.timerOn(); + for (unsigned subloop = 1; subloop <= opt.m_subloop; subloop++) { + my_sema = 0; + if (opt.m_v >= 3) + ndbout << "subloop " << subloop << endl; + if (cc.m_mode == Case::Single) { + Thr& thr = *thrList[1]; + thr.mainStart(cc); + thr.mainStop(); + test.timerCnt(thr.m_test); + } else if (cc.m_mode == Case::Serial) { + for (unsigned n = 1; n <= opt.m_threads; n++) { + Thr& thr = *thrList[n]; + thr.mainStart(cc); + thr.mainStop(); + test.timerCnt(thr.m_test); + } + } else if (cc.m_mode == Case::Thread) { + for (unsigned n = 1; n <= opt.m_threads; n++) { + Thr& thr = *thrList[n]; + thr.mainStart(cc); + } + for (unsigned n = 1; n <= opt.m_threads; n++) { + Thr& thr = *thrList[n]; + thr.mainStop(); + test.timerCnt(thr.m_test); + } + } else { + assert(false); + } + } + test.timerOff(); + if (opt.m_v >= 1) + ndbout << cc.m_name << " total " << test << endl; + } +#ifdef DMALLOC + if (opt.m_v >= 9) // XXX useless now + ndbout << "malloc " << malloc_bytes << " free " << free_bytes << " lost " << malloc_bytes - free_bytes << endl; +#endif + // tell threads to exit + for (unsigned n = 1; n <= opt.m_threads; n++) { + Thr& thr = *thrList[n]; + thr.lock(); + thr.m_state = Thr::Exit; + thr.signal(); + thr.unlock(); + if (opt.m_v >= 4) + ndbout << "thr " << n << " [main] told to exit" << endl; + } + for (unsigned n = 1; n <= opt.m_threads; n++) { + Thr& thr = *thrList[n]; + thr.join(); + if (opt.m_v >= 4) + ndbout << "thr " << n << " [main] joined" << endl; + delete &thr; + } + delete[] thrList; + } +#ifdef ndbODBC + delete ndb; +#endif +} + +static bool +str2num(const char* arg, const char* str, unsigned* num, unsigned lo = 0, unsigned hi = 0) +{ + char* end = 0; + long n = strtol(str, &end, 0); + if (end == 0 || *end != 0 || n < 0) { + ndbout << arg << " " << str << " is invalid number" << endl; + return false; + } + if (lo != 0 && n < lo) { + ndbout << arg << " " << str << " is too small min = " << lo << endl; + return false; + } + if (hi != 0 && n > hi) { + ndbout << arg << " " << str << " is too large max = " << hi << endl; + return false; + } + *num = n; + return true; +} + +NDB_COMMAND(testOdbcDriver, "testOdbcDriver", "testOdbcDriver", "testOdbcDriver", 65535) +{ + while (++argv, --argc > 0) { + const char* arg = argv[0]; + if (strcmp(arg, "-case") == 0) { + if (++argv, --argc > 0) { + assert(opt.m_namecnt < arraySize(opt.m_name)); + opt.m_name[opt.m_namecnt++] = argv[0]; + if (findCase(argv[0])) + continue; + } + } + if (strcmp(arg, "-core") == 0) { + opt.m_core = true; + continue; + } + if (strcmp(arg, "-depth") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_depth)) + continue; + } + } + if (strcmp(arg, "-dsn") == 0) { + if (++argv, --argc > 0) { + opt.m_dsn = argv[0]; + continue; + } + } + if (strcmp(arg, "-frob") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_frob)) + continue; + } + } + if (strcmp(arg, "-errs") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_errs)) + continue; + } + } + if (strcmp(arg, "-fragtype") == 0) { + if (++argv, --argc > 0) { + opt.m_fragtype = argv[0]; + continue; + } + } + if (strcmp(arg, "-home") == 0) { + if (++argv, --argc > 0) { + opt.m_home = argv[0]; + continue; + } + } + if (strcmp(arg, "-loop") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_loop)) + continue; + } + } + if (strcmp(arg, "-nogetd") == 0) { + opt.m_nogetd = true; + continue; + } + if (strcmp(arg, "-noputd") == 0) { + opt.m_noputd = true; + continue; + } + if (strcmp(arg, "-nosort") == 0) { + opt.m_nosort = true; + continue; + } + if (strcmp(arg, "-scale") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_scale)) + continue; + } + } + if (strcmp(arg, "-serial") == 0) { + opt.m_serial = true; + continue; + } + if (strcmp(arg, "-skip") == 0) { + if (++argv, --argc > 0) { + assert(opt.m_skipcnt < arraySize(opt.m_skip)); + opt.m_skip[opt.m_skipcnt++] = argv[0]; + if (findCase(argv[0])) + continue; + } + } + if (strcmp(arg, "-subloop") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_subloop)) + continue; + } + } + if (strcmp(arg, "-table") == 0) { + if (++argv, --argc > 0) { + opt.m_table = argv[0]; + if (findTable()) + continue; + } + } + if (strcmp(arg, "-threads") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_threads, 1, MAX_THR)) + continue; + } + } + if (strcmp(arg, "-trace") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_trace)) + continue; + } + } + if (strcmp(arg, "-v") == 0) { + if (++argv, --argc > 0) { + if (str2num(arg, argv[0], &opt.m_v)) + continue; + } + } + if (strncmp(arg, "-v", 2) == 0 && isdigit(arg[2])) { + if (str2num(arg, &arg[2], &opt.m_v)) + continue; + } + printusage(); + return NDBT_ProgramExit(NDBT_WRONGARGS); + } + homeEnv: { + static char env[1000]; + if (opt.m_home != 0) { + sprintf(env, "NDB_HOME=%s", opt.m_home); + putenv(env); + } + } + traceEnv: { + static char env[40]; + sprintf(env, "NDB_ODBC_TRACE=%u", opt.m_trace); + putenv(env); + } + debugEnv: { + static char env[40]; + sprintf(env, "NDB_ODBC_DEBUG=%d", 1); + putenv(env); + } + testMain(); + return NDBT_ProgramExit(NDBT_OK); +} + +// vim: set sw=4: diff --git a/ndb/test/odbc/test_compiler/Makefile b/ndb/test/odbc/test_compiler/Makefile new file mode 100644 index 00000000000..34819f21171 --- /dev/null +++ b/ndb/test/odbc/test_compiler/Makefile @@ -0,0 +1,21 @@ +include .defs.mk + +TYPE = odbcdriver + +BIN_TARGET = test_compiler + +SOURCES = test_compiler.cpp + +CCFLAGS_LOC += \ + -I$(NDB_TOP)/src/client/odbc/common \ + -I$(NDB_TOP)/src/client/odbc/dictionary \ + -I$(NDB_TOP)/src/client/odbc/compiler + +CCFLAGS_WARNINGS += -Wno-unused + +LIBS_SPEC += \ + -lodbccompiler_pic + + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/test/odbc/test_compiler/test_compiler.cpp b/ndb/test/odbc/test_compiler/test_compiler.cpp new file mode 100644 index 00000000000..042e9e6d4bf --- /dev/null +++ b/ndb/test/odbc/test_compiler/test_compiler.cpp @@ -0,0 +1,233 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/********************************************************************************** + test_compiler.cpp + Tests the code tree generated + by the compiler +***********************************************************************************/ +#include <stdio.h> +#include <memory.h> +#include "SQL_compiler.hpp" +#include "SQL_code_tree.hpp" + +typedef struct stSTMT_REF_tag { + char* szTestStmt ; + SQL_compiler* pC ; + SQL_code_tree* pRefTree ; + int nFlag ; /* indicate if the struct haa a code tree and compiler and should be processed */ +} stSTMT_REF ; + +int compare_trees(SQL_code_tree* pCompilerOutput, SQL_code_tree* pReference) ; + +/* Assign statements to szTestStmt and NULL to pTestRef */ + +static stSTMT_REF stTestRef[] = { +/* 0 */ {"create table foo (pk integer primary key, a integer, b varchar(20), check (a is not null))", NULL, NULL, 0}, +/* 1 */ {"insert into foo (pk, a, b) values (1, 10, 'ett')", NULL, NULL, 0}, +/* 2 */ {"insert into foo values (2, 20)", NULL, NULL, 0}, +/* 3 */ {"delete from foo", NULL, NULL, 1}, +/* 4 */ {"delete from foo where pk=5", NULL, NULL, 0}, +/* 5 */ {"delete from foo where a<10 or b='test'", NULL, NULL, 0}, +/* 6 */ {"update foo set a=100, b=null", NULL, NULL, 0}, +/* 7 */ {"update foo set a=0 where pk=1", NULL, NULL, 0}, +/* 8 */ {"update foo set a=a+pk where b is null", NULL, NULL, 0}, +/* 9 */ {"select * from foo", NULL, NULL, 0}, +/* 10 */ {"select pk, a, b from foo where pk=1", NULL, NULL, 0}, +/* 11 */ {"select * from foo order by a", NULL, NULL, 0}, +/* 12 */ {"select * from foo A, foo B where A.pk=B.a and A.a<2*B.a", NULL, NULL, 0} +} ; + + +int main(int argc, char* argv[]){ + + int retcode = 0 ; + int nTests = sizeof(stTestRef)/sizeof(stSTMT_REF) ; + + for(int c = 0 ; c < nTests ; c++) { + if(stTestRef[c].nFlag){ + stTestRef[c].pC = new SQL_compiler() ; + stTestRef[c].pRefTree = new SQL_code_tree() ; + } + } + + /* Create reference code trees */ + + /* + Statement: 0 "create table foo (pk integer primary key, a integer, b varchar(20), check (a is not null))" + */ + + + /* + Statement: 1 + */ + + + + /* + Statement: 2 + */ + + + + /* + Statement: 3 "delete from foo" + */ + + stTestRef[3].pRefTree->shift('N') ; + stTestRef[3].pRefTree->shift('D') ; + stTestRef[3].pRefTree->shift('B') ; + stTestRef[3].pRefTree->reduce(0x2050400e, 3) ; + stTestRef[3].pRefTree->shift('F') ; + stTestRef[3].pRefTree->shift('O') ; + stTestRef[3].pRefTree->shift('O') ; + stTestRef[3].pRefTree->reduce(0x20502003, 3) ; + stTestRef[3].pRefTree->reduce(0x2050400f, 1) ; + stTestRef[3].pRefTree->reduce(0x20504007, 2) ; + stTestRef[3].pRefTree->reduce(0x21407003, 1) ; + stTestRef[3].pRefTree->shift(0x205021ca) ; + stTestRef[3].pRefTree->reduce(0x20630001, 1) ; + stTestRef[3].pRefTree->reduce(0x20815001, 1) ; + stTestRef[3].pRefTree->shift(0x21407002) ; + stTestRef[3].pRefTree->reduce(0x21407004, 3) ; + stTestRef[3].pRefTree->shift(0x21407002) ; + stTestRef[3].pRefTree->reduce(0x21407005, 1) ; + stTestRef[3].pRefTree->shift(0x21414001) ; + stTestRef[3].pRefTree->shift(0x21414002) ; + stTestRef[3].pRefTree->reduce(0x21407001, 4) ; + stTestRef[3].pRefTree->reduce(0x51506004, 1) ; + stTestRef[3].pRefTree->reduce(0x51506003, 1) ; + + /* + Statement: 4 + */ + + + + /* + Statement: 5 + */ + + + + + /* + Statement: 6 + */ + + + + + /* + Statement: 7 + */ + + + + /* + Statement: 8 + */ + + + + /* + Statement: 9 + */ + + + + /* + Statement: 10 + */ + + + + /* + Statement: 11 + */ + + + + /* + Statement: 12 + */ + + + + for(int i = 0 ; i < nTests ; i++){ + /* Check to see if the statement has an associated code tree and compiler */ + if(stTestRef[i].nFlag){ + stTestRef[i].pC->prepare( stTestRef[i].szTestStmt, strlen(stTestRef[i].szTestStmt)) ; + if( 0 != compare_trees(&stTestRef[i].pC->m_code_tree, stTestRef[i].pRefTree) ){ + printf("\nCompiler generated tree for statement #%d: \"%s\"\ndeviates from its reference\n", i, stTestRef[i].szTestStmt) ; + retcode = -1 ; + break ; + }else{ + printf("\nTrees for statement #%d: \"%s\" match nicely -- OK\n", i, stTestRef[i].szTestStmt) ; + retcode = 0 ; + } + } + } + + for(int d = 0 ; d < nTests ; d++) { + if(stTestRef[d].nFlag){ + delete stTestRef[d].pC ; + delete stTestRef[d].pRefTree ; + } + } + + return retcode ; + +} + + + + +int compare_trees(SQL_code_tree* pCompilerOutput, SQL_code_tree* pReference){ + + int nTop = -1 ; + + if(pCompilerOutput->top()== pReference->top()){ + + nTop = pReference->top() ; + + }else{ + printf("\npCompilerOutput->top() = %d;\tpReference->top() = %d\n", pCompilerOutput->top(), pReference->top()) ; + return -1 ; + } + + pCompilerOutput->beginPostfix() ; + pReference->beginPostfix() ; + + for(int r = 0 ; r < nTop ; r++){ + if(pCompilerOutput->symbol() != pReference->symbol()){ + + printf("Deviation found in position %d\n", r) ; + printf("pCompilerOutput->symbol() = 0x%X;\tpReference->symbol() = 0x%X\n", pCompilerOutput->symbol(), pReference->symbol()) ; + return -1 ; + + }else{ + + pCompilerOutput->nextPostfix() ; + pReference->nextPostfix() ; + + } + } + + return 0 ; + +} + diff --git a/ndb/test/odbc/tpcb/Makefile b/ndb/test/odbc/tpcb/Makefile new file mode 100644 index 00000000000..8ab429c8ea1 --- /dev/null +++ b/ndb/test/odbc/tpcb/Makefile @@ -0,0 +1,30 @@ +include .defs.mk + +TYPE = * + +BIN_TARGET = tpcb + +SOURCES = ttTime.c tpcb.cpp + +CCFLAGS_LOC += \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/include/ndbapi \ + -I$(NDB_TOP)/include/portlib \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/test/include \ + -I/usr/local/include + +CCFLAGS_WARNINGS += -Wno-unused -Wno-sign-compare -Wformat + +CCFLAGS_TOP += -DndbODBC + +BIN_TARGET_LIBS = NDB_API_pic NDB_ODBC_pic NDBT + +ifeq ($(NDB_OS),SOLARIS) +BIN_TARGET_LIBS += dmallocthcxx +CCFLAGS_TOP += -DDMALLOC +endif + +include $(NDB_TOP)/Epilogue.mk + +$(BIN_DIR)$(BIN_TARGET): Makefile diff --git a/ndb/test/odbc/tpcb/Makefile_mysql b/ndb/test/odbc/tpcb/Makefile_mysql new file mode 100644 index 00000000000..4e1b9a25fe2 --- /dev/null +++ b/ndb/test/odbc/tpcb/Makefile_mysql @@ -0,0 +1,33 @@ +include $(NDB_TOP)/Defs.mk + +TYPE = odbcclient + +BIN_TARGET = tpcb + +SOURCES = ttTime.c tpcb.cpp + +CCFLAGS_LOC += -I/usr/local/include \ + -I$(NDB_TOP)/test/include \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/src/client/odbc/common + + + + +#CCFLAGS_WARNINGS += -Wno-unused + +LIBS_LOC += -L/usr/local/lib +BIN_TARGET_LIBS_DIRS += /usr/local/lib +BIN_TARGET_LIBS += odbc odbcinst + +#LIBS_SPEC += -pg +# -lNDBT \ +# -lodbc \ +# -lodbcinst \ +# -lportlib + + + +include $(NDB_TOP)/Epilogue.mk + diff --git a/ndb/test/odbc/tpcb/Makefile_ndb b/ndb/test/odbc/tpcb/Makefile_ndb new file mode 100644 index 00000000000..85960413ef0 --- /dev/null +++ b/ndb/test/odbc/tpcb/Makefile_ndb @@ -0,0 +1,30 @@ +include $(NDB_TOP)/Defs.mk + +TYPE = * + +BIN_TARGET = tpcb + +SOURCES = ttTime.c tpcb.cpp + +CCFLAGS_LOC += \ + -I$(NDB_TOP)/include \ + -I$(NDB_TOP)/include/ndbapi \ + -I$(NDB_TOP)/include/portlib \ + -I$(NDB_TOP)/include/util \ + -I$(NDB_TOP)/test/include \ + -I/usr/local/include + +CCFLAGS_WARNINGS += -Wno-unused -Wno-sign-compare -Wformat + +CCFLAGS_TOP += -DndbODBC + +BIN_TARGET_LIBS = NDB_API_pic NDB_ODBC_pic NDBT + +ifeq ($(NDB_OS),SOLARIS) +BIN_TARGET_LIBS += dmallocthcxx +CCFLAGS_TOP += -DDMALLOC +endif + +include $(NDB_TOP)/Epilogue.mk + +$(BIN_DIR)$(BIN_TARGET): Makefile diff --git a/ndb/test/odbc/tpcb/readme.txt b/ndb/test/odbc/tpcb/readme.txt new file mode 100644 index 00000000000..008cafb9d2f --- /dev/null +++ b/ndb/test/odbc/tpcb/readme.txt @@ -0,0 +1,15 @@ +'tpcb' requires an .odbc.ini file in +/etc/ +or in +/home/user/ + +The .odbc.ini file must contain a DSN entry called ndb: + +#--------- .odbc.ini example -------------------- + +[ndb] +Driver = /path_to_installation/lib/libNDB_ODBC.so + +#--------- End of example ----------------------- + + diff --git a/ndb/test/odbc/tpcb/timesten.h b/ndb/test/odbc/tpcb/timesten.h new file mode 100644 index 00000000000..45579f9d277 --- /dev/null +++ b/ndb/test/odbc/tpcb/timesten.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + * $Revision: 1.1 $ + * (c) Copyright 1997-2003, TimesTen, Inc. + * All rights reserved. + */ + +#ifndef TIMESTEN_H_INCLUDED +#define TIMESTEN_H_INCLUDED + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <sql.h> +#include <sqltypes.h> +#include <sqlext.h> +/* + * TimesTen extension to application data types; only usable + * when application directly linked to the TimesTen driver. + */ +#define SQL_C_ADDR 100 + +#ifndef SQL_C_SBIGINT +#if (ODBCVER < 0x0300) +#define SQL_C_SBIGINT (SQL_BIGINT+SQL_SIGNED_OFFSET) +#define SQL_C_UBIGINT (SQL_BIGINT+SQL_UNSIGNED_OFFSET) +#endif +#endif + +#define SQL_C_BIGINT SQL_C_SBIGINT + +#if (ODBCVER < 0x0300) +#ifdef _WIN32 +typedef __int64 SQLBIGINT; +/* On Unix platforms SQLBIGINT is defined in odbcinclude directory*/ +#endif +#endif + +#define BIGINT SQLBIGINT + +#ifdef _WIN32 +#define UBIGINT unsigned __int64 +#else +#define UBIGINT unsigned long long +#endif + + +#define SQL_WCHAR (-8) +#define SQL_WVARCHAR (-9) +#define SQL_WLONGVARCHAR (-10) +#define SQL_C_WCHAR SQL_WCHAR + +/* SQLGetInfo() InfoTypes */ +#define SQL_CONVERT_WCHAR 122 +#define SQL_CONVERT_WLONGVARCHAR 125 +#define SQL_CONVERT_WVARCHAR 126 + +/* TimesTen specific SQLGetInfo types */ +#define TT_REPLICATION_INVALID (SQL_INFO_DRIVER_START + 2000) + +/* SQLGetInfo() return value bitmasks */ +#ifndef SQL_CVT_WCHAR +/* +** These definitions differ from Microsoft in that they are not +** specified as long (e.g. 0x00200000L), hence they are protected +** by the ifndef above. +*/ +#define SQL_CVT_WCHAR 0x00200000 +#define SQL_CVT_WLONGVARCHAR 0x00400000 +#define SQL_CVT_WVARCHAR 0x00800000 +#endif + +/* +** The Microsoft Driver Manager SQLBindParameter() will not pass SQL_WCHAR +** through. Use this hack to get around it. +*/ +#define SQL_WCHAR_DM_SQLBINDPARAMETER_BYPASS -888 + +/* This is an extension to ODBC's isolation levels. It reflects an + * earlier implementation of read-committed that released locks on + * next fetch, rather than releasing locks before returning value to + * application. */ +#define SQL_TXN_CURSOR_STABILITY 0x00001000 +#define SQL_TXN_NOBLOCK_DELETE 0x00002000 + +/* TimesTen-specific connection option */ +#define TT_PREFETCH_CLOSE 10001 +#define TT_PREFETCH_CLOSE_OFF 0 +#define TT_PREFETCH_CLOSE_ON 1 + +/* Adding a new sql connection option */ +#define TT_PREFETCH_COUNT 10003 +#define TT_PREFETCH_COUNT_MAX 128 + +/* + * Platform specific data types for integers that scale + * with pointer size + */ + +#ifdef _IA64_ +typedef signed __int64 tt_ptrint; +typedef unsigned __int64 tt_uptrint; +#else +#ifdef _WIN32 +typedef signed long tt_ptrint; +typedef unsigned long tt_uptrint; +#else +typedef signed long tt_ptrint; +typedef unsigned long tt_uptrint; +#endif +#endif + +#ifdef _WIN32 +typedef signed __int64 tt_int8; +typedef unsigned __int64 tt_uint8; +#else +typedef signed long long tt_int8; +typedef unsigned long long tt_uint8; +#endif + +/* printf formats for pointer-sized integers */ +#ifdef _IA64_ /* 64-bit NT */ +#define PTRINT_FMT "I64d" +#define UPTRINT_FMT "I64u" +#define xPTRINT_FMT "I64x" +#define XPTRINT_FMT "I64X" +#else +#ifdef _WIN32 /* 32-bit NT */ +#define PTRINT_FMT "ld" +#define UPTRINT_FMT "lu" +#define xPTRINT_FMT "lx" +#define XPTRINT_FMT "lX" +#else /* 32 and 64-bit UNIX */ +#define PTRINT_FMT "ld" +#define UPTRINT_FMT "lu" +#define xPTRINT_FMT "lx" +#define XPTRINT_FMT "lX" +#endif +#endif + +/* printf formats for 8-byte integers */ +#ifndef INT8_FMT_DEFINED +#ifdef _WIN32 /* 32 and 64-bit NT */ +#define INT8_FMT "I64d" +#define UINT8_FMT "I64u" +#define xINT8_FMT "I64x" +#define XINT8_FMT "I64X" +#else /* 32 and 64-bit UNIX */ +#define INT8_FMT "lld" +#define UINT8_FMT "llu" +#define xINT8_FMT "llx" +#define XINT8_FMT "llX" +#endif +#define INT8_FMT_DEFINED 1 +#endif + +/* The following types are defined in the newer odbc include files + from Microsoft +*/ +#if defined (_WIN32) && !defined (_IA64_) +#ifndef SQLROWSETSIZE +#define SQLROWSETSIZE SQLUINTEGER +#define SQLLEN SQLINTEGER +#define SQLROWOFFSET SQLINTEGER +#define SQLROWCOUNT SQLUINTEGER +#define SQLULEN SQLUINTEGER +#define SQLSETPOSIROW SQLUSMALLINT +#endif +#endif + + +#endif diff --git a/ndb/test/odbc/tpcb/tpcb.cpp b/ndb/test/odbc/tpcb/tpcb.cpp new file mode 100644 index 00000000000..60d746e7844 --- /dev/null +++ b/ndb/test/odbc/tpcb/tpcb.cpp @@ -0,0 +1,1415 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +static const volatile char cvsid[] = "$Id: tpcb.cpp,v 1.4 2003/09/26 09:04:34 johan Exp $"; +/* + * $Revision: 1.4 $ + * (c) Copyright 1996-2003, TimesTen, Inc. + * All rights reserved. + */ + +/* This source is best displayed with a tabstop of 4 */ + +#define NDB + +//#define MYSQL + +#ifdef WIN32 +#include <windows.h> +#include "ttRand.h" +#else +#if !defined NDB && !defined MYSQL +#include <sqlunix.h> +#endif +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef SB_P_OS_CHORUS +#include "ttRand.h" +#endif +#endif + +#include <math.h> +#include <time.h> +#include <sql.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#if !defined NDB && !defined MYSQL +#include "ttTime.h" +#include "utils.h" +#include "tt_version.h" +#include "timesten.h" +#endif + +#if defined NDB || defined MYSQL +#include <NdbOut.hpp> +#include <string.h> + +#include <sqlext.h> +#include <sql.h> +extern "C" { +#include "ttTime.h" +#include "timesten.h" + void ttGetWallClockTime(ttWallClockTime* timeP); + void ttCalcElapsedWallClockTime(ttWallClockTime* beforeP, + ttWallClockTime* afterP, + double* nmillisecondsP); + void ttGetThreadTimes(ttThreadTimes * endRes); + void ttCalcElapsedThreadTimes(ttThreadTimes* startRes, + ttThreadTimes * endRes, + double * kernel, + double * user); +} + +#define app_exit exit +#define status_msg0 ndbout_c +#define status_msg1 ndbout_c +#define status_msg2 ndbout_c +#define err_msg0 ndbout_c +#define err_msg1 ndbout_c +#define err_msg3 ndbout_c +#define out_msg0 ndbout_c +#define out_msg1 ndbout_c +#define out_msg3 ndbout_c +#define CONN_STR_LEN 255 +#define DBMS_TIMESTEN 1 +#define DBMS_MSSQL 2 +#define DBMS_UNKNOWN 3 +#define ABORT_DISCONNECT_EXIT 1 +#define NO_EXIT 0 +#define ERROR_EXIT 1 +#define DISCONNECT_EXIT 2 +#endif + +#define VERBOSE_NOMSGS 0 +/* this value is used for results (and err msgs) only */ +#define VERBOSE_RESULTS 1 +/* this value is the default for the cmdline demo */ +#define VERBOSE_DFLT 2 +#define VERBOSE_ALL 3 + +#ifdef MYSQL +#define DSNNAME "DSN=myodbc3" +#elif defined NDB +#define DSNNAME "DSN=ndb" +#else +#define DSNNAME "DSN=" +#endif + +/* number of branches, tellers, and accounts */ + +#define NumBranches 1 +#define TellersPerBranch 10 +#define AccountsPerBranch 10000 + +/* number of transactions to execute */ + +#define NumXacts 25000 + +/* starting seed value for the random number generator */ + +#define SeedVal 84773 + +/* for MS SQL, the drop, create and use database statements */ + +#define DatabaseDropStmt "drop database tpcbDB;" +#ifdef MYSQL +#define DatabaseCreateStmt "create database tpcbDB;" +#else +#define DatabaseCreateStmt "create database tpcbDB ON DEFAULT = %d;" +#endif +#define DatabaseUseStmt "use tpcbDB;" + +/* + * Specifications of table columns. + * Fillers of 80, 80, 84, and 24 bytes, respectively, are used + * to ensure that rows are the width required by the benchmark. + * + * Note: The TimesTen and MS SQL CREATE TABLE statements for the + * accounts, tellers and branches tables are different. + * + */ + +#define TuplesPerPage 256 + + +#ifdef MYSQL + +#define AccountCrTblStmt "create table accounts \ +(number integer not null primary key, \ +branchnum integer not null, \ +balance float not null, \ +filler char(80));" + +#define TellerCrTblStmt "create table tellers \ +(number integer not null primary key, \ +branchnum integer not null, \ +balance float not null, \ +filler char(80));" + +#define BranchCrTblStmt "create table branches \ +(number integer not null primary key, \ +balance float not null, \ +filler char(84));" + +#endif + + +#ifdef NDB +#define AccountCrTblStmt "create table accounts \ +(number integer not null primary key, \ +branchnum integer not null, \ +balance float not null, \ +filler char(80)) nologging" + +#define TellerCrTblStmt "create table tellers \ +(number integer not null primary key, \ +branchnum integer not null, \ +balance float not null, \ +filler char(80)) nologging" + +#define BranchCrTblStmt "create table branches \ +(number integer not null primary key, \ +balance float not null, \ +filler char(84)) nologging" +#endif + +#ifdef NDB + +#define HistoryCrTblStmt "create table History \ +(tellernum integer not null, \ +branchnum integer not null, \ +accountnum integer not null, \ +delta float not null, \ +createtime integer not null, \ +filler char(24), \ +primary key (tellernum, branchnum, accountnum, delta, createtime)) nologging" + +#else + +#ifdef MYSQL + +#define HistoryCrTblStmt "create table History \ +(tellernum integer not null, \ +branchnum integer not null, \ +accountnum integer not null, \ +delta float(53) not null, \ +createtime integer not null, \ +filler char(24))" +#endif + +#define HistoryCrTblStmt "create table History \ +(tellernum integer not null, \ +branchnum integer not null, \ +accountnum integer not null, \ +delta float(53) not null, \ +createtime integer not null, \ +filler char(24));" +#endif + +#define TTAccountCrTblStmt "create table accounts \ +(number integer not null primary key, \ +branchnum integer not null, \ +balance float(53) not null, \ +filler char(80)) unique hash on (number) pages = %" PTRINT_FMT ";" + +#define TTTellerCrTblStmt "create table tellers \ +(number integer not null primary key, \ +branchnum integer not null, \ +balance float(53) not null, \ +filler char(80)) unique hash on (number) pages = %" PTRINT_FMT ";" + +#define TTBranchCrTblStmt "create table branches \ +(number integer not null primary key, \ +balance float(53) not null, \ +filler char(84)) unique hash on (number) pages = %" PTRINT_FMT ";" + + +/* Insertion statements used to populate the tables */ + +#define NumInsStmts 3 +char* insStmt[NumInsStmts] = { + "insert into branches values (?, 0.0, NULL)", + "insert into tellers values (?, ?, 0.0, NULL)", + "insert into accounts values (?, ?, 0.0, NULL)" +}; + +/* Transaction statements used to update the tables */ + +#define NumXactStmts 5 + +#ifdef NDB +char* tpcbXactStmt[NumXactStmts] = { + "update accounts \ +set balance = balance + ? \ +where number = ?", + + "select balance \ +from accounts \ +where number = ?", + + "update tellers \ +set balance = balance + ? \ +where number = ?", + + "update branches \ +set balance = balance + ? \ +where number = ?", + + "insert into History(tellernum, branchnum, \ +accountnum, delta, createtime, filler) \ +values (?, ?, ?, ?, ?, NULL)" +}; + +#else +char* tpcbXactStmt[NumXactStmts] = { + "update accounts \ +set balance = balance + ? \ +where number = ?;", + + "select balance \ +from accounts \ +where number = ?;", + + "update tellers \ +set balance = balance + ? \ +where number = ?;", + + "update branches \ +set balance = balance + ? \ +where number = ?;", + + "insert into History \ +values (?, ?, ?, ?, ?, NULL);" +}; + + +#endif + +/* Global parameters and flags (typically set by parse_args()) */ + +int tabFlag = 0; /* Default is NOT tab output mode */ +char szConnStrIn[CONN_STR_LEN]; /* ODBC Connection String */ +int printXactTimes = 0; /* Transaction statistics + * gathering flag */ +char statFile[FILENAME_MAX]; /* Transaction statistics filename */ +int scaleFactor = 2; /* Default TPS scale factor */ +int numBranchTups; /* Number of branches */ +int numTellerTups; /* Number of tellers */ +int numAccountTups; /* Number of accounts */ +int numNonLocalAccountTups; /* Number of local accounts */ +int numXacts = NumXacts; /* Default number of transactions */ +int verbose = VERBOSE_DFLT; /* Verbose level */ +FILE *statusfp; /* File for status messages */ + + + +int DBMSType; /* DBMS type (DBMS_TIMESTEN, DBMS_MSSQL...) */ + + +SQLHENV henv; /* Environment handle */ + + + + + + + +void handle_errors( SQLHDBC hdbc, SQLHSTMT hstmt, int errcode, int action, char * msg, + char * file, int line) { + + if (errcode == SQL_SUCCESS) + return; + + if(errcode == SQL_ERROR) { + int ret; + long diagCount=0; + short length=0; + SQLCHAR state[10] = ""; + SQLCHAR message[200] = ""; + long native = 0; + if(hstmt != 0) { + ret = SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &diagCount, SQL_IS_INTEGER, 0); + + for(long i = 0; i < diagCount; i++) { + ret = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, (SQLCHAR*)state, &native, (SQLCHAR*)message, 200, &length); + ndbout_c("GetDiagRec: Message : %s ", message); + } + } + } + + if(errcode != SQL_SUCCESS) { + ndbout_c("Message: %s", msg); + switch(errcode) { + case SQL_SUCCESS_WITH_INFO: + ndbout_c("SQL_SUCCESS_WITH_INFO"); + break; + case SQL_STILL_EXECUTING: + ndbout_c("SQL_STILL_EXECUTING"); + break; + case SQL_ERROR: + ndbout_c("SQL_ERROR"); + break; + case SQL_INVALID_HANDLE: + ndbout_c("SQL_INVALID_HANDLE"); + break; + default: + ndbout_c("Some other error"); + } + exit(1); + } + + +} + + + + + +/********************************************************************* + * FUNCTION: usage + * + * DESCRIPTION: This function prints a usage message describing + * the command line options of the program. + * + * PARAMETERS: char* prog full program path name + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +static void usage(char *prog) +{ + char *progname; + + /* Get the name of the program (sans path). */ + +#ifdef WIN32 + progname = strrchr(prog, '\\'); +#else + progname = strrchr(prog, '/'); +#endif + if (progname == 0) + progname = prog; + else + ++progname; + + /* Print the usage message */ + + fprintf(stderr, + "Usage:\t%s [-h] [-help] [-V] [-connStr <string>] [-v <level>]\n" + "\t\t[-xact <xacts>] [-scale <scale>] [-tabs] [-s <statfile>]\n\n" + " -h Prints this message and exits.\n" + " -help Same as -h.\n" + " -V Prints version number and exits.\n" + " -connStr <string> Specifies an ODBC connection string to replace the\n" + " default DSN for the program. The default is\n" + " \"DSN=TpcbData<version>;OverWrite=1\".\n" + " -v <level> Verbose level\n" + " 0 = errors only\n" + " 1 = results only\n" + " 2 = results and some status messages (default)\n" + " 3 = all messages\n" + " -xact <xacts> Specifies the number of transactions to be run\n" + " The default is 25000 transactions.\n" + " -scale <scale> Specifies a scale factor which determines the\n" + " number of branches (scale), tellers (scale x 10),\n" + " accounts (scale x 10000) and non-local accounts\n" + " ((scale-1) x 10000. The default scale factor is 2.\n" + " -tabs Specifies that the output be a tab-separated\n" + " format suitable for import into a spreadsheet.\n" + " Results only go to stdout; status and other\n" + " messages go to stderr.\n" + " -s <statfile> Prints individual transaction times to <statfile>.\n", + progname); +} + +/********************************************************************* + * + * FUNCTION: parse_args + * + * DESCRIPTION: This function parses the command line arguments + * passed to main(), setting the appropriate global + * variables and issuing a usage message for + * invalid arguments. + * + * PARAMETERS: int argc # of arguments from main() + * char *argv[] arguments from main() + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +parse_args(int argc, char *argv[]) +{ + int i = 1; + + *szConnStrIn = 0; + + while (i < argc) { + + if ( !strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") ) { + usage(argv[0]); + app_exit(0); + } + /* + if (!strcmp(argv[i], "-V")) { + printf("%s\n", TTVERSION_STRING); + app_exit(0); + } + */ + if (strcmp(argv[i], "-s") == 0) { + if (argc < i+2 ) { + usage(argv[0]); + app_exit(1); + } + if (sscanf(argv[i+1], "%s", statFile) == 0) { + usage(argv[0]); + app_exit(1); + } + printXactTimes = 1; + i += 2; + } + else if (!strcmp(argv[i], "-connStr")) { + if (argc < i+2 ) { + usage(argv[0]); + app_exit(1); + } + strcpy(szConnStrIn, argv[i+1]); + i += 2; + continue; + } + else if (strcmp("-v", argv[i]) == 0) { + if (argc < i+2 ) { + usage(argv[0]); + app_exit(1); + } + if (sscanf(argv[i+1], "%d", &verbose) == -1 || + verbose < 0 || verbose > 3) { + fprintf(stderr, "-v flag requires an integer parameter (0-3)\n"); + usage(argv[0]); + app_exit(1); + } + i += 2; + } + else if (strcmp("-xact",argv[i]) == 0) { + if (argc < i+2 ) { + usage(argv[0]); + app_exit(1); + } + + if (sscanf(argv[i+1], "%" PTRINT_FMT, &numXacts) == -1 || numXacts < 0) { + fprintf(stderr, "-xact flag requires a non-negative integer argument\n"); + usage(argv[0]); + app_exit(1); + } + + i += 2; + } + else if (strcmp("-scale",argv[i]) == 0) { + if (argc < i+2 ) { + usage(argv[0]); + app_exit(1); + } + if (sscanf(argv[i+1], "%d", &scaleFactor) == -1 || scaleFactor < 1) { + fprintf(stderr, "-scale flag requires an integer argument >= 1\n"); + usage(argv[0]); + app_exit(1); + } + /* Calculate tuple sizes */ + numBranchTups = NumBranches * scaleFactor; + numTellerTups = TellersPerBranch * scaleFactor; + numAccountTups = AccountsPerBranch * scaleFactor; + numNonLocalAccountTups = AccountsPerBranch * (scaleFactor-1); + i += 2; + } + else if (strcmp("-tabs",argv[i]) == 0) { + tabFlag = 1; + statusfp = stderr; + i += 1; + } + else { + usage(argv[0]); + app_exit(1); + } + } +} + +/********************************************************************* + * + * FUNCTION: doImmed + * + * DESCRIPTION: This function executes and frees the specified + * statement. It is used as a direct means to + * create the tables used by this benchmark, + * + * PARAMETERS: SQLHDBC hdbc SQL Connection handle + * SQLHSTMT hs SQL Statement handle + * char* cmd SQL Statement text + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +doImmed(SQLHDBC hdbc, SQLHSTMT hs, char* cmd) +{ + SQLRETURN rc; + + /* Execute the command */ + + rc = SQLExecDirect(hs, (SQLCHAR *) cmd, SQL_NTS); + handle_errors(hdbc, hs, rc, ABORT_DISCONNECT_EXIT, + "Error executing statement", __FILE__, __LINE__); + + /* Close associated cursor and drop pending results */ + + rc = SQLFreeStmt(hs, SQL_CLOSE); + handle_errors(hdbc, hs, rc, ABORT_DISCONNECT_EXIT, + "closing statement handle", + __FILE__, __LINE__); + +} + + +/********************************************************************* + * + * FUNCTION: main + * + * DESCRIPTION: This is the main function of the tpcb benchmark. + * It connects to an ODBC data source, creates and + * populates tables, updates the tables in a user- + * specified number of transactions and reports on + * on the transaction times. + * + * PARAMETERS: int argc # of command line arguments + * char *argv[] command line arguments + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +int +main(int argc, char *argv[]) +{ + + /* variables used for setting up the tables */ + + char cmdStr[1024]; + char errstr[4096]; + + /* variables used during transactions */ + + int accountNum; + int tellerNum; + int branchNum; + int timeStamp; + double delta; + unsigned int lrand; + unsigned short *srands, localLimit; + int lp64; + + /* variables used for timing and statistics */ + + int warmup; + double kernel, user, real; + ttThreadTimes startRes, endRes; + ttWallClockTime startT, endT; + ttWallClockTime** rtStart; + ttWallClockTime** rtEnd; + double** resTime; + double maxTime, totTime; + int i; + int j; + int numLocalXacts=0, numRemoteXacts=0; + + /* variables for ODBC */ + + SQLHDBC hdbc; + SQLHSTMT hstmt; + SQLHSTMT txstmt[NumXactStmts]; + SQLRETURN rc; + char DBMSName[32]; + char DBMSVersion[32]; + int databaseSize; + + int fThreadTime = 1; + +#ifdef WIN32 + OSVERSIONINFO sysInfo; + + sysInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx (&sysInfo); + + /* GetThreadTimes is not supported on 95/98. Hence, + we do not support Resource/User/System times */ + if (sysInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) + fThreadTime = 0; +#endif +#if defined(TTCLIENTSERVER) && defined(__hpux) && !defined(__LP64__) + /* HP requires this for C main programs that call aC++ shared libs */ + _main(); +#endif /* hpux32 */ + + /* Set up default signal handlers */ + +#ifndef NDB + /* StopRequestClear(); + if (HandleSignals() != 0) { + err_msg0("Unable to set signal handlers\n"); + return 1; + } + */ +#endif + /* set IO mode for demo */ + /* set_io_mode(); */ + + /* initialize the file for status messages */ + statusfp = stdout; + + /* set variable for 8-byte longs */ + lp64 = (sizeof(lrand) == 8); + + /* set the default tuple sizes */ + + numBranchTups = NumBranches * scaleFactor; + numTellerTups = TellersPerBranch * scaleFactor; + numAccountTups = AccountsPerBranch * scaleFactor; + numNonLocalAccountTups = AccountsPerBranch * (scaleFactor-1); + + /* parse the command arguments */ + parse_args(argc, argv); + + /* allocate the transaction-based variables */ + + rtStart = (ttWallClockTime**) malloc(numXacts * sizeof(ttWallClockTime*)); + if (!rtStart) { + err_msg0("Cannot allocate the transaction timing structures"); + app_exit(1); + } + for (i = 0; i < numXacts; i++) { + rtStart[i] = (ttWallClockTime*) malloc(sizeof(ttWallClockTime)); + if (!rtStart[i]) { + err_msg0("Cannot allocate the transaction timing structures"); + app_exit(1); + } + } + + rtEnd = (ttWallClockTime**) malloc(numXacts * sizeof(ttWallClockTime*)); + if (!rtEnd) { + err_msg0("Cannot allocate the transaction timing structures"); + app_exit(1); + } + for (i = 0; i < numXacts; i++) { + rtEnd[i] = (ttWallClockTime*) malloc(sizeof(ttWallClockTime)); + if (!rtEnd[i]) { + err_msg0("Cannot allocate the transaction timing structures"); + app_exit(1); + } + } + + resTime = (double**) malloc(numXacts * sizeof(double*)); + if (!resTime) { + err_msg0("Cannot allocate the transaction timing structures"); + app_exit(1); + } + for (i = 0; i < numXacts; i++) { + resTime[i] = (double*) malloc(sizeof(double)); + if (!resTime[i]) { + err_msg0("Cannot allocate the transaction timing structures"); + app_exit(1); + } + } + + /* ODBC initialization */ + + rc = SQLAllocEnv(&henv); + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + /* error occurred -- don't bother calling handle_errors, since handle + * is not valid so SQLError won't work */ + err_msg3("ERROR in %s, line %d: %s\n", + __FILE__, __LINE__, "allocating an environment handle"); + app_exit(1); + } + SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); + + /* call this in case of warning */ + handle_errors(NULL, NULL, rc, NO_EXIT, + "allocating execution environment", + __FILE__, __LINE__); + + rc = SQLAllocConnect(henv, &hdbc); + handle_errors(NULL, NULL, rc, ERROR_EXIT, + "allocating connection handle", + __FILE__, __LINE__); + + /* Connect to data store */ + + status_msg0("Connecting to the data source...\n"); + + /* Set up the connection options if not specified on the command line + * (default to TimesTen settings). + */ + + if ( !*szConnStrIn ) { + /* Running the benchmark with a scale factor creates (scale) branches, + * (scale x 10) tellers, (scale x 10000) accounts and ((scale-1) x 10000) + * non-local accounts. The size of the table rows are branches (141) + * tellers (141) and accounts (141). Therefore the data size requirements + * of this benchmark is: + * size ~= 141 * ((scale * 20011) - 10000) (bytes) + * + * Multiply data size by 20% to account for additional DB overhead (e.g. + * indexes), and round up the nearest 10Mb for safety. + */ + + int est_size = (int) (3.6 * scaleFactor + 10.0); + est_size = est_size - (est_size % 10); + + sprintf(szConnStrIn,"OverWrite=1;PermSize=%d;%s", + est_size, DSNNAME); + status_msg0("Connecting to the data source... %s \n", szConnStrIn); + } + + rc = SQLDriverConnect(hdbc, NULL, (SQLCHAR *) szConnStrIn, SQL_NTS, + NULL, 0, NULL, + SQL_DRIVER_NOPROMPT); + + status_msg0("Connected to the data source...\n"); + sprintf(errstr, "connecting to driver (connect string %s)\n", + szConnStrIn); + handle_errors(hdbc, NULL, rc, ERROR_EXIT, + errstr, __FILE__, __LINE__); + + /* Turn auto-commit off */ + + rc = SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + handle_errors(hdbc, NULL, rc, DISCONNECT_EXIT, + "switching off the AUTO_COMMIT option", + __FILE__, __LINE__); + + /* Allocate a statement handle */ + + rc = SQLAllocStmt(hdbc, &hstmt); + handle_errors(hdbc, NULL, rc, DISCONNECT_EXIT, + "allocating a statement handle", + __FILE__, __LINE__); + + /* (Implicit) Transaction begin */ + + /* Determine the DBMS Type*/ + + DBMSName[0] = '\0'; + rc = SQLGetInfo(hdbc, SQL_DBMS_NAME, (PTR) &DBMSName, + sizeof(DBMSName), NULL); + rc = SQLGetInfo(hdbc, SQL_DRIVER_VER, (PTR) &DBMSVersion, + sizeof(DBMSVersion), NULL); + + if (strcmp(DBMSName, "TimesTen") == 0) + DBMSType = DBMS_TIMESTEN; + else if (strcmp(DBMSName, "Microsoft SQL Server") == 0) + DBMSType = DBMS_MSSQL; + else DBMSType = DBMS_UNKNOWN; + + /* if not TimesTen: delete (if it exists), create & use the new database */ + + if (DBMSType != DBMS_TIMESTEN) { + status_msg0("Deleting the database...\n"); + rc = SQLExecDirect(hstmt, (SQLCHAR *) DatabaseDropStmt, SQL_NTS); + + /* estimate database size, size = data space + log space + * data space = (#tuples)/(tuples per page) * 2K bytes/page + * tuples per page = useable page size / row size (no index) = 2016/(96+2) + * log space = #transactions * average log size for the program transaction mix + * database size is in MB + */ + + databaseSize = (int) ceil((((numBranchTups + numTellerTups + numAccountTups)/ + (2016/98)) * 2048 + (numXacts * 600)) / 1000000.0); + + status_msg1("Creating the database (%dMB)...\n", databaseSize); +#ifndef NDB + sprintf(cmdStr, DatabaseCreateStmt, databaseSize); + doImmed(hdbc, hstmt, cmdStr); + strcpy(cmdStr, DatabaseUseStmt); + doImmed(hdbc, hstmt, cmdStr); +#endif + } + + status_msg2("Connected to '%s' version '%s'...\n", DBMSName, DBMSVersion); + + /* create branches table */ + status_msg0("Creating tasddbles...\n"); +#ifndef NDB + if (DBMSType == DBMS_TIMESTEN) + sprintf(cmdStr, TTBranchCrTblStmt, numBranchTups/TuplesPerPage + 1); + else +#endif + sprintf(cmdStr, BranchCrTblStmt); + doImmed(hdbc, hstmt, cmdStr); + + /* create tellers table */ +#ifndef NDB + if (DBMSType == DBMS_TIMESTEN) + sprintf(cmdStr, TTTellerCrTblStmt, numTellerTups/TuplesPerPage + 1); + + else +#endif + sprintf(cmdStr, TellerCrTblStmt); + doImmed(hdbc, hstmt, cmdStr); + + /* create accounts table */ +#ifndef NDB + if (DBMSType == DBMS_TIMESTEN) + sprintf(cmdStr, TTAccountCrTblStmt, numAccountTups/TuplesPerPage + 1); + else +#endif + sprintf(cmdStr, AccountCrTblStmt); + doImmed(hdbc, hstmt, cmdStr); + + /* create History table */ + + doImmed(hdbc, hstmt, HistoryCrTblStmt); + + /* lock the database during population */ +#ifndef NDB + if ( DBMSType == DBMS_TIMESTEN ) { + rc = SQLExecDirect(hstmt, (SQLCHAR *)"call ttlocklevel('DS')", SQL_NTS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "specifying dbs lock usage", + __FILE__, __LINE__); + /* make sure dbs lock take effect in next transaction */ + rc = SQLTransact(henv,hdbc,SQL_COMMIT); + if ( rc != SQL_SUCCESS) { + handle_errors(hdbc, SQL_NULL_HSTMT, rc, ERROR_EXIT, + "committing transaction", + __FILE__, __LINE__); + } + } +#endif + /* populate branches table */ + + + rc = SQLPrepare(hstmt, (SQLCHAR *) insStmt[0], SQL_NTS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "preparing statement", + __FILE__, __LINE__); + + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 10, 0, &branchNum, sizeof branchNum, NULL); + + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + + status_msg1("Populating branches table (%" PTRINT_FMT " rows)...\n", + numBranchTups); + + + for (i=0; i<numBranchTups; i++) { + branchNum = i; + rc = SQLExecute(hstmt); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "Error executing statement", + __FILE__, __LINE__); + } + + /* Reset all bind-parameters for the statement handle. */ + rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "resetting parms on statement handle", + __FILE__, __LINE__); + + /* populate tellers table */ + + status_msg1("Populating tellers table (%" PTRINT_FMT " rows)...\n", + numTellerTups); + + + rc = SQLPrepare(hstmt, (SQLCHAR *) insStmt[1], SQL_NTS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "preparing statement", + __FILE__, __LINE__); + + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, + 10, 0, &tellerNum, sizeof tellerNum, NULL); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, + 10, 0, &branchNum, sizeof branchNum, NULL); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + for (i=0; i<numTellerTups; i++) { + tellerNum = i; + branchNum = i/TellersPerBranch; + rc = SQLExecute(hstmt); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "Error executing statement", + __FILE__, __LINE__); + } + + /* Reset all bind-parameters for the statement handle. */ + + rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "resetting parms on statement handle", + __FILE__, __LINE__); + + /* populate accounts table */ + + status_msg1("Populating accounts table (%" PTRINT_FMT " rows)...\n", + numAccountTups); + + rc = SQLPrepare(hstmt, (SQLCHAR *) insStmt[2], SQL_NTS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "preparing statement", + __FILE__, __LINE__); + + rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, + 10, 0, &accountNum, sizeof accountNum, NULL); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, + 10, 0, &branchNum, sizeof branchNum, NULL); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + for (i=0; i<numAccountTups; i++) { + accountNum = i; + branchNum = i/AccountsPerBranch; + rc = SQLExecute(hstmt); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "Error executing statement", + __FILE__, __LINE__); + } + status_msg0("Commit...\n"); + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + status_msg0("Commit done...\n"); + handle_errors(hdbc, NULL, rc, ERROR_EXIT, + "committing transaction", + __FILE__, __LINE__); + + /* compile SQL statements of transaction */ + + status_msg0("Compiling statements of transaction...\n"); + for (i=0; i<NumXactStmts; i++) { +#ifndef NDB + rc = SQLAllocStmt(hdbc, &txstmt[i]); + handle_errors(hdbc, NULL, rc, ABORT_DISCONNECT_EXIT, + "allocating a statement handle", + __FILE__, __LINE__); +#else + rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &txstmt[i]); + handle_errors(hdbc, NULL, rc, ABORT_DISCONNECT_EXIT, + "allocating a statement handle", + __FILE__, __LINE__); + +#endif + + rc = SQLPrepare(txstmt[i], (SQLCHAR *) tpcbXactStmt[i], SQL_NTS); + handle_errors(hdbc, txstmt[i], rc, ABORT_DISCONNECT_EXIT, + "preparing statement", + __FILE__, __LINE__); + } + + /* unuse dbs lock */ +#ifndef NDB + if ( DBMSType == DBMS_TIMESTEN ) { + rc = SQLExecDirect(hstmt, (SQLCHAR *)"call ttlocklevel('Row')", SQL_NTS); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "specifying row lock usage", + __FILE__, __LINE__); + } +#endif + + /* commit transaction */ + + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + handle_errors(hdbc, NULL, rc, ERROR_EXIT, + "committing transaction", + __FILE__, __LINE__); + + + /* Initialize random seed and timers */ + + srand48(SeedVal); + localLimit = (unsigned short)((1<<16) * 0.85); + + /* Initialize parameter lists for each of the transactions */ + + rc = SQLBindParameter(txstmt[0], 1, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 15, 0, &delta, sizeof delta, NULL); + handle_errors(hdbc, txstmt[0], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[0], 2, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &accountNum, sizeof accountNum, + NULL); + handle_errors(hdbc, txstmt[0], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[1], 1, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &accountNum, sizeof accountNum, + NULL); + handle_errors(hdbc, txstmt[1], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[2], 1, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 15, 0, &delta, sizeof delta, NULL); + handle_errors(hdbc, txstmt[2], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[2], 2, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &tellerNum, sizeof tellerNum, + NULL); + handle_errors(hdbc, txstmt[2], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[3], 1, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 15, 0, &delta, sizeof delta, NULL); + handle_errors(hdbc, txstmt[3], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[3], 2, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &branchNum, sizeof branchNum, + NULL); + handle_errors(hdbc, txstmt[3], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[4], 1, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &tellerNum, sizeof tellerNum, + NULL); + handle_errors(hdbc, txstmt[4], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[4], 2, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &branchNum, sizeof branchNum, + NULL); + handle_errors(hdbc, txstmt[4], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[4], 3, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &accountNum, sizeof accountNum, + NULL); + handle_errors(hdbc, txstmt[4], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[4], 4, SQL_PARAM_INPUT, SQL_C_DOUBLE, + SQL_DOUBLE, 15, 0, &delta, sizeof delta, NULL); + handle_errors(hdbc, txstmt[4], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + rc = SQLBindParameter(txstmt[4], 5, SQL_PARAM_INPUT, SQL_C_SLONG, + SQL_INTEGER, 10, 0, &timeStamp, sizeof timeStamp, + NULL); + handle_errors(hdbc, txstmt[4], rc, ABORT_DISCONNECT_EXIT, + "binding parameter", + __FILE__, __LINE__); + + /* Execute transaction loop. + * Do it twice, once briefly as a warm-up. */ + + + + for (warmup = 1; warmup >= 0; warmup--) { + + int max_i = (warmup ? numXacts/10 : numXacts); + + /* Execute tpcb transaction max_i times.*/ + + if (warmup) { + status_msg1("\nWarming up with %d tpcb transactions...\n", max_i); + } + else { + status_msg1("Executing and timing %d tpcb transactions...\n", max_i); + } + + ttGetWallClockTime(&startT); + ttGetThreadTimes(&startRes); + + for (i = 0; i < max_i; i++) { + + lrand = lrand48(); + srands = (unsigned short *)(&lrand); + if (lp64) srands += 2; /* skip high half -- all zero */ + + /* randomly choose a teller */ + + tellerNum = srands[0] % numTellerTups; + + /* compute branch */ + + branchNum = (tellerNum / TellersPerBranch); + + /* randomly choose an account */ + + if (srands[1] < localLimit || numBranchTups == 1) { + + /* choose account local to selected branch */ + + accountNum = branchNum * AccountsPerBranch + + (lrand48() % AccountsPerBranch); + + ++numLocalXacts; + + } + else { + /* choose account not local to selected branch */ + + /* first select account in range [0,numNonLocalAccountTups) */ + + accountNum = lrand48() % numNonLocalAccountTups; + + /* if branch number of selected account is at least as big + * as local branch number, then increment account number + * by AccountsPerBranch to skip over local accounts + */ + + if ((accountNum/AccountsPerBranch) >= branchNum) + accountNum += AccountsPerBranch; + + ++numRemoteXacts; + } + + /* select delta amount, -999,999 to +999,999 */ + + delta = ((lrand48() % 1999999) - 999999); + + + /* begin timing the "residence time" */ + + ttGetWallClockTime(rtStart[i]); + + for ( j = 0; j < NumXactStmts - 2; j++) { + rc = SQLExecute(txstmt[j]); + handle_errors(hdbc, txstmt[j], rc, ABORT_DISCONNECT_EXIT, + "Error executing statement1", + __FILE__, __LINE__); + + /* Close the handle after the SELECT statement + * (txstmt[1]) for non TimesTen DBMS' */ + + if ((DBMSType != DBMS_TIMESTEN) && (j == 1)) { + SQLFreeStmt(txstmt[1], SQL_CLOSE); + } + + + } + + /* note that time must be taken within the */ + timeStamp = time(NULL); + + rc = SQLExecute(txstmt[NumXactStmts - 1]); + handle_errors(hdbc, txstmt[NumXactStmts - 1], rc, + ABORT_DISCONNECT_EXIT, "Error executing statement2", + __FILE__, __LINE__); + + rc = SQLTransact(henv, hdbc, SQL_COMMIT); + handle_errors(hdbc, NULL, rc, ERROR_EXIT, + "Error committing transaction", + __FILE__, __LINE__); + + ttGetWallClockTime(rtEnd[i]); + + } /* end fortransaction loop */ + + + + + ttGetThreadTimes(&endRes); + ttGetWallClockTime(&endT); + ttCalcElapsedThreadTimes(&startRes, &endRes, &kernel, &user); + ttCalcElapsedWallClockTime(&startT, &endT, &real); + + if (warmup) { + if (!tabFlag) { + if (verbose) { + if (fThreadTime) { + out_msg0(" time user system\n"); + + out_msg3("Warmup time (sec): %12.3f %12.3f %12.3f\n\n", + real/1000.0, user, kernel); + } else { + out_msg1("Warmup time (sec): %12.3f\n\n", real/1000.0); + } + } + } else { + if (verbose) { + if (fThreadTime) { + out_msg0("\ttime\tuser\tsystem\n"); + + out_msg3("Warmup time (sec):\t%12.3f\t%12.3f\t%12.3f\n", + real/1000.0, user, kernel); + } else { + out_msg1("Warmup time (sec):\t%12.3f\n", real/1000.0); + } + } + } + } + } + + status_msg0("\nExecution completed...\n"); + + /* Compute and report timing statistics */ + + maxTime = 0.0; + totTime = 0.0; + + for (i = 0; i < numXacts; i++) { + ttCalcElapsedWallClockTime(rtStart[i], rtEnd[i], resTime[i]); + totTime += *(resTime[i]); + + if (*(resTime[i]) > maxTime) maxTime = *(resTime[i]); + } + + if (!tabFlag) { + if (verbose) { + if (fThreadTime) { + out_msg0(" time user system\n"); + out_msg3("Total time (sec): %12.3f %12.3f %12.3f\n", + real/1000.0, user, kernel); + } else { + out_msg1("Total time (sec): %12.3f\n", real/1000.0); + } + } + + if (verbose) + out_msg1("\nAverage transaction time (msec):%12.3f\n", + totTime/numXacts); + if (verbose) + out_msg1("Maximum transaction time (msec):%12.3f\n", maxTime); + if (verbose) + out_msg1("\nLocal transactions: %7" PTRINT_FMT "\n", numLocalXacts); + if (verbose) + out_msg1("Remote transactions: %7" PTRINT_FMT "\n", numRemoteXacts); + + } else { + if (verbose) { + if (fThreadTime) { + out_msg0("\ttime\tuser\tsystem\n"); + out_msg3("Total time (sec):\t%12.3f\t%12.3f\t%12.3f\n", + real/1000.0, user, kernel); + } else { + out_msg1("Total time (sec):\t%12.3f\n", real/1000.0); + } + } + + if (verbose) + out_msg1("\nAverage transaction time (msec):\t%12.3f\n", + totTime/numXacts); + if (verbose) + out_msg1("Maximum transaction time (msec):\t%12.3f\n", maxTime); + if (verbose) + out_msg1("Local transactions:\t%7" PTRINT_FMT "\n", numLocalXacts); + + if (verbose) + out_msg1("Remote transactions:\t%7" PTRINT_FMT "\n", numRemoteXacts); + + + + } + + /* If the statfile option is selected, print each transaction's time */ + + if (printXactTimes) { + FILE * fp; + if ( (fp = fopen (statFile, "w")) == NULL ) { + err_msg1("Unable to open stat file %s for writing\n\n", statFile); + } else { + for (int i = 0; i < numXacts; i++) + fprintf(fp,"%6d: %12.3f\n", i, *(resTime[i])); + fclose(fp); + } + } + + /* Disconnect and return */ + + rc = SQLFreeStmt(hstmt, SQL_DROP); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "dropping the statement handle", + __FILE__, __LINE__); + + for (int i=0; i<NumXactStmts; i++) { + rc = SQLFreeStmt(txstmt[i], SQL_DROP); + handle_errors(hdbc, hstmt, rc, ABORT_DISCONNECT_EXIT, + "dropping the statement handle", + __FILE__, __LINE__); + } + + if (verbose >= VERBOSE_DFLT) + status_msg0("Disconnecting from the data source...\n"); + + rc = SQLDisconnect(hdbc); + handle_errors(hdbc, NULL, rc, ERROR_EXIT, + "disconnecting", + __FILE__, __LINE__); + + rc = SQLFreeConnect(hdbc); + handle_errors(hdbc, NULL, rc, ERROR_EXIT, + "freeing connection handle", + __FILE__, __LINE__); + + rc = SQLFreeEnv(henv); + handle_errors(NULL, NULL, rc, ERROR_EXIT, + "freeing environment handle", + __FILE__, __LINE__); + + app_exit(0); + return 0; +} + + + + + +/* Emacs variable settings */ +/* Local Variables: */ +/* tab-width:8 */ +/* indent-tabs-mode:nil */ +/* c-basic-offset:2 */ +/* End: */ + + + diff --git a/ndb/test/odbc/tpcb/ttTime.c b/ndb/test/odbc/tpcb/ttTime.c new file mode 100644 index 00000000000..8f10b0c6b91 --- /dev/null +++ b/ndb/test/odbc/tpcb/ttTime.c @@ -0,0 +1,366 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +static const volatile char cvsid[] = "$Id: ttTime.c,v 1.1 2003/09/23 12:43:46 johan Exp $"; +/* + * $Revision: 1.1 $ + * (c) Copyright 1996-2003, TimesTen, Inc. + * All rights reserved. + * + */ + + +/* Contains functions for performing elapsed-time calculations + in a portable manner */ + +#include "ttTime.h" + +#ifdef WIN32 + +#include <stdio.h> +#include <mapiutil.h> + +/*------------*/ +/* NT VERSION */ +/*------------*/ + +/********************************************************************* + * + * FUNCTION: ttGetThreadTimes + * + * DESCRIPTION: This function sets the supplied parameter's + * user and kernel time for the current thread. + * + * PARAMETERS: ttThreadTimes* timesP thread time structure + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +ttGetThreadTimes(ttThreadTimes* timesP) +{ + BOOL rc; + HANDLE curThread; + FILETIME creationTime; + FILETIME exitTime; + FILETIME kTime; + FILETIME uTime; + + memset (&kTime, 0, sizeof (FILETIME)); + memset (&uTime, 0, sizeof (FILETIME)); + + curThread = GetCurrentThread(); + rc = GetThreadTimes(curThread, + &creationTime, + &exitTime, + &kTime, + &uTime); + + timesP->kernelTime = kTime; + timesP->userTime = uTime; + +} + +/********************************************************************* + * + * FUNCTION: ttCalcElapsedThreadTimes + * + * DESCRIPTION: This function calculates the user and kernel + * time deltas. + * + * PARAMETERS: ttThreadTimes* beforeP beginning timestamp (IN) + * ttThreadTimes* afterP ending timestamp (IN) + * double* kernelDeltaP kernel time delta (OUT) + * double* userDeltaP user time delta (OUT) + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +ttCalcElapsedThreadTimes(ttThreadTimes* beforeP, + ttThreadTimes* afterP, + double* kernelDeltaP, + double* userDeltaP) +{ + static const double secPerHi = (double) 4.294967296; /* 2**32 * 10**-9 */ + FILETIME *before, *after; + + before = &beforeP->kernelTime; + after = &afterP->kernelTime; + *kernelDeltaP = (double) ((after->dwHighDateTime - before->dwHighDateTime) * secPerHi + + (after->dwLowDateTime - before->dwLowDateTime) * 100e-9); + before = &beforeP->userTime; + after = &afterP->userTime; + *userDeltaP = (double) ((after->dwHighDateTime - before->dwHighDateTime) * secPerHi + + (after->dwLowDateTime - before->dwLowDateTime) * 100e-9); +} + +/********************************************************************* + * + * FUNCTION: ttGetWallClockTime + * + * DESCRIPTION: This function gets the current wall-clock time. + * + * PARAMETERS: ttWallClockTime* timeP tms time structure (OUT) + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +ttGetWallClockTime(ttWallClockTime* timeP) +{ + LARGE_INTEGER frequency; + if ( QueryPerformanceFrequency(&frequency) ) { + QueryPerformanceCounter(&(timeP->time64)); + } + else { + _ftime(&(timeP->notSoLargeTime)); + } +} + +/********************************************************************* + * + * FUNCTION: ttCalcElapsedWallClockTime + * + * DESCRIPTION: This function calculates the elapsed wall-clock + * time in msec. + * + * PARAMETERS: ttWallClockTime* beforeP starting timestamp + * ttWallClockTime* afterP ending timestamp + * double* nmillisecondsP elapsed time (OUT) + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +ttCalcElapsedWallClockTime(ttWallClockTime* beforeP, + ttWallClockTime* afterP, + double* nmillisecondsP) +{ + LARGE_INTEGER frequency; + + if ( QueryPerformanceFrequency(&frequency) ) { + *nmillisecondsP = 1000 * ((double) (afterP->time64.QuadPart + - beforeP->time64.QuadPart)) + / frequency.QuadPart; + + } + else { + double start; + double end; + + start = (double) beforeP->notSoLargeTime.time * 1000. + + (double) beforeP->notSoLargeTime.millitm; + end = (double) afterP->notSoLargeTime.time * 1000. + + (double) afterP->notSoLargeTime.millitm; + + *nmillisecondsP = (double) (end - start); + } +} + +#elif defined (RTSYS_VXWORKS) + +/*-----------------*/ +/* VxWorks VERSION */ +/*-----------------*/ + +/* + * The TimeBase registers have a period of 60ns, i.e. + * 0.00000006 or (6e-8) seconds. + */ +#define TIMER_MSEC_PER_CYC (6e-5) + +void +ttGetWallClockTime(ttWallClockTime* timeP) +{ + vxTimeBaseGet(&timeP->sep.upper32, &timeP->sep.lower32); +} + + +void +ttCalcElapsedWallClockTime(ttWallClockTime* beforeP, + ttWallClockTime* afterP, + double* nmillisecondsP) +{ + *nmillisecondsP = (double)(afterP->val - beforeP->val) * TIMER_MSEC_PER_CYC; +} + + +#else + +/*--------------*/ +/* UNIX VERSION */ +/*--------------*/ + +#include <unistd.h> + +/********************************************************************* + * + * FUNCTION: ttGetThreadTimes + * + * DESCRIPTION: This function sets the supplied parameter's + * tms structure. + * + * PARAMETERS: ttThreadTimes* timesP tms time structure + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +#ifdef SB_P_OS_CHORUS +void ttGetThreadTimes(ttThreadTimes* timesP) +{ + KnCap actorCap; + + if (acap (agetId(), &actorCap) == -1) { + timesP->ins.tmSec = 0; + timesP->ins.tmNSec = 0; + timesP->ext.tmSec = 0; + timesP->ext.tmNSec = 0; + } + else { + (void) threadTimes (&actorCap, K_ALLACTORTHREADS, + ×P->ins, ×P->ext); + } +} +#else +void ttGetThreadTimes(ttThreadTimes* timesP) +{ + (void) times(timesP); +} +#endif + +/********************************************************************* + * + * FUNCTION: ttCalcElapsedThreadTimes + * + * DESCRIPTION: This function calculates the user and kernel + * time deltas. + * + * PARAMETERS: ttThreadTimes* beforeP beginning timestamp (IN) + * ttThreadTimes* afterP ending timestamp (IN) + * double* kernelDeltaP kernel time delta (OUT) + * double* userDeltaP user time delta (OUT) + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +#ifdef SB_P_OS_CHORUS +void +ttCalcElapsedThreadTimes(ttThreadTimes* beforeP, + ttThreadTimes* afterP, + double* kernelDeltaP, + double* userDeltaP) +{ + double kernelBefore; + double kernelAfter; + double userBefore; + double userAfter; + + kernelBefore = (beforeP->ext.tmSec) + (beforeP->ext.tmNSec / 1e9); + kernelAfter = (afterP->ext.tmSec) + (afterP->ext.tmNSec / 1e9); + *kernelDeltaP = kernelAfter - kernelBefore; + + userBefore = (beforeP->ins.tmSec) + (beforeP->ins.tmNSec / 1e9); + userAfter = (afterP->ins.tmSec) + (afterP->ins.tmNSec / 1e9); + *userDeltaP = userAfter - userBefore; + +} +#else +void +ttCalcElapsedThreadTimes(ttThreadTimes* beforeP, + ttThreadTimes* afterP, + double* kernelDeltaP, + double* userDeltaP) +{ + double ticks = (double)sysconf(_SC_CLK_TCK); + + *kernelDeltaP = (afterP->tms_stime - beforeP->tms_stime) / ticks; + *userDeltaP = (afterP->tms_utime - beforeP->tms_utime) / ticks; +} +#endif + +/********************************************************************* + * + * FUNCTION: ttGetWallClockTime + * + * DESCRIPTION: This function gets the current wall-clock time. + * + * PARAMETERS: ttWallClockTime* timeP tms time structure (OUT) + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +ttGetWallClockTime(ttWallClockTime* timeP) +{ + gettimeofday(timeP, NULL); +} + +/********************************************************************* + * + * FUNCTION: ttCalcElapsedWallClockTime + * + * DESCRIPTION: This function calculates the elapsed wall-clock + * time is msec. + * + * PARAMETERS: ttWallClockTime* beforeP starting timestamp + * ttWallClockTime* afterP ending timestamp + * double* nmillisecondsP elapsed time (OUT) + * + * RETURNS: void + * + * NOTES: NONE + * + *********************************************************************/ + +void +ttCalcElapsedWallClockTime(ttWallClockTime* beforeP, + ttWallClockTime* afterP, + double* nmillisP) +{ + *nmillisP = (afterP->tv_sec - beforeP->tv_sec)*1000.0 + + (afterP->tv_usec - beforeP->tv_usec)/1000.0; +} + +#endif + +/* Emacs variable settings */ +/* Local Variables: */ +/* tab-width:8 */ +/* indent-tabs-mode:nil */ +/* c-basic-offset:2 */ +/* End: */ diff --git a/ndb/test/odbc/tpcb/ttTime.h b/ndb/test/odbc/tpcb/ttTime.h new file mode 100644 index 00000000000..f78b71667fe --- /dev/null +++ b/ndb/test/odbc/tpcb/ttTime.h @@ -0,0 +1,125 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + * $Revision: 1.1 $ + * (c) Copyright 1996-2003, TimesTen, Inc. + * All rights reserved. + * + */ + +#ifndef __TT_TIME +#define __TT_TIME + + +#ifdef WIN32 + +#include <windows.h> +#include <sys/types.h> +#include <sys/timeb.h> + +typedef struct { + FILETIME kernelTime; + FILETIME userTime; +} ttThreadTimes; + + +typedef union { + LARGE_INTEGER time64; + struct _timeb notSoLargeTime; +} ttWallClockTime; + +#elif defined(RTSYS_VXWORKS) + +#define srand48(x) sb_srand48((x)) +#define drand48() sb_drand48() + +#ifdef SB_P_OS_VXPPC +/* For little-endian switch the lower, upper fields */ +typedef union { + struct { + unsigned int upper32; + unsigned int lower32; + } sep; + long long val; +} ttWallClockTime; + +/* + * This is a VxWorks private function to read the PPC's 64 bit Time Base + * Register. This is the assembler dump of this function. + 001126e4 7cad42e6 mftb r5, TBU + 001126e8 7ccc42e6 mftb r6, TBL + 001126ec 7ced42e6 mftb r7, TBU + 001126f0 7c053800 cmp crf0, 0, r5, r7 + 001126f4 4082fff0 bc 0x4, 0x2, vxTimeBaseGet + 001126f8 90a30000 stw r5, 0x0(r3) + 001126fc 90c40000 stw r6, 0x0(r4) + 00112700 4e800020 blr + * This is a fine grained timer with a period of 60ns. + */ +void vxTimeBaseGet(unsigned int* pUpper32, unsigned int* pLower32); +#endif /* SB_P_OS_VXPPC */ + +#elif defined(SB_P_OS_CHORUS) +#include <sys/types.h> +#include <sys/times.h> +#include <sys/time.h> + +#include <vtimer/chVtimer.h> + +struct chrTimes { + KnTimeVal ins; + KnTimeVal ext; +}; +typedef struct chrTimes ttThreadTimes; + +typedef struct timeval ttWallClockTime; + +#else +/* UNIX version */ + +#include <sys/times.h> +#include <sys/time.h> + +typedef struct tms ttThreadTimes; + +typedef struct timeval ttWallClockTime; + +#endif /* NT, VxWorks, Chorus, Unix */ + + +#ifndef RTSYS_VXWORKS +void ttGetThreadTimes(ttThreadTimes* timesP); +void ttCalcElapsedThreadTimes(ttThreadTimes* beforeP, ttThreadTimes* afterP, + double* kernelDeltaP, double* userDeltaP); +#endif /* ! VXWORKS */ +void ttGetWallClockTime(ttWallClockTime* timeP); +void ttCalcElapsedWallClockTime(ttWallClockTime* beforeP, + ttWallClockTime* afterP, + double* nmillisecondsP); + + + + + +#endif /* __TT_TIME */ + +/* Emacs variable settings */ +/* Local Variables: */ +/* tab-width:8 */ +/* indent-tabs-mode:nil */ +/* c-basic-offset:2 */ +/* End: */ |