src/dbapi/driver/ftds64/freetds/odbc/error.c

Go to the documentation of this file.
00001 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
00002  * Copyright (C) 1998-1999  Brian Bruns
00003  * Copyright (C) 2003, 2004, 2005  Frediano Ziglio
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public
00016  * License along with this library; if not, write to the
00017  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018  * Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #if HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif /* HAVE_CONFIG_H */
00024 
00025 #include <stdio.h>
00026 
00027 #if HAVE_STDLIB_H
00028 #include <stdlib.h>
00029 #endif /* HAVE_STDLIB_H */
00030 
00031 #if HAVE_STRING_H
00032 #include <string.h>
00033 #endif /* HAVE_STRING_H */
00034 
00035 #include <assert.h>
00036 
00037 #include "tdsodbc.h"
00038 #include "tdsstring.h"
00039 #include "replacements.h"
00040 
00041 #if HAVE_ODBCSS_H
00042 #include <odbcss.h>
00043 #endif
00044 
00045 #ifdef DMALLOC
00046 #include <dmalloc.h>
00047 #endif
00048 
00049 TDS_RCSID(var, "$Id: error.c 86967 2006-07-31 15:44:10Z ssikorsk $");
00050 
00051 static void odbc_errs_pop(struct _sql_errors *errs);
00052 static const char *odbc_get_msg(const char *sqlstate);
00053 static void odbc_get_v2state(const char *sqlstate, char *dest_state);
00054 static void sqlstate2to3(char *state);
00055 
00056 struct s_SqlMsgMap
00057 {
00058     const char *msg;
00059     char sqlstate[6];
00060 };
00061 
00062 /* This list contains both v2 and v3 messages */
00063 #define ODBCERR(s3,msg) { msg, s3 }
00064 static const struct s_SqlMsgMap SqlMsgMap[] = {
00065     ODBCERR("IM007", "No data source or driver specified"),
00066     ODBCERR("01000", "Warning"),
00067     ODBCERR("01002", "Disconnect error"),
00068     ODBCERR("01004", "Data truncated"),
00069     ODBCERR("01504", "The UPDATE or DELETE statement does not include a WHERE clause"),
00070     ODBCERR("01508", "Statement disqualified for blocking"),
00071     ODBCERR("01S00", "Invalid connection string attribute"),
00072     ODBCERR("01S01", "Error in row"),
00073     ODBCERR("01S02", "Option value changed"),
00074     ODBCERR("01S06", "Attempt to fetch before the result set returned the first rowset"),
00075     ODBCERR("01S07", "Fractional truncation"),
00076     ODBCERR("07001", "Wrong number of parameters"),
00077     ODBCERR("07002", "Too many columns"),
00078     ODBCERR("07005", "The statement did not return a result set"),
00079     ODBCERR("07006", "Invalid conversion"),
00080     ODBCERR("07009", "Invalid descriptor index"),
00081     ODBCERR("08001", "Unable to connect to data source"),
00082     ODBCERR("08002", "Connection in use"),
00083     ODBCERR("08003", "Connection is closed"),
00084     ODBCERR("08004", "The application server rejected establishment of the connection"),
00085     ODBCERR("08007", "Connection failure during transaction"),
00086     ODBCERR("08S01", "Communication link failure"),
00087     ODBCERR("0F001", "The LOB token variable does not currently represent any value"),
00088     ODBCERR("21S01", "Insert value list does not match column list"),
00089     ODBCERR("22001", "String data right truncation"),
00090     ODBCERR("22002", "Invalid output or indicator buffer specified"),
00091     ODBCERR("22003", "Numeric value out of range"),
00092     ODBCERR("22005", "Error in assignment"),
00093     ODBCERR("22007", "Invalid datetime format"),
00094     ODBCERR("22008", "Datetime field overflow"),
00095     ODBCERR("22011", "A substring error occurred"),
00096     ODBCERR("22012", "Division by zero is invalid"),
00097     ODBCERR("22015", "Interval field overflow"),
00098     ODBCERR("22018", "Invalid character value for cast specification"),
00099     ODBCERR("22019", "Invalid escape character"),
00100     ODBCERR("22025", "Invalid escape sequence"),
00101     ODBCERR("22026", "String data, length mismatch"),
00102     ODBCERR("23000", "Integrity constraint violation"),
00103     ODBCERR("24000", "Invalid cursor state"),
00104     ODBCERR("24504", "The cursor identified in the UPDATE, DELETE, SET, or GET statement is not positioned on a row"),
00105     ODBCERR("25501", "Invalid transaction state"),
00106     ODBCERR("28000", "Invalid authorization specification"),
00107     ODBCERR("34000", "Invalid cursor name"),
00108     ODBCERR("37000", "Invalid SQL syntax"),
00109     ODBCERR("40001", "Serialization failure"),
00110     ODBCERR("40003", "Statement completion unknown"),
00111     ODBCERR("42000", "Syntax error or access violation"),
00112     ODBCERR("42601", "PARMLIST syntax error"),
00113     ODBCERR("42818", "The operands of an operator or function are not compatible"),
00114     ODBCERR("42895", "The value of a host variable in the EXECUTE or OPEN statement cannot be used because of its data type"),
00115     ODBCERR("428A1", "Unable to access a file referenced by a host file variable"),
00116     ODBCERR("44000", "Integrity constraint violation"),
00117     ODBCERR("54028", "The maximum number of concurrent LOB handles has been reached"),
00118     ODBCERR("56084", "LOB data is not supported in DRDA"),
00119     ODBCERR("58004", "Unexpected system failure"),
00120     ODBCERR("HY000", "General driver error"),
00121     ODBCERR("HY001", "Memory allocation failure"),
00122     ODBCERR("HY002", "Invalid column number"),
00123     ODBCERR("HY003", "Program type out of range"),
00124     ODBCERR("HY004", "Invalid data type"),
00125     ODBCERR("HY007", "Associated statement is not prepared"),
00126     ODBCERR("HY008", "Operation was cancelled"),
00127     ODBCERR("HY009", "Invalid argument value"),
00128     ODBCERR("HY010", "Function sequence error"),
00129     ODBCERR("HY011", "Operation invalid at this time"),
00130     ODBCERR("HY012", "Invalid transaction code"),
00131     ODBCERR("HY013", "Unexpected memory handling error"),
00132     ODBCERR("HY014", "No more handles"),
00133     ODBCERR("HY016", "Cannot modify an implementation row descriptor"),
00134     ODBCERR("HY017", "Invalid use of an automatically allocated descriptor handle"),
00135     ODBCERR("HY018", "Server declined cancel request"),
00136     ODBCERR("HY021", "Inconsistent descriptor information"),
00137     ODBCERR("HY024", "Invalid attribute value"),
00138     ODBCERR("HY090", "Invalid string or buffer length"),
00139     ODBCERR("HY091", "Descriptor type out of range"),
00140     ODBCERR("HY092", "Invalid option"),
00141     ODBCERR("HY093", "Invalid parameter number"),
00142     ODBCERR("HY094", "Invalid scale value"),
00143     ODBCERR("HY096", "Information type out of range"),
00144     ODBCERR("HY097", "Column type out of range"),
00145     ODBCERR("HY098", "Scope type out of range"),
00146     ODBCERR("HY099", "Nullable type out of range"),
00147     ODBCERR("HY100", "Uniqueness option type out of range"),
00148     ODBCERR("HY101", "Accuracy option type out of range"),
00149     ODBCERR("HY103", "Direction option out of range"),
00150     ODBCERR("HY104", "Invalid precision value"),
00151     ODBCERR("HY105", "Invalid parameter type"),
00152     ODBCERR("HY106", "Fetch type out of range"),
00153     ODBCERR("HY107", "Row value out of range"),
00154     ODBCERR("HY109", "Invalid cursor position"),
00155     ODBCERR("HY110", "Invalid driver completion"),
00156     ODBCERR("HY111", "Invalid bookmark value"),
00157     ODBCERR("HY501", "Invalid data source name"),
00158     ODBCERR("HY503", "Invalid file name length"),
00159     ODBCERR("HY506", "Error closing a file"),
00160     ODBCERR("HY509", "Error deleting a file"),
00161     ODBCERR("HYC00", "Driver not capable"),
00162     ODBCERR("HYT00", "Timeout expired"),
00163     ODBCERR("HYT01", "Connection timeout expired"),
00164     ODBCERR("S0001", "Database object already exists"),
00165     ODBCERR("S0002", "Database object does not exist"),
00166     ODBCERR("S0011", "Index already exists"),
00167     ODBCERR("S0012", "Index not found"),
00168     ODBCERR("S0021", "Column already exists"),
00169     ODBCERR("S0022", "Column not found"),
00170     ODBCERR("", NULL)
00171 };
00172 
00173 #undef ODBCERR
00174 
00175 struct s_v3to2map
00176 {
00177     char v3[6];
00178     char v2[6];
00179 };
00180 
00181 /* Map a v3 SQLSTATE to a v2 */
00182 static const struct s_v3to2map v3to2map[] = {
00183     {"01001", "01S03"},
00184     {"01001", "01S04"},
00185     {"HY019", "22003"},
00186     {"22007", "22008"},
00187     {"22018", "22005"},
00188     {"07005", "24000"},
00189     {"42000", "37000"},
00190     {"HY018", "70100"},
00191     {"42S01", "S0001"},
00192     {"42S02", "S0002"},
00193     {"42S11", "S0011"},
00194     {"42S12", "S0012"},
00195     {"42S21", "S0021"},
00196     {"42S22", "S0022"},
00197     {"42S23", "S0023"},
00198     {"HY000", "S1000"},
00199     {"HY001", "S1001"},
00200     {"07009", "S1002"},
00201     {"HY003", "S1003"},
00202     {"HY004", "S1004"},
00203     {"HY008", "S1008"},
00204     {"HY009", "S1009"},
00205     {"HY024", "S1009"},
00206     {"HY007", "S1010"},
00207     {"HY010", "S1010"},
00208     {"HY011", "S1011"},
00209     {"HY012", "S1012"},
00210     {"HY090", "S1090"},
00211     {"HY091", "S1091"},
00212     {"HY092", "S1092"},
00213 /*  {"07009", "S1093"}, */
00214     {"HY096", "S1096"},
00215     {"HY097", "S1097"},
00216     {"HY098", "S1098"},
00217     {"HY099", "S1099"},
00218     {"HY100", "S1100"},
00219     {"HY101", "S1101"},
00220     {"HY103", "S1103"},
00221     {"HY104", "S1104"},
00222     {"HY105", "S1105"},
00223     {"HY106", "S1106"},
00224     {"HY107", "S1107"},
00225     {"HY108", "S1108"},
00226     {"HY109", "S1109"},
00227     {"HY110", "S1110"},
00228     {"HY111", "S1111"},
00229     {"HYC00", "S1C00"},
00230     {"HYT00", "S1T00"},
00231     {"08001", "S1000"},
00232     {"IM007", "S1000"},
00233     {"", ""}
00234 };
00235 
00236 /* 
00237  * ODBC messages must be sorted by importance
00238  * 1. Errors regarding the status of a transaction
00239  * 2. Other errors (level ordered)
00240  * 3. No-Data messages with a state class of 02 ??
00241  * 4. Warning
00242  * 5. Informational
00243  */
00244 static void
00245 rank_errors(struct _sql_errors *errs)
00246 {
00247     int settled, current, best;
00248     struct _sql_error swapbuf;
00249     char istrans;
00250 
00251     if (errs->ranked == 0 && errs->num_errors > 1) {
00252         /* Find the highest of all unranked errors until there are none left */
00253         for (settled = 0; settled < errs->num_errors; settled++) {
00254             best = -1;
00255             for (current = settled; current < errs->num_errors; current++) {
00256                 istrans = 0;
00257                 switch (errs->errs[current].native) {
00258                 case 1205:
00259                 case 1211:
00260                 case 2625:
00261                 case 3309:
00262                 case 7112:
00263                 case 266:
00264                 case 277:
00265                 case 611:
00266                 case 628:
00267                 case 3902:
00268                 case 3903:
00269                 case 3906:
00270                 case 3908:
00271                 case 6401:
00272                     istrans = 1;
00273                     break;
00274                 }
00275 
00276                 if (istrans == 0) {
00277                     if (strcmp(errs->errs[current].state3,"25000") == 0)
00278                         istrans = 1;
00279                     else if (strcmp(errs->errs[current].state3,"S1012") == 0)
00280                         istrans = 1;
00281                     else if (strcmp(errs->errs[current].state3,"08007") == 0)
00282                         istrans = 1;
00283                 }
00284 
00285                 /* Transaction errors are always best */
00286                 if (istrans == 1 && errs->errs[current].msgstate >= 10) {
00287                     best = current;
00288                     break;
00289                 }
00290 
00291                 if (best == -1)
00292                     best = current;
00293 
00294                 /* Non-terminating comparisons only below this point */
00295                 if (errs->errs[current].msgstate > errs->errs[best].msgstate)
00296                     best = current;
00297             }
00298 
00299             /* swap settled position with best */
00300             if (best != settled) {
00301                 swapbuf = errs->errs[settled];
00302                 errs->errs[settled] = errs->errs[best];
00303                 errs->errs[best] = swapbuf;
00304             }
00305         }
00306     }
00307     errs->ranked = 1;
00308 }
00309 
00310 static const char *
00311 odbc_get_msg(const char *sqlstate)
00312 {
00313     const struct s_SqlMsgMap *pmap = SqlMsgMap;
00314 
00315     /* TODO set flag and use pointers (no strdup) ?? */
00316     while (pmap->msg) {
00317         if (!strcasecmp(sqlstate, pmap->sqlstate)) {
00318             return strdup(pmap->msg);
00319         }
00320         ++pmap;
00321     }
00322     return strdup("");
00323 }
00324 
00325 static void
00326 odbc_get_v2state(const char *sqlstate, char *dest_state)
00327 {
00328     const struct s_v3to2map *pmap = v3to2map;
00329 
00330     while (pmap->v3[0]) {
00331         if (!strcasecmp(pmap->v3, sqlstate)) {
00332             tds_strlcpy(dest_state, pmap->v2, 6);
00333             return;
00334         }
00335         ++pmap;
00336     }
00337     /* return the original if a v2 state is not found */
00338     tds_strlcpy(dest_state, sqlstate, 6);
00339 }
00340 
00341 void
00342 odbc_errs_reset(struct _sql_errors *errs)
00343 {
00344     int i;
00345 
00346     if (errs->errs) {
00347         for (i = 0; i < errs->num_errors; ++i) {
00348             /* TODO see flags */
00349             if (errs->errs[i].msg)
00350                 free((char *) errs->errs[i].msg);
00351             if (errs->errs[i].server)
00352                 free(errs->errs[i].server);
00353         }
00354         TDS_ZERO_FREE(errs->errs);
00355         errs->num_errors = 0;
00356     }
00357     errs->lastrc = SQL_SUCCESS;
00358     errs->ranked = 0;
00359     assert(errs->num_errors == 0);
00360 }
00361 
00362 /** Remove first element */
00363 static void
00364 odbc_errs_pop(struct _sql_errors *errs)
00365 {
00366     if (!errs || !errs->errs || errs->num_errors <= 0)
00367         return;
00368 
00369     if (errs->num_errors == 1) {
00370         odbc_errs_reset(errs);
00371         return;
00372     }
00373 
00374     /* TODO see flags */
00375     if (errs->errs[0].msg)
00376         free((char *) errs->errs[0].msg);
00377     if (errs->errs[0].server)
00378         free(errs->errs[0].server);
00379 
00380     --errs->num_errors;
00381     memmove(&(errs->errs[0]), &(errs->errs[1]), errs->num_errors * sizeof(errs->errs[0]));
00382 }
00383 
00384 void
00385 odbc_errs_add(struct _sql_errors *errs, const char *sqlstate, const char *msg)
00386 {
00387     struct _sql_error *p;
00388     int n = errs->num_errors;
00389 
00390     assert(sqlstate);
00391 
00392     if (errs->errs)
00393         p = (struct _sql_error *) realloc(errs->errs, sizeof(struct _sql_error) * (n + 1));
00394     else
00395         p = (struct _sql_error *) malloc(sizeof(struct _sql_error));
00396     if (!p)
00397         return;
00398     errs->errs = p;
00399 
00400     memset(&errs->errs[n], 0, sizeof(struct _sql_error));
00401     errs->errs[n].native = 0;
00402     tds_strlcpy(errs->errs[n].state3, sqlstate, 6);
00403     odbc_get_v2state(errs->errs[n].state3, errs->errs[n].state2);
00404 
00405     /* TODO why driver ?? -- freddy77 */
00406     errs->errs[n].server = strdup("DRIVER");
00407     errs->errs[n].msg = msg ? strdup(msg) : odbc_get_msg(errs->errs[n].state3);
00408     ++errs->num_errors;
00409 }
00410 
00411 /* TODO check if TDS_UINT is correct for native error */
00412 void
00413 odbc_errs_add_rdbms(struct _sql_errors *errs, TDS_UINT native, const char *sqlstate, const char *msg, int linenum, int msgstate,
00414             const char *server)
00415 {
00416     struct _sql_error *p;
00417     int n = errs->num_errors;
00418 
00419     if (errs->errs)
00420         p = (struct _sql_error *) realloc(errs->errs, sizeof(struct _sql_error) * (n + 1));
00421     else
00422         p = (struct _sql_error *) malloc(sizeof(struct _sql_error));
00423     if (!p)
00424         return;
00425     errs->errs = p;
00426 
00427     memset(&errs->errs[n], 0, sizeof(struct _sql_error));
00428     errs->errs[n].native = native;
00429     if (sqlstate)
00430         tds_strlcpy(errs->errs[n].state2, sqlstate, 6);
00431     else
00432         errs->errs[n].state2[0] = '\0';
00433     strcpy(errs->errs[n].state3, errs->errs[n].state2);
00434     sqlstate2to3(errs->errs[n].state3);
00435 
00436     /* TODO why driver ?? -- freddy77 */
00437     errs->errs[n].server = (server) ? strdup(server) : strdup("DRIVER");
00438     errs->errs[n].msg = msg ? strdup(msg) : odbc_get_msg(errs->errs[n].state3);
00439     errs->errs[n].linenum = linenum;
00440     errs->errs[n].msgstate = msgstate;
00441     ++errs->num_errors;
00442 }
00443 
00444 #define SQLS_MAP(v2,v3) if (strcmp(p,v2) == 0) {strcpy(p,v3); return;}
00445 static void
00446 sqlstate2to3(char *state)
00447 {
00448     char *p = state;
00449 
00450     if (p[0] == 'S' && p[1] == '0' && p[2] == '0') {
00451         p[0] = '4';
00452         p[1] = '2';
00453         p[2] = 'S';
00454         return;
00455     }
00456 
00457     /* TODO optimize with a switch */
00458     SQLS_MAP("01S03", "01001");
00459     SQLS_MAP("01S04", "01001");
00460     SQLS_MAP("22003", "HY019");
00461     SQLS_MAP("22008", "22007");
00462     SQLS_MAP("22005", "22018");
00463     SQLS_MAP("24000", "07005");
00464     SQLS_MAP("37000", "42000");
00465     SQLS_MAP("70100", "HY018");
00466     SQLS_MAP("S1000", "HY000");
00467     SQLS_MAP("S1001", "HY001");
00468     SQLS_MAP("S1002", "07009");
00469     SQLS_MAP("S1003", "HY003");
00470     SQLS_MAP("S1004", "HY004");
00471     SQLS_MAP("S1008", "HY008");
00472     SQLS_MAP("S1009", "HY009");
00473     SQLS_MAP("S1010", "HY007");
00474     SQLS_MAP("S1011", "HY011");
00475     SQLS_MAP("S1012", "HY012");
00476     SQLS_MAP("S1090", "HY090");
00477     SQLS_MAP("S1091", "HY091");
00478     SQLS_MAP("S1092", "HY092");
00479     SQLS_MAP("S1093", "07009");
00480     SQLS_MAP("S1096", "HY096");
00481     SQLS_MAP("S1097", "HY097");
00482     SQLS_MAP("S1098", "HY098");
00483     SQLS_MAP("S1099", "HY099");
00484     SQLS_MAP("S1100", "HY100");
00485     SQLS_MAP("S1101", "HY101");
00486     SQLS_MAP("S1103", "HY103");
00487     SQLS_MAP("S1104", "HY104");
00488     SQLS_MAP("S1105", "HY105");
00489     SQLS_MAP("S1106", "HY106");
00490     SQLS_MAP("S1107", "HY107");
00491     SQLS_MAP("S1108", "HY108");
00492     SQLS_MAP("S1109", "HY109");
00493     SQLS_MAP("S1110", "HY110");
00494     SQLS_MAP("S1111", "HY111");
00495     SQLS_MAP("S1C00", "HYC00");
00496     SQLS_MAP("S1T00", "HYT00");
00497 }
00498 
00499 static SQLRETURN
00500 _SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT numRecord, SQLCHAR FAR * szSqlState,
00501            SQLINTEGER FAR * pfNativeError, SQLCHAR * szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT FAR * pcbErrorMsg)
00502 {
00503     SQLRETURN result;
00504     struct _sql_errors *errs = NULL;
00505     const char *msg;
00506     char *p;
00507 
00508     static const char msgprefix[] = "[FreeTDS][SQL Server]";
00509 
00510     SQLINTEGER odbc_ver = SQL_OV_ODBC2;
00511 
00512     if (numRecord <= 0 || cbErrorMsgMax < 0)
00513         return SQL_ERROR;
00514 
00515     if (!handle)
00516         return SQL_INVALID_HANDLE;
00517 
00518     switch (handleType) {
00519     case SQL_HANDLE_STMT:
00520         odbc_ver = ((TDS_STMT *) handle)->dbc->env->attr.odbc_version;
00521         errs = &((TDS_STMT *) handle)->errs;
00522         break;
00523 
00524     case SQL_HANDLE_DBC:
00525         odbc_ver = ((TDS_DBC *) handle)->env->attr.odbc_version;
00526         errs = &((TDS_DBC *) handle)->errs;
00527         break;
00528 
00529     case SQL_HANDLE_ENV:
00530         odbc_ver = ((TDS_ENV *) handle)->attr.odbc_version;
00531         errs = &((TDS_ENV *) handle)->errs;
00532         break;
00533 
00534     default:
00535         return SQL_INVALID_HANDLE;
00536     }
00537 
00538     if (numRecord > errs->num_errors)
00539         return SQL_NO_DATA_FOUND;
00540     --numRecord;
00541 
00542     rank_errors(errs);
00543 
00544     if (szSqlState) {
00545         if (odbc_ver == SQL_OV_ODBC3)
00546             strcpy((char *) szSqlState, errs->errs[numRecord].state3);
00547         else
00548             strcpy((char *) szSqlState, errs->errs[numRecord].state2);
00549     }
00550 
00551     msg = errs->errs[numRecord].msg;
00552 
00553     if (asprintf(&p, "%s%s", msgprefix, msg) < 0)
00554         return SQL_ERROR;
00555     result = odbc_set_string(szErrorMsg, cbErrorMsgMax, pcbErrorMsg, p, -1);
00556     free(p);
00557 
00558     if (pfNativeError)
00559         *pfNativeError = errs->errs[numRecord].native;
00560 
00561     return result;
00562 }
00563 
00564 SQLRETURN SQL_API
00565 SQLError(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLCHAR FAR * szSqlState, SQLINTEGER FAR * pfNativeError,
00566      SQLCHAR FAR * szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT FAR * pcbErrorMsg)
00567 {
00568     SQLRETURN result;
00569     struct _sql_errors *errs = NULL;
00570     SQLSMALLINT type;
00571     SQLHANDLE handle;
00572 
00573     if (hstmt) {
00574         errs = &((TDS_STMT *) hstmt)->errs;
00575         handle = hstmt;
00576         type = SQL_HANDLE_STMT;
00577     } else if (hdbc) {
00578         errs = &((TDS_DBC *) hdbc)->errs;
00579         handle = hdbc;
00580         type = SQL_HANDLE_DBC;
00581     } else if (henv) {
00582         errs = &((TDS_ENV *) henv)->errs;
00583         handle = henv;
00584         type = SQL_HANDLE_ENV;
00585     } else
00586         return SQL_INVALID_HANDLE;
00587 
00588     rank_errors(errs);
00589 
00590     result = _SQLGetDiagRec(type, handle, 1, szSqlState, pfNativeError, szErrorMsg, cbErrorMsgMax, pcbErrorMsg);
00591 
00592     if (result == SQL_SUCCESS) {
00593         /* remove first error */
00594         odbc_errs_pop(errs);
00595     }
00596 
00597     return result;
00598 }
00599 
00600 #if (ODBCVER >= 0x0300)
00601 SQLRETURN SQL_API
00602 SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT numRecord, SQLCHAR FAR * szSqlState,
00603           SQLINTEGER FAR * pfNativeError, SQLCHAR * szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT FAR * pcbErrorMsg)
00604 {
00605     return _SQLGetDiagRec(handleType, handle, numRecord, szSqlState, pfNativeError, szErrorMsg, cbErrorMsgMax, pcbErrorMsg);
00606 }
00607 
00608 SQLRETURN SQL_API
00609 SQLGetDiagField(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT numRecord, SQLSMALLINT diagIdentifier, SQLPOINTER buffer,
00610         SQLSMALLINT cbBuffer, SQLSMALLINT FAR * pcbBuffer)
00611 {
00612     SQLRETURN result = SQL_SUCCESS;
00613     struct _sql_errors *errs = NULL;
00614     const char *msg;
00615 
00616     SQLINTEGER odbc_ver = SQL_OV_ODBC2;
00617     int cplen;
00618     TDS_STMT *stmt = NULL;
00619     TDS_DBC *dbc = NULL;
00620     TDS_ENV *env = NULL;
00621     char tmp[16];
00622 
00623     if (cbBuffer < 0)
00624         return SQL_ERROR;
00625 
00626     if (!handle)
00627         return SQL_INVALID_HANDLE;
00628 
00629     switch (handleType) {
00630     case SQL_HANDLE_STMT:
00631         stmt = ((TDS_STMT *) handle);
00632         dbc = stmt->dbc;
00633         env = dbc->env;
00634         errs = &stmt->errs;
00635         break;
00636 
00637     case SQL_HANDLE_DBC:
00638         dbc = ((TDS_DBC *) handle);
00639         env = dbc->env;
00640         errs = &dbc->errs;
00641         break;
00642 
00643     case SQL_HANDLE_ENV:
00644         env = ((TDS_ENV *) handle);
00645         errs = &env->errs;
00646         break;
00647 
00648     default:
00649         return SQL_INVALID_HANDLE;
00650     }
00651     odbc_ver = env->attr.odbc_version;
00652 
00653     /* header (numRecord ignored) */
00654     switch (diagIdentifier) {
00655     case SQL_DIAG_DYNAMIC_FUNCTION:
00656         if (handleType != SQL_HANDLE_STMT)
00657             return SQL_ERROR;
00658 
00659         /* TODO */
00660         return odbc_set_string(buffer, cbBuffer, pcbBuffer, "", 0);
00661 
00662     case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
00663         *(SQLINTEGER *) buffer = 0;
00664         return SQL_SUCCESS;
00665 
00666     case SQL_DIAG_NUMBER:
00667         *(SQLINTEGER *) buffer = errs->num_errors;
00668         return SQL_SUCCESS;
00669 
00670     case SQL_DIAG_RETURNCODE:
00671         *(SQLRETURN *) buffer = errs->lastrc;
00672         return SQL_SUCCESS;
00673 
00674     case SQL_DIAG_CURSOR_ROW_COUNT:
00675         if (handleType != SQL_HANDLE_STMT)
00676             return SQL_ERROR;
00677 
00678         /* TODO */
00679         *(SQLINTEGER *) buffer = 0;
00680         return SQL_SUCCESS;
00681 
00682     case SQL_DIAG_ROW_COUNT:
00683         if (handleType != SQL_HANDLE_STMT)
00684             return SQL_ERROR;
00685 
00686         return _SQLRowCount((SQLHSTMT) handle, (SQLLEN FAR *) buffer);
00687     }
00688 
00689     if (numRecord > errs->num_errors)
00690         return SQL_NO_DATA_FOUND;
00691 
00692     if (numRecord <= 0)
00693         return SQL_ERROR;
00694     --numRecord;
00695 
00696     switch (diagIdentifier) {
00697     case SQL_DIAG_ROW_NUMBER:
00698         *(SQLINTEGER *) buffer = SQL_ROW_NUMBER_UNKNOWN;
00699         break;
00700 
00701     case SQL_DIAG_CLASS_ORIGIN:
00702     case SQL_DIAG_SUBCLASS_ORIGIN:
00703         if (odbc_ver == SQL_OV_ODBC2)
00704             result = odbc_set_string(buffer, cbBuffer, pcbBuffer, "ISO 9075", -1);
00705         else
00706             result = odbc_set_string(buffer, cbBuffer, pcbBuffer, "ODBC 3.0", -1);
00707         break;
00708 
00709     case SQL_DIAG_COLUMN_NUMBER:
00710         *(SQLINTEGER *) buffer = SQL_COLUMN_NUMBER_UNKNOWN;
00711         break;
00712 
00713 #ifdef SQL_DIAG_SS_MSGSTATE
00714     case SQL_DIAG_SS_MSGSTATE:
00715         if (errs->errs[numRecord].msgstate == 0)
00716             return SQL_ERROR;
00717         else
00718             *(SQLINTEGER *) buffer = errs->errs[numRecord].msgstate;
00719         break;
00720 #endif
00721 
00722 #ifdef SQL_DIAG_SS_LINE
00723     case SQL_DIAG_SS_LINE:
00724         if (errs->errs[numRecord].linenum == 0)
00725             return SQL_ERROR;
00726         else
00727             *(SQLUSMALLINT *) buffer = errs->errs[numRecord].linenum;
00728         break;
00729 #endif
00730 
00731     case SQL_DIAG_CONNECTION_NAME:
00732         if (dbc && dbc->tds_socket && dbc->tds_socket->spid > 0)
00733             cplen = sprintf(tmp, "%d", dbc->tds_socket->spid);
00734         else
00735             cplen = 0;
00736 
00737         result = odbc_set_string(buffer, cbBuffer, pcbBuffer, tmp, cplen);
00738         break;
00739 
00740     case SQL_DIAG_MESSAGE_TEXT:
00741         msg = errs->errs[numRecord].msg;
00742         result = odbc_set_string(buffer, cbBuffer, pcbBuffer, msg, -1);
00743         break;
00744 
00745     case SQL_DIAG_NATIVE:
00746         *(SQLINTEGER *) buffer = errs->errs[numRecord].native;
00747         break;
00748 
00749     case SQL_DIAG_SERVER_NAME:
00750         msg = "";
00751         switch (handleType) {
00752         case SQL_HANDLE_ENV:
00753             break;
00754         case SQL_HANDLE_DBC:
00755             msg = tds_dstr_cstr(&dbc->server);
00756             break;
00757         case SQL_HANDLE_STMT:
00758             msg = tds_dstr_cstr(&stmt->dbc->server);
00759             /*
00760              * if dbc->server is not initialized, init it
00761              * from the errs structure
00762              */
00763             if (!msg[0] && errs->errs[numRecord].server) {
00764                 tds_dstr_copy(&stmt->dbc->server, errs->errs[numRecord].server);
00765                 msg = errs->errs[numRecord].server;
00766             }
00767             break;
00768         }
00769         result = odbc_set_string(buffer, cbBuffer, pcbBuffer, msg, -1);
00770         break;
00771 
00772     case SQL_DIAG_SQLSTATE:
00773         if (odbc_ver == SQL_OV_ODBC3)
00774             msg = errs->errs[numRecord].state3;
00775         else
00776             msg = errs->errs[numRecord].state2;
00777 
00778         result = odbc_set_string(buffer, cbBuffer, pcbBuffer, msg, 5);
00779         break;
00780 
00781     default:
00782         return SQL_ERROR;
00783     }
00784     return result;
00785 }
00786 #endif
00787 
00788 

Generated on Sun Dec 6 22:23:12 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:59 2009 by modify_doxy.py rev. 173732