Tuesday, July 3, 2012

[C++]Functii odbc operare baza date access 2003-2007




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.

[C++]Generator de lista cuvinte(passwords)




Va prezint un proiect ceva mai vechi de al meu, acesta a fost scris in principiu pentru a genera toate combinatiile, ordonat, ale unei liste de caractere. Generarea cuvintelor se face incepand cu un cuvant format din prima litera a sirului * lungimea dorita a cuvantului si se va termina cu un cuvant format din ultima litera din sir * lingimea cuvantului cerut.De exemplu pentru un sir de caracter a-z si lungimea cuvantului de 5 caractere, functia va incepe cu "aaaaa" si va termina cu "zzzzz". Generarea se face printr-o functie recursiva, intr-un thread separat pentru a nu bloca interfata aplicatiei. Sistemul nu este nici cel mai eficient si nici cel mai rapid, totusi poate fi folosit ca punct de plecare. Proiectul a fost scris utilizant framework-ul wxWidgets, inclusiv modelul de threading al acestuia. Puteti compila cele 4 fisiere cpp/h adaugandu-le unui proiect menit sa compileze o aplicatie wxWidgets. In mod normal ar trebui sa poata fi compilata chiar si pe linux cu un minim de modificari, totusi nu am testat la momentul respectiv. Proiectul a fost postat initial aici, unde puteti si adresa intrebari daca aveti. Link-ul direct pentru a descarca proiectul se gaseste aici.