

#include <iostream>
#include <occi.h>
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<char*>(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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }

    conn->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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }

    conn->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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }

    conn->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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }

    conn->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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }

    stmt->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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }
    conn->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"<<endl;
     cout<<"Error number: "<<  ex.getErrorCode() << endl;
     cout<<ex.getMessage() << endl;
    }

    stmt->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<vector<string>> 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<unsigned int>(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<string> 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<unsigned int>(resultData.size());
        printf("DEBUG: Starting to fetch remaining rows\n");
        fflush(stdout);

        while (rset->next()) {
            printf("DEBUG: Fetching next row\n");
            fflush(stdout);

            vector<string> 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<int>(numCols);
        *outputValueCount = static_cast<int>(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;
//}
