edv:prg:esql_c:example:db_exec_sql
db_exec_sql
Modul mit einigen (Informix-)DB-Funktionen
db_exec_sql.h:
/********************************************************************* * * Autor: Jürgen Kreick * Version: 1.0.0 vom 24.11.2010 * ********************************************************************** * * Hinweise zum Modul/Quelltext: * * In der aktuellen Version werden nur Verbindungen zu einer einzigen * DB pro Sitzung unterstützt. * Unterstützung von parallelen Sitzungen (zeitgleiche mehrere DB-Verbindungen zu * jeweils unterschiedlichen DB) sind momentan nicht geplant. * ********************************************************************** * * Release Notes: * * Ver 1.0.0 (vom 24.11.2010): * Die erste Version des Moduls. Umfasst (nach aussen) folgende Funktionen: * dbInit(), dbDone(), dbSetIsolation(), dbSetModeWait(). * **********************************************************************/ #ifndef db_exec_sql_h_H #define db_exec_sql_h_H // Rückgabewerte: #define RC_DB_OK 0 #define RC_DB_ERR -1 #define RC_DB_NOTFOUND 100 // IsolationsLevel #define DIRTY_READ 1 // "Dirty Read" und "Uncommitted Read" ist das gleiche #define UNCOMMITTED_READ 1 #define COMMITTED_READ 2 // Die Liste ist nicht vollständig! // Werte für dbEndTransaction() #define TRANSACTION_COMMIT 1 #define TRANSACTION_ROLLBACK 2 // Transaktionskontext: ON = erforderlich, OFF = nicht erforderlich #define TRANSACTION_OFF 0 #define TRANSACTION_ON 1 // Transaktion: IN_OF_TRNS = man befindet sich innerhalb eines Transaktionskontextes, OUT_OF_TRNS = außerhalb #define TRANSACTION_IN_OF_TRNS 1 #define TRANSACTION_OUT_OF_TRNS 0 // Log-Meldungen #define LOG_FEHLGESCHLAGEN "fehlgeschlagen." #define LOG_BEGIN_WORK "BEGIN WORK" #define LOG_BEGIN_WORK_FEHLGESCHLAGEN "BEGIN WORK fehlgeschlagen." #define LOG_COMMIT_WORK "COMMIT WORK" #define LOG_COMMIT_WORK_FEHLGESCHLAGEN "COMMIT WORK fehlgeschlagen." #define LOG_ROLLBACK_WORK "ROLLBACK WORK" #define LOG_ROLLBACK_WORK_FEHLGESCHLAGEN "ROLLBACK WORK fehlgeschlagen." #define LOG_TRANSACTION_PARAM_ERROR "Falsche Parameter beim Aufruf von dbEndTransaction()" // ******************** Prototypen **************************************** // dbInit() wird ein Mal pro DB-Sitzung aufgerufen und baut eine Verbindung zur // DB auf. // // Parameter: // // char *dbName : Name der DB (z.B. "test_db@test_system") // int extLogFileID : externe LogFileID für das Logging-System // // Rückgabewert: RC_DB_OK (Erfolg) oder RC_DB_ERR (bei Fehlern) int dbInit (const char *dbName, int extLogFileID); // dbDone() wird ein Mal pro DB-Sitzung aufgerufen und baut die existierende // Verbindung zur DB ab. // // Parameter: keine. // // Rückgabewert: RC_DB_OK (Erfolg) oder RC_DB_ERR (bei Fehlern) int dbDone (); // dbSetIsolation() setzt den aktuellen IsolationsLevel für die Verbindung int dbSetIsolation (int level); // dbSetModeWait() setzt die Wartezeit in Sekunden beim Warten auf einen gelockten Satz. // Negative Werte für "sec" bedeuten kein Warten. // sec = 0 bedeutet keine Begrenzung beim Warten. int dbSetModeWait (int sec); // Diese Funktion führt einfache SQLs aus. // Eingabeparameter: // sql - SQL-String, der ausgeführt werden soll; // text - Text (z.B. updated / deleted / inserted) für Massenoperationen // funktionname - "__func__"-Makro der aufrufenden Funktion (für Trace) // Ausgabeparameter: // rows - Falls NULL, wird ignoriert, sonst wird dort bei Erfolg die Zahl durch SQL betroffener Sätze zurück gegeben int execSimpleSQL (const char *sql, const int *rows, const char *text, const char *modulName, int lineNumber, const char *functName); // Transaktionkontext öffnen (BEGIN WORK;) int dbBeginTransaction (); // Transaktion beenden (mit COMMIT WORK; oder ROLLBACK WORK;) int dbEndTransaction (int transactionEnd); /* Everything else goes here */ #endif
db_exec_sql.ec:
#include "db_exec_sql.h" // Wehen Logging: #include "logging_ext.h" // Konstanten: #define TMP_STR_LEN_MAX 8191 #define ON 1 #define OFF 0 // ******************** lokale Strukturen **************************************** // ******************** externe Variablen **************************************** int dbLogFileID = 0; // ******************** lokale Variablen **************************************** int dbConnected = 0; // 0 - keine Verbindung, 1 - Verbindung existiert (oder OFF/ON) // ******************** interne Funktionen **************************************** // ******************** export-Funktionen **************************************** int dbInit (const char *dbName, int extLogFileID) { int rc = RC_OK; int rc_SQL = RC_DB_OK; char logStr [TMP_STR_LEN_MAX + 1]; EXEC SQL BEGIN DECLARE SECTION; char dbDatabase [TMP_STR_LEN_MAX + 1]; EXEC SQL END DECLARE SECTION; dbLogFileID = extLogFileID; // Da es von außen gesetzt wird, übernehmen wir es blind (sicherheitstechnisch unkritisch). memset(logStr, '\0', sizeof(logStr)); memset(dbDatabase, '\0', sizeof(dbDatabase)); logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); // Plausibilitätsprüfung: if (dbName) // dbName existiert? { strlcpy(dbDatabase, dbName, sizeof(dbDatabase)); // Vor dem trim'men umkopieren trimAll(dbDatabase, NULL, sizeof(dbDatabase)); // Von den Leerzeichen links und rechts befreien if (strlen(dbDatabase) <= 0) // Der DB-Name darf nicht leer sein { logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, "Fehlerhafter Aufruf: Name der DB ist leer."); rc = RC_ERR; } // if } else // dbName darf nicht NULL sein { logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, "Fehlerhafter Aufruf: Parameter 'dbName' ist NULL."); rc = RC_ERR; } // if if (!rc) { logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, "Es wird versucht eine Verbindung zur DB aufzubauen..."); if (dbConnected) // Verbindung ist bereits vorhanden { logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, "Eine Verbindung zur DB existiert bereits."); rc = RC_ERR; } // if } // if if (!rc) { snprintf(logStr, sizeof(logStr), "Database = [%s]", dbDatabase); logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, logStr); EXEC SQL DATABASE :dbDatabase ; if (rc_SQL = sqlca.sqlcode) rc = RC_ERR; } // if if (!rc) logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, "Verbindung zur DB erfolgreich aufgebaut."); else logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, "Verbindung zur DB konnte nicht aufgebaut werden."); if (!rc) dbConnected = ON; logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc); return rc; } // dbInit() int dbDone () { int rc = RC_OK; logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); if (dbConnected) // Verbindung existiert { // TODO: z.B. Cursor frei geben } // if if (dbConnected) dbConnected = OFF; else rc = RC_ERR; // Es gibt keine Verbindung, die abgebaut werden soll. logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc); return rc; } // dbDone() int dbSetIsolation (int level) { int rc = RC_OK; int rc_SQL = RC_DB_OK; logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); switch (level) { case DIRTY_READ: logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, "SET ISOLATION TO DIRTY READ;"); EXEC SQL SET ISOLATION TO DIRTY READ; if (rc_SQL = sqlca.sqlcode) rc = RC_ERR; break; // case DIRTY_READ case COMMITTED_READ: logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, "SET ISOLATION TO COMMITTED READ;"); EXEC SQL SET ISOLATION TO COMMITTED READ; if (rc_SQL = sqlca.sqlcode) rc = RC_ERR; break; // case COMMITTED_READ default: rc = RC_ERR; } // switch (level) if (rc) logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, "IsolationsLevel konnte nicht gesetzt werden."); logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc); return rc; } // int dbSetIsolation() int dbSetModeWait (int sec) { int rc = RC_OK; int rc_SQL = RC_DB_OK; EXEC SQL BEGIN DECLARE SECTION; char tmpStrSQL [TMP_STR_LEN_MAX + 1]; EXEC SQL END DECLARE SECTION; logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); memset(tmpStrSQL, '\0', sizeof(tmpStrSQL)); if (sec < 0) // Kein Warten. { logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, "SET LOCK MODE TO NOT WAIT;"); EXEC SQL SET LOCK MODE TO NOT WAIT; if (rc_SQL = sqlca.sqlcode) rc = RC_ERR; } else if (sec == 0) // Keine Begrenzung beim Warten. { logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, "SET LOCK MODE TO WAIT;"); EXEC SQL SET LOCK MODE TO WAIT; if (rc_SQL = sqlca.sqlcode) rc = RC_ERR; } else // "sec" Sekunden Warten. { snprintf(tmpStrSQL, sizeof(tmpStrSQL), "SET LOCK MODE TO WAIT %i;", sec); logLog(LOG_NOTICE, dbLogFileID, __FILE__, __LINE__, __func__, tmpStrSQL); EXEC SQL EXECUTE IMMEDIATE :tmpStrSQL; if (rc_SQL = sqlca.sqlcode) rc = RC_ERR; } // if if (rc) logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, "WaitMode konnte nicht gesetzt werden."); logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc); return rc; } // int dbSetModeWait() int execSimpleSQL (const char *sql, const int *rows, const char *text, const char *modulName, int lineNumber, const char *functName) // Führt einfache SQLs aus { int rc_SQL = RC_DB_OK; int countRows = 0; char tmpStr [TMP_STR_LEN_MAX + 1]; EXEC SQL BEGIN DECLARE SECTION; char tmpStrSQL [TMP_STR_LEN_MAX + 1]; EXEC SQL END DECLARE SECTION; countRows = 0; memset(tmpStr, '\0', sizeof(tmpStr)); memset(tmpStrSQL, '\0', sizeof(tmpStrSQL)); logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); logLog(LOG_DEBUG, dbLogFileID, __FILE__, __LINE__, __func__, sql); strlcpy(tmpStrSQL, sql, sizeof(tmpStrSQL)); logLog(LOG_INFO, dbLogFileID, __FILE__, __LINE__, __func__, tmpStrSQL); EXEC SQL EXECUTE IMMEDIATE :tmpStrSQL; if (rc_SQL = sqlca.sqlcode) { logLogRC_SQL(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, LOG_FEHLGESCHLAGEN, tmpStrSQL, rc_SQL); snprintf(tmpStr, sizeof(tmpStr), "Aufgerufen aus %s[%d]:%s()", modulName, lineNumber, functName); logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, tmpStr); } else { countRows = sqlca.sqlerrd[2]; // Anzahl betroffener Saetze uebernehmen if (text) // Falls nicht NULL { snprintf(tmpStr, sizeof(tmpStr), "%d rows %s.", countRows, text); logLog(LOG_INFO, dbLogFileID, __FILE__, __LINE__, __func__, tmpStr); } // if if (rows) // Falls nicht NULL { // Anzahl betroffener Saetze zurueck geben *rows = countRows; // Achtung! Es wird nicht ueberprueft, ob "*rows" ausreichend Platz hat! } // if } // if logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc_SQL); return rc_SQL; } // execSimpleSQL() int dbBeginTransaction () // Transaktionkontext öffnen { int rc_SQL = RC_DB_OK; logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); logLog(LOG_INFO, dbLogFileID, __FILE__, __LINE__, __func__, LOG_BEGIN_WORK); EXEC SQL BEGIN WORK; if (rc_SQL = sqlca.sqlcode) logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, LOG_BEGIN_WORK_FEHLGESCHLAGEN); logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc_SQL); return rc_SQL; } // dbBeginTransaction() int dbEndTransaction (int transactionEnd) // Transaktion beenden (mit COMMIT WORK; oder ROLLBACK WORK;) { int rc_SQL = RC_DB_OK; logEntry(LOG_INFO, dbLogFileID, __FILE__, __func__); switch (transactionEnd) // Entweder COMMIT WORK; oder ROLLBACK WORK; { case TRANSACTION_COMMIT: // COMMIT WORK; logLog(LOG_INFO, dbLogFileID, __FILE__, __LINE__, __func__, LOG_COMMIT_WORK); EXEC SQL COMMIT WORK; if (rc_SQL = sqlca.sqlcode) logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, LOG_COMMIT_WORK_FEHLGESCHLAGEN); break; // case TRANSACTION_COMMIT: case TRANSACTION_ROLLBACK: // ROLLBACK WORK; logLog(LOG_INFO, dbLogFileID, __FILE__, __LINE__, __func__, LOG_ROLLBACK_WORK); EXEC SQL ROLLBACK WORK; if (rc_SQL = sqlca.sqlcode) logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, LOG_ROLLBACK_WORK_FEHLGESCHLAGEN); break; // case TRANSACTION_ROLLBACK: default: // Unzulässiger Parameterwert logLog(LOG_ERR, dbLogFileID, __FILE__, __LINE__, __func__, LOG_TRANSACTION_PARAM_ERROR); rc_SQL = RC_DB_ERR; } // switch (transactionEnd) logExitRC(LOG_INFO, dbLogFileID, __FILE__, __func__, rc_SQL); return rc_SQL; } // dbEndTransaction() // EOF
Stand: 24.11.2010
— : Jürgen Kreick
EOF
edv/prg/esql_c/example/db_exec_sql.txt · Zuletzt geändert: 2020/01/11 01:23 von 127.0.0.1