home_site

Lab09 - Język SQL osadzony w języku C [ ver. BD1.2025.12.02.003 ]

Zawartość strony

Plan zajęć

Połączenie z bazą danych PostgreSQL

Programy z wbudowanym językiem SQL wymagają dwóch etapów kompilacji. Początkowo przetwarzamy progam przy pomocy preprocesora, który przetwarza polecenia SQL na odpowiednie funkcje w języku gospodarza. Następnie kompilujemy z wykorzystaniem odpowiedniego kompilatora, na koniec dołączamy odpowiednie biblioteki związane z bazą danych.

ecpg program.pqc
gcc -g -I/usr/include/postgresql program.c -o program -lecpg
  1. Połączenie z bazą danych i odczytanie nazwy aktualnej bazy danych.

    Plik prog1.pqc ( [listing dokumentu] [link do dokumentu] )

       #include <stdio.h>
    #include "test.h"
    
    EXEC SQL BEGIN DECLARE SECTION;
        char dbname[1024];
        char db[15];
        char usr[15];
        char pas[15];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      

    Zadanie: Zmodyfikować program dodając odczytanie również bieżącego użytkownika ( current_user ).

Zapytanie SELECT - określona liczba zwróconych wartości

W ramach ćwiczenia zapoznamy się z odczytem danych z tablicy oraz obsługą błędów.

Do obsługi błędów zwracanych przez bazę danych do aplikacji dostępna jest struktura sqlca, która jest dostępna w kodzie aplikacji po dołączeniu pliku sqlca.h. Opis struktury przedstawiono poniżej.

