Avaleht
uus teema   vasta Tarkvara »  Programmeerimine »  access andmebaasiga ühendus C keeles märgi kõik teemad loetuks
märgi mitteloetuks
vaata eelmist teemat :: vaata järgmist teemat
Hinnavaatlus :: Foorum :: Uudised :: Ärifoorumid :: HV F1 ennustusvõistlus :: Pangalink :: Telekavad :: HV toote otsing
autor
sõnum Saada viide sõbrale.  :: Teata moderaatorile teata moderaatorile
otsing:  
O.B.L
HV vaatleja
O.B.L

liitunud: 27.10.2003




sõnum 17.03.2010 22:07:56 access andmebaasiga ühendus C keeles vasta tsitaadiga

Selline mure, kuidas luua C's access anmebaasiga ühendus? Programm, millega kirjutan on DevC++. ADO kasutamine ei ole (vist) võimalik, kuna ado15.dll #import meetodil ei toetata. Järelikult tuleb läbi ODBC teha. (kusjuures DSN ei saa kasutada, siis ei töötaks see teises masinas).
Millised teegid tuleb inkluudida? On teekide järjekord oluline?

Tänud, kui keegi jagaks kogemusi SELECT päringuga.
tagasi üles
vaata kasutaja infot saada privaatsõnum
mikk36
HV Guru
mikk36

liitunud: 21.02.2004




sõnum 17.03.2010 22:54:00 Re: access andmebaasiga ühendus C keeles vasta tsitaadiga

O.B.L kirjutas:
Tänud, kui keegi jagaks kogemusi SELECT päringuga.
http://technet.microsoft.com/en-us/library/cc966377.aspx
Kommentaarid: 85 loe/lisa Kasutajad arvavad:  :: 0 :: 2 :: 78
tagasi üles
vaata kasutaja infot saada privaatsõnum
h2nk
HV vaatleja
h2nk

liitunud: 18.03.2010




sõnum 18.03.2010 01:15:59 vasta tsitaadiga

Miks MS Visuali ei kasuta ?
Tean , et MS visual ja access töötavad omavahel ideealselt.
Kommentaarid: 1 loe/lisa Kasutajad arvavad:  :: 0 :: 0 :: 1
tagasi üles
vaata kasutaja infot saada privaatsõnum
andreie
HV vaatleja
andreie

liitunud: 09.09.2006




sõnum 30.03.2010 14:50:41 vasta tsitaadiga

ODBC ikka. Vaja kasutada päisefaile sql.h ja sqlext.h. Edasi kasutad funktsioone SQLAllocHandle, SQLBindParameter, SQLPrepare, SQLExecDirect jne.

Üldiselt üsna tüütu on, aga saad hakkama küll, kui vähegi viitsid läbi mõelda enne koodi kribamist asjad.

