summaryrefslogtreecommitdiff
path: root/lang/sql/adapter/db_sequence.c
diff options
context:
space:
mode:
Diffstat (limited to 'lang/sql/adapter/db_sequence.c')
-rw-r--r--lang/sql/adapter/db_sequence.c103
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(