#include #include using namespace oracle::occi; using namespace std; class occidml { private: public: Environment* env; oracle::occi::Connection* conn; Statement* stmt; occidml (string user, string passwd, string db) { #ifdef _WIN32 _putenv("NLS_LANG=AMERICAN_AMERICA.ZHS16GBK"); #else setenv("NLS_LANG", "SIMPLIFIED CHINESE_CHINA.ZHS16GBK", 1); #endif printf("0-\n"); env = Environment::createEnvironment (Environment::DEFAULT); printf("1-\n"); conn = env->createConnection (user, passwd, db); printf("2-\n"); } ~occidml () { printf("3-\n"); env->terminateConnection (conn); printf("4-\n"); Environment::terminateEnvironment (env); printf("5-\n"); } string safeGetString(ResultSet* rset, int colIndex) { try { if (rset->isNull(colIndex)) { return "NULL"; } Bytes bytes = rset->getBytes(colIndex); if (bytes.length() <= 0) { return ""; } // 复制字节 unsigned char* buf = new unsigned char[bytes.length()]; bytes.getBytes(buf, bytes.length()); string result(reinterpret_cast(buf), bytes.length()); delete[] buf; return result; } catch (...) { return "ERROR"; } } /** * Insertion of a row with dynamic binding, PreparedStatement functionality. */ void insertBind (int c1, string c2) { string sqlStmt = "INSERT INTO author_tab VALUES (:x, :y)"; stmt=conn->createStatement (sqlStmt); try{ stmt->setInt (1, c1); stmt->setString (2, c2); stmt->executeUpdate (); cout << "insert - Success" << endl; }catch(SQLException ex) { cout<<"Exception thrown for insertBind"<terminateStatement (stmt); } /** * Inserting a row into the table. */ void insertRow () { string sqlStmt = "INSERT INTO author_tab VALUES (111, 'ASHOK')"; stmt = conn->createStatement (sqlStmt); try{ stmt->executeUpdate (); cout << "insert - Success" << endl; }catch(SQLException ex) { cout<<"Exception thrown for insertRow"<terminateStatement (stmt); } /** * updating a row */ void updateRow (int c1, string c2) { string sqlStmt = "UPDATE author_tab SET author_name = :x WHERE author_id = :y"; stmt = conn->createStatement (sqlStmt); try{ stmt->setString (1, c2); stmt->setInt (2, c1); stmt->executeUpdate (); cout << "update - Success" << endl; }catch(SQLException ex) { cout<<"Exception thrown for updateRow"<terminateStatement (stmt); } /** * deletion of a row */ void deleteRow (int c1, string c2) { string sqlStmt = "DELETE FROM author_tab WHERE author_id= :x AND author_name = :y"; stmt = conn->createStatement (sqlStmt); try{ stmt->setInt (1, c1); stmt->setString (2, c2); stmt->executeUpdate (); cout << "delete - Success" << endl; }catch(SQLException ex) { cout<<"Exception thrown for deleteRow"<terminateStatement (stmt); } /** * displaying all the rows in the table */ void displayAllRows () { string sqlStmt = "SELECT author_id, author_name FROM author_tab \ order by author_id"; stmt = conn->createStatement (sqlStmt); ResultSet *rset = stmt->executeQuery (); try{ while (rset->next ()) { cout << "author_id: " << rset->getInt (1) << " author_name: " << rset->getString (2) << endl; } }catch(SQLException ex) { cout<<"Exception thrown for displayAllRows"<closeResultSet (rset); conn->terminateStatement (stmt); } /** * Inserting a row into elements table. * Demonstrating the usage of BFloat and BDouble datatypes */ void insertElement (string elm_name, float mvol=0.0, double awt=0.0) { BFloat mol_vol; BDouble at_wt; if (!(mvol)) mol_vol.isNull = TRUE; else mol_vol.value = mvol; if (!(awt)) at_wt.isNull = TRUE; else at_wt.value = awt; string sqlStmt = "INSERT INTO elements VALUES (:v1, :v2, :v3)"; stmt = conn->createStatement (sqlStmt); try{ stmt->setString(1, elm_name); stmt->setBFloat(2, mol_vol); stmt->setBDouble(3, at_wt); stmt->executeUpdate (); cout << "insertElement - Success" << endl; }catch(SQLException ex) { cout<<"Exception thrown for insertElement"<terminateStatement (stmt); } /** * displaying rows from element table */ void displayElements () { string sqlStmt = "SELECT element_name, molar_volume, atomic_weight FROM elements \ order by element_name"; stmt = conn->createStatement (sqlStmt); ResultSet *rset = stmt->executeQuery (); try{ cout.precision(7); while (rset->next ()) { string elem_name = rset->getString(1); BFloat mol_vol = rset->getBFloat(2); BDouble at_wt = rset->getBDouble(3); cout << "Element Name: " << elem_name << endl; if ( mol_vol.isNull ) cout << "Molar Volume is NULL" << endl; else cout << "Molar Volume: " << mol_vol.value << " cm3 mol-1" << endl; if ( at_wt.isNull ) cout << "Atomic Weight is NULL" << endl; else cout << "Atomic Weight: " << at_wt.value << " g/mole" << endl; } }catch(SQLException ex) { cout<<"Exception thrown for displayElements"<closeResultSet (rset); conn->terminateStatement (stmt); } /** * 封装 OCCI executeQuery 为 C 风格接口 * * @param conn OCCI 数据库连接 * @param sql SQL 查询语句 * @param outputColumn 输出:列数(通过指针返回) * @param outputValueCount 输出:总数据项数量(行数 × 列数) * @param outputValue 输出:二维数组 char[row][col],需调用者释放 * @return 0=成功, -1=失败 */ int executeQuery( oracle::occi::Connection* conn, const char* sql, int* outputColumn, int* outputValueCount, char**** outputValue) { printf("DEBUG: Entering executeQuery function\n"); fflush(stdout); // 初始化输出参数 *outputColumn = 0; printf("DEBUG: Initialized outputColumn = 0\n"); fflush(stdout); *outputValueCount = 0; printf("DEBUG: Initialized outputValueCount = 0\n"); fflush(stdout); *outputValue = nullptr; printf("DEBUG: Set outputValue to nullptr\n"); fflush(stdout); Statement* stmt = nullptr; ResultSet* rset = nullptr; vector> resultData; try { printf("DEBUG: Entering try block\n"); fflush(stdout); printf("DEBUG: sql====%s\n", sql); fflush(stdout); // 创建语句 stmt = conn->createStatement(sql); printf("DEBUG: Created statement from connection\n"); fflush(stdout); // 执行查询 rset = stmt->executeQuery(); printf("DEBUG: Executed query and got ResultSet\n"); fflush(stdout); // 【关键修复】先调用 next() 再获取元数据,防止崩溃 bool hasData = rset->next(); printf("DEBUG: First rset->next() called for initialization, hasData = %s\n", hasData ? "true" : "false"); fflush(stdout); // 获取列元数据(必须在 next() 之后调用才安全) auto metaData = rset->getColumnListMetaData(); unsigned int numCols = 0; if (!metaData.empty()) { numCols = static_cast(metaData.size()); printf("DEBUG: Got number of columns = %u\n", numCols); fflush(stdout); } else { printf("ERROR: Metadata is empty after next(), unable to get column count.\n"); fflush(stdout); stmt->closeResultSet(rset); conn->terminateStatement(stmt); return -1; } fflush(stdout); // 如果有数据,保存第一行 if (hasData) { vector firstRow; for (unsigned int i = 1; i <= numCols; ++i) { printf("DEBUG: Processing column %u of first row\n", i); fflush(stdout); try { //string val = rset->getString(i); //printf("DEBUG: Retrieved value for column %u: '%s'\n", i, val.c_str()); //fflush(stdout); //firstRow.push_back(val); string val = safeGetString(rset, i); printf("DEBUG: Retrieved value for column %u: '%s'\n", i, val.c_str()); firstRow.push_back(val); printf("1111111111111111111111111\n"); } catch (SQLException&) { printf("DEBUG: Exception getting column %u, using 'NULL'\n", i); fflush(stdout); firstRow.push_back("NULL"); } catch (exception& e) { printf("exception=========%u\n", i); printf("Exception caught on column %u: %s\n", i, e.what()); fflush(stdout); } } printf("22222222222222222222\n"); resultData.push_back(firstRow); printf("DEBUG: First row saved to resultData\n"); fflush(stdout); } // 继续读取剩余行 unsigned int rowCount = static_cast(resultData.size()); printf("DEBUG: Starting to fetch remaining rows\n"); fflush(stdout); while (rset->next()) { printf("DEBUG: Fetching next row\n"); fflush(stdout); vector row; for (unsigned int i = 1; i <= numCols; ++i) { try { string val = safeGetString(rset,i); row.push_back(val); printf("DEBUG: Retrieved value for row %u, col %u: '%s'\n", rowCount, i, val.c_str()); fflush(stdout); } catch (SQLException&) { row.push_back("NULL"); printf("DEBUG: NULL value at row %u, col %u\n", rowCount, i); fflush(stdout); } } resultData.push_back(row); ++rowCount; printf("DEBUG: Completed row %u\n", rowCount); fflush(stdout); } printf("DEBUG: Finished fetching all rows, total count = %u\n", rowCount); fflush(stdout); // 设置输出参数 *outputColumn = static_cast(numCols); *outputValueCount = static_cast(rowCount); printf("DEBUG: Set outputColumn = %d, outputValueCount = %d\n", *outputColumn, *outputValueCount); fflush(stdout); // 分配输出内存:char*** -> char**[] -> char*[] -> char[] char*** rows = nullptr; if (rowCount > 0) { rows = new char** [rowCount]; // 每行是一个 char** printf("DEBUG: Allocated %u row pointers\n", rowCount); fflush(stdout); for (unsigned int i = 0; i < rowCount; ++i) { char** cols = new char* [numCols]; printf("DEBUG: Allocated %u column pointers for row %u\n", numCols, i); fflush(stdout); for (unsigned int j = 0; j < numCols; ++j) { const string& s = resultData[i][j]; cols[j] = new char[s.length() + 1]; strcpy(cols[j], s.c_str()); printf("DEBUG: Copied '%s' to outputValue[%u][%u]\n", s.c_str(), i, j); fflush(stdout); } rows[i] = cols; } } else { rows = nullptr; // 空结果集 } *outputValue = rows; printf("DEBUG: Assigned result to *outputValue\n"); fflush(stdout); // 清理 OCCI 资源 stmt->closeResultSet(rset); printf("DEBUG: Closed ResultSet\n"); fflush(stdout); conn->terminateStatement(stmt); printf("DEBUG: Terminated Statement\n"); fflush(stdout); printf("DEBUG: Query executed successfully, returning 0\n"); fflush(stdout); return 0; // 成功 } catch (SQLException& e) { printf("DEBUG: SQLException caught\n"); fflush(stdout); cerr << "SQL Error: " << e.getMessage() << endl; cerr << "SQL: " << sql << endl; // 清理资源 if (rset && stmt) { try { stmt->closeResultSet(rset); } catch (...) {} } if (stmt) { try { conn->terminateStatement(stmt); } catch (...) {} } printf("DEBUG: Returning -1 due to SQL error\n"); fflush(stdout); return -1; } catch (bad_alloc& e) { printf("DEBUG: bad_alloc exception caught: %s\n", e.what()); fflush(stdout); cerr << "Memory allocation failed!" << endl; // 清理资源 if (rset && stmt) { try { stmt->closeResultSet(rset); } catch (...) {} } if (stmt) { try { conn->terminateStatement(stmt); } catch (...) {} } printf("DEBUG: Returning -2 due to memory allocation failure\n"); fflush(stdout); return -2; } catch (...) { printf("DEBUG: Unknown exception caught\n"); fflush(stdout); if (rset && stmt) { try { stmt->closeResultSet(rset); } catch (...) {} } if (stmt) { try { conn->terminateStatement(stmt); } catch (...) {} } printf("DEBUG: Returning -1 due to unknown error\n"); fflush(stdout); return -1; } } }; // end of class occidml //int main (void) //{ // string user = "scott"; // string passwd = "tiger"; // string db = ""; // try{ // cout << "occidml - Exhibiting simple insert, delete & update operations" // << endl; // occidml *demo = new occidml (user, passwd, db); // cout << "Displaying all records before any operation" << endl; // demo->displayAllRows (); // // cout << "Inserting a record into the table author_tab " // << endl; // demo->insertRow (); // // cout << "Displaying the records after insert " << endl; // demo->displayAllRows (); // // cout << "Inserting a records into the table author_tab using dynamic bind" // << endl; // demo->insertBind (222, "ANAND"); // // cout << "Displaying the records after insert using dynamic bind" << endl; // demo->displayAllRows (); // // cout << "deleting a row with author_id as 222 from author_tab table" << endl; // demo->deleteRow (222, "ANAND"); // // cout << "updating a row with author_id as 444 from author_tab table" << endl; // demo->updateRow (444, "ADAM"); // // cout << "displaying all rows after all the operations" << endl; // demo->displayAllRows (); // // cout << "inserting radio active element properties" << endl; // demo->insertElement ("Uranium", 12.572, 238.0289 ); // demo->insertElement ("Plutonium", 12.12, 244.0642 ); // demo->insertElement ("Curium", 18.17, 247.0703 ); // demo->insertElement ("Thorium"); // demo->insertElement ("Radium", 41.337, 226.0254); // // cout << "displaying all radio active element properties" << endl; // demo->displayElements (); // // delete (demo); // } // catch (SQLException ex){ // cout << ex.getMessage() << endl; // } // cout << "occidml - done" << endl; //}