| /* |
| * 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. |
| */ |
| |
| #ifdef _WIN32 |
| #include <windows.h> |
| #endif |
| |
| #include <sql.h> |
| #include <sqlext.h> |
| |
| #include <iostream> |
| #include <iomanip> |
| #include <vector> |
| #include <string> |
| #include <sstream> |
| |
| #include "ignite/ignite.h" |
| #include "ignite/ignition.h" |
| |
| #include "ignite/examples/person.h" |
| #include "ignite/examples/organization.h" |
| |
| using namespace ignite; |
| |
| using namespace examples; |
| |
| /** |
| * This example populates cache with sample data and runs several SQL queries |
| * over this data using system ODBC API and Apache Ignite ODBC driver. |
| * |
| * To run this example you should first install ODBC driver as described in |
| * README file for the ODBC driver project. |
| * |
| * After all pre-requirements are fulfilled just build project as described |
| * in README and run resulting file. |
| * |
| * Note, that all fields which used in queries must be listed in config file |
| * under queryEntities property of the caches. You can find config file in |
| * config directory: cpp/examples/odbc-example/config/example-odbc.xml |
| * |
| * In addition to all the fields listed under QueryEntity bean, each table |
| * have two special predefined fields: _key and _val, which represent links |
| * to whole key and value objects. In some queries _key column is used. Key |
| * in our case works like an ID for the row and it should always present in |
| * INSERT statements. |
| */ |
| |
| /** Read buffer size. */ |
| enum { ODBC_BUFFER_SIZE = 1024 }; |
| |
| /** |
| * Represents simple string buffer. |
| */ |
| struct OdbcStringBuffer |
| { |
| SQLCHAR buffer[ODBC_BUFFER_SIZE]; |
| SQLLEN reallen; |
| }; |
| |
| /** |
| * Print result set returned by query. |
| * |
| * @param stmt Statement. |
| */ |
| void PrintOdbcResultSet(SQLHSTMT stmt) |
| { |
| SQLSMALLINT columnsCnt = 0; |
| |
| // Getting number of columns in result set. |
| SQLNumResultCols(stmt, &columnsCnt); |
| |
| std::vector<OdbcStringBuffer> columns(columnsCnt); |
| |
| // Binding colums. |
| for (SQLSMALLINT i = 0; i < columnsCnt; ++i) |
| SQLBindCol(stmt, i + 1, SQL_CHAR, columns[i].buffer, ODBC_BUFFER_SIZE, &columns[i].reallen); |
| |
| while (true) |
| { |
| SQLRETURN ret = SQLFetch(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| break; |
| |
| std::cout << ">>> "; |
| |
| for (size_t i = 0; i < columns.size(); ++i) |
| std::cout << std::setw(16) << std::left << columns[i].buffer << " "; |
| |
| std::cout << std::endl; |
| } |
| } |
| |
| /** |
| * Extract error message. |
| * |
| * @param handleType Type of the handle. |
| * @param handle Handle. |
| * @return Error message. |
| */ |
| std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle) |
| { |
| SQLCHAR sqlstate[7] = {}; |
| SQLINTEGER nativeCode; |
| |
| SQLCHAR message[ODBC_BUFFER_SIZE]; |
| SQLSMALLINT reallen = 0; |
| |
| SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen); |
| |
| return std::string(reinterpret_cast<char*>(sqlstate)) + ": " + |
| std::string(reinterpret_cast<char*>(message), reallen); |
| } |
| |
| /** |
| * Extract error from ODBC handle and throw it as IgniteError. |
| * |
| * @param handleType Type of the handle. |
| * @param handle Handle. |
| * @param msg Error message. |
| */ |
| void ThrowOdbcError(SQLSMALLINT handleType, SQLHANDLE handle, std::string msg) |
| { |
| std::stringstream builder; |
| |
| builder << msg << ": " << GetOdbcErrorMessage(handleType, handle); |
| |
| std::string errorMsg = builder.str(); |
| |
| throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, errorMsg.c_str()); |
| } |
| |
| /** |
| * Fetch cache data using ODBC interface. |
| */ |
| void GetDataWithOdbc(SQLHDBC dbc, const std::string& query) |
| { |
| SQLHSTMT stmt; |
| |
| // Allocate a statement handle |
| SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); |
| |
| std::vector<SQLCHAR> buf(query.begin(), query.end()); |
| |
| SQLRETURN ret = SQLExecDirect(stmt, &buf[0], static_cast<SQLSMALLINT>(buf.size())); |
| |
| if (SQL_SUCCEEDED(ret)) |
| PrintOdbcResultSet(stmt); |
| else |
| std::cerr << "Failed to execute query: " << GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt) << std::endl; |
| |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| } |
| |
| /** |
| * Populate Person cache with sample data. |
| * |
| * @param dbc Database connection. |
| */ |
| void PopulatePerson(SQLHDBC dbc) |
| { |
| SQLHSTMT stmt; |
| |
| // Allocate a statement handle |
| SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle"); |
| |
| try |
| { |
| SQLCHAR query[] = |
| "INSERT INTO Person (id, orgIdAff, orgId, firstName, lastName, resume, salary) " |
| "VALUES (?, ?, ?, ?, ?, ?, ?)"; |
| |
| ret = SQLPrepare(stmt, query, static_cast<SQLSMALLINT>(sizeof(query))); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to prepare query"); |
| |
| // Binding columns. |
| |
| int64_t keyId = 0; |
| int64_t keyOrgIdAff = 0; |
| |
| int64_t orgId = 0; |
| char firstName[1024] = { 0 }; |
| SQLLEN firstNameLen = SQL_NTS; |
| char lastName[1024] = { 0 }; |
| SQLLEN lastNameLen = SQL_NTS; |
| char resume[1024] = { 0 }; |
| SQLLEN resumeLen = SQL_NTS; |
| double salary = 0.0; |
| |
| ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &keyId, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &keyOrgIdAff, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &orgId, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, |
| sizeof(firstName), sizeof(firstName), firstName, 0, &firstNameLen); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, |
| sizeof(lastName), sizeof(lastName), lastName, 0, &lastNameLen); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, |
| sizeof(resume), sizeof(resume), resume, 0, &resumeLen); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &salary, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| // Filling cache. |
| keyId = 1; |
| keyOrgIdAff = 1; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "John", sizeof(firstName)); |
| strncpy(lastName, "Doe", sizeof(lastName)); |
| strncpy(resume, "Master Degree.", sizeof(resume)); |
| salary = 2200.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 1; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "Jane", sizeof(firstName)); |
| strncpy(lastName, "Doe", sizeof(lastName)); |
| strncpy(resume, "Bachelor Degree.", sizeof(resume)); |
| salary = 1300.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 2; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "John", sizeof(firstName)); |
| strncpy(lastName, "Smith", sizeof(lastName)); |
| strncpy(resume, "Bachelor Degree.", sizeof(resume)); |
| salary = 1700.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 2; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "Jane", sizeof(firstName)); |
| strncpy(lastName, "Smith", sizeof(lastName)); |
| strncpy(resume, "Master Degree.", sizeof(resume)); |
| salary = 2500.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 2; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "John", sizeof(firstName)); |
| strncpy(lastName, "Roe", sizeof(lastName)); |
| strncpy(resume, "Bachelor Degree.", sizeof(resume)); |
| salary = 1500.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 2; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "Jane", sizeof(firstName)); |
| strncpy(lastName, "Roe", sizeof(lastName)); |
| strncpy(resume, "Bachelor Degree.", sizeof(resume)); |
| salary = 1000.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 1; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "Richard", sizeof(firstName)); |
| strncpy(lastName, "Miles", sizeof(lastName)); |
| strncpy(resume, "Master Degree.", sizeof(resume)); |
| salary = 2400.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| |
| ret = SQLMoreResults(stmt); |
| |
| if (ret != SQL_NO_DATA) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "No more data expected"); |
| |
| ++keyId; |
| keyOrgIdAff = 2; |
| |
| orgId = keyOrgIdAff; |
| strncpy(firstName, "Mary", sizeof(firstName)); |
| strncpy(lastName, "Major", sizeof(lastName)); |
| strncpy(resume, "Bachelor Degree.", sizeof(resume)); |
| salary = 900.0; |
| |
| ret = SQLExecute(stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute prepared statement"); |
| } |
| catch(...) |
| { |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| |
| // Re-throwing expection. |
| throw; |
| } |
| |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| } |
| |
| /** |
| * Populate Organization cache with sample data. |
| * |
| * @param dbc Database connection. |
| */ |
| void PopulateOrganization(SQLHDBC dbc) |
| { |
| SQLHSTMT stmt; |
| |
| // Allocate a statement handle |
| SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle"); |
| |
| try |
| { |
| SQLCHAR query1[] = "INSERT INTO \"Organization\".Organization (_key, name) VALUES (1L, 'Microsoft')"; |
| |
| ret = SQLExecDirect(stmt, query1, static_cast<SQLSMALLINT>(sizeof(query1))); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query"); |
| |
| SQLFreeStmt(stmt, SQL_CLOSE); |
| |
| SQLCHAR query2[] = "INSERT INTO \"Organization\".Organization (_key, name) VALUES (2L, 'Red Cross')"; |
| |
| ret = SQLExecDirect(stmt, query2, static_cast<SQLSMALLINT>(sizeof(query2))); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query"); |
| } |
| catch (...) |
| { |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| |
| // Re-throwing expection. |
| throw; |
| } |
| |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| } |
| |
| /** |
| * Adjust salary for specified employee. |
| * |
| * @param dbc Database connection. |
| * @param id Person id. |
| * @param salary New salary. |
| */ |
| void AdjustSalary(SQLHDBC dbc, int64_t id, double salary) |
| { |
| SQLHSTMT stmt; |
| |
| // Allocate a statement handle |
| SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle"); |
| |
| try |
| { |
| SQLCHAR query[] = "UPDATE Person SET salary=? WHERE id=?"; |
| |
| ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &salary, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &id, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLExecDirect(stmt, query, static_cast<SQLSMALLINT>(sizeof(query))); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query"); |
| } |
| catch (...) |
| { |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| |
| // Re-throwing expection. |
| throw; |
| } |
| |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| } |
| |
| /** |
| * Remove specified person. |
| * |
| * @param dbc Database connection. |
| * @param id Person id. |
| */ |
| void DeletePerson(SQLHDBC dbc, int64_t id) |
| { |
| SQLHSTMT stmt; |
| |
| // Allocate a statement handle |
| SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to allocate statement handle"); |
| |
| try |
| { |
| SQLCHAR query[] = "DELETE FROM Person WHERE id=?"; |
| |
| ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &id, 0, 0); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to bind parameter"); |
| |
| ret = SQLExecDirect(stmt, query, static_cast<SQLSMALLINT>(sizeof(query))); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_STMT, stmt, "Failed to execute query"); |
| } |
| catch (...) |
| { |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| |
| // Re-throwing expection. |
| throw; |
| } |
| |
| // Releasing statement handle. |
| SQLFreeHandle(SQL_HANDLE_STMT, stmt); |
| } |
| |
| /** |
| * Query tables. |
| * |
| * @param dbc Database connection. |
| */ |
| void QueryData(SQLHDBC dbc) |
| { |
| std::cout << std::endl; |
| std::cout << ">>> Getting list of persons:" << std::endl; |
| |
| GetDataWithOdbc(dbc, "SELECT firstName, lastName, resume, salary FROM Person ORDER BY id"); |
| |
| std::cout << std::endl; |
| std::cout << ">>> Getting average salary by degree:" << std::endl; |
| |
| GetDataWithOdbc(dbc, "SELECT resume, AVG(salary) FROM Person GROUP BY resume ORDER BY resume"); |
| |
| std::cout << std::endl; |
| std::cout << ">>> Getting people with organizations:" << std::endl; |
| |
| GetDataWithOdbc(dbc, |
| "SELECT firstName, lastName, Organization.name FROM Person " |
| "INNER JOIN \"Organization\".Organization ON Person.orgId = Organization._KEY " |
| "ORDER BY Person.id"); |
| } |
| |
| /** |
| * Program entry point. |
| * |
| * @return Exit code. |
| */ |
| int main() |
| { |
| IgniteConfiguration cfg; |
| |
| cfg.springCfgPath = "platforms/cpp/examples/odbc-example/config/example-odbc.xml"; |
| |
| try |
| { |
| // Start a node. |
| Ignite grid = Ignition::Start(cfg); |
| |
| SQLHENV env; |
| |
| // Allocate an environment handle |
| SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); |
| |
| // We want ODBC 3 support |
| SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0); |
| |
| SQLHDBC dbc; |
| |
| // Allocate a connection handle |
| SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); |
| |
| // Combining connect string |
| std::string connectStr = "DRIVER={Apache Ignite};SERVER=localhost;PORT=10800;SCHEMA=Person;"; |
| |
| SQLCHAR outstr[ODBC_BUFFER_SIZE]; |
| SQLSMALLINT outstrlen; |
| |
| // Connecting to ODBC server. |
| SQLRETURN ret = SQLDriverConnect(dbc, NULL, reinterpret_cast<SQLCHAR*>(&connectStr[0]), |
| static_cast<SQLSMALLINT>(connectStr.size()), outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE); |
| |
| if (!SQL_SUCCEEDED(ret)) |
| ThrowOdbcError(SQL_HANDLE_DBC, dbc, "Failed to connect"); |
| |
| std::cout << std::endl; |
| std::cout << ">>> Cache ODBC example started." << std::endl; |
| std::cout << std::endl; |
| |
| // Populate caches. |
| PopulatePerson(dbc); |
| PopulateOrganization(dbc); |
| |
| QueryData(dbc); |
| |
| std::cout << std::endl; |
| std::cout << std::endl; |
| std::cout << ">>> Adjusted salary for Mary Major. Querying again." << std::endl; |
| |
| AdjustSalary(dbc, 8, 1200.0); |
| |
| QueryData(dbc); |
| |
| std::cout << std::endl; |
| std::cout << std::endl; |
| std::cout << ">>> Removing several employees. Querying again." << std::endl; |
| |
| DeletePerson(dbc, 4); |
| DeletePerson(dbc, 5); |
| |
| QueryData(dbc); |
| |
| // Disconneting from the server. |
| SQLDisconnect(dbc); |
| |
| // Releasing allocated handles. |
| SQLFreeHandle(SQL_HANDLE_DBC, dbc); |
| SQLFreeHandle(SQL_HANDLE_ENV, env); |
| |
| // Stop node. |
| Ignition::StopAll(false); |
| } |
| catch (IgniteError& err) |
| { |
| std::cout << "An error occurred: " << err.GetText() << std::endl; |
| |
| return err.GetCode(); |
| } |
| |
| std::cout << std::endl; |
| std::cout << ">>> Example finished, press 'Enter' to exit ..." << std::endl; |
| std::cout << std::endl; |
| |
| std::cin.get(); |
| |
| return 0; |
| } |