Josef Troch (troch@mail.ru)
23.10.2002 (poslední změna 4.11.2002)

Embedded SQL v Oraclu - Pro*C/C++

Pozn.: Všechny níže uvedené informace by se měly vztahovat k Oraclu 8.1.5

Embedded SQL

Embedded SQL ("vložené SQL") je jednou z metod, jak přistupovat k databázi z prostředí nějakého procedurálního programovacího jazyka. Jak název napovídá, jde o vkládání SQL příkazů mezi příkazy programovacího jazyka.
Embedded SQL je obsaženo ve většině významnějších databázových produktů včetně Oraclu. Oracle nabízí podporu pro několik vyšších programovacích jazyků - nás bude zajímat podpora pro jazyky C a C++. Tu zajišťuje prekompilálor Pro*C/C++.

Postup při tvorbě programu

  1. Vytvoření programu v C / C++ obsahujícího embedded SQL (dle konvence by se měl jmenovat filename.pc)
  2. Prekompilace programu pomocí Pro*C/C++ (vznikne nám soubor filename.c)
  3. Kompilace programu (standartním C či C++ kompilátorem)
  4. Slinkování s Oracle run-time knihovnou
Prakticky:
Budeme se zabývat spouštěním prekompilátoru atd. na naší unixové instalaci.
Pozn.: Za momentálního stavu je třeba přenastavit proměnnou ORACLE_HOME na ..../8.1.5 a adekvátně upravit i LD_LIBRARY_PATH.

Příklad jednoduchého programu v Embedded SQL

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlda.h>
#include <sqlcpr.h>
#include <sqlca.h>


EXEC SQL BEGIN DECLARE SECTION;
/* Hostitelske promenne: */
VARCHAR     username[20];
VARCHAR     password[20];
VARCHAR     name[20];
VARCHAR     job[20];

/* Indikatorove promenne: */
short nameIndicator;

EXEC SQL END DECLARE SECTION;

int main()
{
    strncpy((char *) username.arr, "user", 20);
    username.len = (unsigned short) strlen((char *) username.arr);

    strncpy((char *) password.arr, "password", 20);
    password.len = (unsigned short) strlen((char *) password.arr);


    EXEC SQL CONNECT :username IDENTIFIED BY :password;

    EXEC SQL SELECT ename, job
      INTO :name:nameIndicator, :job
      FROM EMP WHERE EMPNO = '7934';

    printf("Name:        Job:\n");
    if (nameIndicator == -1) printf("NULL");
    else printf("%s", name.arr);

    printf("   %s", job.arr);

    EXEC SQL ROLLBACK WORK RELEASE;

    return 0;
}
Výše uvedený příklad najdete přímo připravený v souboru zde.
Příklady (samozřejmě výrazně složitější) dodávané s Oraclem v adresáři $ORACLE_HOME/PRECOMP/DEMO/PROC/

Syntaxe Embedded SQL

V programu je možno libovolně prokládat kompletní SQL výrazy a kompletní C výrazy a používat C-proměnné či struktury v SQL výrazech. Často jediným požadavkem na vkládané SQL výrazy je to, že musí začínat EXEC SQL a končit středníkem.
Prekompilátor překládá všechna EXEC SQL makra na volání runtimové knihovny SQLLIBS. Jak vypadá kód jednoduchého PL/SQL příkazu po prekompilaci si můžete prohlédnout zde (či zde v lokální kopii).

PL/SQL bloky - prekompilátor se k PL/SQL bloku chová jako kdyby byl jedním Embedded SQL výrazem. PL/SQL blok se zde uzavírá mezi výrazy EXEC SQL EXECUTE a END-EXEC.

Komentáře - v Embedded SQL lze používat stejné typy komentářů jako v PL-SQL, tedy: Problém nastává u jednořádkových komentářů - použijete-li výše uvedenou syntaxi, při prekompilaci nebudou vadit, ale prekompilátor je v kódu (alespoň v některých případech - např. řádek začínající --) nechá, což způsobí chybu při vlastní kompilaci. Oproti tomu třeba v sekci deklarací nelze použít ani C++ jednořádkových komentářů - kvůli prekompilátoru. Proto je nejbezpečnější všude používat (potencielně) víceřádkové komentáře - ty jsou stejné v C/C++ i v Embedded SQL.

Hostitelské a indikátorové proměnné

Hostitelské proměnné (host variables) slouží ke komunikaci Oraclu s naším programem - jsou to jednoduché či složené deklarované v C a sdílené s Oraclem (tedy náš program i Oracle k nim mohou přistupovat). Dle způsobu použití (vzhledem k Oraclu) je lze rozdělit na vstupní a výstupní.
V SQL výrazech musí být hostitelské proměnné prefixovány dvojtečkou (př.: EXEC SQL SELECT name INTO :mojePromenna FROM ....;)
Několik hostitelských proměnných můžeme sdružit do C struktury (struct). Když pak použijeme jméno struktury v Embedded SQL výrazu (zase prefixované dvojtečkou), Oracle použije každý z prvků struktury jako hostitelskou proměnnou.
Hostitelskou proměnnou nelze použít pro zastoupení nějakého SQL klíčového slova nebo jména Oraclovského objektu - potřebujeme-li něco takového, lze to řešit pomocí dynamického Embedded SQL.

