diff options
Diffstat (limited to 'lang/sql/adapter/db_sequence.c')
-rw-r--r-- | lang/sql/adapter/db_sequence.c | 103 |
1 files changed, 76 insertions, 27 deletions
diff --git a/lang/sql/adapter/db_sequence.c b/lang/sql/adapter/db_sequence.c index 4c4d1265..ae9281c1 100644 --- a/lang/sql/adapter/db_sequence.c +++ b/lang/sql/adapter/db_sequence.c @@ -1,7 +1,7 @@ /* * See the file LICENSE for redistribution information. * - * Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -54,8 +54,10 @@ #define DB_SEQ_NEXT 0x0000 #define DB_SEQ_CURRENT 0x0001 -#define MSG_CREATE_FAIL "Sequence create failed: " -#define MSG_MALLOC_FAIL "Malloc failed during sequence operation." +#define MSG_CREATE_FAIL "Sequence create failed: " +#define MSG_MALLOC_FAIL "Malloc failed during sequence operation." +#define MSG_INTMPDB_FAIL "Sequences do not support in-memory or" \ + " temporary databases." #define CACHE_ENTRY_VALID(_e) \ (_e != NULL && \ @@ -78,6 +80,7 @@ static int btreeSeqPutCookie( sqlite3_context *context, Btree *p, SEQ_COOKIE *cookie, u_int32_t flags); static int btreeSeqRemoveHandle( sqlite3_context *context, Btree *p, CACHED_DB *cache_entry); +static void btreeSeqSetSeqName(SEQ_COOKIE *cookie, const char *name); static int btreeSeqStartTransaction( sqlite3_context *context, Btree *p, int is_write); @@ -96,6 +99,7 @@ static void db_seq_create_func( "create_sequence()"); return; } + log_msg(LOG_NORMAL, "db_seq_create_func(%s)", sqlite3_value_text(argv[0])); /* * Ensure that the sequence name is OK with our static buffer * size. We need extra characters for "seq_" and "_db". @@ -126,9 +130,8 @@ static void db_seq_create_func( memset(&cookie, 0, sizeof(SEQ_COOKIE)); cookie.incr = 1; - sqlite3_snprintf(BT_MAX_SEQ_NAME, cookie.name, "seq_%s", - sqlite3_value_text(argv[0])); - cookie.name_len = (int)strlen(cookie.name); + btreeSeqSetSeqName(&cookie, sqlite3_value_text(argv[0])); + log_msg(LOG_NORMAL, "db_seq_drop_func(%s)", cookie.name); if (pBt->dbStorage == DB_STORE_NAMED && btreeSeqExists(context, p, cookie.name) == 1) { btreeSeqError(context, SQLITE_ERROR, @@ -160,7 +163,7 @@ static void db_seq_create_func( "%sInvalid parameter.", MSG_CREATE_FAIL); goto err; } - cookie.cache = sqlite3_value_int(argv[i]); + cookie.cache = (u32)sqlite3_value_int(argv[i]); } else if (strncmp((char *)sqlite3_value_text(argv[i]), "incr", 4) == 0) { if (i == argc || @@ -255,7 +258,7 @@ static void db_seq_create_func( if ((rc = btreeSeqGetHandle(context, p, SEQ_HANDLE_CREATE, &cookie)) != SQLITE_OK) { - if (rc != SQLITE_ERROR) + if (rc != DB_NOINTMP) btreeSeqError(context, dberr2sqlite(rc, NULL), "Failed to create sequence %s. Error: %s", (const char *)sqlite3_value_text(argv[0]), @@ -290,9 +293,8 @@ static void db_seq_drop_func( return; } - sqlite3_snprintf(BT_MAX_SEQ_NAME, cookie.name, "seq_%s", - sqlite3_value_text(argv[0])); - cookie.name_len = (int)strlen(cookie.name); + btreeSeqSetSeqName(&cookie, sqlite3_value_text(argv[0])); + log_msg(LOG_NORMAL, "db_seq_drop_func(%s)", cookie.name); rc = btreeSeqGetHandle(context, p, SEQ_HANDLE_OPEN, &cookie); if (rc != SQLITE_OK) { @@ -300,7 +302,7 @@ static void db_seq_drop_func( if (rc == DB_NOTFOUND) btreeSeqError(context, dberr2sqlite(rc, NULL), "no such sequence: %s", cookie.name + 4); - else if (rc != SQLITE_ERROR) + else if (rc != DB_NOINTMP) btreeSeqError(context, dberr2sqlite(rc, NULL), "Fail to drop sequence %s. Error: %s", cookie.name + 4, db_strerror(rc)); @@ -322,18 +324,19 @@ static void db_seq_drop_func( goto done; } + /* + * Drop the mutex - it's not valid to begin a transaction while + * holding the mutex. We can drop it safely because it's use is to + * protect handle cache changes. + */ sqlite3_mutex_leave(pBt->mutex); + if ((rc = btreeSeqStartTransaction(context, p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "Could not begin transaction for drop."); return; } - /* - * Drop the mutex - it's not valid to begin a transaction while - * holding the mutex. We can drop it safely because it's use is to - * protect handle cache changes. - */ sqlite3_mutex_enter(pBt->mutex); btreeSeqRemoveHandle(context, p, cache_entry); done: sqlite3_mutex_leave(pBt->mutex); @@ -369,6 +372,8 @@ static void btreeSeqGetVal( p = db->aDb[0].pBt; pBt = p->pBt; memset(&cookie, 0, sizeof(cookie)); + log_msg(LOG_NORMAL, "btreeSeqGetVal(%s, %s)", name, + mode == DB_SEQ_NEXT ? "next" : "current"); if (!p->connected && (rc = btreeOpenEnvironment(p, 1)) != SQLITE_OK) { @@ -378,15 +383,14 @@ static void btreeSeqGetVal( return; } - sqlite3_snprintf(BT_MAX_SEQ_NAME, cookie.name, "seq_%s", name); - cookie.name_len = (int)strlen(cookie.name); + btreeSeqSetSeqName(&cookie, name); rc = btreeSeqGetHandle(context, p, SEQ_HANDLE_OPEN, &cookie); if (rc != SQLITE_OK) { if (rc == DB_NOTFOUND) btreeSeqError(context, dberr2sqlite(rc, NULL), "no such sequence: %s", name); - else if (rc != SQLITE_ERROR) + else if (rc != DB_NOINTMP) btreeSeqError(context, dberr2sqlite(rc, NULL), "Fail to get next value from seq %s. Error: %s", name, db_strerror(rc)); @@ -448,7 +452,7 @@ static void btreeSeqGetVal( } /* Cached gets can't be transactionally protected. */ if ((ret = cookie.handle->get(cookie.handle, NULL, - cookie.incr, &val, 0)) != 0) { + (u_int32_t)cookie.incr, &val, 0)) != 0) { if (ret == EINVAL) btreeSeqError(context, SQLITE_ERROR, "Sequence value out of bounds."); @@ -509,10 +513,20 @@ static int btreeSeqGetHandle(sqlite3_context *context, Btree *p, /* Does not support in-memory db and temp db for now */ if (pBt->dbStorage != DB_STORE_NAMED) { - btreeSeqError(context, SQLITE_ERROR, - "Sequences do not support in-memory or " - "temporary databases."); - return (SQLITE_ERROR); + btreeSeqError(context, SQLITE_ERROR, MSG_INTMPDB_FAIL); + return (DB_NOINTMP); + } + + /* Tell sqlite3VdbeHalt() that this step has a transaction to end. */ + if (p->db->pVdbe->bIsReader == 0) { + p->db->pVdbe->bIsReader = 1; + p->db->nVdbeRead++; + } + + /* Tell sqlite3VdbeHalt() that this step has a transaction to end. */ + if (p->db->pVdbe->bIsReader == 0) { + p->db->pVdbe->bIsReader = 1; + p->db->nVdbeRead++; } /* @@ -863,6 +877,41 @@ static int btreeSeqPutCookie( } /* + * According to the documentation the sequence name should be converted + * to lowercase unless it is surrounded by quotation marks. + * This function assumes that the sequence name fits in the buffer to which + * cookie.name points. + */ +static void btreeSeqSetSeqName(SEQ_COOKIE *cookie, const char *name) +{ + char lowercase[BT_MAX_SEQ_NAME]; + int i; + size_t len; + + if (name == NULL) { + strcpy(cookie->name, "seq_"); + cookie->name_len = 4; + return; + } + + len = strlen(name); + if (name[0] == '"' && name[len-1] == '"') + sqlite3_snprintf( + BT_MAX_SEQ_NAME, cookie->name, "seq_%s", name); + else { + memset(lowercase, 0, BT_MAX_SEQ_NAME); + for (i = 0; i < len; i++) { + lowercase[i] = sqlite3UpperToLower[*(name + i)]; + } + sqlite3_snprintf( + BT_MAX_SEQ_NAME, cookie->name, "seq_%s", lowercase); + } + cookie->name_len = (int)strlen(cookie->name); + + return; +} + +/* * SQLite manages explicit transactions by setting a flag when a BEGIN; is * issued, then starting an actual transaction in the btree layer when the * first operation happens (a read txn if it's a read op, a write txn if write) @@ -873,7 +922,7 @@ static int btreeSeqPutCookie( * write operations, and thus we need a valid statement_txn. * - In an explicit transaction, and the first statement. Start a txn and a statement txn. - * - In an explicit transaction and not the first statemetn. Start a statement + * - In an explicit transaction and not the first statement. Start a statement * transaction. * * The SQLite vdbe will take care of closing the statement transaction for us, @@ -883,7 +932,7 @@ static int btreeSeqPutCookie( * that case (and this function should not be called). * * It's safe to call this method multiple times since both - * sqlite3BtreeBeginTrans and sqlite3BtreeBeginStmt are no-ops on subsequent + * btreeBeginTransInternal and sqlite3BtreeBeginStmt are no-ops on subsequent * calls. */ static int btreeSeqStartTransaction( |