static int do_stmt(Con& con, const char *sqlstr) { SQLHSTMT hstmt; SQLCHAR errmsg[256]; SQLCHAR colname[32]; SQLSMALLINT coltype; SQLSMALLINT colnamelen; SQLSMALLINT nullable; SQLUINTEGER collen[MAXCOLS]; SQLSMALLINT scale; SQLINTEGER outlen[MAXCOLS]; SQLCHAR *data[MAXCOLS]; SQLSMALLINT nresultcols = 0; SQLINTEGER rowcount; SQLINTEGER stmttype; SQLRETURN rc; /* allocate a statement handle */ SQLAllocHandle(SQL_HANDLE_STMT, con.hdbc, &hstmt); /* execute the SQL statement */ rc = SQLExecDirect(hstmt, (SQLCHAR*)sqlstr, SQL_NTS); if (rc == SQL_ERROR) { ndbout << "Operation failed" << endl; print_err(SQL_HANDLE_STMT, hstmt); return -1; } if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA_FOUND) { ndbout << "Operation returned unknown code " << rc << endl; return -1; } /* see what kind of statement it was */ SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_DYNAMIC_FUNCTION_CODE, (SQLPOINTER)&stmttype, SQL_IS_INTEGER, (SQLSMALLINT *)NULL); switch (stmttype) { /* SELECT statement */ case SQL_DIAG_SELECT_CURSOR: /* determine number of result columns */ SQLNumResultCols(hstmt, &nresultcols); /*********************** * Display column names ***********************/ /* Print vertical divider */ printf("|"); for (int i=0; i<nresultcols; i++) { SQLDescribeCol(hstmt, i+1, colname, sizeof(colname), &colnamelen, &coltype, &collen[i], &scale, &nullable); collen[i] = display_length(coltype, collen[i], colname); for (SQLUINTEGER j=0; j<collen[i]; j++) printf("-"); printf("--+"); } printf("\n"); printf("|"); for (int i=0; i<nresultcols; i++) { SQLDescribeCol(hstmt, i+1, colname, sizeof(colname), &colnamelen, &coltype, &collen[i], &scale, &nullable); /* assume there is a display_length function which computes correct length given the data type */ collen[i] = display_length(coltype, collen[i], colname); (void)printf(" %*.*s |", (int)collen[i], (int)collen[i], (char *)colname); /* allocate memory to bind column */ data[i] = (SQLCHAR *) malloc(collen[i]); if (data[i] == NULL) { ndbout << "Failed to allocate malloc memory in NDB SQL program" << endl; exit(-1); } /* bind columns to program vars, converting all types to CHAR */ SQLBindCol(hstmt, i+1, SQL_C_CHAR, data[i], collen[i], &outlen[i]); } printf("\n"); /* Print vertical divider */ printf("|"); for (int i=0; i<nresultcols; i++) { SQLDescribeCol(hstmt, i+1, colname, sizeof(colname), &colnamelen, &coltype, &collen[i], &scale, &nullable); collen[i] = display_length(coltype, collen[i], colname); for (SQLUINTEGER j=0; j<collen[i]; j++) printf("-"); printf("--+"); } printf("\n"); /********************** * Display result rows **********************/ { int no_of_rows_fetched=0; while (1) { rc=SQLFetch(hstmt); errmsg[0] = '\0'; if (rc == SQL_ERROR) { print_err(SQL_HANDLE_STMT, hstmt); break; } if (rc == SQL_NO_DATA) break; if (rc == SQL_SUCCESS) { printf("|"); for (int i=0; i<nresultcols; i++) { if (outlen[i] == SQL_NULL_DATA || outlen[i] >= (SQLINTEGER) collen[i]) build_indicator_message(errmsg, (SQLPOINTER *)data[i], collen[i], &outlen[i], i); (void)printf(" %*.*s |", (int)collen[i], (int)collen[i], (char *)data[i]); } /* print any truncation messages */ (void)printf("\n%s", (char *)errmsg); } else if (rc == SQL_SUCCESS_WITH_INFO) { printf("|"); for (int i=0; i<nresultcols; i++) { if (outlen[i] == SQL_NULL_DATA || outlen[i] >= (SQLINTEGER) collen[i]) build_indicator_message(errmsg, (SQLPOINTER *)data[i], collen[i], &outlen[i], i); (void)printf(" %*.*s |", (int)collen[i], (int)collen[i], (char *)data[i]); } /* for all columns in this row */ /* print any truncation messages */ (void)printf("\n%s", (char *)errmsg); } no_of_rows_fetched++; } /* while rows to fetch */ /* Print vertical divider */ printf("|"); for (int i=0; i<nresultcols; i++) { SQLDescribeCol(hstmt, i+1, colname, sizeof(colname), &colnamelen, &coltype, &collen[i], &scale, &nullable); collen[i] = display_length(coltype, collen[i], colname); for (SQLUINTEGER j=0; j<collen[i]; j++) printf("-"); printf("--+"); } printf("\n"); ndbout << no_of_rows_fetched << " rows fetched" << endl; } SQLCloseCursor(hstmt); break; /* searched DELETE, INSERT or searched UPDATE statement */ case SQL_DIAG_DELETE_WHERE: case SQL_DIAG_INSERT: case SQL_DIAG_UPDATE_WHERE: /* check rowcount */ SQLRowCount(hstmt, (SQLINTEGER*)&rowcount); ndbout << (int)rowcount << " rows affected" << endl; break; /* other statements */ case SQL_DIAG_ALTER_TABLE: case SQL_DIAG_CREATE_TABLE: case SQL_DIAG_CREATE_VIEW: case SQL_DIAG_DROP_TABLE: case SQL_DIAG_DROP_VIEW: case SQL_DIAG_CREATE_INDEX: case SQL_DIAG_DROP_INDEX: case SQL_DIAG_DYNAMIC_DELETE_CURSOR: case SQL_DIAG_DYNAMIC_UPDATE_CURSOR: case SQL_DIAG_GRANT: case SQL_DIAG_REVOKE: ndbout << "Operation successful" << endl; break; /* implementation-defined statement */ default: (void)printf("Unknown Statement type=%ld\n", stmttype); break; } /* free data buffers */ for (int i=0; i<nresultcols; i++) { (void)free(data[i]); } SQLFreeHandle(SQL_HANDLE_STMT, hstmt); // free statement handle return(0); }
/*-----------------------------------------------------------------------------*/ void ODBCDescribeSelect() { int j; UCHAR colname[50]; SWORD colnamelen; SWORD scale; SWORD nullable; UDWORD collen; struct Cursor *cur = (struct Cursor *)ptoc_int(2); cur->NumCols = 0; SQLNumResultCols(cur->hstmt, (SQLSMALLINT*)&(cur->NumCols)); if (!(cur->NumCols)) { /* no columns are affected, set cursor status to unused */ cur->Status = 1; ctop_int(3,2); return; } /* if we aren't reusing a closed statement handle, we need to get*/ /* resulting rowset info and allocate memory for it*/ if (cur->Status != 2) { cur->ColTypes = (SWORD *)malloc(sizeof(SWORD) * cur->NumCols); if (!cur->ColTypes) xsb_exit("Not enough memory for ColTypes!"); cur->Data = (UCHAR **)malloc(sizeof(char *) * cur->NumCols); if (!cur->Data) xsb_exit("Not enough memory for Data!"); cur->OutLen = (UDWORD *)malloc(sizeof(UDWORD) * cur->NumCols); if (!cur->OutLen) xsb_exit("Not enough memory for OutLen!"); cur->ColLen = (UDWORD *)malloc(sizeof(UDWORD) * cur->NumCols); if (!cur->ColLen) xsb_exit("Not enough memory for ColLen!"); for (j = 0; j < cur->NumCols; j++) { SQLDescribeCol(cur->hstmt, (short)(j+1), (UCHAR FAR*)colname, sizeof(colname), &colnamelen, &(cur->ColTypes[j]), &collen, &scale, &nullable); /* SQLServer returns this wierd type for a system table, treat it as varchar?*/ if (cur->ColTypes[j] == -9) cur->ColTypes[j] = SQL_VARCHAR; colnamelen = (colnamelen > 49) ? 49 : colnamelen; colname[colnamelen] = '\0'; if (!(cur->ColLen[j] = DisplayColSize(cur->ColTypes[j],collen,colname))) { /* let SetCursorClose function correctly free all the memory allocated*/ /* for Data storage: cur->Data[j]'s*/ cur->NumCols = j; /* set so close frees memory allocated thus far*/ SetCursorClose(cur); /* return(1);*/ ctop_int(3,1); return; } cur->Data[j] = (UCHAR *) malloc(((unsigned) cur->ColLen[j]+1)*sizeof(UCHAR)); if (!cur->Data[j]) xsb_exit("Not enough memory for Data[j]!"); } } /* bind them*/ for (j = 0; j < cur->NumCols; j++) { SQLBindCol(cur->hstmt, (short)(j+1), ODBCToXSBType(cur->ColTypes[j]), cur->Data[j], cur->ColLen[j], (SDWORD FAR *)(&(cur->OutLen[j]))); } /* return 0;*/ ctop_int(3,0); return; }