Salut, va prezint un alt proiect mai vechi, de aceasta data legat de operarea cu bazele de date access - asta aveam nevoie la timpul respectiv. Sunt doar 4 functii simple una pentru "select" din sql, alta pentru "insert", una pentru recuperarea erori/erorilor si una pentru a face curat dupa celelalte 3 functii. Functiile sunt foarte simple, dar pentru proiectul la care am avut nevoie la momentul respectiv si-au facut treaba cu brio. Pentru a le utiliza aveti nevoie sa legati (link) libraria odbc32. Functiile se folosesc de api-ul ODBC, si pot fi modificate pentru a putea rula cu orice tip de baza de date la care va puteti conecta cu ODBC. Pentru a le utiliza nu trebuie decat sa adaugati cele 2 fisiere proiectului vostru.
functii_odbc.h
#ifndef FUNCTII_ODBC_H_INCLUDED #define FUNCTII_ODBC_H_INCLUDED #include <iostream> #include <string> #include <sstream> #include <fstream> #include <vector> #include <windows.h> #include <sql.h> #include <sqlext.h> int select(std::string dns, int numarCampuri, std::string querry, std::vector<std::vector< std::string> >& array, std::string& erroare); void getErrors(SQLSMALLINT type,SQLHANDLE handle, std::string& error); void freeDbResources(HSTMT& hStmt, HENV& hEnv, HDBC& hDbc); int insert(std::string dns, std::string num_Tabel, std::vector<std::string> Campuri, std::vector<std::string> Valori, std::string& error); #endif // FUNCTII_ODBC_H_INCLUDED
functii_odbc.cpp
#include "functii_odbc.h" /** * Lista argumente: * string dns = adresa fisierului acces mdb/accdb pe hard-disk * numarCampuri = numarul de campuri care urmeaza a fi selectate prin querry-ul respectiv * vector<vector<string> >& array = este un vector de vectori de stringuri, trimis prin referinta care va contine datele extrase * in felul urmator: array[0][0] va fi prima coloana returnata pe primul rand * array[0][1] va fi a 2-a coloana * array[0][2] va fi a 3-a coloana smd * iar array[x][0], x va desemna randul de date extrase * string& eroare = va contine mesajele de eroare, in situatia in care apare o eroare in executia functiei sau a querry-ului atunci aceasta va fi salvata in acest string * Functia are doar 2 valori de return 1 = succes in executarea querry-ului, sau -1 eroare * Functia face doar cateva verificari de baza in privinta corectitudinii querry-ului * De asta trebuie sa se asigure utilizatorul inainte * Functia va verifica doar daca exista un posibil insert in querry caz in care iese. */ using namespace std; int select(string dns, int numarCampuri, string querry, vector<vector<string> >& array, string& erroare) { if(querry.find("SELECT") == string::npos || querry.find("INSERT") != string::npos) { erroare = "Nu ai introdus o comanda de select;"; } else { SQLCHAR valoareCustomers[numarCampuri][128]; HSTMT querryStmt; string tempNume; int retCode[numarCampuri]; HENV hEnv; HDBC hDbc; RETCODE rc; int len = querry.size(); char szConnStrOut[255]; int iConnStrLength2Ptr; char szDSN[256] = "Driver={Microsoft Access Driver (*.mdb)};DSN='';DBQ="; unsigned char* statementQuerry = (unsigned char*)querry.c_str(); //vStrArray.clear(); // golim vectorul primit ca container de output (este datoria utilizatorului sa se asigure ca nu are nimic important in vector inainte de a fi trimis acestei functii strcat(szDSN, dns.c_str()); rc = SQLAllocEnv(&hEnv); if(!SQL_SUCCEEDED(rc)) { erroare = "Nu am putut aloca Envorimentul."; cout << "Nu am putut aloca envorimentul."; freeDbResources(querryStmt, hEnv, hDbc); return -1; } rc = SQLAllocConnect(hEnv, &hDbc); if(!SQL_SUCCEEDED(rc)) { erroare = "Nu am putut aloca conexiunea."; cout << "Nu am putut aloca conexiunea."; freeDbResources(querryStmt, hEnv, hDbc); return -1; } rc = SQLDriverConnect(hDbc, NULL, (SQLCHAR*)szDSN, SQL_NTS, (SQLCHAR*)szConnStrOut, 255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT); if(!SQL_SUCCEEDED(rc)) { getErrors(SQL_HANDLE_DBC , hDbc, erroare); freeDbResources(querryStmt, hEnv, hDbc); return -1; } rc = SQLAllocStmt(hDbc, &querryStmt); if(!SQL_SUCCEEDED(rc)) { erroare = "Nu am putut aloca statementul."; cout << "Nu am putut aloca statementul."; freeDbResources(querryStmt, hEnv, hDbc); return -1; } rc = SQLPrepare(querryStmt, statementQuerry, SQL_NTS); if(!SQL_SUCCEEDED(rc)) { erroare = "Nu am putut pregatii statementul."; cout << "Nu am putut pregatii statementul."; freeDbResources(querryStmt, hEnv, hDbc); return -1; } for(int i = 0; i < numarCampuri; i++) { rc = SQLBindCol(querryStmt, (i + 1), SQL_C_CHAR, valoareCustomers[i], 128, (SQLINTEGER*)&retCode[i]); if(!SQL_SUCCEEDED(rc)) { erroare = "Nu am putut bindui coloana."; cout << "Nu am putut bindui coloana."; freeDbResources(querryStmt, hEnv, hDbc); return -1; } } cout << endl << endl << statementQuerry << endl; rc = SQLExecute(querryStmt); if(SQL_ERROR == rc || SQL_SUCCESS_WITH_INFO == rc) { cout << "Eroare in executare statement, sau SQL_SUCCESS_WITH_INFO"; erroare = "Eroare in executare statement, sau SQL_SUCCESS_WITH_INFO"; getErrors(SQL_HANDLE_STMT, querryStmt, erroare); return -1; } else if(SQL_NEED_DATA == rc) { cout << "SQL_NEED_DATA."; erroare = "SQL_NEED_DATA."; getErrors(SQL_HANDLE_STMT, querryStmt, erroare); return -1; } else if(SQL_STILL_EXECUTING == rc) { cout << "SQL_STILL_EXECUTING."; erroare = "SQL_STILL_EXECUTING."; getErrors(SQL_HANDLE_STMT, querryStmt, erroare); return -1; } else if(SQL_NO_DATA == rc) { cout << "SQL_NO_DATA."; erroare = "SQL_NO_DATA."; getErrors(SQL_HANDLE_STMT, querryStmt, erroare); return -1; } else if(SQL_INVALID_HANDLE == rc) { cout << "SQL_INVALID_HANDLE."; erroare = "SQL_INVALID_HANDLE"; getErrors(SQL_HANDLE_STMT, querryStmt, erroare); return -1; } rc = SQLFetch(querryStmt); if(SQL_SUCCESS == rc) { while(SQL_SUCCEEDED(rc)) { vector<string> vString; string temp; for(int i = 0; i < numarCampuri; i++) { temp = (char*)valoareCustomers[i]; vString.push_back(temp); } array.push_back(vString); rc = SQLFetch(querryStmt); } freeDbResources(querryStmt, hEnv, hDbc); return 1; } else if(SQL_SUCCESS_WITH_INFO == rc || SQL_ERROR == rc) { cout << "Nu am putut executa SQLFetch.\n"; cout << "Nu am putut executa SQLFetch.\n"; getErrors(SQL_HANDLE_STMT, querryStmt, erroare); freeDbResources(querryStmt, hEnv, hDbc); return -1; } else if(SQL_STILL_EXECUTING == rc) { cout << "Inca se executa statementul.\n"; erroare = "Inca se executa statementul.\n"; freeDbResources(querryStmt, hEnv, hDbc); return -1; } else if(SQL_NO_DATA == rc) { cout << "Nu exista date de returnat.\n"; erroare = "Nu exista date de returnat.\n"; freeDbResources(querryStmt, hEnv, hDbc); return -1; } } return -1; } /** * Functia preia prin referinta handle-urile pentru conexiune, mediu si statement si le elibereaza */ void freeDbResources(HSTMT& hStmt, HENV& hEnv, HDBC& hDbc) { SQLFreeStmt(hStmt, SQL_UNBIND); SQLFreeHandle(SQL_HANDLE_STMT, hStmt); SQLDisconnect(hDbc); SQLFreeHandle(SQL_HANDLE_DBC, hDbc); SQLFreeHandle(SQL_HANDLE_ENV, hEnv); } /** * Functia preia datele necesare pentru a putea prelua o eroare legata de un handle pentru conexiune, statement sau mediu * SQLSMALLINT type poate fi: QL_HANDLE_DBC, SQL_HANDLE_DBC_INFO_TOKEN, SQL_HANDLE_DESC, SQL_HANDLE_ENV, SQL_HANDLE_STMT * SQLHANDLE handle va fi de fapt handle-ul pentru care aven nevoie sa preluam eroarea * string& eroare = va tine textul erori * Functia preia doar erorile care pot fi preluate prin SQLGetDiagRec. * Mai multe informatii despre SQLGetDiagRec aici: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716256(v=vs.85).aspx */ void getErrors(SQLSMALLINT type,SQLHANDLE handle, string& eroare) { SQLINTEGER i = 1; SQLINTEGER native; // codul nativ al erori ( depinde de sistemul de operare si de driver SQLCHAR state[7]; // starea driverului mai multe informatii despre state : http://msdn.microsoft.com/en-us/library/windows/desktop/ms716412(v=vs.85).aspx SQLCHAR text[256]; // textul erori SQLSMALLINT len; // marimea textului erori SQLRETURN ret; // stocheaza raspunsul functiei SQLGetDiagRec ret = SQLGetDiagRec(type, handle, i, (SQLCHAR*)state, &native, (SQLCHAR*)text, sizeof(text), &len ); if(SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret) { stringstream buffer(stringstream::in | stringstream::out); string temp; eroare = "Eroare:\n"; eroare.append("State: "); cout << "State: " << state << endl; buffer << state; buffer >> temp; eroare.append(temp); buffer.flush(); string temp3((char*)text); eroare.append("\nTextul eroarei: "); eroare.append(temp3); buffer.flush(); cout << "Textul erori: " << text << endl; } else if(SQL_ERROR == ret) { eroare = "eroare Raporting: SQLGetDiagRec returneaza o eroare.\n"; } else if(SQL_INVALID_HANDLE == ret) { eroare = "eroare Raporting: Handleul furnizat pentru preluarea erori a fost incorect.\n"; } else if(SQL_NO_DATA == ret) { eroare = "eroare Raporting: Nu au fost date de returnat.\n"; } } /** * Lista argumente: * string dns = adresa pe disk a fisierului access * string num_Tabel = numele tabelului in care se face inserarea * vector<string> Campuri = Un vector ce contine campurile in care se va face inserarea * vector<string> Valori = Un vector cu valorile ce vor fi introduse in fiecare camp * string& eroare va tine textul oricarei posibile erori * Pentru cei doi vectori marimea lor trebuie sa fie identica. * Exemplu Campuri va contine stringurile "Nume", "Prenume" "telefon" * vectorul Valori va contine "ION", "VASILE", "02345241590" * Functia are doar 2 valori de return 1 = succes in inserarea datelor, sau -1 eroare */ int insert(string dns, string num_Tabel, vector<string> Campuri, vector<string> Valori, string& eroare) { //Incepem pregatirea statmentului string comanda = "INSERT INTO "; string comanda2 = ") VALUES ('"; string comanda3 = ");"; string campuri_tabel; string campuri_valori; //verificam daca numarul de campuri si de valori e identic if(Campuri.size() != Valori.size()) { eroare = "Numarul de campuri si de valori nu este identic. Pentru ca inserarea sa se poata efectua este necesar ca cele 2 sa fie identice.\n"; return -1; } // pregatim lista cu campurile in care se introduc datele for(unsigned int i = 0; i < Campuri.size(); i++) { if(i == (Campuri.size() - 1)) { campuri_tabel.append(Campuri[i]); //campuri_tabel.append(")"); } else { campuri_tabel.append(Campuri[i]); campuri_tabel.append(", "); } } // pregatim lista cu valorile de introdus for(unsigned int i = 0; i < Valori.size(); i++) { if(i == (Valori.size() - 1)) { campuri_valori.append(Valori[i]); campuri_valori.append("'"); } else { campuri_valori.append(Valori[i]); campuri_valori.append("', '"); } } string sql_statement; sql_statement.append(comanda); sql_statement.append(num_Tabel); sql_statement.append("("); sql_statement.append(campuri_tabel); sql_statement.append(comanda2); sql_statement.append(campuri_valori); sql_statement.append(");"); // am terminat pregatirea statementului // pregatim conexiunea la bd // inceput definitii variabile necesare conexiunii la db HENV hEnv; HDBC hDbc; HSTMT hStmt; RETCODE rc; char szConnStrOut[255]; int iConnStrLength2Ptr; char szDSN[256] = "Driver={Microsoft Access Driver (*.mdb)};DSN='';DBQ="; // incheiere definitii // Initiem conexiunea strcat(szDSN, dns.c_str()); rc = SQLAllocEnv(&hEnv); if(!SQL_SUCCEEDED(rc)) { eroare = "Nu am putut aloca Envorimentul."; cout << "Nu am putut aloca envorimentul."; return -1; } rc = SQLAllocConnect(hEnv, &hDbc); if(!SQL_SUCCEEDED(rc)) { eroare = "Nu am putut aloca conexiunea."; cout << "Nu am putut aloca conexiunea."; return -1; } rc = SQLDriverConnect(hDbc, NULL, (SQLCHAR*)szDSN, SQL_NTS, (SQLCHAR*)szConnStrOut, 255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT); if(!SQL_SUCCEEDED(rc)) { getErrors(SQL_HANDLE_DBC , hDbc, eroare); freeDbResources(hStmt, hEnv, hDbc); return -1; } rc = SQLAllocStmt(hDbc, &hStmt); rc = SQLPrepare(hStmt, (SQLCHAR*)sql_statement.c_str(), SQL_NTS); rc = SQLExecute(hStmt); if(!SQL_SUCCEEDED(rc)) { eroare = "Inserarea nu a putut fi efectuata."; cout << "Inserarea nu a putut fi efectuata."; getErrors(SQL_HANDLE_STMT, hStmt, eroare); freeDbResources(hStmt, hEnv, hDbc); return -1; } else if(SQL_SUCCEEDED(rc)) { freeDbResources(hStmt, hEnv, hDbc); return 1; } return -1; }Sper sa va fie utile.