Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MySQLStatement.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MySQLStatement.cxx
1 // $Id: MySQLStatement.cxx,v 1.1.1.1 2004/02/18 20:58:02 dave Exp $
2 //*-- Author : Valeriy Onuchin 24/02/2001
3 //
4 // RDBC driver to MySQL database implemented with MySQL C API.
5 //
6 
8 //
9 // The object used for executing a static SQL statement and
10 // obtaining the results produced by it.
11 //
12 // Only one TSQLResultSet per TSQLStatement can be open at any point
13 // in time. Therefore, if the reading of one TSQLResultSet is
14 // interleaved with the reading of another, each must have been
15 // generated by different TSQLStatements. All statement execute
16 // methods implicitly close a statment's current TSQLResultSet if
17 // an open one exists.
18 //
19 // See also:
20 // TSQLConnection::CreateStatement(), TSQLResultSet
21 // TSQLCallableStatement TSQLPreparedStatement
22 //Begin_Html
23 /*
24 <P>
25  The <TT>TSQLStatement</TT> class encapsulates SQL queries to your database.
26 Using several methods, these calls return objects that contain the
27 results of your SQL query. When you execute an SQL query, the data
28 that is returned to you is commonly called the result set. You can
29 choose from several result sets, depending on your needs:
30 <UL>
31 <LI><TT>TSQLResultSet* ExecuteQuery( const TString& sqlStatement)<BR></TT>
32 This method sends the SQL query contained in <TT>sqlStatement</TT>
33 and returns a single set of results. This method is best used
34 in sending <TT>SELECT</TT> statements. These statements typically
35 return a result set. This method implicitly deletes previous resultset.
36 
37 <LI><TT>Int_t ExecuteUpdate( const TString& sqlStatement )<BR></TT>
38 This method sends the SQL query contained in <TT>sqlStatement</TT>
39 and returns an integer. This method is useful when you send SQL
40 <TT>INSERT</TT>s, <TT>DELETE</TT>s, and <TT>UPDATE</TT>s. These commands return
41 a count of rows that were affected by your query. This statement
42 should not be used for queries that return result sets.
43 
44 <LI><TT>Bool_t Execute( const TString& sqlStatement )<BR></TT>
45 This method sends the <TT>sqlStatement</TT> to the database and returns
46 <TT>kTRUE</TT> if the statement returns a result set or <TT>kFALSE</TT> if the
47 statement returns an integer. This method is best used when multiple
48 result sets can be returned.
49 </UL>
50 <P>
51 Use the following methods to easily navigate the results a query returns:
52 <UL>
53 <LI><TT>Bool_t GetMoreResults()<BR> </TT>
54 This moves to the next result set in the <TT>TSQLStatement</TT>. This,
55 like the <TT>Execute()</TT> method, returns <TT>kTRUE</TT> if the next
56 result is a result set or <TT>kFALSE</TT> if it is an integer.
57 If you have already retrieved a <TT>TSQLResultSet</TT> from the
58 <TT>TSQLStatement</TT>, this method will close it before returning.
59 
60 <LI><TT>TSQLResultSet* GetResultSet()<BR></TT>
61 This method returns to you a result set in a <TT>TSQLResultSet</TT>
62 object. This result set is the current result set.
63 
64 <LI><TT>Int_t GetUpdateCount()<BR></TT>
65 This method returns to you the integer result that an
66 <TT>Execute()</TT> method returned.
67 </UL>
68 <P>
69 */
70 //End_Html
72 
73 #include <RDBC/TSQLStatement.h>
74 #include <RDBC/TSQLResultSet.h>
75 #include <RDBC/TSQLConnection.h>
76 #include <TList.h>
77 #include "MySQLStatementPrivate.h"
78 
79 
81 
82 
83 //___________________________________________________________________
85  void* imp ):TSQL(imp)
86 {
87  // ctor
88 
89  fBatches = new TList();
90  fConnection = con;
91  fCurrentResult = 0;
92  fImp = new MySQLStatementPrivate();
93 }
94 
95 //___________________________________________________________________
97 {
98  // Destructor.
99  //
100  // Note: When a TSQLStatement is closed, its current
101  // TSQLResultSet, if one exists, is also closed.
102  //
103 
104  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
105  delete imp;
106 
107  ClearBatch();
108  SafeDelete(fBatches);
109 
110  fConnection->GetListOfStatements()->Remove(this);
111  if(fCurrentResult) delete fCurrentResult;
112  Destroyed();
113 }
114 
115 //___________________________________________________________________
117 {
118  // Executes a SQL statement that returns a single TSQLResultSet
119  //
120  // This method also implicitly closes current TSQLResultSet
121  //
122  // Returns:
123  // a TSLResultSet that contains the data produced by the query;
124  // NULL - in case of error
125  //
126  // Throws:
127  // TSQLException - if a database access error occurs
128 
129  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
131 
132  imp->fQuery = sql;
133 
134  ClearWarnings();
135 
137  else fCurrentResult = new TSQLResultSet(this,new MySQLResultSetPrivate());
138 
139  MySQLResultSetPrivate* result = (MySQLResultSetPrivate*)fCurrentResultSet->fImp;
140 
141  TString oldCatalog;
142 
143  if( fConnection->GetCatalog() != imp->fCatalog ) {
144  oldCatalog = fConnection->GetCatalog();
145  fConnection->SetCatalog(imp->fCatalog);
146  }
147 
148  if( imp->fMaxRows && imp->fMaxRows != (Ulong_t)~0L ) {
149  if( !imp->fQuery.Contains("LIMIT",TString::kIgnoreCase) ) {
150  Int_t pos = imp->fQuery.Index("select",0,TString::kIgnoreCase);
151  imp->fQuery.Insert(pos+6,Form(" limit %lu",imp->fMaxRows));
152  }
153  }
154 
155  if( con->CheckIfServerIsAlive() || mysql_query(con->fMYSQL,imp->fQuery)) {
156  Throw(new TSQLException(mysql_error(con->fMYSQL),"S1000",mysql_errno(con->fMYSQL)) );
157  if( !oldCatalog.IsNull() ) fConnection->SetCatalog(oldCatalog);
158  return 0;
159  }
160 
161 #ifdef NOT_USED
162  if( imp->fCursorType == kCURSOR_FORWARD_ONLY &&
163  !(con->fMYSQL->flag & FLAG_SAFE))
164  result->fMYSQL_RES = mysql_use_result(con->fMYSQL);
165  else
166 #endif
167 
168  result->fMYSQL_RES = mysql_store_result(con->fMYSQL);
169 
170  if( !oldCatalog.IsNull() ) fConnection->SetCatalog(oldCatalog);
171 
172  if( !result->fMYSQL_RES ) {
173  if( !mysql_field_count(con->fMYSQL) ) {
174  stmt->state = ST_EXECUTED;
175  stmt->affected_rows = mysql_affected_rows(con->fMYSQL);
176  result->fReallyResult = kFALSE; // no result set
177  return fCurrentResult;
178  }
179 
180  Throw(new TSQLException(mysql_error(con->fMYSQL),"S1000",mysql_errno(con->fMYSQL)));
181  return 0;
182  }
183 
184  result->fCurrentRow = 0;
185  result->fReallyResult = kTRUE;
186  imp->fLastInsertId = fCurrenResult->GetUpdateID();
187 
188  return fCurrentResult;
189 }
190 
191 //___________________________________________________________________
192 Bool_t TSQLStatement::Execute( const TString& sql )
193 {
194  // Executes a SQL statement that may return multiple results.
195  // Under some (uncommon) situations a single SQL statement may
196  // return multiple result sets and/or update counts. Normally you
197  // can ignore this unless you are (1) executing a stored
198  // procedure that you know may return multiple results or (2) you
199  // are dynamically executing an unknown SQL string. The methods
200  // execute, GetMoreResults(), GetResultSet(), and GetUpdateCount()
201  // let you navigate through multiple results.
202  // The execute method executes a SQL statement and indicates the
203  // form of the first result. You can then use GetResultSet() or
204  // GetUpdateCount() to retrieve the result, and GetMoreResults()
205  // to move to any subsequent result(s).
206  //
207  // Parameters:
208  // sql - any SQL statement
209  // Returns:
210  // kTRUE if the next result is a TSQLResultSet;
211  // kFALSE if it is an update count or there are no more
212  // results
213  // Throws:
214  // TSQLException - if a database access error occurs
215  // See Also:
216  // GetResultSet(), GetUpdateCount(), GetMoreResults()
217 
218 
219  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
221 
222  imp->fQuery = sql;
223  ClearWarnings();
224 
226  else fCurrentResult = new TSQLResultSet(this,new MySQLResultSetPrivate());
227 
228  MySQLResultSetPrivate* result = (MySQLResultSetPrivate*)fCurrentResultSet->fImp;
229 
230  TString oldCatalog;
231 
232  if( fConnection->GetCatalog() != imp->fCatalog ) {
233  oldCatalog = fConnection->GetCatalog();
234  fConnection->SetCatalog(imp->fCatalog);
235  }
236 
237  if( imp->fMaxRows && imp->fMaxRows != (Ulong_t)~0L ) {
238  if( !imp->fQuery.Contains("LIMIT",TString::kIgnoreCase) ) {
239  Int_t pos = imp->fQuery.Index("select",0,TString::kIgnoreCase);
240  imp->fQuery.Insert(pos+6,Form(" limit %lu",imp->fMaxRows));
241  }
242  }
243 
244  if( con->CheckIfServerIsAlive() || mysql_query(con->fMYSQL,imp->fQuery)) {
245  Throw(new TSQLException(mysql_error(con->fMYSQL),"S1000",mysql_errno(con->fMYSQL)) );
246  if( !oldCatalog.IsNull() ) fConnection->SetCatalog(oldCatalog);
247  return 0;
248  }
249 
250 #ifdef NOT_USED
251  if( imp->fCursorType == kCURSOR_FORWARD_ONLY &&
252  !(con->fMYSQL->flag & FLAG_SAFE))
253  result->fMYSQL_RES = mysql_use_result(con->fMYSQL);
254  else
255 #endif
256 
257  result->fMYSQL_RES = mysql_store_result(con->fMYSQL);
258 
259  if( !oldCatalog.IsNull() ) fConnection->SetCatalog(oldCatalog);
260 
261  if( !result->fMYSQL_RES ) {
262  if( !mysql_field_count(con->fMYSQL) ) {
263  stmt->state = ST_EXECUTED;
264  stmt->affected_rows = mysql_affected_rows(con->fMYSQL);
265  result->fReallyResult = kFALSE; // no result set
266  return kFALSE;
267  }
268 
269  Throw(new TSQLException(mysql_error(con->fMYSQL),"S1000",mysql_errno(con->fMYSQL)));
270  return kFALSE;
271  }
272 
273  result->fCurrentRow = 0;
274  result->fReallyResult = kTRUE;
275  imp->fLastInsertId = fCurrenResult->GetUpdateID();
276 
277  return kTRUE;
278 }
279 
280 //___________________________________________________________________
281 Int_t TSQLStatement::ExecuteUpdate( const TString& sql )
282 {
283  // Executes an SQL INSERT, UPDATE or DELETE statement.
284  // In addition, SQL statements that return nothing,
285  // such as SQL DDL statements, can be executed.
286  //
287  // Parameters:
288  // sql - a SQL INSERT, UPDATE or DELETE statement or
289  // a SQL statement that returns nothing
290  //
291  // Returns:
292  // either the row count for INSERT, UPDATE or DELETE or
293  // 0 for SQL statements that return nothing
294  // Throws:
295  // TSQLException - if a database access error occurs
296 
297  return return_value;
298 }
299 
300 //___________________________________________________________________
302 {
303  // Returns the current result as a TSQLResultSet object.
304  // This method should be called only once per result.
305  //
306  // This method also implicitly closes any current TSQLResultSet
307  //
308  // Returns:
309  // the current result as a TSQLResultSet; null if the result
310  // is an update count or there are no more results
311  // Throws:
312  // TSQLException - if a database access error occurs
313  // See Also:
314  // Execute(const TString&)
315 
316 }
317 
318 //___________________________________________________________________
320 {
321  // Returns the current result as an update count;
322  // if there are no more results, -1 is returned.
323  // This method should be called only once per result.
324  //
325  // Returns:
326  // the current result as an update count; -1 if it is a
327  // TSQLResultSet or there are no more results
328  // Throws:
329  // TSQLException - if a database access error occurs
330  // See Also:
331  // Execute(const TString&)
332 
333  return return_value;
334 }
335 
336 //___________________________________________________________________
338 {
339  // Moves to a TSQLStatement's next result. It returns kTRUE if
340  // this result is a TSQLResultSet.
341  //
342  // There are no more results when
343  // (!GetMoreResults() && (GetUpdateCount() == -1)
344  //
345  // Returns:
346  // kTRUE if the next result is a TSQLResultSet;
347  // kFALSE if it is an update count or there are no more results
348  //
349  // Throws:
350  // TSQLException - if a database access error occurs
351  // See Also:
352  // Execute(const TString&)
353 
354  return return_value;
355 }
356 
357 //___________________________________________________________________
359 {
360  // Returns the maximum number of bytes allowed for any column
361  // value. This limit is the maximum number of bytes that can be
362  // returned for any column value. The limit applies only to
363  // kBINARY, kVARBINARY, kLONGVARBINARY, kCHAR, kVARCHAR, and
364  // kLONGVARCHAR columns (see TSQLTypes.h). If the limit is exceeded,
365  // the excess data is silently discarded.
366  //
367  // Returns:
368  // the current max column size limit; zero means unlimited
369  // Throws:
370  // TSQLException - if a database access error occurs
371 
372  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
373  reutrn imp->fMaxFieldSize;
374 }
375 
376 //___________________________________________________________________
378 {
379  // Sets the limit for the maximum number of bytes in a column to
380  // the given number of bytes. This is the maximum number of bytes
381  // that can be returned for any column value. This limit applies
382  // only to kBINARY, kVARBINARY, kLONGVARBINARY, kCHAR, kVARCHAR,
383  // and kLONGVARCHAR fields (see TSQLTypes.h) . If the limit is exceeded,
384  // the excess data is silently discarded. For maximum portability,
385  // use values greater than 256.
386  //
387  // Parameters:
388  // max - the new max column size limit; zero means unlimited
389  // Throws:
390  // TSQLException - if a database access error occurs
391 
392  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
393 
394  if( max > MysqlIO.MAXBUF )
395  throw new java.sql.SQLException("Attempt to set max field size > " + MysqlIO.MAXBUF + " (compile time default)", "S1009");
396  else
397  imp->fMaxFieldSize = max;
398 }
399 
400 //___________________________________________________________________
402 {
403  // Retrieves the maximum number of rows that a TSQLResultSet can
404  // contain. If the limit is exceeded, the excess rows are silently
405  // dropped.
406  //
407  // Returns:
408  // the current max row limit; zero means unlimited
409  // Throws:
410  // TSQLException - if a database access error occurs
411 
412  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
413  return imp->fMaxRows <=0 ? 0 : imp->fMaxRows;
414 }
415 
416 //___________________________________________________________________
417 void TSQLStatement::SetMaxRows( Int_t max )
418 {
419  // Sets the limit for the maximum number of rows that any
420  // TSQLResultSet can contain to the given number. If the limit is
421  // exceeded, the excess rows are silently dropped.
422  //
423  // Parameters:
424  // max - the new max rows limit; zero means unlimited
425  // Throws:
426  // TSQLException - if a database access error occurs
427 
428  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
429 
430  if (max > MysqlDefs.MAX_ROWS) {
431  throw new java.sql.SQLException("setMaxRows() out of range. " + max + " > " + MysqlDefs.MAX_ROWS + ".", "S1009");
432  }
433 
434  if (max == 0) {
435  max = -1;
436  }
437 
438  _max_rows = max;
439 
440  // Most people don't use setMaxRows()
441  // so don't penalize them
442  // with the extra query it takes
443  // to do it efficiently unless we need
444  // to.
445 
446  _Conn.maxRowsChanged();
447 }
448 
449 //___________________________________________________________________
451 {
452  // Sets escape processing on or off. If escape scanning is on
453  // (the default), the driver will do escape substitution before
454  // sending the SQL to the database.
455  //
456  // Note:
457  // Since prepared statements have usually been parsed prior to
458  // making this call, disabling escape processing for prepared
459  // statements will have no effect.
460  //
461  // Parameters:
462  // enable - kTRUE to enable; kFALSE to disable
463  // Throws:
464  // TSQLException - if a database access error occurs
465 
466  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
467  imp->fEscapeProcessing = enable;
468 }
469 
470 //___________________________________________________________________
472 {
473  // Returns if escape processing is on or off.
474  // If escape scanning is on (the default), the driver will do escape
475  // substitution before sending the SQL to the database.
476  //
477  // Note:
478  // Since prepared statements have usually been parsed prior to
479  // making this call, disabling escape processing for prepared
480  // statements will have no effect.
481  //
482  // Parameters:
483  // enable - kTRUE to enable; kFALSE to disable
484  // Throws:
485  // TSQLException - if a database access error occurs
486 
487  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
488  return imp->fEscapeProcessing;
489 }
490 
491 //___________________________________________________________________
493 {
494  // Retrieves the number of seconds the driver will wait for a
495  // TSQLStatement to execute. If the limit is exceeded, a
496  // TSQLException is thrown.
497  //
498  // Returns:
499  // the current query timeout limit in seconds; zero means
500  // unlimited
501  // Throws:
502  // TSQLException - if a database access error occurs
503 
504  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
505  return imp->fQueryTimeout;
506 }
507 
508 //___________________________________________________________________
509 void TSQLStatement::SetQueryTimeout( Int_t seconds )
510 {
511  // Sets the number of seconds the driver will wait for a
512  // TSQLStatement to execute to the given number of seconds.
513  // If the limit is exceeded, a TSQLException is thrown.
514  //
515  // Parameters:
516  // seconds - the new query timeout limit in seconds;
517  // zero means unlimited
518  // Throws:
519  // TSQLException - if a database access error occurs
520 
521  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
522  imp->fQueryTimeout = 0; // not imlemented yet
523 }
524 
525 //___________________________________________________________________
527 {
528  // Cancels this statement object if both the DBMS and driver
529  // support aborting an SQL statement. This method can be used by
530  // one thread to cancel a statement that is being executed by
531  // another thread.
532  //
533  // Throws:
534  // TSQLException - if a database access error occurs
535 
536 }
537 
538 //___________________________________________________________________
540 {
541  // Avoid using this method. Use delete TSQLStatement instead.
542  //
543  // Note: When a TSQLStatement is closed, its current
544  // TSQLResultSet, if one exists, is also closed.
545  //
546  // Throws:
547  // TSQLException - if a database access error occurs
548 
549  fImp = 0;
550  Destroyed();
551 }
552 
553 //___________________________________________________________________
554 void TSQLStatement::SetCursorName( const TString& name )
555 {
556  // Defines the SQL cursor name that will be used by subsequent
557  // TSQLStatement execute methods. This name can then be used in
558  // SQL positioned update/delete statements to identify the
559  // current row in the TSQLResultSet generated by this statement.
560  // If the database doesn't support positioned update/delete,
561  // this method is a noop. To insure that a cursor has the proper
562  // isolation level to support updates, the cursor's SELECT
563  // statement should be of the form 'SELECT FOR UPDATE ...'. If
564  // the 'FOR UPDATE' phrase is omitted, positioned updates may
565  // fail.
566  //
567  // Note: By definition, positioned update/delete execution must
568  // be done by a different TSQLStatement than the one which
569  // generated the TSQLResultSet being used for positioning.
570  // Also, cursor names must be unique within a connection.
571  //
572  // Parameters:
573  // name - the new cursor name, which must be unique within
574  // a connection
575  // Throws:
576  // TSQLException - if a database access error occurs
577  //
578  // This MySQL driver does not support cursors.
579 }
580 
581 //___________________________________________________________________
582 void TSQLStatement::SetFetchDirection( Int_t direction )
583 {
584  // Gives the driver a hint as to the direction in which the
585  // rows in a result set will be processed. The hint applies only
586  // to result sets created using this TSQLStatement object.
587  // The default value is TSQLResultSet::kTYPE_FORWARD_ONLY
588  //
589  // Note that this method sets the default fetch direction for
590  // result sets generated by this TSQLStatement object.
591  //
592  // Parameters:
593  // direction - the initial direction for processing rows
594  // Throws:
595  // TSQLException - if a database access error occurs or the
596  // given direction is not one of
597  //
598 }
599 
600 //___________________________________________________________________
602 {
603  // Retrieves the direction for fetching rows from database
604  // tables that is the default for result sets generated from this
605  // TSQLStatement object. If this TSQLStatement object has not set
606  // a fetch direction by calling the method SetFetchDirection(),
607  // the return value is implementation-specific.
608  //
609  // Returns:
610  // the default fetch direction for result sets generated
611  // from this TSQLStatement object
612  // Throws:
613  // TSQLException - if a database access error occurs
614 
615  Int_t return_value = 0;
616  return return_value;
617 }
618 
619 //___________________________________________________________________
621 {
622  // Gives the driver a hint as to the number of rows that
623  // should be fetched from the database when more rows are needed.
624  // The number of rows specified affects only result sets created
625  // using this statement. If the value specified is zero, then the
626  // hint is ignored. The default value is zero.
627  //
628  // Parameters:
629  // rows - the number of rows to fetch
630  // Throws:
631  // TSQLException - if a database access error occurs, or
632  // the condition 0 <= rows <= GetMaxRows() is not satisfied.
633 
634 }
635 
636 //___________________________________________________________________
638 {
639  // Retrieves the number of result set rows that is the default
640  // fetch size for result sets generated from this TSQLStatement
641  // object. If this TSQLStatement object has not set a fetch size
642  // by calling the method SetFetchSize(), the return value is
643  // implementation-specific.
644  //
645  // Returns:
646  // the default fetch size for result sets generated from
647  // this TSQLStatement object
648  // Throws:
649  // TSQLException - if a database access error occurs
650 
651  Int_t return_value = 0;
652  return return_value;
653 }
654 
655 //___________________________________________________________________
657 {
658  // Retrieves the result set concurrency.
659  //
660  // enum EResultSetConcurrency{
661  // kCONCUR_READ_ONLY,
662  // kCONCUR_UPDATABLE
663  // };
664 
665  return kCONCUR_UPDATABLE; // MyODBC says "Anything goes"
666 }
667 
668 //___________________________________________________________________
670 {
671  // Determine the result set type.
672  //
673  // enum EResultSetType{
674  // kTYPE_FORWARD_ONLY,
675  // kTYPE_SCROLL_INSENSITIVE,
676  // kTYPE_SCROLL_SENSITIVE
677  // };
678  //
679 
680  MySQLStatementPrivate* imp = (MySQLStatementPrivate*)fImp;
681  return imp->fCursorType;
682 }
683 
684 //___________________________________________________________________
685 void TSQLStatement::AddBatch( const TString& sql )
686 {
687  // Adds a SQL command to the current batch of commmands for
688  // the statement. This method is optional.
689  //
690  // Parameters:
691  // sql - typically this is a static SQL INSERT or UPDATE
692  // statement
693  // Throws:
694  // TSQLException - if a database access error occurs, or
695  // the driver does not support batch statements
696 
697 }
698 
699 //___________________________________________________________________
701 {
702  // Makes the set of commands in the current batch empty. This
703  // method is optional.
704  //
705  // Throws:
706  // TSQLException - if a database access error occurs or
707  // the driver does not support batch statements
708 
709 }
710 
711 //___________________________________________________________________
713 {
714  // Submits a batch of commands to the database for execution.
715  // This method is optional.
716  //
717  // Returns:
718  // an array of update counts containing one element for
719  // each command in the batch. The array is ordered
720  // according to the order in which commands were inserted
721  // into the batch.
722  //
723  // Throws:
724  // TSQLException - if a database access error occurs or
725  // the driver does not support batch statements
726 
727  return 0;
728 }