int odbcdr_xlt_status( /* Return RDBI equiv of SQL Server status */ odbcdr_context_def *context, SQLRETURN odbcdr_status, SQLSMALLINT handle_type, SQLHANDLE handle ) { int rdbi_status = RDBI_GENERIC_ERROR; debug_on1( "odbcdr_xlt_status","ODBC status: %d", odbcdr_status ); switch( odbcdr_status ) { case SQL_SUCCESS : case SQL_SUCCESS_WITH_INFO : rdbi_status = RDBI_SUCCESS; break; /* DS: THIS IS NOT TRUE! ** SQL_SUCESS_WITH_INFO is returned after executing array DML, if ** there are ignorable errors or if a row operation failed. ** Therefore, we need to search the diagnostic record to see if any ** real errors occured. /* ** In the SQL_ERROR case, we need to check if we can convert it to a ** more specific database error type. The message is saved in the ** context->odbcdr_last_err_msg field. */ case SQL_ERROR : rdbi_status = get_error_from_diag_rec(context, handle_type, handle); break; case SQL_NO_DATA : rdbi_status = RDBI_END_OF_FETCH; break; case SQL_NEED_DATA : case SQL_INVALID_HANDLE : case SQL_STILL_EXECUTING : rdbi_status = RDBI_GENERIC_ERROR; if (context->odbcdr_UseUnicode) save_err_msgW(context, handle_type, handle, 1); // 1 = assuming a connection has already been made else save_err_msg(context, handle_type, handle, 1); // 1 = assuming a connection has already been made break; default: rdbi_status = RDBI_GENERIC_ERROR; } debug_return(NULL, rdbi_status); }
/* ** Execute a statement or set of statements. Print ** any result rows/columns depending on the current mode ** set via the supplied callback. ** ** This is very similar to SQLite's built-in sqlite3_exec() ** function except it takes a slightly different callback ** and callback data argument. */ static int shell_exec( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ int (*xCallback)(void*,int,char**,char**,int*), /* Callback function (not the same as sqlite3_exec) */ struct callback_data *pArg, /* Pointer to struct callback_data */ char **pzErrMsg /* Error msg written here */ ) { sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ int rc = SQLITE_OK; /* Return Code */ const char *zLeftover; /* Tail of unprocessed SQL */ if( pzErrMsg ){ *pzErrMsg = NULL; } while( zSql[0] && (SQLITE_OK == rc) ){ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); if( SQLITE_OK != rc ){ if( pzErrMsg ){ *pzErrMsg = save_err_msg(db); } }else{ if( !pStmt ){ /* this happens for a comment or white-space */ zSql = zLeftover; while( isspace(zSql[0]) ) zSql++; continue; } /* save off the prepared statment handle and reset row count */ if( pArg ){ pArg->pStmt = pStmt; pArg->cnt = 0; } /* perform the first step. this will tell us if we ** have a result set or not and how wide it is. */ rc = sqlite3_step(pStmt); /* if we have a result set... */ if( SQLITE_ROW == rc ){ /* if we have a callback... */ if( xCallback ){ /* allocate space for col name ptr, value ptr, and type */ int nCol = sqlite3_column_count(pStmt); void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1); if( !pData ){ rc = SQLITE_NOMEM; }else{ char **azCols = (char **)pData; /* Names of result columns */ char **azVals = &azCols[nCol]; /* Results */ int *aiTypes = (int *)&azVals[nCol]; /* Result types */ int i; assert(sizeof(int) <= sizeof(char *)); /* save off ptrs to column names */ for(i=0; i<nCol; i++){ azCols[i] = (char *)sqlite3_column_name(pStmt, i); } do{ /* extract the data and data types */ for(i=0; i<nCol; i++){ azVals[i] = (char *)sqlite3_column_text(pStmt, i); aiTypes[i] = sqlite3_column_type(pStmt, i); if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ rc = SQLITE_NOMEM; break; /* from for */ } } /* end for */ /* if data and types extracted successfully... */ if( SQLITE_ROW == rc ){ /* call the supplied callback with the result row data */ if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ rc = SQLITE_ABORT; }else{ rc = sqlite3_step(pStmt); } } } while( SQLITE_ROW == rc ); sqlite3_free(pData); } }else{ do{ rc = sqlite3_step(pStmt); } while( rc == SQLITE_ROW ); } } /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** next statement to execute. */ rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ zSql = zLeftover; while( isspace(zSql[0]) ) zSql++; }else if( pzErrMsg ){ *pzErrMsg = save_err_msg(db); } /* clear saved stmt handle */ if( pArg ){ pArg->pStmt = NULL; } } } /* end while */ return rc; }
static int get_error_from_diag_rec( odbcdr_context_def *context, SQLSMALLINT handle_type, SQLHANDLE handle) { int rdbi_status = RDBI_SUCCESS; int crit_err_found = FALSE; RETCODE rec_retcode = SQL_SUCCESS; RETCODE field_retcode = SQL_SUCCESS; SQLWCHAR szSqlState[ODBCDR_MAX_BUFF_SIZE]; SQLWCHAR szErrorMsg[ODBCDR_MAX_BUFF_SIZE]; SDWORD pfNativeError = 0L; SWORD pcbErrorMsg = 0; SQLSMALLINT cRecNmbr = 1; SDWORD SS_Severity = 0; SQLINTEGER Rownumber = 0; SQLINTEGER Colnumber = 0; szSqlState[0] = L'\0'; szErrorMsg[0] = L'\0'; /* ** Loop through the diagnostic records until there are no records ** left or a critical error is found. ** For now, we will only deal with the first critical error, and ** ignore the rest. */ while ((rec_retcode != SQL_NO_DATA_FOUND) && !crit_err_found) { rec_retcode = (context->odbcdr_UseUnicode) ? SQLGetDiagRecW(handle_type, handle, cRecNmbr, szSqlState, &pfNativeError, szErrorMsg, ODBCDR_MAX_BUFF_SIZE, &pcbErrorMsg) : SQLGetDiagRec(handle_type, handle, cRecNmbr, (SQLCHAR*)szSqlState, &pfNativeError, (SQLCHAR*)szErrorMsg, ODBCDR_MAX_BUFF_SIZE, &pcbErrorMsg); if (rec_retcode != SQL_NO_DATA_FOUND) { field_retcode = (context->odbcdr_UseUnicode) ? SQLGetDiagFieldW( handle_type, handle, cRecNmbr, SQL_DIAG_ROW_NUMBER, &Rownumber, SQL_IS_INTEGER, NULL) : SQLGetDiagField( handle_type, handle, cRecNmbr, SQL_DIAG_ROW_NUMBER, &Rownumber, SQL_IS_INTEGER, NULL); if (Rownumber != SQL_NO_ROW_NUMBER && Rownumber != SQL_ROW_NUMBER_UNKNOWN) { field_retcode = (context->odbcdr_UseUnicode) ? SQLGetDiagFieldW( handle_type, handle, cRecNmbr, SQL_DIAG_COLUMN_NUMBER , &Colnumber, SQL_IS_INTEGER, NULL) : SQLGetDiagField( handle_type, handle, cRecNmbr, SQL_DIAG_COLUMN_NUMBER , &Colnumber, SQL_IS_INTEGER, NULL); } #ifdef _WIN32 field_retcode = (context->odbcdr_UseUnicode) ? SQLGetDiagFieldW( handle_type, handle, cRecNmbr, SQL_DIAG_SS_SEVERITY, &SS_Severity, SQL_IS_INTEGER, NULL): SQLGetDiagField(handle_type, handle, cRecNmbr, SQL_DIAG_SS_SEVERITY, &SS_Severity, SQL_IS_INTEGER,NULL); #endif switch( pfNativeError ) { case 208 : rdbi_status = RDBI_NO_SUCH_TABLE; crit_err_found = TRUE; break; case 916 : rdbi_status = RDBI_NOT_VALID_USER_IN_DATABASE; crit_err_found = TRUE; break; case 1555 : rdbi_status = RDBI_RESOURCE_BUSY; crit_err_found = TRUE; break; case 18456 : rdbi_status = RDBI_INVLD_USER_PSWD; crit_err_found = TRUE; break; case 913: // "Could not find database ID 52. Database may not be activated yet or may be in transition." // Severity 16. This is rather a bug related to updating views. rdbi_status = RDBI_GENERIC_ERROR; break; case 2601: case 2627: // Duplicate index found. rdbi_status = RDBI_DUPLICATE_INDEX; crit_err_found = TRUE; break; case 2714: // There is already an object named '%.*ls' in the database. rdbi_status = RDBI_OBJECT_EXISTS; crit_err_found = TRUE; break; case 3701: // No such object rdbi_status = RDBI_NO_SUCH_TABLE; crit_err_found = TRUE; break; case 229: // insufficient privileges rdbi_status = RDBI_INSUFFICIENT_PRIVS; crit_err_found = TRUE; break; default : // If we did not identify any specific errors in the // diagnostic record, use the severity level to // determine if a error occurred // *** DS doesn't agree. //if (SS_Severity > 10) { rdbi_status = RDBI_GENERIC_ERROR; crit_err_found = TRUE; //} else { // rdbi_status = RDBI_SUCCESS; //} } //switch cRecNmbr++; //Increment to next diagnostic record. } //if plm_retcode } // End while. if (context->odbcdr_UseUnicode) save_err_msgW( context, handle_type, handle, 1); // 1 = assuming a connection has already been made else save_err_msg( context, handle_type, handle, 1); // 1 = assuming a connection has already been made return rdbi_status; }