Annotation of embedaddon/strongswan/src/libstrongswan/plugins/sqlite/sqlite_database.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013 Tobias Brunner
        !             3:  * Copyright (C) 2007 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "sqlite_database.h"
        !            18: 
        !            19: #include <sqlite3.h>
        !            20: #include <unistd.h>
        !            21: #include <library.h>
        !            22: #include <utils/debug.h>
        !            23: #include <threading/mutex.h>
        !            24: #include <threading/thread_value.h>
        !            25: 
        !            26: typedef struct private_sqlite_database_t private_sqlite_database_t;
        !            27: 
        !            28: /**
        !            29:  * private data of sqlite_database
        !            30:  */
        !            31: struct private_sqlite_database_t {
        !            32: 
        !            33:        /**
        !            34:         * public functions
        !            35:         */
        !            36:        sqlite_database_t public;
        !            37: 
        !            38:        /**
        !            39:         * sqlite database connection
        !            40:         */
        !            41:        sqlite3 *db;
        !            42: 
        !            43:        /**
        !            44:         * thread-specific transaction, as transaction_t
        !            45:         */
        !            46:        thread_value_t *transaction;
        !            47: 
        !            48:        /**
        !            49:         * mutex used to lock execute(), if necessary
        !            50:         */
        !            51:        mutex_t *mutex;
        !            52: };
        !            53: 
        !            54: /**
        !            55:  * Database transaction
        !            56:  */
        !            57: typedef struct {
        !            58: 
        !            59:        /**
        !            60:         * Refcounter if transaction() is called multiple times
        !            61:         */
        !            62:        refcount_t refs;
        !            63: 
        !            64:        /**
        !            65:         * TRUE if transaction was rolled back
        !            66:         */
        !            67:        bool rollback;
        !            68: 
        !            69: } transaction_t;
        !            70: 
        !            71: /**
        !            72:  * Check if the SQLite library is thread safe
        !            73:  */
        !            74: static bool is_threadsafe()
        !            75: {
        !            76: #if SQLITE_VERSION_NUMBER >= 3005000
        !            77:        return sqlite3_threadsafe() > 0;
        !            78: #endif
        !            79:        /* sqlite connections prior to 3.5 may be used by a single thread only */
        !            80:        return FALSE;
        !            81: }
        !            82: 
        !            83: /**
        !            84:  * Create and run a sqlite stmt using a sql string and args
        !            85:  */
        !            86: static sqlite3_stmt* run(private_sqlite_database_t *this, char *sql,
        !            87:                                                 va_list *args)
        !            88: {
        !            89:        sqlite3_stmt *stmt = NULL;
        !            90:        int params, i, res = SQLITE_OK;
        !            91: 
        !            92: #ifdef HAVE_SQLITE3_PREPARE_V2
        !            93:        if (sqlite3_prepare_v2(this->db, sql, -1, &stmt, NULL) == SQLITE_OK)
        !            94: #else
        !            95:        if (sqlite3_prepare(this->db, sql, -1, &stmt, NULL) == SQLITE_OK)
        !            96: #endif
        !            97:        {
        !            98:                params = sqlite3_bind_parameter_count(stmt);
        !            99:                for (i = 1; i <= params; i++)
        !           100:                {
        !           101:                        switch (va_arg(*args, db_type_t))
        !           102:                        {
        !           103:                                case DB_INT:
        !           104:                                {
        !           105:                                        res = sqlite3_bind_int(stmt, i, va_arg(*args, int));
        !           106:                                        break;
        !           107:                                }
        !           108:                                case DB_UINT:
        !           109:                                {
        !           110:                                        res = sqlite3_bind_int64(stmt, i, va_arg(*args, u_int));
        !           111:                                        break;
        !           112:                                }
        !           113:                                case DB_TEXT:
        !           114:                                {
        !           115:                                        const char *text = va_arg(*args, const char*);
        !           116:                                        res = sqlite3_bind_text(stmt, i, text, -1,
        !           117:                                                                                        SQLITE_TRANSIENT);
        !           118:                                        break;
        !           119:                                }
        !           120:                                case DB_BLOB:
        !           121:                                {
        !           122:                                        chunk_t c = va_arg(*args, chunk_t);
        !           123:                                        res = sqlite3_bind_blob(stmt, i, c.ptr, c.len,
        !           124:                                                                                        SQLITE_TRANSIENT);
        !           125:                                        break;
        !           126:                                }
        !           127:                                case DB_DOUBLE:
        !           128:                                {
        !           129:                                        res = sqlite3_bind_double(stmt, i, va_arg(*args, double));
        !           130:                                        break;
        !           131:                                }
        !           132:                                case DB_NULL:
        !           133:                                {
        !           134:                                        res = sqlite3_bind_null(stmt, i);
        !           135:                                        break;
        !           136:                                }
        !           137:                                default:
        !           138:                                {
        !           139:                                        res = SQLITE_MISUSE;
        !           140:                                        break;
        !           141:                                }
        !           142:                        }
        !           143:                        if (res != SQLITE_OK)
        !           144:                        {
        !           145:                                break;
        !           146:                        }
        !           147:                }
        !           148:        }
        !           149:        else
        !           150:        {
        !           151:                DBG1(DBG_LIB, "preparing sqlite statement failed: %s",
        !           152:                         sqlite3_errmsg(this->db));
        !           153:        }
        !           154:        if (res != SQLITE_OK)
        !           155:        {
        !           156:                DBG1(DBG_LIB, "binding sqlite statement failed: %s",
        !           157:                         sqlite3_errmsg(this->db));
        !           158:                sqlite3_finalize(stmt);
        !           159:                return NULL;
        !           160:        }
        !           161:        return stmt;
        !           162: }
        !           163: 
        !           164: typedef struct {
        !           165:        /** implements enumerator_t */
        !           166:        enumerator_t public;
        !           167:        /** associated sqlite statement */
        !           168:        sqlite3_stmt *stmt;
        !           169:        /** number of result columns */
        !           170:        int count;
        !           171:        /** column types */
        !           172:        db_type_t *columns;
        !           173:        /** back reference to parent */
        !           174:        private_sqlite_database_t *database;
        !           175: } sqlite_enumerator_t;
        !           176: 
        !           177: METHOD(enumerator_t, sqlite_enumerator_destroy, void,
        !           178:        sqlite_enumerator_t *this)
        !           179: {
        !           180:        sqlite3_finalize(this->stmt);
        !           181:        if (!is_threadsafe())
        !           182:        {
        !           183:                this->database->mutex->unlock(this->database->mutex);
        !           184:        }
        !           185:        free(this->columns);
        !           186:        free(this);
        !           187: }
        !           188: 
        !           189: METHOD(enumerator_t, sqlite_enumerator_enumerate, bool,
        !           190:        sqlite_enumerator_t *this, va_list args)
        !           191: {
        !           192:        int i;
        !           193: 
        !           194:        switch (sqlite3_step(this->stmt))
        !           195:        {
        !           196:                case SQLITE_ROW:
        !           197:                        break;
        !           198:                default:
        !           199:                        DBG1(DBG_LIB, "stepping sqlite statement failed: %s",
        !           200:                                 sqlite3_errmsg(this->database->db));
        !           201:                        /* fall */
        !           202:                case SQLITE_DONE:
        !           203:                        return FALSE;
        !           204:        }
        !           205: 
        !           206:        for (i = 0; i < this->count; i++)
        !           207:        {
        !           208:                switch (this->columns[i])
        !           209:                {
        !           210:                        case DB_INT:
        !           211:                        {
        !           212:                                int *value = va_arg(args, int*);
        !           213:                                *value = sqlite3_column_int(this->stmt, i);
        !           214:                                break;
        !           215:                        }
        !           216:                        case DB_UINT:
        !           217:                        {
        !           218:                                u_int *value = va_arg(args, u_int*);
        !           219:                                *value = (u_int)sqlite3_column_int64(this->stmt, i);
        !           220:                                break;
        !           221:                        }
        !           222:                        case DB_TEXT:
        !           223:                        {
        !           224:                                const unsigned char **value = va_arg(args, const unsigned char**);
        !           225:                                *value = sqlite3_column_text(this->stmt, i);
        !           226:                                break;
        !           227:                        }
        !           228:                        case DB_BLOB:
        !           229:                        {
        !           230:                                chunk_t *chunk = va_arg(args, chunk_t*);
        !           231:                                chunk->len = sqlite3_column_bytes(this->stmt, i);
        !           232:                                chunk->ptr = (u_char*)sqlite3_column_blob(this->stmt, i);
        !           233:                                break;
        !           234:                        }
        !           235:                        case DB_DOUBLE:
        !           236:                        {
        !           237:                                double *value = va_arg(args, double*);
        !           238:                                *value = sqlite3_column_double(this->stmt, i);
        !           239:                                break;
        !           240:                        }
        !           241:                        default:
        !           242:                                DBG1(DBG_LIB, "invalid result type supplied");
        !           243:                                return FALSE;
        !           244:                }
        !           245:        }
        !           246:        return TRUE;
        !           247: }
        !           248: 
        !           249: METHOD(database_t, query, enumerator_t*,
        !           250:        private_sqlite_database_t *this, char *sql, ...)
        !           251: {
        !           252:        sqlite3_stmt *stmt;
        !           253:        va_list args;
        !           254:        sqlite_enumerator_t *enumerator = NULL;
        !           255:        int i;
        !           256: 
        !           257:        if (!is_threadsafe())
        !           258:        {
        !           259:                this->mutex->lock(this->mutex);
        !           260:        }
        !           261: 
        !           262:        va_start(args, sql);
        !           263:        stmt = run(this, sql, &args);
        !           264:        if (stmt)
        !           265:        {
        !           266:                INIT(enumerator,
        !           267:                        .public = {
        !           268:                                .enumerate = enumerator_enumerate_default,
        !           269:                                .venumerate = _sqlite_enumerator_enumerate,
        !           270:                                .destroy = _sqlite_enumerator_destroy,
        !           271:                        },
        !           272:                        .stmt = stmt,
        !           273:                        .count = sqlite3_column_count(stmt),
        !           274:                        .database = this,
        !           275:                );
        !           276:                enumerator->columns = malloc(sizeof(db_type_t) * enumerator->count);
        !           277:                for (i = 0; i < enumerator->count; i++)
        !           278:                {
        !           279:                        enumerator->columns[i] = va_arg(args, db_type_t);
        !           280:                }
        !           281:        }
        !           282:        va_end(args);
        !           283:        return (enumerator_t*)enumerator;
        !           284: }
        !           285: 
        !           286: METHOD(database_t, execute, int,
        !           287:        private_sqlite_database_t *this, int *rowid, char *sql, ...)
        !           288: {
        !           289:        sqlite3_stmt *stmt;
        !           290:        int affected = -1;
        !           291:        va_list args;
        !           292: 
        !           293:        /* we need a lock to get our rowid/changes correctly */
        !           294:        this->mutex->lock(this->mutex);
        !           295:        va_start(args, sql);
        !           296:        stmt = run(this, sql, &args);
        !           297:        va_end(args);
        !           298:        if (stmt)
        !           299:        {
        !           300:                if (sqlite3_step(stmt) == SQLITE_DONE)
        !           301:                {
        !           302:                        if (rowid)
        !           303:                        {
        !           304:                                *rowid = sqlite3_last_insert_rowid(this->db);
        !           305:                        }
        !           306:                        affected = sqlite3_changes(this->db);
        !           307:                }
        !           308:                else
        !           309:                {
        !           310:                        DBG1(DBG_LIB, "sqlite execute failed: %s",
        !           311:                                 sqlite3_errmsg(this->db));
        !           312:                }
        !           313:                sqlite3_finalize(stmt);
        !           314:        }
        !           315:        this->mutex->unlock(this->mutex);
        !           316:        return affected;
        !           317: }
        !           318: 
        !           319: METHOD(database_t, transaction, bool,
        !           320:        private_sqlite_database_t *this, bool serializable)
        !           321: {
        !           322:        transaction_t *trans;
        !           323:        char *cmd = serializable ? "BEGIN EXCLUSIVE TRANSACTION"
        !           324:                                                         : "BEGIN TRANSACTION";
        !           325: 
        !           326:        trans = this->transaction->get(this->transaction);
        !           327:        if (trans)
        !           328:        {
        !           329:                ref_get(&trans->refs);
        !           330:                return TRUE;
        !           331:        }
        !           332:        if (execute(this, NULL, cmd) == -1)
        !           333:        {
        !           334:                return FALSE;
        !           335:        }
        !           336:        INIT(trans,
        !           337:                .refs = 1,
        !           338:        );
        !           339:        this->transaction->set(this->transaction, trans);
        !           340:        return TRUE;
        !           341: }
        !           342: 
        !           343: /**
        !           344:  * Finalize a transaction depending on the reference count and if it should be
        !           345:  * rolled back.
        !           346:  */
        !           347: static bool finalize_transaction(private_sqlite_database_t *this,
        !           348:                                                                 bool rollback)
        !           349: {
        !           350:        transaction_t *trans;
        !           351:        char *command = "COMMIT TRANSACTION";
        !           352:        bool success;
        !           353: 
        !           354:        trans = this->transaction->get(this->transaction);
        !           355:        if (!trans)
        !           356:        {
        !           357:                DBG1(DBG_LIB, "no database transaction found");
        !           358:                return FALSE;
        !           359:        }
        !           360: 
        !           361:        if (ref_put(&trans->refs))
        !           362:        {
        !           363:                if (trans->rollback)
        !           364:                {
        !           365:                        command = "ROLLBACK TRANSACTION";
        !           366:                }
        !           367:                success = execute(this, NULL, command) != -1;
        !           368: 
        !           369:                this->transaction->set(this->transaction, NULL);
        !           370:                free(trans);
        !           371:                return success;
        !           372:        }
        !           373:        else
        !           374:        {       /* set flag, can't be unset */
        !           375:                trans->rollback |= rollback;
        !           376:        }
        !           377:        return TRUE;
        !           378: }
        !           379: 
        !           380: METHOD(database_t, commit_, bool,
        !           381:        private_sqlite_database_t *this)
        !           382: {
        !           383:        return finalize_transaction(this, FALSE);
        !           384: }
        !           385: 
        !           386: METHOD(database_t, rollback, bool,
        !           387:        private_sqlite_database_t *this)
        !           388: {
        !           389:        return finalize_transaction(this, TRUE);
        !           390: }
        !           391: 
        !           392: METHOD(database_t, get_driver, db_driver_t,
        !           393:        private_sqlite_database_t *this)
        !           394: {
        !           395:        return DB_SQLITE;
        !           396: }
        !           397: 
        !           398: /**
        !           399:  * Busy handler implementation
        !           400:  */
        !           401: static int busy_handler(private_sqlite_database_t *this, int count)
        !           402: {
        !           403:        /* add a backoff time, quadratically increasing with every try */
        !           404:        usleep(count * count * 1000);
        !           405:        /* always retry */
        !           406:        return 1;
        !           407: }
        !           408: 
        !           409: METHOD(database_t, destroy, void,
        !           410:        private_sqlite_database_t *this)
        !           411: {
        !           412:        if (sqlite3_close(this->db) == SQLITE_BUSY)
        !           413:        {
        !           414:                DBG1(DBG_LIB, "sqlite close failed because database is busy");
        !           415:        }
        !           416:        this->transaction->destroy(this->transaction);
        !           417:        this->mutex->destroy(this->mutex);
        !           418:        free(this);
        !           419: }
        !           420: 
        !           421: /*
        !           422:  * see header file
        !           423:  */
        !           424: sqlite_database_t *sqlite_database_create(char *uri)
        !           425: {
        !           426:        char *file;
        !           427:        private_sqlite_database_t *this;
        !           428: 
        !           429:        /**
        !           430:         * parse sqlite:///path/to/file.db uri
        !           431:         */
        !           432:        if (!strpfx(uri, "sqlite://"))
        !           433:        {
        !           434:                return NULL;
        !           435:        }
        !           436:        file = uri + 9;
        !           437: 
        !           438:        INIT(this,
        !           439:                .public = {
        !           440:                        .db = {
        !           441:                                .query = _query,
        !           442:                                .execute = _execute,
        !           443:                                .transaction = _transaction,
        !           444:                                .commit = _commit_,
        !           445:                                .rollback = _rollback,
        !           446:                                .get_driver = _get_driver,
        !           447:                                .destroy = _destroy,
        !           448:                        },
        !           449:                },
        !           450:                .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
        !           451:                .transaction = thread_value_create(NULL),
        !           452:        );
        !           453: 
        !           454:        if (sqlite3_open(file, &this->db) != SQLITE_OK)
        !           455:        {
        !           456:                DBG1(DBG_LIB, "opening SQLite database '%s' failed: %s",
        !           457:                         file, sqlite3_errmsg(this->db));
        !           458:                destroy(this);
        !           459:                return NULL;
        !           460:        }
        !           461: 
        !           462:        sqlite3_busy_handler(this->db, (void*)busy_handler, this);
        !           463: 
        !           464:        return &this->public;
        !           465: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>