- Pro*C
-
Pro*C [pɹoʊˈsiː]/Pro*C++ [-ˈplʌs ˈplʌs] ist ein Precompiler des Unternehmens Oracle für die Programmiersprache C und C++. Mittels des Precompilers ist es möglich, SQL-Ausdrücke und normale C oder C++ Quellcode-Elemente miteinander zu vermischen. Dies gilt jedoch ausschließlich für DML-Befehle, DDL- und DCL-Befehle müssen nach wie vor beispielsweise mit dem Programm SQL*Plus ausgeführt werden. Die daraus resultierende Datei wird schließlich in gültigen Quellcode übersetzt, um diesen mit einem herkömmlichen Compiler übersetzen zu können. Intern werden die im Quellcode eingebetteten SQL-Ausdrücke durch den Precompiler in normale Oracle Funktionsaufrufe umgewandelt.
Inhaltsverzeichnis
Unterstützte Konzepte
Mittels Pro*C ist es möglich, mit einer Datenbank innerhalb eines C-Programms auf verschiedenen Arten zu kommunizieren. Verglichen mit Ansätzen wie beispielsweise SQLJ ist Pro*C so eine sehr flexible Lösung um Datenbankanwendungen zu erstellen. Nachfolgend sind die aktuellen Eigenschaften genannt, die ein Pro*C Compiler unterstützt.
- Embedded SQL, statisch, erfordert einen Precompiler
- PL SQL, statisch, erfordert einen Precompiler
- Host Arrays
- Dynamisches SQL
Dynamisches SQL - Varianten
Dynamisches SQL wird in verschiedene Varianten aufgeteilt. Je nach Variante ist es möglich eine richtige SQL-Abfrage auszuführen. Die geeignete Methode ermittelt man mit Hilfe eines Entscheidungsbaums.
Methode 1
Diese Methode ermöglicht es ein Programm zu schreiben, welches dynamische SQL-Ausdrücke ausführt oder neue Ausdrücke erstellt. Jeder Ausdruck wird unmittelbar mittels des EXECUTE IMMEDIATE Befehls ausgeführt. Der SQL-Ausdruck darf allerdings keine Abfrage (SELECT Ausdruck) und keine Platzhalter für Input-Host-Variablen enthalten. Der nachfolgende Ausdruck ist ein gültiger Ausdruck für die Methode 1:
'DELETE FROM EMP WHERE DEPTNO = 20' 'GRANT SELECT ON EMP TO scott'
Wird Methode 1 benutzt, so wird der SQL-Ausdruck, der ausgeführt werden soll, bei jeder Ausführung analysiert.
Methode 2
Diese Methode ermöglicht es ein Programm zu schreiben, welches dynamische SQL-Ausdrücke ausführt oder neue Ausdrücke erstellt. Anschließend ist es möglich, die einzelnen SQL-Ausdrücke mittels PREPARE oder EXECUTE Befehl zu verarbeiten. Der SQL-Ausdruck darf allerdings nicht eine Abfrage (SELECT Ausdruck) enthalten. Die Anzahl der Platzhalter für die Host-Variablen und deren Datentypen müssen zum Zeitpunkt der Übersetzung bekannt sein. Das nachfolgende Beispiel würde einem dynamischen SQL-Ausdruck dieser Kategorie entsprechen:
'INSERT INTO EMP (ENAME, JOB) VALUES (:emp_name, :job_title)' 'DELETE FROM EMP WHERE EMPNO = :emp_number'
Wird Methode 2 verwendet, so wird der SQL-Ausdruck nur einmal analysiert. Trotzdem kann der Ausdruck mehrmals mit unterschiedlichen Host-Variablen ausgeführt werden. SQL-DDL Ausdrücke wie beispielsweise CREATE oder GRANT werden ausgeführt, wenn diese PREPAREd, also vorbereitet werden.
Methode 3
Diese Methode ermöglicht es, ein Programm zu schreiben, welches dynamische SQL-Ausdrücke ausführt oder neue Ausdrücke erstellt. Anschließend ist es möglich, die einzelnen SQL-Ausdrücke mittels PREPARE Befehl und den Cursor-Befehlen DECLARE, OPEN, FETCH und CLOSE zu verarbeiten. Die Anzahl der Select-List-Elemente, die Anzahl der Platzhalter für die Input-Host-Variablen sowie die Datentypen der Input-Host-Variablen müssen zum Zeitpunkt der Übersetzung bekannt sein. Das nachfolgende Beispiel entspricht einem solchen SQL-Ausdruck:
'SELECT DEPTNO, MIN(SAL), MAX(SAL) FROM EMP GROUP BY DEPTNO' 'SELECT ENAME, EMPNO FROM EMP WHERE DEPTNO = :dept_number'
Methode 4
Diese Methode ermöglicht es, ein Programm zu schreiben, welches dynamische SQL-Ausdrücke ausführt oder neue Ausdrücke erstellt. Anschließend wird der SQL-Ausdruck mittel Deskriptoren verarbeitet. Die Anzahl der Select-List Elemente, die Anzahl der Platzhalter für die Input-Host-Variablen sowie die Datentypen der Input-Host-Variablen können bis zum Zeitpunkt der Ausführung unbekannt sein. Der nachfolgende Quelltext fällt in diese Kategorie:
'INSERT INTO EMP (<unknown>) VALUES (<unknown>)' 'SELECT <unknown> FROM EMP WHERE DEPTNO = 20'
Methode 4 wird für dynamische SQL-Ausdrücke benötigt, bei welchen die Anzahl der Select-List Elemente oder die Anzahl der Input-Host-Variablen unbekannt ist.
Embedded SQL Beispiel
Das nachfolgende Quellcode-Beispiel veranschaulicht, wie mittels Pro*C ein bestimmter Wikipedia Artikel angezeigt werden könnte.
/* * wikipedia.pc * * Prompts the user for a Wikipedia title, * then queries the page table for the page's * title, number of page visits and length. * */ #include <stdio.h> #include <string.h> /* Define constants for VARCHAR lengths. */ #define UNAME_LEN 40 #define PWD_LEN 40 /* Declare variables. No declare section is needed if MODE=ORACLE.*/ VARCHAR username[UNAME_LEN]; /* VARCHAR is an Oracle-supplied struct */ varchar password[PWD_LEN]; /* varchar can be in lower case also. */ /* Define a host structure for the output values of a SELECT statement. */ struct { VARCHAR title[UNAME_LEN]; long visits; int length; } pagerec; /* Input host variable. */ int title; int total_queried; /* Include the SQL Communications Area. You can use #include or EXEC SQL INCLUDE. */ #include <sqlca.h> /* Declare error handling function. */ void sql_error(); /* the actual program starts here */ main() { char temp_char[32]; /* Connect to ORACLE-- * Copy the username into the VARCHAR. */ strncpy((char *) username.arr, "SCOTT", UNAME_LEN); /* Set the length component of the VARCHAR. */ username.len = strlen((char *) username.arr); /* Copy the password. */ strncpy((char *) password.arr, "TIGER", PWD_LEN); password.len = strlen((char *) password.arr); /* Register sql_error() as the error handler. */ EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--\n"); /* Connect to ORACLE. Program will call sql_error() * if an error occurs when connecting to the default database. */ EXEC SQL CONNECT :username IDENTIFIED BY :password; printf("\nConnected to ORACLE as user: %s\n", username.arr); /* Loop, selecting individual employee's results */ total_queried = 0; for (;;) { /* Break out of the inner loop when a * 1403 ("No data found") condition occurs. */ EXEC SQL WHENEVER NOT FOUND DO break; for (;;) { title = char[255]; printf("\nEnter Wikipedia title (0 to quit): "); gets(temp_char); title = atoi(temp_char); if (strlen(title) > 0) break; EXEC SQL SELECT page_title, page_counter, page_len INTO :emprec INDICATOR :emprec_ind FROM EMP WHERE EMPNO = :emp_number; /* Print data. */ printf("\n\nTitle\tVisits\t\tLength\n"); printf("--------\t------\t\t----------\n"); /* Null-terminate the output string data. */ pagerec.title.arr[pagerec.title.len] = '\0'; printf("%-8s\t%6.2f\t\t", pagerec.title.arr, pagerec.visits); printf("%6.2f\n", pagerec.length); total_queried++; } /* end inner for (;;) */ if (strlen(title) == 0) break; printf("\nNot a valid Wikipedia title - try again.\n"); } /* end outer for(;;) */ printf("\n\nTotal rows returned was %d.\n", total_queried); printf("\nG'day.\n\n\n"); /* Disconnect from ORACLE. */ EXEC SQL COMMIT WORK RELEASE; exit(0); } void sql_error(msg) char *msg; { char err_msg[128]; int buf_len, msg_len; EXEC SQL WHENEVER SQLERROR CONTINUE; printf("\n%s\n", msg); buf_len = sizeof (err_msg); sqlglm(err_msg, &buf_len, &msg_len); if (msg_len > buf_len) msg_len = buf_len; printf("%.*s\n", msg_len, err_msg); EXEC SQL ROLLBACK RELEASE; exit(1); }
Literatur
- Oracle Corporation: Pro*C/C++ Programmer's Guide 10g Release 2 (10.2). Part Number B14407-01. Oracle Technology Network
- Oracle Corporation: Pro*C/C++ Programmer's Guide Release 9.2. Part Number A97269-03. Freier Oracle Support
Siehe auch
Wikimedia Foundation.