Mina tegin C++ mähkurid, 1 kala neis on veel kindlasti sees, aga mingi idee ehk annavad:
c++:
  1. #ifndef include_utils_odbc_h_
  2. #define include_utils_odbc_h_
  3.  
  4. #include <utils/global.h>
  5. #include <memory>   // std::auto_ptr
  6. #include <list>     // std::list
  7. #include <vector>   // std::vector
  8. #include <utils/util.h> // utils::Option
  9.  
  10. namespace utils {
  11. namespace ODBC {
  12.  
  13. typedef utils::Numeric<unsigned int, 1, 4096>   ColumnIndex;
  14.  
  15. /*****************************************************************************/
  16. /** Internal use only.
  17.  
  18. Wrapper around \c SQLHANDLE.
  19.  
  20. Closing order is childs first, parents last and this is ensured by
  21. maintaining pointers to childs and parents.
  22. */
  23. class Handle {
  24. private:
  25.     void*               h_;         ///< Handle itself.
  26.     int                 h_type_;    ///< Handle type.
  27.     Handle*             parent_;    ///< Parent handle, not for descriptors.
  28.     std::list<Handle*>  childs_;    ///< Childs.
  29. public:
  30.     /** Allocate environment handle and set ODBC version, too.
  31.     \param[in]  handle_type Must be \c SQL_HANDLE_ENV.
  32.     */
  33.     Handle( int     handle_type);
  34.     /** Allocate connection, statement or description handle.
  35.     \param[in]  handle_type One of SQL_HANDLE_DBC, SQL_HANDLE_STMT or SQL_HANDLE_DESC.
  36.     \param[in]  parent      Parent handle.
  37.     */
  38.     Handle( int     handle_type,
  39.             Handle& parent);
  40.  
  41.     /** Destructor also closes the handle. */
  42.     ~Handle();
  43.  
  44.     /** Close the handle, childs first and remove itself from the parent's list of childs. */
  45.     void
  46.     close();
  47.  
  48.     /** Access the handle. */
  49.     void*
  50.     operator()();
  51.  
  52.     /** Access the handle. */
  53.     void*
  54.     handle();
  55.  
  56.     /** Throw exception if the given call resulted in failure.
  57.     \param[in]  caller_name Name of the caller.
  58.     \param[in]  r           Result of the last ODBC call.
  59.     \param[in]  call_name   Name of the ODBC function called.
  60.                             Displayed up to the first opening parenthise '('.
  61.     \param[in]  filename    Name of the C++ file.
  62.     \param[in]  lineno      Line number in the C++ file.
  63.     */
  64.     void
  65.     fail_on_error(  const char*         caller_name,
  66.                     int                 r,
  67.                     const char*         call_name,
  68.                     const char*         filename,
  69.                     const unsigned int  lineno);
  70. }; // class Handle
  71.  
  72. /*****************************************************************************/
  73. /** Query result column data type. */
  74. typedef int DataType;
  75.  
  76. /*****************************************************************************/
  77. /** Column metainfo. */
  78. typedef struct {
  79.     std::string                 name;           ///< Name.
  80.     DataType                    data_type;      ///< SQL Data type.
  81.     utils::Option<unsigned int> size;           ///< Size of the column.
  82.     utils::Option<unsigned int> decimal_digits; ///< Number of decimal digits.
  83.     utils::Option<bool>         nullable;       ///< Is the field nullable.
  84. } ColumnInfo;
  85.  
  86. /*****************************************************************************/
  87. /** Parameter for the prepared query. */
  88. class Parameter {
  89. private:
  90.     friend class Statement;
  91.     friend Parameter*
  92.             makeParameterInt(   const int           param,
  93.                                 Parameter*          next);
  94.     friend Parameter*
  95.             makeParameterInt64( const __int64       param,
  96.                                 Parameter*          next);
  97.  
  98.     friend Parameter*
  99.             makeParameterFloat( const double        param,
  100.                                 Parameter*          next);
  101.  
  102.     friend Parameter*
  103.             makeParameterFloat( const utils::Option<double>&    param,
  104.                                 Parameter*                      next);
  105.  
  106.     friend Parameter*
  107.             makeParameterString(const std::string&  param,
  108.                                 Parameter*          next);
  109.  
  110.     friend Parameter*
  111.             makeParameterStringOut(
  112.                                 std::string&        param,
  113.                                 const unsigned int  max_length,
  114.                                 Parameter*          next);
  115.  
  116.     friend Parameter*
  117.             makeParameterTimestamp( const utils::my_time&   param,
  118.                                     Parameter*              next);
  119.  
  120.     /** SQL data type. */
  121.     typedef enum {
  122.         TYPE_INT_NULL,      ///< Converts to \c SQL_NULL_DATA
  123.         TYPE_INT,           ///< Converts to \c SQL_INTEGER
  124.         TYPE_INT64,         ///< Converts to \c SQL_BIGINT
  125.         TYPE_DOUBLE,        ///< Converts to \c SQL_DOUBLE
  126.         TYPE_DOUBLE_NULL,   ///< Converts to \c SQL_NULL_DATA
  127.         TYPE_STRING,        ///< Converts to \c SQL_CHAR
  128.         TYPE_TIMESTAMP,     ///< Converts to \c SQL_TIMESTAMP
  129.     } TYPE;
  130.  
  131.     /** Parameter direction. */
  132.     typedef enum {
  133.         DIRECTION_IN,
  134.         DIRECTION_OUT,
  135.     } DIRECTION;
  136.  
  137.     TYPE                        type_;          ///< Type of the parameter.
  138.     DIRECTION                   direction_;     ///< Direction.
  139.     std::string                 param_string_;  ///< String parameter.
  140.     std::string*                param_string_out_;  ///< String out parameter.
  141.     long                        param_int_;     ///< 32-bit integer parameter.
  142.     __int64                     param_int64_;   ///< 64-bit integer parameter.
  143.     double                      param_float_;   ///< Floating point parameter.
  144.     long                        param_timestamp_[7];    ///< Timestamp buffer.
  145.     long                        bind_return_;   ///< uh.
  146.     std::auto_ptr<Parameter>    next_;          ///< Next parameter in the row...
  147.  
  148.     /** Construct a parameter. */
  149.     Parameter(  const TYPE          type,
  150.                 Parameter*          next);
  151.  
  152.     /** Bind parameter.
  153.     \param[in]  statement   Statement of prepared query to bind to.
  154.     \param[in]  number      Parameter number, starting from 1.
  155.     */
  156.     void
  157.     bind_parameter( Handle&             statement,
  158.                     const unsigned int  number);
  159. public:
  160.  
  161.     /** Update output parameters, if any.
  162.     *
  163.     * Note: Automatically calls all the others in the chain, too.
  164.     */
  165.     void
  166.     update_output();
  167. }; // class Parameter
  168.  
  169. /*****************************************************************************/
  170. /** Construct \c 32-bit \c integer parameter. */
  171. Parameter*
  172. makeParameterInt(   const int           param,
  173.                     Parameter*          next = 0);
  174.  
  175. /** Construct \c 64-bit \c integer parameter. */
  176. Parameter*
  177. makeParameterInt64( const __int64       param,
  178.                     Parameter*          next = 0);
  179.  
  180. /** Construct \c floating-point parameter. */
  181. Parameter*
  182. makeParameterFloat( const double        param,
  183.                     Parameter*          next = 0);
  184.  
  185. /** Construct \c floating-point parameter. Insert no data if null. */
  186. Parameter*
  187. makeParameterFloat( const utils::Option<double>&    param,
  188.                     Parameter*                      next = 0);
  189.  
  190. /** Construct \c string parameter. */
  191. Parameter*
  192. makeParameterString(const std::string&  param,
  193.                     Parameter*          next = 0);
  194.  
  195. /** Out-parameter of type \c string. */
  196. Parameter*
  197. makeParameterStringOut(
  198.                     std::string&        param,
  199.                     const unsigned int  max_length,
  200.                     Parameter*          next = 0);
  201.  
  202. /** Construct \c datetime parameter. */
  203. Parameter*
  204. makeParameterTimestamp( const utils::my_time&   param,
  205.                         Parameter*              next = 0);
  206. /*****************************************************************************/
  207. /** ODBC statement handle wrapper. */
  208. class Statement {
  209. private:
  210.     friend class Database;
  211.     /** Type of statement. */
  212.     typedef enum {
  213.         TYPE_SINGLE,
  214.         TYPE_PREPARE
  215.     } TYPE;
  216.  
  217.     /** Type of binded data. */
  218.     typedef enum {
  219.         BIND_INT,
  220.         BIND_INT64,
  221.         BIND_DOUBLE,
  222.         BIND_DOUBLE_NULL,    ///< Float, may be null.
  223.         BIND_STRING,
  224.         BIND_TIMESTAMP,
  225.     } BIND;
  226.  
  227.     /** Bind storage. */
  228.     class BindColumn {
  229.     public:
  230.         BindColumn( const BIND  _bind_type);
  231.  
  232.         BIND                    bind_type;
  233.         int*                    ptr_int;
  234.         __int64*                ptr_int64;
  235.         double*                 ptr_float;
  236.         utils::Option<double>*  ptr_float_null;
  237.         std::string*            ptr_string;
  238.         utils::my_time*         ptr_timestamp;
  239.         std::vector<char>       buffer;         ///< buffer used for \c ptr_float_null, \c ptr_string and \c ptr_timestamp.
  240.         long                    buffer_read_;   ///< string length or null data indicator.
  241.     };
  242.  
  243.     std::auto_ptr<Handle>       statement_;     ///< ODBC statement handle.
  244.     std::string                 query_;         ///< Query, just in case icon_smile.gif
  245.     TYPE                        type_;          ///< Single or prepared statement...
  246.     unsigned int                param_count_;   ///< Number of parameters in prepared statement (count of question marks).
  247.     std::auto_ptr<Parameter>    last_params_;   ///< Last parameters passed to the \c execute.
  248.     bool                        columns_fetched_;   ///< Has the column info already been fetched?
  249.     std::list<BindColumn*>      bindings_;      ///< Output column bindings. Updated with \c fetch.
  250. private:
  251.     /** Construct a Statement.
  252.     \param[in]  connection  Connection to be used.
  253.     \param[in]  query       Query to be used.
  254.     \param[in]  type        Type of the statement.
  255.     */
  256.     Statement(  Handle&             connection,
  257.                 const std::string&  query,
  258.                 TYPE                type);
  259.  
  260.     /** Update \c bindings_. Call this after \c SQLFetch(). */
  261.     void
  262.     update_bindings_();
  263. public:
  264.     /** Deconstruct the Statement. */
  265.     ~Statement();
  266.  
  267.     /** Column info. DON'T CHANGE. Call \c fetch_column_info for updating. */
  268.     std::vector<ColumnInfo>  column_info;
  269.  
  270.     /** Fetch column info if not already tried. */
  271.     void
  272.     fetch_column_info();
  273.  
  274.     /** Bind integer. */
  275.     void
  276.     bind(   const ColumnIndex&      column,
  277.             int&                    data);
  278.     /** Bind unsigned integer. */
  279.     void
  280.     bind(   const ColumnIndex&      column,
  281.             unsigned int&           data);
  282.     /** Bind 64-bit integer. */
  283.     void
  284.     bind(   const ColumnIndex&      column,
  285.             __int64&                data);
  286.     /** Bind floating point. */
  287.     void
  288.     bind(   const ColumnIndex&      column,
  289.             double&                 data);
  290.     /** Bind optional floating point data, can be null. */
  291.     void
  292.     bind(   const ColumnIndex&      column,
  293.             utils::Option<double>&  data);
  294.     /** Bind string. */
  295.     void
  296.     bind(   const ColumnIndex&      column,
  297.             std::string&            data,
  298.             const int               max_length = 100);
  299.     /** Bind timestamp. */
  300.     void
  301.     bind(   const ColumnIndex&      column,
  302.             utils::my_time& data);
  303.  
  304.     /** Fetch another row, if possible. */
  305.     bool
  306.     fetch();
  307.  
  308.     /** Fetch another row of generic data. Updates column info by calling \c fetch_column_info. */
  309.     bool
  310.     fetch(  std::vector<std::string>&   row);
  311.  
  312.     /** Execute prepared statement with paremeters.
  313.     \param[in]  params  Parameters, if any. They are deleted automatically.
  314.     */
  315.     void
  316.     execute(    Parameter*  params = 0);
  317.  
  318.     /** Execute prepared statement and return the first column of the first row as integer. */
  319.     int
  320.     query1_int( Parameter*  params = 0);
  321. }; // class Statement
  322.  
  323. /*****************************************************************************/
  324. /** Database connection. */
  325. class Database {
  326. private:
  327.     std::auto_ptr<Handle>   env_;   ///< Environment.
  328.     std::auto_ptr<Handle>   conn_;  ///< Connection
  329.     std::string             dsn_;   ///< Stored DSN name.
  330.     std::auto_ptr<Statement>    last_insert_id_stmt_;   ///< Query for last insert id, cached.
  331.     __int64                     last_insert_id_;
  332. public:
  333.     /** Create database connection.
  334.     \param[in]  dsn         ODBC Data Source Name.
  335.     \param[in]  username    User name.
  336.     \param[in]  password    Password.
  337.     */
  338.     Database(   const std::string&  dsn,
  339.                 const std::string&  username,
  340.                 const std::string&  password);
  341.  
  342.     /** Get DSN name. */
  343.     std::string
  344.     dsn() const;
  345.  
  346.     /** Execute query, no results expected. */
  347.     void
  348.     execute(    const std::string&  query);
  349.  
  350.     /** Execute query and return cursor with results. */
  351.     std::auto_ptr<Statement>
  352.     query(      const std::string&  query);
  353.  
  354.     /** Execute single query and return the first column of the first row as integer. */
  355.     int
  356.     query1_int( const std::string&  query);
  357.  
  358.     /** Prepare a statement for later execution. */
  359.     std::auto_ptr<Statement>
  360.     prepare(    const std::string&  query);
  361.  
  362.     /** Query last insert id. */
  363.     __int64
  364.     last_insert_id();
  365.  
  366. }; // class Connection
  367.  
  368. } // namespace ODBC
  369. } // namespace utils
  370.  
  371. #endif /* include_odbc_h_ */
  372.  
  373.  


