dev/bench/odbc/main.cc (168 lines of code) (raw):
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <stdio.h>
#include <string.h>
#include <chrono>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#define ERRMSG_LEN 200
SQLINTEGER checkError(SQLRETURN rc, SQLSMALLINT handleType, SQLHANDLE handle,
SQLWCHAR* errmsg) {
SQLRETURN retcode = SQL_SUCCESS;
SQLSMALLINT errNum = 1;
SQLCHAR sqlState[6]; // always exactly 5 characters + NUL
SQLINTEGER nativeError;
SQLCHAR errMsg[ERRMSG_LEN];
SQLSMALLINT textLengthPtr;
if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO) && (rc != SQL_NO_DATA)) {
SQLLEN numRecs = 0;
SQLGetDiagField(SQL_HANDLE_STMT, handle, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
while (retcode != SQL_NO_DATA) {
retcode = SQLGetDiagRecA(handleType, handle, errNum, sqlState, &nativeError, errMsg,
ERRMSG_LEN, &textLengthPtr);
if (retcode == SQL_INVALID_HANDLE) {
std::cerr << "checkError function was called with an invalid handle!!"
<< std::endl;
return 1;
}
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) {
wprintf(L"ERROR: %d: %ls : %ls\n", nativeError, sqlState, errMsg);
}
errNum++;
}
wprintf(L"%ls\n", errmsg);
return 1;
}
return 0;
}
#define CHECK_OK(EXPR, ERROR) \
do { \
auto ret = (EXPR); \
if (checkError(ret, SQL_HANDLE_DBC, dbc, (SQLWCHAR*)L##ERROR)) { \
exit(1); \
} \
} while (0)
int main(int argc, char** argv) {
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLHSTMT stmt1;
if (argc != 2) {
std::cerr << "Expected exactly 1 argument: the DSN for connecting, got " << argc - 1
<< "arguments. exiting...";
return 1;
}
std::string dsn(argv[1]);
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
// we want ODBC3 support, set env handle
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3_80), 0);
// allocate connection handle
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
// connect to the DSN using dbc handle
CHECK_OK(SQLDriverConnectA(dbc, nullptr,
reinterpret_cast<SQLCHAR*>(const_cast<char*>(dsn.c_str())),
SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_COMPLETE),
"Error -- Driver Connect failed");
std::ofstream timing_output("odbc_perf_record");
for (size_t iter = 0; iter < 100; iter++) {
CHECK_OK(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt),
"Error -- Statement handle alloc failed");
const auto start{std::chrono::steady_clock::now()};
CHECK_OK(SQLExecDirect(
stmt,
(SQLCHAR*)"SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1000.LINEITEM "
"LIMIT 100000000",
SQL_NTS),
"Error -- Statement execution failed");
const SQLULEN bulkSize = 10000;
CHECK_OK(SQLSetStmtAttr(stmt, SQL_ATTR_ROW_ARRAY_SIZE,
reinterpret_cast<SQLPOINTER>(bulkSize), 0),
"Error -- SetStmtAttr failed");
// bind columns to buffers
SQLINTEGER val_orderkey[bulkSize];
SQLINTEGER val_partkey[bulkSize];
SQLINTEGER val_suppkey[bulkSize];
SQLINTEGER val_linenumber[bulkSize];
SQLDOUBLE val_quantity[bulkSize];
SQLDOUBLE val_extendedprice[bulkSize];
SQLDOUBLE val_discount[bulkSize];
SQLDOUBLE val_tax[bulkSize];
SQLCHAR val_retflag[bulkSize][2];
SQLCHAR val_linestatus[bulkSize][2];
SQL_DATE_STRUCT val_shipdate[bulkSize];
SQL_DATE_STRUCT val_commitdate[bulkSize];
SQL_DATE_STRUCT val_receiptdate[bulkSize];
SQLCHAR val_shipinstruct[bulkSize][26];
SQLCHAR val_shipmode[bulkSize][11];
SQLCHAR val_comment[bulkSize][45];
CHECK_OK(SQLBindCol(stmt, 1, SQL_C_LONG, reinterpret_cast<SQLPOINTER>(val_orderkey),
sizeof(val_orderkey), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 2, SQL_C_LONG, reinterpret_cast<SQLPOINTER>(val_partkey),
sizeof(val_partkey), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 3, SQL_C_LONG, reinterpret_cast<SQLPOINTER>(val_suppkey),
sizeof(val_suppkey), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 4, SQL_C_LONG, reinterpret_cast<SQLPOINTER>(val_linenumber),
sizeof(val_linenumber), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 5, SQL_C_DOUBLE, reinterpret_cast<SQLPOINTER>(val_quantity),
sizeof(val_quantity), nullptr),
"BindCol failed");
CHECK_OK(
SQLBindCol(stmt, 6, SQL_C_DOUBLE, reinterpret_cast<SQLPOINTER>(val_extendedprice),
sizeof(val_extendedprice), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 7, SQL_C_DOUBLE, reinterpret_cast<SQLPOINTER>(val_discount),
sizeof(val_discount), nullptr),
"BindCol failed");
CHECK_OK(
SQLBindCol(stmt, 8, SQL_C_DOUBLE, (SQLPOINTER)val_tax, sizeof(val_tax), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 9, SQL_C_CHAR, (SQLPOINTER)val_retflag,
sizeof(val_retflag[0]), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 10, SQL_C_CHAR, (SQLPOINTER)val_linestatus,
sizeof(val_linestatus[0]), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 11, SQL_C_DATE, (SQLPOINTER)val_shipdate,
sizeof(val_shipdate), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 12, SQL_C_DATE, (SQLPOINTER)val_commitdate,
sizeof(val_commitdate), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 13, SQL_C_DATE, (SQLPOINTER)val_receiptdate,
sizeof(val_receiptdate), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 14, SQL_C_CHAR, (SQLPOINTER)val_shipinstruct,
sizeof(val_shipinstruct[0]), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 15, SQL_C_CHAR, (SQLPOINTER)val_shipmode,
sizeof(val_shipmode[0]), nullptr),
"BindCol failed");
CHECK_OK(SQLBindCol(stmt, 16, SQL_C_CHAR, (SQLPOINTER)val_comment,
sizeof(val_comment[0]), nullptr),
"BindCol failed");
SQLRETURN ret;
while (true) {
ret = SQLFetch(stmt);
if (checkError(ret, SQL_HANDLE_DBC, dbc, (SQLWCHAR*)L"fetch failed")) {
exit(1);
}
if (ret == SQL_NO_DATA) break;
}
const auto end{std::chrono::steady_clock::now()};
const std::chrono::duration<double> elapsed{end - start};
timing_output << elapsed.count() << std::endl;
SQLFreeStmt(stmt, SQL_CLOSE);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
if (iter % 10 == 0) {
std::cout << "Run " << iter << std::endl;
std::cout << "\tRuntime: " << elapsed.count() << " s" << std::endl;
}
}
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
}