struct
{ char sqlcaid[8];
  long sqlabc;
  long sqlcode;
  struct
  {
    int sqlerrml;
    char sqlerrmc[SQLERRMC_LEN]; } sqlerrm;
  char sqlerrp[8];
  long sqlerrd[6];
  char sqlwarn[8];
  char sqlstate[5];
} sqlca;
  1. Odczyt jednego rekordu z bazy danych.

    Plik prog2.pqc ( [listing dokumentu] [link do dokumentu] )

    #include <stdio.h>
    #include "test.h"
    
    EXEC SQL BEGIN DECLARE SECTION;
        char db[15];
        char usr[15];
        char pas[15];
        char dbname[1024];
        int id;
        char fname[20];
        char lname[20];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL SELECT id_uczestnik, imie, nazwisko INTO :id, :fname, :lname FROM kurs.uczestnik LIMIT 1;
    
        printf("%i  %s  %s\n",id,fname,lname);
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      
  2. Włączenie obsługi debagowania połączenia z bazą danych.

    Plik prog2d.pqc ( [listing dokumentu] [link do dokumentu] )

    #include <stdio.h>
    #include "test.h"
    
    EXEC SQL BEGIN DECLARE SECTION;
        char db[15];
        char usr[15];
        char pas[15];
        char dbname[1024];
        int id;
        char fname[20];
        char lname[20];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        ECPGdebug(1,stderr);
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL SELECT id_uczestnik, imie, nazwisko INTO :id, :fname, :lname FROM kurs.uczestnik LIMIT 1;
    
        printf("%i  %s  %s\n",id,fname,lname);
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      
  3. Program z błędem po stronie bazy danych.

    Plik prog2e.pqc ( [listing dokumentu] [link do dokumentu] )

    #include <stdio.h>
    #include "test.h"
    
    EXEC SQL BEGIN DECLARE SECTION;
        char db[15];
        char usr[15];
        char pas[15];
        char dbname[1024];
        int id;
        char fname[20];
        char lname[20];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        ECPGdebug(1,stderr);
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL SELECT id_uczestnik, imie, nazwisko INTO :id, :fname, :lname FROM kurs.uczestnik ;
    
        printf("%i  %s  %s\n",id,fname,lname);
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      
  4. Obsługa błędów zwracanych przez bazę danych - wersja 1.

    Plik prog2em1.pqc ( [listing dokumentu] [link do dokumentu] )

    #include <stdio.h>
    #include "test.h"
    
    EXEC SQL BEGIN DECLARE SECTION;
        char db[15];
        char usr[15];
        char pas[15];
        char dbname[1024];
        int id;
        char fname[20];
        char lname[20];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        ECPGdebug(1,stderr);
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL SELECT id_uczestnik, imie, nazwisko INTO :id, :fname, :lname FROM kurs.uczestnik ;
    
        if  (sqlca.sqlcode == 0 )
          printf(" %i  %s  %s\n",id,fname,lname);
        else
         {  printf(" SQLCA.SQLCODE: %i\n", sqlca.sqlcode);
            printf(" SQLCA.SQLSTATE: %s\n", sqlca.sqlstate);
            printf(" SQLCA.SQLERRM: %i  %s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); }
    
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      
  5. Obsługa błędów zwracanych przez bazę danych - wersja 2.

    Plik prog2em2.pqc ( [listing dokumentu] [link do dokumentu] )

    #include <stdio.h>
    #include "test.h"
    
    EXEC SQL include sqlca;
    EXEC SQL whenever sqlwarning sqlprint;
    EXEC SQL whenever sqlerror do Prnt();
    
    void Prnt()
    {
       fprintf(stderr, "*******************************************\n");
       fprintf(stderr, "Fatal Error\n");
       sqlprint();
       fprintf(stderr, "*******************************************\n");
    }
    
    EXEC SQL BEGIN DECLARE SECTION;
        char db[15];
        char usr[15];
        char pas[15];
        char dbname[1024];
        int id;
        char fname[20];
        char lname[20];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        ECPGdebug(1,stderr);
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL SELECT id_uczestnik, imie, nazwisko INTO :id, :fname, :lname FROM kurs.uczestnik ;
    
        if  (sqlca.sqlcode == 0 )
          printf(" %i  %s  %s\n",id,fname,lname);
        else
         {  printf(" SQLCA.SQLCODE: %i\n", sqlca.sqlcode);
            printf(" SQLCA.SQLSTATE: %s\n", sqlca.sqlstate);
            printf(" SQLCA.SQLERRM: %i  %s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc); }
    
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      

Obsługa kursorów

  1. Kursor w kodzie wbudowanego SQL.

    Plik prog3.pqc ( [listing dokumentu] [link do dokumentu] )

    #include <stdio.h>
    #include "test.h"
    
    EXEC SQL BEGIN DECLARE SECTION;
        char db[15];
        char usr[15];
        char pas[15];
        char dbname[1024];
        int id;
        char fname[20];
        char lname[20];
    EXEC SQL END DECLARE SECTION;
    
    int
    main()
    {
        strncpy(db,dbase,15);
        strncpy(usr,user,15);
        strncpy(pas,pass,15);
        /* ECPGdebug(1,stderr);  */
        EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;
    
        EXEC SQL SELECT current_database() INTO :dbname;
        printf("current database=%s \n", dbname);
    
        EXEC SQL DECLARE c1 CURSOR FOR SELECT * FROM kurs.uczestnik ;
    
        EXEC SQL OPEN c1;
        EXEC SQL FETCH c1 INTO :id, :fname, :lname;
    
        printf("%i  %s  %s\n",id,fname,lname);
        EXEC SQL CLOSE c1;
    
        EXEC SQL DISCONNECT ALL;
        return 0;
    }
      

    Zadanie: Wykorzystując cursor zwrócić zawartość dowolnej tabeli relacyjnej.

Wprowadzanie danych

Plik prog4ei.pqc ( [listing dokumentu] [link do dokumentu] )

#include <stdio.h>
#include "test.h"

EXEC SQL BEGIN DECLARE SECTION;
    char dbname[1024];
    char db[15];
    char usr[15];
    char pas[15];
    char insertStmt[100];
EXEC SQL END DECLARE SECTION;

static void handle_error(void);
int main()
{

   EXEC SQL WHENEVER SQLERROR DO handle_error();
   ECPGdebug(1,stderr);
   strncpy(db,dbase,15);
   strncpy(usr,user,15);
   strncpy(pas,pass,15);
   EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;

   strncpy(insertStmt,"INSERT INTO kurs.uczesnik  VALUES(45, 'Adrian', 'Zawadzki')",50);

   EXEC SQL EXECUTE IMMEDIATE :insertStmt;
   EXEC SQL COMMIT;
   fprintf(stderr, "ok\n");
   return 0;
}


static void handle_error(void)
{
   fprintf(stderr, "%s\n", sqlca.sqlerrm.sqlerrmc);
   EXEC SQL WHENEVER SQLERROR CONTINUE;
   /* EXEC SQL ROLLBACK RELEASE; */
}

  

Plik prog4pe.pqc ( [listing dokumentu] [link do dokumentu] )

#include <stdio.h>
#include "test.h"

EXEC SQL BEGIN DECLARE SECTION;
    char dbname[1024];
    char db[15];
    char usr[15];
    char pas[15];
    char insertStmt[100];
    char sqlStmt[100];
    int par_val;
EXEC SQL END DECLARE SECTION;

static void handle_error(void);
int main()
{

   EXEC SQL WHENEVER SQLERROR DO handle_error();
   ECPGdebug(1,stderr);
   strncpy(db,dbase,15);
   strncpy(usr,user,15);
   strncpy(pas,pass,15);
   EXEC SQL CONNECT TO :db AS con1  USER :usr USING :pas;

   /* strncpy(insertStmt,"INSERT INTO osoba VALUES(5, 'Adrian', 'Zawadzki')",50);

   EXEC SQL EXECUTE IMMEDIATE :insertStmt;
   EXEC SQL COMMIT;*/

   strncpy(sqlStmt,"SELECT id_uczestnik, imie, nazwisko FROM kurs.uczestnik WHERE id_uczestnik = ?", 50);
   EXEC SQL PREPARE s1 FROM :sqlStmt;
   par_val = 1; 
   EXEC SQL EXECUTE s1 INTO :id, :fname, :lname USING :par_val; 
   
   fprintf(stderr, "ok\n");
   return 0;
}


static void handle_error(void)
{
   fprintf(stderr, "%s\n", sqlca.sqlerrm.sqlerrmc);
   EXEC SQL WHENEVER SQLERROR CONTINUE;
   /* EXEC SQL ROLLBACK RELEASE; */
}