c++:
  1. #include <windows.h>    // Needed for ODBC.
  2. #include <sql.h>        // ODBC
  3. #include <sqlext.h>     // SQL_OV_ODBC3
  4. #include <utils/ODBC.h>       // ourselves.
  5.  
  6. #include <utils/util.h>
  7. #include <utils/mystring.h>     // int_of
  8.  
  9.  
  10. using namespace std;
  11. using namespace utils;
  12.  
  13. namespace utils {
  14. namespace ODBC {
  15.  
  16. #define FAIL_ON_ERROR(caller_name, handle, func) (handle).fail_on_error((caller_name), func, #func, __FILE__, __LINE__ )
  17.  
  18. /*****************************************************************************/
  19. /*****************************************************************************/
  20. Handle::Handle( int     handle_type)
  21. :   h_(SQL_NULL_HANDLE)
  22.     ,h_type_(SQL_HANDLE_ENV)
  23.     ,parent_(0)
  24. {
  25.     if (handle_type == SQL_HANDLE_ENV) {
  26.         SQLRETURN   r = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &h_);
  27.         if (!SQL_SUCCEEDED(r)) {
  28.             throw Error("ODBC Error: Unable to allocate environment handle!");
  29.         }
  30.  
  31.         SQLINTEGER  version = SQL_OV_ODBC3;
  32.         try {
  33.             FAIL_ON_ERROR("ODBC::Handle", *this, SQLSetEnvAttr(h_, SQL_ATTR_ODBC_VERSION, (void*)(version), sizeof(version)));
  34.         } catch (exception&) {
  35.             SQLFreeHandle(h_type_, h_);
  36.             throw; // rethrow...
  37.         }
  38.     } else {
  39.         throw Error("ODBC::Handle: invalid parameter (%d) specified for environment handle!", handle_type);
  40.     }
  41. }
  42.  
  43. /*****************************************************************************/
  44. Handle::Handle( int     handle_type,
  45.                 Handle& parent)
  46. :   h_(SQL_NULL_HANDLE)
  47.     ,h_type_(handle_type)
  48.     ,parent_(0)
  49. {
  50.     if (handle_type==SQL_HANDLE_DBC || handle_type==SQL_HANDLE_STMT || handle_type==SQL_HANDLE_DESC) {
  51.         FAIL_ON_ERROR("ODBC::Handle", parent, SQLAllocHandle(handle_type, parent(), &h_));
  52.         parent.childs_.push_front(this);
  53.         parent_ = &parent;
  54.     } else {
  55.         throw Error("ODBC::Handle: invalid parameter (%d) specified for environment handle!", handle_type);
  56.     }
  57. }
  58.  
  59. /*****************************************************************************/
  60. void*
  61. Handle::operator()()
  62. {
  63.     return h_;
  64. }
  65.  
  66. /*****************************************************************************/
  67. void*
  68. Handle::handle()
  69. {
  70.     return h_;
  71. }
  72.  
  73. /*****************************************************************************/
  74. Handle::~Handle()
  75. {
  76.     close();
  77. }
  78.  
  79. /*****************************************************************************/
  80. void
  81. Handle::close()
  82. {
  83.     // Close all childs.
  84.     while (!childs_.empty()) {
  85.         Handle* ch = childs_.front();
  86.         childs_.pop_front();
  87.         ch->close();
  88.     }
  89.  
  90.     // Close ourselves.
  91.     if (h_ != SQL_NULL_HANDLE) {
  92.         SQLFreeHandle(h_type_, h_);
  93.     }
  94.  
  95.     // Unregister us with the parents.
  96.     if (parent_!=0) {
  97.         parent_->childs_.remove(this);
  98.     }
  99. }
  100.  
  101. /*****************************************************************************/
  102. void
  103. Handle::fail_on_error(  const char*         caller_name,
  104.                         int                 r,
  105.                         const char*         call_name,
  106.                         const char*         filename,
  107.                         const unsigned int  lineno)
  108. {
  109.     if (!SQL_SUCCEEDED(r)) {
  110.         SQLCHAR     sqlstate[10];
  111.         SQLINTEGER  native_r;
  112.         SQLCHAR     message[1024];
  113.         SQLSMALLINT message_size;
  114.         memset(sqlstate, 0, sizeof(sqlstate));
  115.         memset(message, 0, sizeof(message));
  116.  
  117.         string      real_call_name(call_name);
  118.         {
  119.             string::size_type  ppos = real_call_name.find('(');
  120.             if (ppos != string::npos) {
  121.                 real_call_name.resize(ppos);
  122.             }
  123.         }
  124.  
  125.         string      real_filename(filename);
  126.         {
  127.             string::size_type   ppos = real_filename.rfind('\\');
  128.             if (ppos != string::npos) {
  129.                 for (unsigned int i=ppos + 1; i<real_filename.size(); ++i) {
  130.                     real_filename[i - ppos - 1] = real_filename[i];
  131.                 }
  132.                 real_filename.resize(real_filename.size() - ppos - 1);
  133.             }
  134.         }
  135.  
  136.         const int   rr = SQLGetDiagRec(h_type_, h_,
  137.                             1,
  138.                             sqlstate,
  139.                             &native_r,
  140.                             message,
  141.                             sizeof(message),
  142.                             &message_size);
  143.         if (SQL_SUCCEEDED(rr)) {
  144.             throw Error("%s: ODBC failed, error: %s, sql state: %s, call: %s, file %s, line %d.",
  145.                     caller_name, message, sqlstate, real_call_name.c_str(), real_filename.c_str(), lineno);
  146.         } else {
  147.             throw Error("%s: ODBC failed for unknown reasons, call: %s", caller_name, call_name);
  148.         }
  149.     }
  150. }
  151.  
  152. /*****************************************************************************/
  153. /*****************************************************************************/
  154. Parameter::Parameter(   const TYPE      type,
  155.                         Parameter*      next)
  156. :   type_(type)
  157.     ,direction_(DIRECTION_IN)
  158.     ,param_int_(0)
  159.     ,param_int64_(0)
  160.     ,param_float_(0)
  161.     ,next_(next)
  162. {
  163. }
  164.  
  165. /*****************************************************************************/
  166. void
  167. Parameter::bind_parameter(  Handle&             statement,
  168.                             const unsigned int  number)
  169. {
  170.     SQLSMALLINT direction = direction_==DIRECTION_IN ? SQL_PARAM_INPUT : SQL_PARAM_OUTPUT;
  171.     SQLSMALLINT value_type = 0// C type
  172.     SQLSMALLINT parameter_type = 0; // SQL type.
  173.     SQLUINTEGER column_size = 0;
  174.     SQLSMALLINT decimal_digits = 0;
  175.     SQLPOINTER  parameter_value = 0; // Pointer to data.
  176.     SQLINTEGER  buffer_length = 0; // Data length.
  177.     bind_return_    = 0;
  178.     switch (type_) {
  179.     case TYPE_INT_NULL:
  180.         value_type      = SQL_C_SLONG;
  181.         parameter_type  = SQL_INTEGER;
  182.         parameter_value = &param_int_;
  183.         bind_return_    = SQL_NULL_DATA;
  184.     case TYPE_INT:
  185.         value_type      = SQL_C_SLONG;
  186.         parameter_type  = SQL_INTEGER;
  187.         parameter_value = &param_int_;
  188.         break;
  189.     case TYPE_INT64:
  190.         value_type      = SQL_C_SBIGINT;
  191.         parameter_type  = SQL_BIGINT;
  192.         parameter_value = &param_int64_;
  193.         break;
  194.     case TYPE_DOUBLE:
  195.         value_type      = SQL_C_DOUBLE;
  196.         parameter_type  = SQL_DOUBLE;
  197.         parameter_value = &param_float_;
  198.         break;
  199.     case TYPE_DOUBLE_NULL:
  200.         value_type      = SQL_C_DOUBLE;
  201.         parameter_type  = SQL_DOUBLE;
  202.         parameter_value = &param_float_;
  203.         bind_return_    = SQL_NULL_DATA;
  204.         break;
  205.     case TYPE_STRING:
  206.         value_type      = SQL_C_CHAR;
  207.         parameter_type  = SQL_CHAR;
  208.         if (direction_ == DIRECTION_IN) {
  209.             column_size     = param_string_.size();
  210.             parameter_value = const_cast<char*>(param_string_.c_str());
  211.         } else {
  212.             column_size     = param_string_out_->size();
  213.             parameter_value = const_cast<char*>(param_string_out_->c_str());
  214.             buffer_length   = param_string_out_->size();
  215.         }
  216.         bind_return_    = SQL_NTS;
  217.         break;
  218.     case TYPE_TIMESTAMP:
  219.         value_type      = SQL_C_TYPE_TIMESTAMP;
  220.         parameter_type  = SQL_TYPE_TIMESTAMP;
  221.         parameter_value = &param_timestamp_[0];
  222.         break;
  223.     }
  224.  
  225.     FAIL_ON_ERROR("ODBC::Parameter", statement,
  226.         SQLBindParameter(statement(), number, direction, value_type, parameter_type,
  227.                         column_size, decimal_digits, parameter_value, buffer_length, &bind_return_));
  228. }
  229.  
  230. /*****************************************************************************/
  231. void
  232. Parameter::update_output()
  233. {
  234.     if (direction_ == DIRECTION_OUT) {
  235.         switch (type_) {
  236.         case TYPE_STRING:
  237.             {
  238.                 const char*         ptr = param_string_out_->c_str();
  239.                 const unsigned int  length = strlen(ptr);
  240.                 param_string_out_->resize(length);
  241.             }
  242.             break;
  243.         }
  244.     }
  245.  
  246.     if (next_.get() != 0) {
  247.         next_->update_output();
  248.     }
  249. }
  250.  
  251. /*****************************************************************************/
  252. Parameter*
  253. makeParameterInt(   const int           param,
  254.                     Parameter*          next)
  255. {
  256.     Parameter*   r = new Parameter(Parameter::TYPE_INT, next);
  257.     r->param_int_ = param;
  258.     return r;
  259. }
  260.  
  261. /*****************************************************************************/
  262. Parameter*
  263. makeParameterInt64( const __int64       param,
  264.                     Parameter*          next)
  265. {
  266.     Parameter*   r = new Parameter(Parameter::TYPE_INT64, next);
  267.     r->param_int64_ = param;
  268.     return r;
  269. }
  270.  
  271. /*****************************************************************************/
  272. Parameter*
  273. makeParameterFloat( const double        param,
  274.                     Parameter*          next)
  275. {
  276.     Parameter*   r = new Parameter(Parameter::TYPE_DOUBLE, next);
  277.     r->param_float_ = param;
  278.     return r;
  279. }
  280.  
  281. /*****************************************************************************/
  282. Parameter*
  283. makeParameterFloat( const utils::Option<double>&    param,
  284.                     Parameter*                      next)
  285. {
  286.     if (param.some()) {
  287.         Parameter*   r = new Parameter(Parameter::TYPE_DOUBLE, next);
  288.         r->param_float_ = param();
  289.         return r;
  290.     } else {
  291.         Parameter*   r = new Parameter(Parameter::TYPE_DOUBLE_NULL, next);
  292.         return r;
  293.     }
  294. }
  295.  
  296. /*****************************************************************************/
  297. Parameter*
  298. makeParameterString(const std::string&  param,
  299.                     Parameter*          next)
  300. {
  301.     Parameter*   r = new Parameter(Parameter::TYPE_STRING, next);
  302.     r->param_string_ = param;
  303.     return r;
  304. }
  305.  
  306. /*****************************************************************************/
  307. Parameter*
  308. makeParameterStringOut(
  309.                     std::string&        param,
  310.                     const unsigned int  max_length,
  311.                     Parameter*          next)
  312. {
  313.     Parameter*   r = new Parameter(Parameter::TYPE_STRING, next);
  314.     r->direction_ = Parameter::DIRECTION_OUT;
  315.     r->param_string_out_ = &param;
  316.     r->param_string_out_->resize(max_length);
  317.     return r;
  318. }
  319.  
  320.  
  321. /*****************************************************************************/
  322. Parameter*
  323. makeParameterTimestamp( const utils::my_time&   param,
  324.                         Parameter*              next)
  325. {
  326.     Parameter*   r = new Parameter(Parameter::TYPE_TIMESTAMP, next);
  327.     SQL_TIMESTAMP_STRUCT*   ts = reinterpret_cast<SQL_TIMESTAMP_STRUCT*>(&r->param_timestamp_[0]);
  328.     ts->year    = param.year;
  329.     ts->month   = param.month;
  330.     ts->day     = param.day;
  331.     ts->hour    = param.hour;
  332.     ts->minute  = param.minute;
  333.     ts->second  = param.second;
  334.     ts->fraction= param.millisecond * 1000 * 1000;
  335.     return r;
  336. }
  337.  
  338. /*****************************************************************************/
  339. /*****************************************************************************/
  340.  
  341. Statement::BindColumn::BindColumn( const BIND  _bind_type)
  342. :   bind_type(_bind_type)
  343.     ,ptr_int(0)
  344.     ,ptr_int64(0)
  345.     ,ptr_float(0)
  346.     ,ptr_float_null(0)
  347.     ,ptr_string(0)
  348.     ,ptr_timestamp(0)
  349.     ,buffer_read_(0)
  350. {
  351. }
  352.  
  353. /*****************************************************************************/
  354. Statement::Statement(   Handle&             connection,
  355.                         const std::string&  query,
  356.                         TYPE                type)
  357. :
  358.     statement_(new Handle(SQL_HANDLE_STMT, connection))
  359.     ,query_(query)
  360.     ,type_(type)
  361.     ,param_count_(0)
  362.     ,columns_fetched_(false)
  363. {
  364.  
  365.     switch (type_) {
  366.     case TYPE_SINGLE:
  367.         // Execute the given query. */
  368.         FAIL_ON_ERROR("ODBC::Statement", *statement_,
  369.             SQLExecDirect(statement_->handle(), (unsigned char*)(query.c_str()), query.size()));
  370.         break;
  371.     case TYPE_PREPARE:
  372.         // Prepare the statement.
  373.         FAIL_ON_ERROR("ODBC::Statement", *statement_,
  374.             SQLPrepare(statement_->handle(), (unsigned char*)(query.c_str()), query.size()));
  375.  
  376.         // Count number of parameters.
  377.         {
  378.             unsigned int    i;
  379.             for (i=0; i<query.size(); ++i) {
  380.                 if (query[i] == '?') {
  381.                     ++param_count_;
  382.                 }
  383.             }
  384.         }
  385.         break;
  386.     }
  387. }
  388.  
  389. /*****************************************************************************/
  390. void
  391. Statement::update_bindings_()
  392. {
  393.     list<BindColumn*>::iterator  it;
  394.     for (it=bindings_.begin(); it!=bindings_.end(); ++it) {
  395.         BindColumn* bc = *it;
  396.         switch (bc->bind_type) {
  397.         case BIND_INT:
  398.             if (bc->buffer_read_ == SQL_NULL_DATA) {
  399.                 *(bc->ptr_int) = 0;
  400.             }
  401.             break;
  402.         case BIND_INT64:
  403.             if (bc->buffer_read_ == SQL_NULL_DATA) {
  404.                 *(bc->ptr_int64) = 0;
  405.             }
  406.             break;
  407.         case BIND_DOUBLE:
  408.             if (bc->buffer_read_ == SQL_NULL_DATA) {
  409.                 *(bc->ptr_float) = 0;
  410.             }
  411.             break;
  412.         case BIND_DOUBLE_NULL:
  413.             if (bc->buffer_read_ == SQL_NULL_DATA) {
  414.                 *(bc->ptr_float_null) = utils::Option<double>();
  415.             } else {
  416.                 *(bc->ptr_float_null) = utils::Option<double>(*reinterpret_cast<double*>(&bc->buffer[0]));
  417.             }
  418.             break;
  419.         case BIND_STRING:
  420.             if (bc->buffer_read_ == SQL_NULL_DATA || bc->buffer_read_<0) {
  421.                 bc->ptr_string->resize(0);
  422.             } else {
  423.                 const unsigned int  n = bc->buffer_read_;
  424.                 string&             s = *(bc->ptr_string);
  425.                 vector<char>&       buffer = bc->buffer;
  426.                 s.resize(n);
  427.                 for (unsigned int i=0; i<n; ++i) {
  428.                     s[i] = buffer[i];
  429.                 }
  430.             }
  431.             break;
  432.         case BIND_TIMESTAMP:
  433.             memset(bc->ptr_timestamp, 0, sizeof(utils::my_time));
  434.             if (bc->buffer_read_ != SQL_NULL_DATA) {
  435.                 const SQL_TIMESTAMP_STRUCT& sql_ts = *reinterpret_cast<SQL_TIMESTAMP_STRUCT*>(&bc->buffer[0]);
  436.                 my_time&                    ts = *bc->ptr_timestamp;
  437.                 ts.year     = sql_ts.year;
  438.                 ts.month    = sql_ts.month;
  439.                 ts.day      = sql_ts.day;
  440.                 ts.hour     = sql_ts.hour;
  441.                 ts.minute   = sql_ts.minute;
  442.                 ts.second   = sql_ts.second;
  443.                 ts.millisecond  = sql_ts.fraction / 1000 / 1000;
  444.             }
  445.             break;
  446.         }
  447.     }
  448. }
  449.  
  450. /*****************************************************************************/
  451. Statement::~Statement()
  452. {
  453.     // Free \c bindings_.
  454.     while (!bindings_.empty()) {
  455.         BindColumn* bc = bindings_.front();
  456.         bindings_.pop_front();
  457.         xdelete(bc);
  458.     }
  459. }
  460.  
  461. /*****************************************************************************/
  462. void
  463. Statement::bind(    const ColumnIndex&  column,
  464.                     int&        data)
  465. {
  466.     BindColumn* r = new BindColumn(BIND_INT);
  467.     r->ptr_int = &data;
  468.     try {
  469.         FAIL_ON_ERROR("ODBC::bind", *statement_,
  470.             SQLBindCol(statement_->handle(), column(), SQL_C_SLONG, r->ptr_int, 0, &r->buffer_read_));
  471.     } catch (const std::exception&) {
  472.         xdelete(r);
  473.         throw;
  474.     }
  475.     bindings_.push_front(r);
  476. }
  477.  
  478. /*****************************************************************************/
  479. void
  480. Statement::bind(    const ColumnIndex&  column,
  481.                     unsigned int&       data)
  482. {
  483.     bind(column, reinterpret_cast<int&>(data));
  484. }
  485. /*****************************************************************************/
  486. void
  487. Statement::bind(    const ColumnIndex&  column,
  488.                     __int64&    data)
  489. {
  490.     BindColumn* r = new BindColumn(BIND_INT64);
  491.     r->ptr_int64 = &data;
  492.     try {
  493.         FAIL_ON_ERROR("ODBC::bind", *statement_,
  494.             SQLBindCol(statement_->handle(), column(), SQL_C_SBIGINT, r->ptr_int64, 0, &r->buffer_read_));
  495.     } catch (const std::exception&) {
  496.         xdelete(r);
  497.         throw;
  498.     }
  499.     bindings_.push_front(r);
  500. }
  501.  
  502. /*****************************************************************************/
  503. void
  504. Statement::bind(    const ColumnIndex&  column,
  505.                     double&             data)
  506. {
  507.     BindColumn* r = new BindColumn(BIND_DOUBLE);
  508.     r->ptr_float = &data;
  509.     try {
  510.         FAIL_ON_ERROR("ODBC::bind", *statement_,
  511.             SQLBindCol(statement_->handle(), column(), SQL_C_DOUBLE, r->ptr_float, 0, &r->buffer_read_));
  512.     } catch (const std::exception&) {
  513.         xdelete(r);
  514.         throw;
  515.     }
  516.     bindings_.push_front(r);
  517. }
  518.  
  519. /*****************************************************************************/
  520. void
  521. Statement::bind(    const ColumnIndex&      column,
  522.                     utils::Option<double>&  data)
  523. {
  524.     BindColumn* r = new BindColumn(BIND_DOUBLE_NULL);
  525.     r->ptr_float_null = &data;
  526.     r->buffer.resize(sizeof(double));
  527.     try {
  528.         FAIL_ON_ERROR("ODBC::bind", *statement_,
  529.             SQLBindCol(statement_->handle(), column(), SQL_C_DOUBLE, &r->buffer[0], 0, &r->buffer_read_));
  530.     } catch (const std::exception&) {
  531.         xdelete(r);
  532.         throw;
  533.     }
  534.     bindings_.push_front(r);
  535. }
  536.  
  537. /*****************************************************************************/
  538. void
  539. Statement::bind(    const ColumnIndex&  column,
  540.                     std::string&        data,
  541.                     const int           max_length)
  542. {
  543.     BindColumn* r = new BindColumn(BIND_STRING);
  544.     r->ptr_string = &data;
  545.     r->buffer.resize(max_length+1);
  546.     try {
  547.         FAIL_ON_ERROR("ODBC::bind", *statement_,
  548.             SQLBindCol(statement_->handle(), column(), SQL_C_CHAR, &r->buffer[0], r->buffer.size(), &r->buffer_read_));
  549.     } catch (const std::exception&) {
  550.         xdelete(r);
  551.         throw;
  552.     }
  553.     bindings_.push_front(r);
  554. }
  555.  
  556. /*****************************************************************************/
  557. void
  558. Statement::bind(    const ColumnIndex&  column,
  559.                     utils::my_time&     data)
  560. {
  561.     BindColumn* r = new BindColumn(BIND_TIMESTAMP);
  562.     r->ptr_timestamp = &data;
  563.     r->buffer.resize(sizeof(SQL_TIMESTAMP_STRUCT));
  564.     try {
  565.         FAIL_ON_ERROR("ODBC::bind", *statement_,
  566.             SQLBindCol(statement_->handle(), column(), SQL_C_TIMESTAMP, &r->buffer[0], 0, &r->buffer_read_));
  567.     } catch (const std::exception&) {
  568.         xdelete(r);
  569.         throw;
  570.     }
  571.     bindings_.push_front(r);
  572. }
  573.  
  574. /*****************************************************************************/
  575. void
  576. Statement::fetch_column_info()
  577. {
  578.     if (columns_fetched_) {
  579.         return;
  580.     } else {
  581.         columns_fetched_ = true;
  582.  
  583.         // Number of results.
  584.         SQLSMALLINT ncol;
  585.         FAIL_ON_ERROR("ODBC::NumColumns", *statement_,
  586.             SQLNumResultCols(statement_->handle(),
  587.                 &ncol));
  588.  
  589.         // Any results?
  590.         if (ncol>0) {
  591.             // Get column info.
  592.             char        info_name[1024];
  593.             SQLSMALLINT info_namelength;
  594.             SQLSMALLINT info_datatype;
  595.             SQLUINTEGER info_colsize;
  596.             SQLSMALLINT info_decimaldigits;
  597.             SQLSMALLINT info_nullable;
  598.  
  599.             column_info.resize(ncol);
  600.             for (int i=0; i<ncol; ++i) {
  601.                 FAIL_ON_ERROR("ODBC::ColumnInfo", *statement_,
  602.                     SQLDescribeCol(statement_->handle(),
  603.                                     i+1,
  604.                                     reinterpret_cast<unsigned char*>(info_name), sizeof(info_name), &info_namelength,
  605.                                     &info_datatype,
  606.                                     &info_colsize,
  607.                                     &info_decimaldigits,
  608.                                     &info_nullable));
  609.                 ColumnInfo& ci = column_info[i];
  610.                 ci.name         = info_name;
  611.                 ci.data_type    = info_datatype;
  612.                 if (info_colsize>0) {
  613.                     ci.size = info_colsize;
  614.                 }
  615.                 if (info_decimaldigits>0) {
  616.                     ci.decimal_digits = info_decimaldigits;
  617.                 }
  618.                 switch (info_nullable) {
  619.                 case SQL_NO_NULLS:
  620.                     ci.nullable = false;
  621.                     break;
  622.                 case SQL_NULLABLE:
  623.                     ci.nullable = true;
  624.                     break;
  625.                 }
  626.             }
  627.         } else {
  628.             throw Error("Statement: query returned no columns.");
  629.         }
  630.     }
  631. }
  632.  
  633. /*****************************************************************************/
  634. bool
  635. Statement::fetch()
  636. {
  637.     SQLRETURN   r = SQLFetch(statement_->handle());
  638.     const bool  ok = SQL_SUCCEEDED(r);
  639.     if (ok) {
  640.         update_bindings_();
  641.     }
  642.     return ok;
  643. }
  644.  
  645. /*****************************************************************************/
  646. bool
  647. Statement::fetch(  std::vector<std::string>&   row)
  648. {
  649.     fetch_column_info();
  650.  
  651.     SQLRETURN   r = SQLFetch(statement_->handle());
  652.     if (SQL_SUCCEEDED(r)) {
  653.         // Update bindings, if any.
  654.         update_bindings_();
  655.  
  656.         // Prepare...
  657.         const unsigned int  ncols = column_info.size();
  658.         char                colbuffer[2048]; // hopefully not longer icon_smile.gif
  659.         SQLINTEGER          colsize;
  660.         row.resize(ncols);
  661.  
  662.         // and SQLGetData All.
  663.         for (unsigned int ColumnIndex=0; ColumnIndex<ncols; ++ColumnIndex) {
  664.             colsize = 0;
  665.             FAIL_ON_ERROR("ODBC::fetch", *statement_,
  666.                 SQLGetData(statement_->handle(),
  667.                             ColumnIndex+1,
  668.                             SQL_C_CHAR,
  669.                             colbuffer,
  670.                             sizeof(colbuffer),
  671.                             &colsize));
  672.             colbuffer[colsize] = 0;
  673.             row[ColumnIndex] = colbuffer;
  674.         }
  675.  
  676.         return true;
  677.     }
  678.     return false;
  679. }
  680.  
  681. /*****************************************************************************/
  682. void
  683. Statement::execute(    Parameter*  params)
  684. {
  685.     // Automatically delete parameters on destroying the statement...
  686.     last_params_ = auto_ptr<Parameter>(params);
  687.  
  688.     // Close open cursor, if any.
  689.     SQLFreeStmt(statement_->handle(), SQL_CLOSE);
  690.  
  691.     // Check type.
  692.     if (type_ != TYPE_PREPARE) {
  693.         throw Error("Tried to execute query that has not been prepared.");
  694.     }
  695.  
  696.     // Count params and check the numbers.
  697.     vector<Parameter*>  vparams;
  698.     {
  699.         for (Parameter* p = params; p!=0; p=p->next_.get()) {
  700.             vparams.push_back(p);
  701.         }
  702.     }
  703.     if (vparams.size() != param_count_) {
  704.         throw Error("Number of parameters given (%d) doesn't match number of parameters in prepared query (%d)!",
  705.                 vparams.size(), param_count_);
  706.     }
  707.  
  708.     // Bind parameters, if any.
  709.     unsigned int ParamIndex;
  710.     for (ParamIndex=0; ParamIndex<vparams.size(); ++ParamIndex) {
  711.         Parameter*  param = vparams[ParamIndex];
  712.         param->bind_parameter(*statement_, ParamIndex+1);
  713.     }
  714.  
  715.     // Execute prepared query.
  716.     FAIL_ON_ERROR("ODBC::execute", *statement_, SQLExecute(statement_->handle()));
  717.  
  718.     // Update output parameters, if any.
  719.     if (params != 0) {
  720.         params->update_output();
  721.     }
  722. }
  723.  
  724. /*****************************************************************************/
  725. int
  726. Statement::query1_int( Parameter*  params)
  727. {
  728.     execute(params);
  729.     vector<string>      row;
  730.     if (fetch(row)) {
  731.         return int_of(row[0]);
  732.     }
  733.     throw Error("query1_int: Expected at least one row, got none.");
  734.     return -1;
  735. }
  736.  
  737. /*****************************************************************************/
  738. /*****************************************************************************/
  739. Database::Database( const std::string&  dsn,
  740.                     const std::string&  username,
  741.                     const std::string&  password)
  742. :   dsn_(dsn)
  743. {
  744.     // Create handles.
  745.     env_    = auto_ptr<Handle>(new Handle(SQL_HANDLE_ENV));
  746.     conn_   = auto_ptr<Handle>(new Handle(SQL_HANDLE_DBC, *env_));
  747.  
  748.     // Connect.
  749.     FAIL_ON_ERROR("ODBC::Database", *conn_,
  750.         SQLConnect(conn_->handle(),
  751.                 (unsigned char*)(dsn.c_str()),      dsn.size(),
  752.                 (unsigned char*)(username.c_str()),     username.size(),
  753.                 (unsigned char*)(password.c_str()),     password.size()
  754.             ));
  755.     // gdblog("ODBC", "Opened data source \"%s\", username \"%s\"", dsn.c_str(), username.c_str());
  756. }
  757.  
  758. /*****************************************************************************/
  759. std::string
  760. Database::dsn() const
  761. {
  762.     return dsn_;
  763. }
  764.  
  765. /*****************************************************************************/
  766. void
  767. Database::execute(  const std::string&  query)
  768. {
  769.     TRACE_PRINT("ODBC", ("Execute: %s", query.c_str()));
  770.     Handle  stmt(SQL_HANDLE_STMT, *conn_);
  771.     FAIL_ON_ERROR("ODBC::execute", *conn_,
  772.         SQLExecDirect(stmt(), (unsigned char*)(query.c_str()), query.size()));
  773. }
  774.  
  775. /*****************************************************************************/
  776. std::auto_ptr<Statement>
  777. Database::query(      const std::string&  query)
  778. {
  779.     TRACE_PRINT("ODBC", ("Query: %s", query.c_str()));
  780.     return auto_ptr<Statement>(new Statement(*conn_, query, Statement::TYPE_SINGLE));
  781. }
  782.  
  783. /*****************************************************************************/
  784. int
  785. Database::query1_int( const std::string&  query)
  786. {
  787.     auto_ptr<Statement> cursor(this->query(query));
  788.     vector<string>      row;
  789.     if (cursor->fetch(row)) {
  790.         return int_of(row[0]);
  791.     }
  792.     throw Error("query1_int: Expected at least one row, got none.");
  793.     return -1;
  794. }
  795.  
  796. /*****************************************************************************/
  797. std::auto_ptr<Statement>
  798. Database::prepare(    const std::string&  query)
  799. {
  800.     TRACE_PRINT("ODBC", ("Prepare: %s", query.c_str()));
  801.     return auto_ptr<Statement>(new Statement(*conn_, query, Statement::TYPE_PREPARE));
  802. }
  803.  
  804. /*****************************************************************************/
  805. __int64
  806. Database::last_insert_id()
  807. {
  808.     if (last_insert_id_stmt_.get() == 0) {
  809.         last_insert_id_stmt_ = prepare("select @@identity");
  810.         last_insert_id_stmt_->bind(1, last_insert_id_);
  811.     }
  812.     last_insert_id_stmt_->execute();
  813.     if (last_insert_id_stmt_->fetch()) {
  814.         return last_insert_id_;
  815.     } else {
  816.         conn_->fail_on_error("last_insert_id", -1, "SQLFetch @@identity", __FILE__, __LINE__);
  817.     }
  818.     return -1;
  819. }
  820.  
  821. } // namespace ODBC
  822. } // namespace utils
  823.  


O.B.L kirjutas:
(kusjuures DSN ei saa kasutada, siis ei töötaks see teises masinas).

Pead kasutama kasutama andmebaasi tüüreli spetsiifilist süntaksi. Mõnikord see sõltub ka tüüreli versioonist (näiteks mysql-i puhul on nii).

_________________
Unix survives only because everyone else has done so badly.
Kommentaarid: 5 loe/lisa Kasutajad arvavad:  :: 0 :: 0 :: 5
tagasi üles
vaata kasutaja infot saada privaatsõnum
näita postitusi alates eelmisest:   
uus teema   vasta Tarkvara »  Programmeerimine »  access andmebaasiga ühendus C keeles
[vaata eelmist teemat] [vaata järgmist teemat]
 lisa lemmikuks
näita foorumit:  
 ignoreeri teemat 
sa ei või postitada uusi teemasid siia foorumisse
sa ei või vastata selle foorumi teemadele
sa ei või muuta oma postitusi selles foorumis
sa ei või kustutada oma postitusi selles foorumis
sa ei või vastata küsitlustele selles foorumis
sa ei saa lisada manuseid selles foorumis
sa võid manuseid alla laadida selles foorumis



Hinnavaatlus ei vastuta foorumis tehtud postituste eest.