Logo
~Database~
~ C++ ~
~Contact~

Query.cpp

Go to the documentation of this file.
00001 /*
00002  **     Query.cpp
00003  **
00004  **     Published / author: 2006-03-29 / grymse@alhem.net
00005  **/
00006 /*
00007 Copyright (C) 2006 Anders Hedstrom
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00022 */
00023 #ifdef _WIN32
00024 #pragma warning(disable:4786)
00025 #endif
00026 
00027 #ifdef _WIN32
00028 #include <afxdb.h>
00029 #include <sql.h>
00030 #endif
00031 
00032 #include "Query.h"
00033 #include "Database.h"
00034 #include "IError.h"
00035 #include "Session.h"
00036 
00037 
00038 #ifdef ODBCW_NAMESPACE
00039 namespace ODBCW_NAMESPACE {
00040 #endif
00041 
00042 
00043 Query::Query(Database& dbin)
00044 :m_db(dbin)
00045 ,m_odb(m_db.grabdb())
00046 ,m_hstmt(NULL)
00047 ,m_hres(NULL)
00048 ,m_currentcolumn(0)
00049 ,m_results(0)
00050 ,m_fetchrows(0)
00051 ,m_qcols(0)
00052 ,m_currentcol(0)
00053 {
00054 }
00055 
00056 
00057 Query::Query(Database& dbin,const std::string& sql)
00058 :m_db(dbin)
00059 ,m_odb(m_db.grabdb())
00060 ,m_hstmt(NULL)
00061 ,m_hres(NULL)
00062 ,m_currentcolumn(0)
00063 ,m_results(0)
00064 ,m_fetchrows(0)
00065 ,m_qcols(0)
00066 ,m_currentcol(0)
00067 {
00068         execute(sql);
00069 }
00070 
00071 
00072 Query::~Query()
00073 {
00074         if (m_hstmt)
00075         {
00076                 SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
00077         }
00078         if (m_hres)
00079         {
00080                 delete m_hres;
00081         }
00082         if (m_odb)
00083         {
00084                 m_db.freedb(m_odb);
00085         }
00086 }
00087 
00088 
00089 short Query::execute(const std::string& sql)    // query, no result
00090 {
00091         SQLRETURN retcode;
00092         m_last_query = sql;
00093         if (m_odb && m_hres)
00094         {
00095                 error("Query::execute(): Query busy");
00096         }
00097         if (m_odb && !m_hres)
00098         {
00099                 m_results = 0;
00100                 m_fetchrows = 0;
00101                 m_qcols = 0;
00102                 m_currentcol = 0;
00103 
00104                 // Free statement handle
00105                 if (m_hstmt)
00106                 {
00107                         SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
00108                 }
00109 
00110                 // Allocate statement handle (STMT)
00111                 retcode = SQLAllocHandle(SQL_HANDLE_STMT, static_cast<SQLHDBC>(m_odb -> GetHandle()), &m_hstmt);
00112                 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
00113                 {
00114                         error("Query::execute(): Allocate statement handle (STMT) failed");
00115                         return 0;        // 0 failed
00116                 }
00117 
00118                 retcode = SQLExecDirect(m_hstmt, (unsigned char *)sql.c_str(), sql.size());
00119                 if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
00120                 {
00121                         Session *tmp = dynamic_cast<Session *>(m_odb);
00122                         if (tmp)
00123                         {
00124                                 tmp -> ShowErrorInfo(retcode, SQL_HANDLE_STMT, m_hstmt);
00125                         }
00126                 }
00127                 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
00128                 {
00129                         error("Query::execute(): SQL Query failed:");
00130                         error(sql);
00131                         return 0;        // 0 failed
00132                 }
00133                 m_results = num_rows();
00134                 return 1;
00135         }
00136         return 0;
00137 }
00138 
00139 
00140 bool Query::get_result(const std::string& sql,char **attrs)
00141 {
00142         UNUSED_ALWAYS(attrs);
00143         if (m_odb && m_hres)
00144         {
00145                 error("Query::get_result(): Query busy");
00146         }
00147         if (m_odb && !m_hres)
00148         {
00149                 if (execute(sql))
00150                 {
00151                         return odbc_store_result();
00152                 }
00153                 else
00154                 {
00155                         error("Query::get_result(): Query failed");
00156                 }
00157         }
00158         return false;
00159 }
00160 
00161 
00162 void Query::free_result()
00163 {
00164         if (m_odb && m_hres)
00165         {
00166                 delete m_hres;
00167                 m_hres = NULL;
00168         }
00169         while (m_nmap.size())
00170         {
00171                 std::map<std::string,int>::iterator it = m_nmap.begin();
00172                 m_nmap.erase(it);
00173         }
00174 }
00175 
00176 
00177 bool Query::get_result(SQLSMALLINT func)
00178 {
00179         if (m_odb && m_hres)
00180         {
00181                 error("Query::get_result(): Query busy");
00182         }
00183         if (m_odb && !m_hres)
00184         {
00185                 SQLRETURN retcode = SQL_ERROR;
00186                 bool result = false;
00187 
00188                 m_results = 0;
00189                 m_fetchrows = 0;
00190                 m_qcols = 0;
00191                 m_currentcol = 0;
00192 
00193                 // Free statement handle
00194                 if (m_hstmt)
00195                 {
00196                         SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
00197                 }
00198 
00199                 // Allocate statement handle (STMT)
00200                 retcode = SQLAllocHandle(SQL_HANDLE_STMT, static_cast<SQLHDBC>(m_odb -> GetHandle()), &m_hstmt);
00201                 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
00202                 {
00203                         error("Query::execute(): Allocate statement handle (STMT) failed");
00204                         return 0;        // 0 failed
00205                 }
00206 
00207                 switch (func)
00208                 {
00209                 case SQLGET_CATALOGS:
00210                         retcode = SQLTables(m_hstmt, // catalogs, schemas, tables, table types
00211                                 (unsigned char *)SQL_ALL_CATALOGS, SQL_NTS,
00212                                 (unsigned char *)NULL, 0,
00213                                 (unsigned char *)NULL, 0,
00214                                 (unsigned char *)NULL, 0
00215                                 );
00216                         break;
00217                 case SQLGET_SCHEMAS:
00218                         retcode = SQLTables(m_hstmt, // catalogs, schemas, tables, table types
00219                                 (unsigned char *)NULL, 0,
00220                                 (unsigned char *)SQL_ALL_SCHEMAS, SQL_NTS,
00221                                 (unsigned char *)NULL, 0,
00222                                 (unsigned char *)NULL, 0
00223                                 );
00224                         break;
00225                 case SQLGET_TABLES:
00226                         retcode = SQLTables(m_hstmt, // catalogs, schemas, tables, table types
00227                                 (unsigned char *)SQL_ALL_CATALOGS, SQL_NTS,
00228                                 (unsigned char *)NULL, 0,
00229                                 (unsigned char *)"%%", SQL_NTS, // TODO: single %?
00230                                 (unsigned char *)"TABLE", 5
00231                                 );
00232                         break;
00233                 case SQLGET_VIEWS:
00234                         retcode = SQLTables(m_hstmt, // catalogs, schemas, tables, table types
00235                                 (unsigned char *)SQL_ALL_CATALOGS, SQL_NTS,
00236                                 (unsigned char *)NULL, 0,
00237                                 (unsigned char *)"%%", SQL_NTS, // TODO: single %?
00238                                 (unsigned char *)"VIEW", 4
00239                                 );
00240                         break;
00241                 case SQLGET_TABLETYPES:
00242                         retcode = SQLTables(m_hstmt, // catalogs, schemas, tables, table types
00243                                 (unsigned char *)"", 0,
00244                                 (unsigned char *)"", 0,
00245                                 (unsigned char *)"", 0,
00246                                 (unsigned char *)SQL_ALL_TABLE_TYPES, SQL_NTS
00247                                 );
00248                         break;
00249                 }
00250 
00251                 if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
00252                 {
00253                         Session *tmp = dynamic_cast<Session *>(m_odb);
00254                         if (tmp)
00255                         {
00256                                 tmp -> ShowErrorInfo(retcode, SQL_HANDLE_STMT, m_hstmt);
00257                         }
00258                 }
00259                 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
00260                 {
00261                         result = true;
00262                 }
00263                 else
00264                 {
00265                 }
00266 
00267                 if (result)
00268                 {
00269                         return odbc_store_result();
00270                 }
00271                 else
00272                 {
00273                         error("Query::get_result(): Query failed");
00274                 }
00275         }
00276         return false;
00277 }
00278 
00279 
00280 bool Query::get_result(SQLSMALLINT func, const std::string& catalog, const std::string& schema, const std::string& tablename)
00281 {
00282         if (m_odb && m_hres)
00283         {
00284                 error("Query::get_result(): Query busy");
00285         }
00286         if (m_odb && !m_hres)
00287         {
00288                 SQLRETURN retcode = SQL_ERROR;
00289                 bool result = false;
00290 
00291                 m_results = 0;
00292                 m_fetchrows = 0;
00293                 m_qcols = 0;
00294                 m_currentcol = 0;
00295 
00296                 // Free statement handle
00297                 if (m_hstmt)
00298                 {
00299                         SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
00300                 }
00301 
00302                 // Allocate statement handle (STMT)
00303                 retcode = SQLAllocHandle(SQL_HANDLE_STMT, static_cast<SQLHDBC>(m_odb -> GetHandle()), &m_hstmt);
00304                 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
00305                 {
00306                         error("Query::execute(): Allocate statement handle (STMT) failed");
00307                         return 0;        // 0 failed
00308                 }
00309 
00310                 switch (func)
00311                 {
00312                 case SQLGET_COLUMNS:
00313                         retcode = SQLColumns(m_hstmt,
00314                                 (unsigned char *) (catalog.size() ? catalog.c_str() : NULL), (SQLSMALLINT) (catalog.size() ? SQL_NTS : 0),
00315                                 (unsigned char *) (schema.size() ? schema.c_str() : NULL), (SQLSMALLINT) (schema.size() ? SQL_NTS : 0),
00316                                 (unsigned char *)tablename.c_str(), (SQLSMALLINT)SQL_NTS,
00317                                 (unsigned char *)NULL, (SQLSMALLINT)0);
00318                         break;
00319                 case SQLGET_SPECIALCOLUMNS:
00320                         retcode = SQLSpecialColumns(m_hstmt,
00321                                 SQL_BEST_ROWID,                                  // SQL_ROWVER,
00322                                 (unsigned char *) (catalog.size() ? catalog.c_str() : NULL), (SQLSMALLINT) (catalog.size() ? SQL_NTS : 0),
00323                                 (unsigned char *) (schema.size() ? schema.c_str() : NULL), (SQLSMALLINT) (schema.size() ? SQL_NTS : 0),
00324                                 (unsigned char *)tablename.c_str(), (SQLSMALLINT)SQL_NTS,
00325                                 SQL_SCOPE_TRANSACTION, // SQL_SCOPE_SESSION,
00326                                 SQL_NULLABLE);
00327                         break;
00328                 case SQLGET_PRIMARYKEYS:
00329                         retcode = SQLPrimaryKeys(m_hstmt,
00330                                 (unsigned char *) (catalog.size() ? catalog.c_str() : NULL), (SQLSMALLINT) (catalog.size() ? SQL_NTS : 0),
00331                                 (unsigned char *) (schema.size() ? schema.c_str() : NULL), (SQLSMALLINT) (schema.size() ? SQL_NTS : 0),
00332                                 (unsigned char *)tablename.c_str(), (SQLSMALLINT)SQL_NTS
00333                                 );
00334                         break;
00335                 }
00336 
00337                 if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
00338                 {
00339                         Session *tmp = dynamic_cast<Session *>(m_odb);
00340                         if (tmp)
00341                         {
00342                                 tmp -> ShowErrorInfo(retcode, SQL_HANDLE_STMT, m_hstmt);
00343                         }
00344                 }
00345                 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
00346                 {
00347                         result = true;
00348                 }
00349                 else
00350                 {
00351                 }
00352 
00353                 if (result)
00354                 {
00355                         return odbc_store_result();
00356                 }
00357                 else
00358                 {
00359                         error("Query::get_result(): Query failed");
00360                 }
00361         }
00362         return false;
00363 }
00364 
00365 
00366 bool Query::fetch_row()
00367 {
00368         m_currentcolumn = 0; // ODBC columns start at 1
00369         m_fetchrows++;
00370         if (m_odb && m_hstmt && m_hres)
00371         {
00372                 SQLRETURN retcode = SQLFetch(m_hstmt);
00373                 if (retcode == SQL_SUCCESS)
00374                 {
00375                         return true;
00376                 }
00377         }
00378         return false;
00379 }
00380 
00381 
00382 long Query::insert_id()
00383 {
00384         return -1;
00385 }
00386 
00387 
00388 long Query::num_rows()
00389 {
00390         SQLINTEGER rowCount;
00391 
00392         if (m_hstmt)
00393         {
00394                 SQLRETURN retcode = SQLRowCount(m_hstmt, &rowCount);
00395                 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
00396                 {
00397                 }
00398         }
00399         else
00400         {
00401                 rowCount = -1;
00402         }
00403         return rowCount;
00404 }
00405 
00406 
00407 bool Query::is_null(int x)
00408 {
00409         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
00410         {
00411                 SQLHCOL *col = m_hres -> m_cols[x + 1];
00412                 if (col -> cbBuffer == SQL_NULL_DATA)
00413                         return true;
00414         }
00415         return false;
00416 }
00417 
00418 
00419 bool Query::is_null()
00420 {
00421         return is_null(m_currentcolumn++);
00422 }
00423 
00424 
00425 bool Query::is_null(const std::string& x)
00426 {
00427         int index = m_nmap[x] - 1;
00428         if (index >= 0)
00429                 return is_null(index);
00430         error("Column name lookup failure: " + x);
00431         return false;
00432 }
00433 
00434 
00435 const char *Query::getstr(int x)
00436 {
00437         SQLHCOL *col;
00438         char slask[80];          // sprintf format
00439 
00440         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
00441         {
00442                 col = m_hres -> m_cols[x + 1];
00443                 if (col -> nCType == SQL_C_CHAR && !strcmp(col -> szTypeName,"SQL_DECIMAL"))
00444                 {
00445                         double d = atof(col -> buffer -> String);
00446                         char *s;
00447                         if (!col -> tmpstr)
00448                         {
00449                                 col -> tmpstr = new char[80];
00450                         }
00451                         sprintf(slask,"%%%d.%df",col -> nColumnSizePtr,col -> nDecimalDigitsPtr);
00452                         sprintf(col -> tmpstr, slask, d);
00453                         if ((s = strstr(col -> tmpstr,".")) != NULL)
00454                         {
00455                                 *s = m_db.GetDecimalChar();
00456                         }
00457                         return col -> tmpstr;
00458                 }
00459                 else
00460                 switch (col -> nCType)
00461                 {
00462                 case SQL_C_CHAR:
00463                         return col -> buffer -> String;
00464                 case SQL_C_WCHAR:                        // unicode
00465                         return col -> buffer -> String;
00466 //              case SQL_C_TCHAR:
00467 //                      return col -> buffer -> String;
00468                 case SQL_C_FLOAT:
00469                         if (!col -> tmpstr)
00470                         {
00471                                 col -> tmpstr = new char[80];
00472                         }
00473                         sprintf(slask,"%%%d.%df",col -> nColumnSizePtr,col -> nDecimalDigitsPtr);
00474                         sprintf(col -> tmpstr, slask, col -> buffer -> f);
00475                         return col -> tmpstr;
00476                 case SQL_C_DOUBLE:
00477                         if (!col -> tmpstr)
00478                         {
00479                                 col -> tmpstr = new char[80];
00480                         }
00481                         sprintf(slask,"%%%d.%df",col -> nColumnSizePtr,col -> nDecimalDigitsPtr);
00482                         sprintf(col -> tmpstr, slask, col -> buffer -> d);
00483                         return col -> tmpstr;
00484                 case SQL_C_BIT:
00485                         if (!col -> tmpstr)
00486                         {
00487                                 col -> tmpstr = new char[80];
00488                         }
00489                         sprintf(col -> tmpstr,"%u",col -> buffer -> c & 1);
00490                         return col -> tmpstr;
00491                 case SQL_C_STINYINT:
00492                         if (!col -> tmpstr)
00493                         {
00494                                 col -> tmpstr = new char[20];
00495                         }
00496                         sprintf(slask,"%%%dd",col -> nColumnSizePtr);
00497                         sprintf(col -> tmpstr, slask, col -> buffer -> c);
00498                         return col -> tmpstr;
00499                 case SQL_C_SSHORT:
00500                         if (!col -> tmpstr)
00501                         {
00502                                 col -> tmpstr = new char[20];
00503                         }
00504                         sprintf(slask,"%%%dd",col -> nColumnSizePtr);
00505                         sprintf(col -> tmpstr, slask, col -> buffer -> s);
00506                         return col -> tmpstr;
00507                 case SQL_C_SLONG:
00508                         if (!col -> tmpstr)
00509                         {
00510                                 col -> tmpstr = new char[20];
00511                         }
00512                         strcpy(slask,"%ld");
00513                         sprintf(col -> tmpstr, slask, col -> buffer -> l);
00514                         return col -> tmpstr;
00515                 case SQL_C_SBIGINT: // _int64
00516                         if (!col -> tmpstr)
00517                         {
00518                                 col -> tmpstr = new char[80];
00519                         }
00520                         sprintf(slask,"%%%dI64d",col -> nColumnSizePtr);
00521                         sprintf(col -> tmpstr, slask, col -> buffer -> bigint);
00522                         return col -> tmpstr;
00523                 case SQL_C_BINARY:
00524                         return col -> buffer -> String;
00525                 case SQL_C_TYPE_DATE:            // SQL_DATE_STRUCT
00526                         if (!col -> tmpstr)
00527                         {
00528                                 col -> tmpstr = new char[20];
00529                         }
00530                         sprintf(col -> tmpstr,"%d-%02d-%02d",
00531                                 col -> buffer -> date.year,
00532                                 col -> buffer -> date.month,
00533                                 col -> buffer -> date.day);
00534                         return col -> tmpstr;
00535                 case SQL_C_TYPE_TIME:
00536                         if (!col -> tmpstr)
00537                         {
00538                                 col -> tmpstr = new char[20];
00539                         }
00540                         sprintf(col -> tmpstr,"%02d:%02d:%02d",
00541                                 col -> buffer -> time.hour,
00542                                 col -> buffer -> time.minute,
00543                                 col -> buffer -> time.second);
00544                         return col -> tmpstr;
00545                 case SQL_C_TYPE_TIMESTAMP:
00546                         if (!col -> tmpstr)
00547                         {
00548                                 col -> tmpstr = new char[80];
00549                         }
00550                         sprintf(col -> tmpstr,"%d-%02d-%02d %02d:%02d:%02d", //.%u",
00551                                 col -> buffer -> timestamp.year,
00552                                 col -> buffer -> timestamp.month,
00553                                 col -> buffer -> timestamp.day,
00554                                 col -> buffer -> timestamp.hour,
00555                                 col -> buffer -> timestamp.minute,
00556                                 col -> buffer -> timestamp.second);
00557                         return col -> tmpstr;
00558 
00559                 case SQL_INTERVAL_MONTH:
00560                 case SQL_INTERVAL_YEAR:
00561                 case SQL_INTERVAL_YEAR_TO_MONTH:
00562                 case SQL_INTERVAL_DAY:
00563                 case SQL_INTERVAL_HOUR:
00564                 case SQL_INTERVAL_MINUTE:
00565                 case SQL_INTERVAL_SECOND:
00566                 case SQL_INTERVAL_DAY_TO_HOUR:
00567                 case SQL_INTERVAL_DAY_TO_MINUTE:
00568                 case SQL_INTERVAL_DAY_TO_SECOND:
00569                 case SQL_INTERVAL_HOUR_TO_MINUTE:
00570                 case SQL_INTERVAL_HOUR_TO_SECOND:
00571                 case SQL_INTERVAL_MINUTE_TO_SECOND:
00572                         break;
00573 
00574                 default:
00575                         {
00576                                 char msg[200];
00577                                 sprintf(msg, "Query::getstr():  Conversion not supported (%s)\n",col -> szTypeName);
00578                                 error(msg);
00579                         }
00580                         break;
00581                 }
00582         }
00583         return NULL;
00584 }
00585 
00586 
00587 double Query::getnum(int x)
00588 {
00589         SQLHCOL *col;
00590 
00591         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
00592         {
00593                 col = m_hres -> m_cols[x + 1];
00594                 switch (col -> nCType)
00595                 {
00596                 case SQL_C_FLOAT:
00597                         return col -> buffer -> f;
00598                 case SQL_C_DOUBLE:
00599                         return col -> buffer -> d;
00600                 case SQL_C_CHAR:
00601                         if (!strcmp(col -> szTypeName,"SQL_DECIMAL"))
00602                         {
00603                                 double d = atof(col -> buffer -> String);
00604                                 return d;
00605                         }
00606                         {
00607                                 char msg[200];
00608                                 sprintf(msg, "Query::getnum():  Conversion not supported (%s)\n",col -> szTypeName);
00609                                 error(msg);
00610                         }
00611                         break;
00612 
00613                 default:
00614                         {
00615                                 char msg[200];
00616                                 sprintf(msg, "Query::getnum():  Conversion not supported (%s)\n",col -> szTypeName);
00617                                 error(msg);
00618                         }
00619                         break;
00620                 }
00621         }
00622         return 0;
00623 }
00624 
00625 
00626 long Query::getval(int x)
00627 {
00628         SQLHCOL *col;
00629         long l;
00630 
00631         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
00632         {
00633                 col = m_hres -> m_cols[x + 1];
00634                 switch (col -> nCType)
00635                 {
00636                 case SQL_C_BIT:
00637                         return col -> buffer -> c & 1;
00638                 case SQL_C_STINYINT:
00639                         return col -> buffer -> c;
00640                 case SQL_C_SSHORT:
00641                         return col -> buffer -> s;
00642                 case SQL_C_SLONG:
00643                         return col -> buffer -> l;
00644                 case SQL_C_SBIGINT:
00645                         l = (long)col -> buffer -> bigint;
00646                         return static_cast<long>(col -> buffer -> bigint);
00647 
00648                 default:
00649                         {
00650                                 char msg[200];
00651                                 sprintf(msg, "Query::getval():  Conversion not supported (%s)\n",col -> szTypeName);
00652                                 error(msg);
00653                         }
00654                         break;
00655                 }
00656         }
00657         return 0L;
00658 }
00659 
00660 
00661 _int64 Query::getbigint(int x)
00662 {
00663         SQLHCOL *col;
00664 
00665         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
00666         {
00667                 col = m_hres -> m_cols[x + 1];
00668                 switch (col -> nCType)
00669                 {
00670                 case SQL_C_SBIGINT:
00671                         return col -> buffer -> bigint;
00672 
00673                 default:
00674                         {
00675                                 char msg[200];
00676                                 sprintf(msg, "Query::getbigint():       Conversion not supported (%s)\n",col -> szTypeName);
00677                                 error(msg);
00678                         }
00679                         break;
00680                 }
00681         }
00682         return 0L;
00683 }
00684 
00685 
00686 SQL_INTERVAL_STRUCT *Query::getinterval(int x)
00687 {
00688         SQLHCOL *col;
00689 
00690         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
00691         {
00692                 col = m_hres -> m_cols[x + 1];
00693                 switch (col -> nCType)
00694                 {
00695                 case SQL_INTERVAL_MONTH:
00696                 case SQL_INTERVAL_YEAR:
00697                 case SQL_INTERVAL_YEAR_TO_MONTH:
00698                 case SQL_INTERVAL_DAY:
00699                 case SQL_INTERVAL_HOUR:
00700                 case SQL_INTERVAL_MINUTE:
00701                 case SQL_INTERVAL_SECOND:
00702                 case SQL_INTERVAL_DAY_TO_HOUR:
00703                 case SQL_INTERVAL_DAY_TO_MINUTE:
00704                 case SQL_INTERVAL_DAY_TO_SECOND:
00705                 case SQL_INTERVAL_HOUR_TO_MINUTE:
00706                 case SQL_INTERVAL_HOUR_TO_SECOND:
00707                 case SQL_INTERVAL_MINUTE_TO_SECOND:
00708                         return &col -> buffer -> interval;
00709 
00710                 default:
00711                         {
00712                                 char msg[200];
00713                                 sprintf(msg, "Query::getinterval():     Conversion not supported (%s)\n",col -> szTypeName);
00714                                 error(msg);
00715                         }
00716                         break;
00717                 }
00718         }
00719         return NULL;
00720 }
00721 
00722 
00723 const char *Query::getstr()
00724 {
00725         return getstr(m_currentcolumn++);
00726 }
00727 
00728 
00729 double Query::getnum()
00730 {
00731         return getnum(m_currentcolumn++);
00732 }
00733 
00734 
00735 long Query::getval()
00736 {
00737         return getval(m_currentcolumn++);
00738 }
00739 
00740 
00741 _int64 Query::getbigint()
00742 {
00743         return getbigint(m_currentcolumn++);
00744 }
00745 
00746 
00747 SQL_INTERVAL_STRUCT *Query::getinterval()
00748 {
00749         return getinterval(m_currentcolumn++);
00750 }
00751 
00752 
00753 const char *Query::getstr(const std::string& x)
00754 {
00755         int index = m_nmap[x] - 1;
00756         if (index >= 0)
00757                 return getstr(index);
00758         error("Column name lookup failure: " + x);
00759         return "";
00760 }
00761 
00762 
00763 double Query::getnum(const std::string& x)
00764 {
00765         int index = m_nmap[x] - 1;
00766         if (index >= 0)
00767                 return getnum(index);
00768         error("Column name lookup failure: " + x);
00769         return 0;
00770 }
00771 
00772 
00773 long Query::getval(const std::string& x)
00774 {
00775         int index = m_nmap[x] - 1;
00776         if (index >= 0)
00777                 return getval(index);
00778         error("Column name lookup failure: " + x);
00779         return 0;
00780 }
00781 
00782 
00783 _int64 Query::getbigint(const std::string& x)
00784 {
00785         int index = m_nmap[x] - 1;
00786         if (index >= 0)
00787                 return getbigint(index);
00788         error("Column name lookup failure: " + x);
00789         return 0;
00790 }
00791 
00792 
00793 SQL_INTERVAL_STRUCT *Query::getinterval(const std::string& x)
00794 {
00795         int index = m_nmap[x] - 1;
00796         if (index >= 0)
00797                 return getinterval(index);
00798         error("Column name lookup failure: " + x);
00799         return 0;
00800 }
00801 
00802 
00803 const char *Query::get_string(const std::string& sql)
00804 {
00805         m_tmpstr = "";
00806         if (get_result(sql))
00807         {
00808                 if (fetch_row())
00809                 {
00810                         m_tmpstr = getstr();
00811                 }
00812                 free_result();
00813         }
00814         return m_tmpstr.c_str();
00815 }
00816 
00817 
00818 double Query::get_num(const std::string& sql)
00819 {
00820         double l = 0;
00821 
00822         if (get_result(sql))
00823         {
00824                 if (fetch_row())
00825                 {
00826                         l = getnum();
00827                 }
00828                 free_result();
00829         }
00830         return l;
00831 }
00832 
00833 
00834 long Query::get_count(const std::string& sql)
00835 {
00836         long l = 0;
00837 
00838         if (get_result(sql))
00839         {
00840                 if (fetch_row())
00841                 {
00842                         l = getval();
00843                 }
00844                 free_result();
00845         }
00846         return l;
00847 }
00848 
00849 
00850 bool Query::odbc_store_result()
00851 {
00852         SQLRETURN retcode;
00853         SQLHCOL *tmp;
00854         SQLSMALLINT q;
00855         long buf_len;
00856 
00857         retcode = SQLNumResultCols(m_hstmt, &q);
00858         m_qcols = q;
00859 
00860         m_hres = new DSQLHRES(q);
00861 
00862         for (int i = 1; i <= m_hres -> m_num_cols; i++)
00863         {
00864                 tmp = new SQLHCOL;
00865                 retcode = SQLDescribeCol(m_hstmt, (SQLSMALLINT)i, tmp -> szColumnName, STR_LEN,
00866                                         &tmp -> nNameLengthPtr,&tmp -> nDataTypePtr,&tmp -> nColumnSizePtr,
00867                                         &tmp -> nDecimalDigitsPtr,&tmp -> nNullablePtr);
00868                 m_nmap[ (char *)tmp -> szColumnName] = i;
00869                 if (tmp -> nColumnSizePtr == 0x7fffffff)
00870                 {
00871                         buf_len = BUF_LEN;
00872                 }
00873                 else
00874                 {
00875                         buf_len = (tmp -> nColumnSizePtr > BUF_LEN ? tmp -> nColumnSizePtr : BUF_LEN) + 1;
00876                 }
00877                 tmp -> buffer = (SQLUNIONBUFFER *)new char[buf_len];
00878                 *tmp -> szTypeName = 0;
00879                 switch (tmp -> nDataTypePtr)
00880                 {
00881                 case SQL_CHAR:
00882                         strcpy(tmp -> szTypeName, "SQL_CHAR");
00883                         tmp -> nCType = SQL_C_TCHAR; // SQL_C_CHAR;
00884                         break;
00885                 case SQL_VARCHAR:
00886                         strcpy(tmp -> szTypeName, "SQL_VARCHAR");
00887                         tmp -> nCType = SQL_C_TCHAR; // SQL_C_CHAR;
00888                         break;
00889                 case SQL_LONGVARCHAR:
00890                         strcpy(tmp -> szTypeName, "SQL_LONGVARCHAR");
00891                         tmp -> nCType = SQL_C_TCHAR; // SQL_C_CHAR;
00892                         break;
00893                 case SQL_WCHAR:
00894                         strcpy(tmp -> szTypeName, "SQL_WCHAR");
00895                         tmp -> nCType = SQL_C_TCHAR; // SQL_C_WCHAR;
00896                         break;
00897                 case SQL_WVARCHAR:
00898                         strcpy(tmp -> szTypeName, "SQL_WVARCHAR");
00899                         tmp -> nCType = SQL_C_TCHAR; // SQL_C_WCHAR;
00900                         break;
00901                 case SQL_WLONGVARCHAR:
00902                         strcpy(tmp -> szTypeName, "SQL_WLONGVARCHAR");
00903                         tmp -> nCType = SQL_C_TCHAR; // SQL_C_WCHAR;
00904                         break;
00905                 case SQL_DECIMAL:
00906                         strcpy(tmp -> szTypeName, "SQL_DECIMAL");
00907                         tmp -> nCType = SQL_C_CHAR;
00908                         break;
00909                 case SQL_NUMERIC:
00910                         strcpy(tmp -> szTypeName, "SQL_NUMERIC");
00911                         tmp -> nCType = SQL_C_CHAR;
00912                         break;
00913                 case SQL_SMALLINT:
00914                         strcpy(tmp -> szTypeName, "SQL_SMALLINT");
00915                         tmp -> nCType = SQL_C_SSHORT;    // SQL_C_USHORT
00916                         break;
00917                 case SQL_INTEGER:
00918                         strcpy(tmp -> szTypeName, "SQL_INTEGER");
00919                         tmp -> nCType = SQL_C_SLONG;            // SQL_C_ULONG
00920                         break;
00921                 case SQL_REAL:
00922                         strcpy(tmp -> szTypeName, "SQL_REAL");
00923                         tmp -> nCType = SQL_C_FLOAT;
00924                         break;
00925                 case SQL_FLOAT:
00926                         strcpy(tmp -> szTypeName, "SQL_FLOAT");
00927                         tmp -> nCType = SQL_C_DOUBLE;
00928                         break;
00929                 case SQL_DOUBLE:
00930                         strcpy(tmp -> szTypeName, "SQL_DOUBLE");
00931                         tmp -> nCType = SQL_C_DOUBLE;
00932                         break;
00933                 case SQL_BIT:
00934                         strcpy(tmp -> szTypeName, "SQL_BIT");
00935                         tmp -> nCType = SQL_C_BIT;
00936                         break;
00937                 case SQL_TINYINT:
00938                         strcpy(tmp -> szTypeName, "SQL_TINYINT");
00939                         tmp -> nCType = SQL_C_STINYINT; // SQL_C_UTINYINT
00940                         break;
00941                 case SQL_BIGINT:
00942                         strcpy(tmp -> szTypeName, "SQL_BIGINT");
00943                         tmp -> nCType = SQL_C_SBIGINT;          // SQL_C_UBININT
00944                         break;
00945                 case SQL_BINARY:
00946                         strcpy(tmp -> szTypeName, "SQL_BINARY");
00947                         tmp -> nCType = SQL_C_BINARY;
00948                         break;
00949                 case SQL_VARBINARY:
00950                         strcpy(tmp -> szTypeName, "SQL_VARBINARY");
00951                         tmp -> nCType = SQL_C_BINARY;
00952                         break;
00953                 case SQL_LONGVARBINARY:
00954                         strcpy(tmp -> szTypeName, "SQL_LONGVARBINARY");
00955                         tmp -> nCType = SQL_C_BINARY;
00956                         break;
00957                 case SQL_TYPE_DATE:
00958                         strcpy(tmp -> szTypeName, "SQL_TYPE_DATE");
00959                         tmp -> nCType = SQL_C_TYPE_DATE;
00960                         break;
00961                 case SQL_TYPE_TIME:
00962                         strcpy(tmp -> szTypeName, "SQL_TYPE_TIME");
00963                         tmp -> nCType = SQL_C_TYPE_TIME;
00964                         break;
00965                 case SQL_TYPE_TIMESTAMP:
00966                         strcpy(tmp -> szTypeName, "SQL_TYPE_TIMESTAMP");
00967                         tmp -> nCType = SQL_C_TYPE_TIMESTAMP;
00968                         break;
00969                 case SQL_INTERVAL_MONTH:
00970                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_MONTH");
00971                         tmp -> nCType = SQL_C_INTERVAL_MONTH;
00972                         break;
00973                 case SQL_INTERVAL_YEAR:
00974                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_YEAR");
00975                         tmp -> nCType = SQL_C_INTERVAL_YEAR;
00976                         break;
00977                 case SQL_INTERVAL_YEAR_TO_MONTH:
00978                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_YEAR_TO_MONTH");
00979                         tmp -> nCType = SQL_C_INTERVAL_YEAR_TO_MONTH;
00980                         break;
00981                 case SQL_INTERVAL_DAY:
00982                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_DAY");
00983                         tmp -> nCType = SQL_C_INTERVAL_DAY;
00984                         break;
00985                 case SQL_INTERVAL_HOUR:
00986                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_HOUR");
00987                         tmp -> nCType = SQL_C_INTERVAL_HOUR;
00988                         break;
00989                 case SQL_INTERVAL_MINUTE:
00990                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_MINUTE");
00991                         tmp -> nCType = SQL_C_INTERVAL_MINUTE;
00992                         break;
00993                 case SQL_INTERVAL_SECOND:
00994                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_SECOND");
00995                         tmp -> nCType = SQL_C_INTERVAL_SECOND;
00996                         break;
00997                 case SQL_INTERVAL_DAY_TO_HOUR:
00998                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_DAY_TO_HOUR");
00999                         tmp -> nCType = SQL_C_INTERVAL_DAY_TO_HOUR;
01000                         break;
01001                 case SQL_INTERVAL_DAY_TO_MINUTE:
01002                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_DAY_TO_MINUTE");
01003                         tmp -> nCType = SQL_C_INTERVAL_DAY_TO_MINUTE;
01004                         break;
01005                 case SQL_INTERVAL_DAY_TO_SECOND:
01006                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_DAY_TO_SECOND");
01007                         tmp -> nCType = SQL_C_INTERVAL_DAY_TO_SECOND;
01008                         break;
01009                 case SQL_INTERVAL_HOUR_TO_MINUTE:
01010                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_HOUR_TO_MINUTE");
01011                         tmp -> nCType = SQL_C_INTERVAL_HOUR_TO_MINUTE;
01012                         break;
01013                 case SQL_INTERVAL_HOUR_TO_SECOND:
01014                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_HOUR_TO_SECOND");
01015                         tmp -> nCType = SQL_C_INTERVAL_HOUR_TO_SECOND;
01016                         break;
01017                 case SQL_INTERVAL_MINUTE_TO_SECOND:
01018                         strcpy(tmp -> szTypeName, "SQL_INTERVAL_MINUTE_TO_SECOND");
01019                         tmp -> nCType = SQL_C_INTERVAL_MINUTE_TO_SECOND;
01020                         break;
01021                 case SQL_GUID:
01022                         strcpy(tmp -> szTypeName, "SQL_GUID");
01023                         tmp -> nCType = SQL_C_CHAR;
01024                         break;
01025                 default:
01026                         sprintf(tmp -> szTypeName, "<Unknown type id#%d>", tmp -> nDataTypePtr);
01027                         tmp -> nCType = -1;
01028                         error("Query::get_result(): Unknown result set column data type");
01029                 }
01030                 memset(tmp -> buffer -> String, 0, buf_len);
01031                 m_hres -> add_col(tmp);
01032                 tmp -> cbBuffer = buf_len;
01033                 tmp -> tmpstr = NULL;
01034                 retcode = SQLBindCol(m_hstmt, (SQLSMALLINT)i, tmp -> nCType, (SQLPOINTER)tmp -> buffer, buf_len, &tmp -> cbBuffer);
01035         }
01036         return true;
01037 }
01038 
01039 
01040 bool Query::GetColumnInfo(short x,SQLHCOL& hc)
01041 {
01042         if (m_odb && m_hstmt && m_hres && x >= 0 && x < m_hres -> m_num_cols)
01043         {
01044                 memmove(&hc, m_hres -> m_cols[x + 1], sizeof(SQLHCOL));
01045                 hc.next = NULL;
01046                 hc.buffer = NULL;
01047                 hc.tmpstr = NULL;
01048                 return true;
01049         }
01050         return false;
01051 }
01052 
01053 
01054 bool Query::GotMore()
01055 {
01056         return (m_fetchrows < m_results) ? true : false;
01057 }
01058 
01059 
01060 DSQLHRES::DSQLHRES(int q) : m_num_cols((SQLSMALLINT)q)
01061 {
01062         m_colbase = NULL;
01063         m_cols = new SQLHCOL *[q + 1];
01064         for (int i = 0; i <= q; i++)
01065         {
01066                 m_cols[i] = NULL;
01067         }
01068         m_qcols = 0;
01069 }
01070 
01071 
01072 DSQLHRES::~DSQLHRES()
01073 {
01074         SQLHCOL *tmp;
01075 
01076         while (m_colbase)
01077         {
01078                 tmp = m_colbase -> next;
01079                 // ta bort members i m_colbase
01080                 delete m_colbase -> buffer;
01081                 if (m_colbase -> tmpstr)
01082                 {
01083                         delete m_colbase -> tmpstr;
01084                 }
01085                 // ta bort m_colbase
01086                 delete m_colbase;
01087                 m_colbase = tmp;
01088         }
01089         delete m_cols;
01090 }
01091 
01092 
01093 void DSQLHRES::add_col(SQLHCOL *item)
01094 {
01095         SQLHCOL *q = m_colbase;
01096 
01097         item -> next = NULL;
01098         if (!q)
01099         {
01100                 m_colbase = item;
01101         }
01102         else
01103         {
01104                 while (q -> next)
01105                 {
01106                         q = q -> next;
01107                 }
01108                 q -> next = item;
01109         }
01110         m_qcols++;
01111         m_cols[m_qcols] = item;
01112 }
01113 
01114 
01115 void Query::ReturnRowAsXML(std::string& xml,const std::string& strObjectName,long dwFlags)
01116 {
01117         SQLHCOL *col;
01118         std::string typ;
01119         std::string str;
01120         bool endtag = (dwFlags & DQ_XML_ENDTAG) ? true : false;
01121         bool cdata = (dwFlags & DQ_XML_CDATASTRINGS) ? true : false;
01122         bool typeinfo = (dwFlags & DQ_XML_TYPEINFO) ? true : false;
01123         bool append = (dwFlags & DQ_XML_APPEND) ? true : false;
01124         bool xmlbegin = (dwFlags & DQ_XML_BEGIN) ? true : false;
01125         bool xmlend = (dwFlags & DQ_XML_END) ? true : false;
01126         char slask[32000];
01127 
01128         if (m_odb && m_hstmt && m_hres)
01129         {
01130                 if (!append)
01131                 {
01132                         xml = "";
01133                 }
01134                 if (xmlbegin)
01135                 {
01136                         xml += "<xml version=\"1.0\" encoding=\"ISO-8859-1\">\n";
01137                 }
01138                 if (strObjectName != "")
01139                 {
01140                         xml += "<";
01141                         xml += strObjectName;
01142                         xml += ">\n";
01143                 }
01144                 for (int x = 0; x < m_hres -> m_num_cols; x++)
01145                 {
01146                         col = m_hres -> m_cols[x + 1];
01147                         // xml'safe data std::string
01148                         // ---
01149                         if (typeinfo)
01150                         {
01151                                 sprintf(slask," TYPE=\"%s\"", col -> szTypeName);
01152                                 typ = slask;
01153                         }
01154                         else
01155                         {
01156                                 typ = "";
01157                         }
01158                         if (!*getstr(x))
01159                         {
01160                                 sprintf(slask,"<%s%s/>", col -> szColumnName, typ);
01161                                 str = slask;
01162                         }
01163                         else
01164                         if (cdata && (col -> nCType == SQL_C_CHAR || col -> nCType == SQL_C_TCHAR))
01165                         {
01166                                 sprintf(slask,"<%s%s><![CDATA[%s]]></%s>\n", col -> szColumnName, typ, m_db.xmlsafestr(getstr(x)), col -> szColumnName);
01167                                 str = slask;
01168                         }
01169                         else
01170                         {
01171                                 sprintf(slask,"<%s%s>%s</%s>\n", col -> szColumnName, typ, m_db.xmlsafestr(getstr(x)), col -> szColumnName);
01172                                 str = slask;
01173                         }
01174                         xml += str;
01175                 }
01176                 if (endtag && strObjectName != "")
01177                 {
01178                         xml += "</";
01179                         xml += strObjectName;
01180                         xml += ">\n";
01181                 }
01182                 if (xmlend)
01183                 {
01184                         xml += "</xml>\n";
01185                 }
01186         }
01187 }
01188 
01189 
01190 int Query::num_cols()
01191 {
01192         return m_qcols;
01193 }
01194 
01195 
01196 bool Query::getcol(std::string& colname,std::string& coltype,int& width,int& dec,int& nullable)
01197 {
01198         return getcol(m_currentcol++, colname, coltype, width, dec, nullable);
01199 }
01200 
01201 
01202 bool Query::getcol(int x,std::string& colname,std::string& coltype,int& width,int& dec,int& nullable)
01203 {
01204         if (x < m_qcols)
01205         {
01206                 SQLHCOL *col;
01207 
01208                 col = m_hres -> m_cols[x + 1];
01209                 colname = (char *)(col -> szColumnName);
01210                 coltype = col -> szTypeName;
01211                 width = col -> nColumnSizePtr;
01212                 dec = col -> nDecimalDigitsPtr;
01213                 nullable = col -> nNullablePtr;
01214                 return true;
01215         }
01216         else
01217         {
01218                 return false;
01219         }
01220 }
01221 
01222 
01223 void Query::error(const std::string& text)
01224 {
01225         if (m_db.GetErrHandler())
01226         {
01227                 m_db.GetErrHandler() -> error(m_db, *this, text);
01228         }
01229 }
01230 
01231 
01232 bool Query::Connected()
01233 {
01234         return true; // TODO: implement
01235 }
01236 
01237 
01238 Database& Query::GetDatabase() const
01239 {
01240         return m_db;
01241 }
01242 
01243 
01244 const std::string& Query::GetLastQuery()
01245 {
01246         return m_last_query;
01247 }
01248 
01249 
01250 const std::string& Query::GetError()
01251 {
01252         m_errtext = "";
01253         if (m_odb)
01254         {
01255                 m_odb->GetLastError(m_sql_state, m_errtext);
01256         }
01257         return m_errtext;
01258 }
01259 
01260 
01261 int Query::GetErrno()
01262 {
01263         if (m_odb)
01264         {
01265                 return m_odb->GetLastError(m_sql_state, m_errtext);
01266         }
01267         return -1;
01268 }
01269 
01270 
01271 #ifdef ODBCW_NAMESPACE
01272 } // namespace ODBCW_NAMESPACE {
01273 #endif
Page, code, and content Copyright (C) 2006 by Anders Hedström