Indikátorové proměnné - libovolnou hostitelskou proměnnou lze v Embedded SQL výrazu svázat s indikátorovou proměnnou. Indikátorová proměnná je typu short a indikuje stav či hodnotu hostitelské proměnné. Indikátorovou proměnnou lze použít k přiřazení NULL hodnoty do Oraclu (samotnou hostitelskou proměěnou to nejde) nebo k detekci NULL hodnot či oříznutých hodnot ve výstupních hostitelských proměnných.
V SQL výrazech musí být jméno indikátorové proměnné uvozeno dvojtečkou a okamžitě následovat za jménem hostitelské proměnné (resp. mezi tyto dvě proměnné lze vložit klíčové slovo INDICATOR - zbytečné).
Obdobně jako hostitelské proměnné i indikátorové proměnné lze sdružovat do struktur - v SQL výrazu pak píšeme
... :strukturaHostitelskychPromennych:strukturaIndikatorovych promennych ...
Samozřejmě, obě struktury zde musí mít stejně prvků - a tyto si odpovídají pořadím.
Pozn.: Pro vstupní hostitelskou proměnnou, má-li indikační proměnná hodnotu -1, dosadí Oracle do příslušného sloupce NULL hodnotu a ignoruje hodnotu v hostitelské proměnné. Má-li indikátorová proměnná nezápornou hodnotu, Oracle zapíše do sloupce hodnotu hostitelské proměnné. Opačně u výstupní host. proměnné: indikační hodnota 0 = hodnota v host. proměnné je v pořádku; -1 = hodnata sloupce je NULL, hodnota host. proměnné neurčena; >0 = v hostitelské proměnné se vrací ořezaná hodnota, indikační proměnná udává původní délku hodnoty ve sloupci; -2 = jako předchozí, původní délku nelze určit.

Pozn.: Hostitelské proměnné jsou externích datových typů, při práci s Oraclem dochází ke konverzím na interní datové typy a opačně.

Sekce deklarací

Všechny hostitelské (a snad i indikátorové) proměnné je třeba uvést v sekci deklarací (declare section). Takovýchto sekcí může být v programu více a mohou se vyskytovat všude, kde se v hostitelském programovacím jazyce mohou objevit deklarace proměnných.
Syntaxe je následující:
EXEC SQL BEGIN DECLARE SECTION;
    VARCHAR name[20];
    ...
    ...
EXEC SQL END DECLARE SECTION;

Řetězcové typy

V Embedded SQL lze jako vstupní i výstupní řetězcovou proměnné používat proměnné typu char *. Zatímco jejich použití pro vstupní (hostitelské) proměnné je bezproblémové (tedy za předpokladu, že nepředáváte C-čkový NULL), u výstupních vznikají potíže - Oracle netuší, kolik prostoru pro danou řetězcovou proměnnou má k dispozici, a tedy kolik do ní může naplnit byte-ů. Řeší to tedy tak, že na danou proměnnou spustí strlen() - a dle jeho výsledku se zařídí.
Pokud tedy chcete používat char * i pro výstupní hostitelské proměnné, nezbývá vám, než (typicky) před každým použitím proměnnou naplnit tak, aby strlen vrátil "správnou" hodnotu.

Jako rozumnější se tedy jeví používat "Oraclovský" typ VARCHAR - jde o strukturu obsahující C-čkové pole a prvek udávající platnou délku. Její použití je vidět ve výše uvedeném příkladě.

Připojení se k databázi

Abychom mohli v programu s databází pracovat, musíme se k ní připojit. K tomu nám poslouží příkaz CONNECT, jehož zjednodušená syntaxe je:
EXEC SQL CONNECT :user IDENTIFIED BY :password;

Proměnné user a password by měly být dle Oraclu typu char (asi spíše char[]) či VARCHAR. Lze použít rovněž syntaxi:
EXEC SQL CONNECT :usr_pwd; , kde usr_pwd obsahuje username a password oddělené lomítkem.

Příklady (statického) Embedded SQL


Zdroje a odkazy:


Tento článek smí být používán libovolně, za předpokladu, že nebude modifikován a že takto bude učiněno se zmínkou o autorovi a odkazem na stránku http://jt.sf.cz, odkud by měla být dostupná aktuální verse tohoto článku.
Snažím se, aby informace zde uvedené byly pravdivé a pokud možno přesné, nicméně nenesu žádnou odpovědnost za to, že tomu tak opravdu je, ani za jakékoli škody, které by někomu v důsledku případných špatných či nepřesných informací z tohoto článku mohly vzniknout.



Jakékoliv dotazy či připomínky mi můžete poslat mailem.

Zpět na stránku referátů a jiných výtvorů