Connessione a MS Sqlserver

di il
7 risposte

Connessione a MS Sqlserver

Buongiorno a tutti.

Sto partendo da zero con C++ con editor Notepad++ e come compilatore G++ (mingw64). Oltre agli esempi di base con cui fare delle prove mi vorrei avventurare a leggere e scrivere in un db Microsoft SqlServer. Mi sono arenato subito con questo sorgente di esempio trovato in rete (se serve lo posto per intero):

#include <iostream>
#include <windows.h>
#include <sqltypes.h>
#include <sql.h>
#include <sqlext.h>
[…]
printf("Driver Initialised\n");
SQLTCHAR retconstring[1024];
printf("about to Driver Conneect\n");
retcode = SQLDriverConnect(sqlconnectionhandle,
   NULL,
   (SQLTCHAR*)"DRIVER={SQL Server};SERVER=nomedelmioserver, 3055;DATABASE=nomedelmiodb;UID=sa;PWD=miapasssword;",
   SQL_NTS,
   retconstring,
   1024,
   NULL,
   SQL_DRIVER_NOPROMPT);

In fase di compilazione mi dà (tra le altre):

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\WSI09\AppData\Local\Temp\ccCK9PhV.o:sqlodbc.c++:(.text+0x1da): undefined reference to `SQLDriverConnect'

Ovviamente lo stesso errore me lo dà anche per altre funzioni (SQLFreeHandle, SQLDisconnect, ecc.). Ora ho provato a scaricare un “client SDK” di Microsoft (che non sono per niente sicuro che c’entri qualcosa) con la libreria “msodbcsql18.lib” ma anche compilando con:

“g++ sqlodbc.c++  -L"C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Lib\x64\msodbcsql18.lib" -o"sqlodbc.exe" “ 

Ottengo lo stesso risultato. In prima battuta i dubbi sono: dove prendere la libreria giusta e come compilarlo? Però in seconda battuta non sono fissato con ODBC (anzi!), potrei anche usare OLEDB o qualsiasi altra cosa mi consigliate … purché funzioni :-)

Qual è la strada più semplice e sicura per accedere a questo tipo di db sql?

C’è un tutorial a prova di newbie che mi aiuti passo passo? Perché ho cercato in Internet (veramente tanto, ma probabilmente in modo errato) e non ho trovato niente. Mi pare inoltre che Microsoft spinga pesantemente verso Visual C++, cosa che vorrei evitare.

Grazie anticipato a chi potrà darmi una mano.

7 Risposte

  • Re: Connessione a MS Sqlserver

    Tutto sbagliato! 

    Tutto da rifare!

    Per essere inesperto stai tentando di seguire la strada piu' complicata. 

    Ma peggio: TALMENTE complicata che NEMMENO uno con n-mila anni di esperienza seguirebbe.

    Installati Visual studio, e usa quello, 

    OPPURE usa MySQL, postgresql.

    OPPURE cerca il connettore Mingw/GNU per SQL Server

    Visual C++ NON ESISTE! 

    E' normale C++ (compilatore Microsoft) e Visual Studio come IDE!

    Le cose compatibili con il compilatore Microsoft NON SONO COMPATIBILI con i compilatori GNU a meno di non fare salti mortali eptupli all'indietro in ambiente a gravità 10g!

  • Re: Connessione a MS Sqlserver

    I “Tutto sbagliato! ” e “Tutto da rifare!” me li aspettavo serenamente, e anche giustamente visto che sono proprio nella fase “ci sto mettendo il naso per la prima volta”.

    Quello che speravo di non sentirmi dire era proprio "TALMENTE complicata che NEMMENO uno con n-mila anni di esperienza seguirebbe", che equivale più o meno ad un vicolo cieco.

    Ora visto che MySQL e postgresql non sono un'opzione per me (purtroppo!), non mi resta che provare (ahimè!) Visual Studio.

  • Re: Connessione a MS Sqlserver

    Probabile che vada indicata la libreria nelle dipendenze del linker (es. msodbcsql18.lib), come indicato qui (vedi tabella in basso):

    https://learn.microsoft.com/en-us/sql/connect/odbc/windows/system-requirements-installation-and-driver-files?view=sql-server-ver16

    Ma forse se usi gli strumenti di VS non devi farlo a mano. 

  • Re: Connessione a MS Sqlserver

    Ho installato Visual Studio e ho fatto qualche passo avanti, ma alla fine non funziona. Adesso con Visual Studio il programma si compila, si esegue, ho trovato anche l'exe nella cartella del progetto e ho visto che anche questo si esegue tale e quale come il sorgente col debug.

    Peccato che la stringa di connessione non funzioni e mi restituisca un “-1” . Mi spiego meglio:

    
       printf("Driver Initialised\n");
       SQLWCHAR retconstring[1024];
       
       printf("about to Driver Connect\n");
       retcode = SQLDriverConnectW(sqlconnectionhandle,
           NULL,
           (SQLWCHAR*)"DRIVER={SQL Server};UID=sa;;PWD=MiaPWD;DATABASE=MioDB;WSID=NB-miopc;APP=Sistema operativo Microsoft® Windows®;SERVER=MioServer;Description=Test;",
           SQL_NTS,
           retconstring,
           1024,
           NULL,
           SQL_DRIVER_NOPROMPT);
       cout << retcode <<"\n"<<retconstring;

    il risultato è:

    Driver Initialised
    about to Driver Connect
    -1
    0000007F1A6FF0A0
    Program End, press enter key to exit!

    A uno verrebbe da dire che la stringa di connessione è sbagliata, ma se i primi 10 tentativi li ho fatti a memoria mettendo solo l'essenziale e potrei averli sbagliati, i successivi 10 tentativi  li ho fatti con il file testo creato dal “DSN su file” di Windows, ho solo dovuto aggiungere la PWD perché quella non la salva. e il DSN di Windows se c'è qualcosa di sbagliato (utente, pwd o server) dà errore. ho pescto il file ascii ho messo tutto su una riga dividendo con il “;” e la stringa risultante è quella che si vede nel codice (ovviamente con i nomi giusti). “Sql Server” me lo scarica senza graffe, ma co o senza è ugualem non funziona.

    Due piccole stranezze, che però forse non sono importanti:

    1) la documentazione ufficiale Windows mi dice che la stringa di connessione è di tipo "SQLCHAR", mentre il compilatore mi obbliga a mettere “SQLWCHAR”: non sono riuscito a capire o a trovare in rete la differenza tra i due

    2) se cerco di impostare una variabile, come succede per la “retconstring” non mi accetta il cast (vedi il codice sotto). In rete ho trovato un accenno che potrebbe dipendere dall'UNICODE, ma ho provato a cambiarlo e dà lo stesso errore.

    SQLWCHAR stringadiconnessione;
    stringadiconnessione = (SQLWCHAR*)"DRIVER={SQL Server};UID=sa;DATABASE=Tool_GIV;WSID=NB-BEGHINI;APP=Sistema operativo Microsoft® Windows®;SERVER=CALSQL;Description=Test;";
  • Re: Connessione a MS Sqlserver

    Prova ad aggiungere una L prima della stringa per convertire in unicode. 

    L"DRIVER=…"

    Hai messo 2 volte il punto e virgola dopo l'UID. 

  • Re: Connessione a MS Sqlserver

    Grazie per l’indicazione, ma purtroppo la “L” davanti alla stringa temo che non basti (il doppio punto e virgola è stato uno dei tanti tentativi cambiando la stringa di connessione, ma non è quello il problema).

    Sto ricostruendo la logica, ma devo ammettere che è stranamente complicato. Dico stranamente perché sembra che mi stia avventurando in territori inesplorati ma non dovrebbe essere così: Sql Server di Microsoft è senz’altro uno dei database più diffusi al mondo, così come c++ è uno dei linguaggi più usati. Ovviamente i due si parlano alla fine, ho copia/incollato questo programma di esempio:

    https://learn.microsoft.com/en-us/sql/connect/odbc/cpp-code-example-app-connect-access-sql-db?source=recommendations&view=sql-server-ver16

    e funziona benissimo, peccato che anche qui per compilarlo ho dovuto fare una correzione:

        if (argc > 1)
        {
           pwszConnStr = *++argv;
        }
       else
        {
           //pwszConnStr = L""; 
           //dà errore: error C2440: '=': impossibile convertire da 'const wchar_t [1]' a 'WCHAR *'
           
           pwszConnStr = *++argv;  //era tanto per mettere qualcosa e andare avanti, ovviamente non ha senso
        }

    Il programma in questione di Microsoft fa selezionare i DSN da una finestra di popup e poi apre una riga comando ()tipo cmd del dos) dove si possono dare dei comandi Transact SQL.

    Detto questo solo a titolo di esempio, non è dove volevo arrivare io, per cui tornando un passo indietro ho scoperto che non è così semplice passare da una normalissima stringa di c++ al tipo SQLWCHAR che è un tipo complesso e che mi pare di aver capito che è un array di wchar_t. Questo è il codice più vicino alla soluzione teorica che ho trovato:

       SQLWCHAR stringadiconnessione;
       string wsdc = "DRIVER={SQL Server};UID=sa;PWD=Miapwd;DATABASE=Miodb;WSID=NB-miopc;APP=Sistema operativo Microsoft® Windows®;SERVER=Mioserver;Description=Test;";
       
        int wchars_num = MultiByteToWideChar(CP_UTF8, 0, wsdc.c_str(), -1, NULL, 0);
       wchar_t* wstr = new wchar_t[wchars_num]; // Qui mi dà errore
       MultiByteToWideChar(CP_UTF8, 0, wsdc.c_str(), -1, wstr, wchars_num);
       
       //stringadiconnessione = (SQLWCHAR)wstr; Questa non gli piace propro

    In pratica da quel poco che capisco, da ignorante di c++ quale sono, si tratta di trasformare la stringa di connessione in un array di wchar_t (probabilmente a causa dell'UTF8 i caratteri normali non bastano) passando dalla funzione “MultiByteToWideChar”, la quale però necessita di due chiamate: la prima per recuperare la lunghezza, e la seconda per fare la trasformazione vera e propria. Il “new” dovrebbe trasformarmi la funzione (array?) in un puntatore di memoria, ma il compilatore si indigna e dice testualmente “C2362: inizializzazione di 'wstr' ignorata da istruzione 'goto END'” che è uno dei messaggi più misteriosi che io abbia mai visto. Anche riuscendo a superare questo scoglio però dovrei fare in qualche modo il cast ad una variabile (stringadiconnessione) compatibile col tipo della funzione (SQLWCHAR). E qui si arrabbia parecchio, forse preventivamente, non so se a causa dell’errore prima o se sto sparando a caso col cast perché non c’ho capito niente.

    Mi permetto di insistere perché anche non dovendo riuscire ad arrivare in fondo, magari lascio una traccia, un aiuto, per futuri eroici esploratori che faranno ricerche in rete e su questo argomento in italiano si trova poco.

  • Re: Connessione a MS Sqlserver

    SOLUZIONE FINALE (parziale ma soddisfacente per me per il momento) ad uso di futuri autodidatti che si vogliano cimentare nell’impresa.

    1. Volendo partire con C++ a lavorare su SQL Server, come mi è stato consigliato in questo thread, conviene passare da Visual studio e non direttamente dal compilatore. (Ok, ma non mi do per vinto: prima o poi scoprirò che libreria passare in fase di compilazione)
    2. Un ottimo punto di partenza è il programma (Microsoft) di esempio che si trova qui: https://learn.microsoft.com/en-us/sql/connect/odbc/cpp-code-example-app-connect-access-sql-db?source=recommendations&view=sql-server-ver16
    3. Questo programma però non si compila, perché c’è un errore clamoroso che non mi spiego come abbia fatto a sfuggire a chi l’ha fatto/messo in linea:
    WCHAR*      pwszConnStr;
    […]
    if (argc > 1)
        {
            pwszConnStr = *++argv;
        }
        else
        {
            pwszConnStr = L"";
        }

    L’idea è onesta: se c’è la stringa di connessione come parametro durante il lancio (argc > 1) prendi quella, altrimenti inizializza come vuota “pwszConnStr”. Non può funzionare perché una qualsiasi stringa racchiusa tra virgolette nel codice è di fatto una “una matrice di const char” (o “const WCHAR” se metto la “L”) come spiegano qua: https://learn.microsoft.com/it-it/cpp/error-messages/compiler-errors-1/compiler-error-c2440?view=msvc-170 , per cui non può essere semplicemente messa nel una “nonconst WCHAR*”. Per riuscire a compilare il programma senza diventar matto ho scelto la soluzione di sostituire << pwszConnStr = L"";>> con << pwszConnStr = *++argv;>>, rendendo di fatto inutile la “if”, ma tenendola buona per un domani quando diventerò un po’ più esperto di C++ (sono ottimista)

    4. Arrivato qui ho scoperto che con questo programma ci sono due possibilità ragionevoli, anzi buone per stabilire la connessione:

                      a. Tengo la “SQLDriverConnect” così com’è con il parametro “SQL_DRIVER_COMPLETE” e mi esce il popup per selezionare l’opportuno DSN e mi chiede le credenziali per collegarmi a SQL (sistema tecnicamente più corretto perlomeno a livello sicurezza)

                      b. Passo la stringa di connessione (magari con un .bat) come parametro di lancio del programma, metto il parametro SQL_DRIVER_NOPROMPT e mi entra diretto senza chiedere nulla (certo che sul fronte sicurezza è un po’ così)

          5. A questo punto (sia nel caso .a che nel caso .b) il programma prevede di leggere da riga comando l’istruzione di Transact SQL e funziona perfettamente, però per lavorarci sopra dovrò necessariamente compormi le istruzioni Transact SQL a codice e qui si apre un bel capitolo perché a fronte di una “WCHAR      wszInput[SQL_QUERY_SIZE];” non è che posso agevolmente muovermi come se fosse una classe “string” (come farei in JAVA per capirci), ma devo passare (ad esempio, ma forse ci sono altri metodi) da un qualcosa tipo << MultiByteToWideChar(CP_ACP, 0, "Select * from miaTabella\0", 30, wszInput, _countof(wszInput));>> dove CP_ACP a me va bene perché è l’ANSI di Windows, il ”\0” mi pare di ver capito che è indispensabile per la chiusura della stringa e il 30 è più o meno la lunghezza dell’istruzione stando larghi (forse dovrei mettere 1000 o una funzione che dia la lunghezza esatta).

    Un po’ alla volta …

Devi accedere o registrarti per scrivere nel forum
7 risposte