In the command-line client, forbid
[svn.git] / subversion / libsvn_fs_util / node-origins-sqlite-index.c
blobaa275a0b5c687a323baf6bc15d818b361b9a8618
1 /* node-origins-sqlite-index.c
3 * ====================================================================
4 * Copyright (c) 2006-2007 CollabNet. All rights reserved.
6 * This software is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at http://subversion.tigris.org/license-1.html.
9 * If newer versions of this license are posted there, you may use a
10 * newer version instead, at your option.
12 * This software consists of voluntary contributions made by many
13 * individuals. For exact contribution history, see the revision
14 * history and logs, available at http://subversion.tigris.org/.
15 * ====================================================================
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <assert.h>
24 #include <apr_general.h>
25 #include <apr_pools.h>
27 #include <sqlite3.h>
29 #include "svn_fs.h"
30 #include "svn_path.h"
31 #include "svn_pools.h"
33 #include "private/svn_fs_sqlite.h"
34 #include "private/svn_fs_node_origins.h"
35 #include "../libsvn_fs/fs-loader.h"
36 #include "svn_private_config.h"
38 #include "sqlite-util.h"
41 /* A flow-control helper macro for sending processing to the 'cleanup'
42 label when the local variable 'err' is not SVN_NO_ERROR. */
43 #define MAYBE_CLEANUP if (err) goto cleanup
45 static svn_error_t *
46 get_origin(const char **node_rev_id,
47 sqlite3 *db,
48 const char *node_id,
49 apr_pool_t *pool)
51 svn_fs__sqlite_stmt_t *stmt;
52 svn_boolean_t got_row;
54 SVN_ERR(svn_fs__sqlite_prepare(&stmt, db,
55 "SELECT node_rev_id FROM node_origins "
56 "WHERE node_id = ?", pool));
57 SVN_ERR(svn_fs__sqlite_bind_text(stmt, 1, node_id));
58 SVN_ERR(svn_fs__sqlite_step(&got_row, stmt));
60 *node_rev_id = got_row
61 ? apr_pstrdup(pool, svn_fs__sqlite_column_text(stmt, 0))
62 : NULL;
64 SVN_ERR(svn_fs__sqlite_finalize(stmt));
66 return SVN_NO_ERROR;
69 static svn_error_t *
70 set_origin(sqlite3 *db,
71 const char *node_id,
72 const svn_string_t *node_rev_id,
73 apr_pool_t *pool)
75 svn_fs__sqlite_stmt_t *stmt;
76 const char *old_node_rev_id;
78 /* First figure out if it's already there. (Don't worry, we're in a
79 transaction.) */
80 SVN_ERR(get_origin(&old_node_rev_id, db, node_id, pool));
81 if (old_node_rev_id != NULL)
83 if (!strcmp(node_rev_id->data, old_node_rev_id))
84 return SVN_NO_ERROR;
85 else
86 return svn_error_createf
87 (SVN_ERR_FS_CORRUPT, NULL,
88 _("Node origin for '%s' exists with a different "
89 "value (%s) than what we were about to store (%s)"),
90 node_id, old_node_rev_id, node_rev_id->data);
93 SVN_ERR(svn_fs__sqlite_prepare(&stmt, db,
94 "INSERT INTO node_origins (node_id, "
95 "node_rev_id) VALUES (?, ?);", pool));
96 SVN_ERR(svn_fs__sqlite_bind_text(stmt, 1, node_id));
97 SVN_ERR(svn_fs__sqlite_bind_text(stmt, 2, node_rev_id->data));
99 SVN_ERR(svn_fs__sqlite_step_done(stmt));
101 SVN_ERR(svn_fs__sqlite_finalize(stmt));
103 return SVN_NO_ERROR;
107 svn_error_t *
108 svn_fs__set_node_origins(svn_fs_t *fs,
109 apr_hash_t *node_origins,
110 apr_pool_t *pool)
112 sqlite3 *db;
113 apr_hash_index_t *hi;
114 svn_error_t *err;
115 apr_pool_t *subpool = svn_pool_create(pool);
116 apr_pool_t *iterpool = svn_pool_create(subpool);
118 SVN_ERR(svn_fs__sqlite_open(&db, fs->path, subpool));
119 err = svn_fs__sqlite_exec(db, "BEGIN TRANSACTION;");
120 MAYBE_CLEANUP;
122 for (hi = apr_hash_first(subpool, node_origins);
123 hi != NULL;
124 hi = apr_hash_next(hi))
126 const void *key;
127 void *val;
128 const char *node_id;
129 const svn_fs_id_t *node_rev_id;
131 svn_pool_clear(iterpool);
133 apr_hash_this(hi, &key, NULL, &val);
134 node_id = key;
135 node_rev_id = val;
137 err = set_origin(db, node_id,
138 svn_fs_unparse_id(node_rev_id, iterpool),
139 iterpool);
140 MAYBE_CLEANUP;
143 err = svn_fs__sqlite_exec(db, "COMMIT TRANSACTION;");
144 MAYBE_CLEANUP;
146 cleanup:
147 /* It's just an "optional" cache, so it's OK if the database is
148 readonly. */
149 /* ### Instead of checking twice here, maybe add an IGNORE_READONLY
150 ### argument to svn_fs__sqlite_close? */
151 if (err && err->apr_err == SVN_ERR_FS_SQLITE_READONLY)
153 svn_error_clear(err);
154 err = NULL;
156 err = svn_fs__sqlite_close(db, err);
157 if (err && err->apr_err == SVN_ERR_FS_SQLITE_READONLY)
159 svn_error_clear(err);
160 err = NULL;
162 svn_pool_destroy(iterpool);
163 svn_pool_destroy(subpool);
164 return err;
167 svn_error_t *
168 svn_fs__set_node_origin(svn_fs_t *fs,
169 const char *node_id,
170 const svn_fs_id_t *node_rev_id,
171 apr_pool_t *pool)
173 apr_hash_t *origins = apr_hash_make(pool);
175 apr_hash_set(origins, node_id, APR_HASH_KEY_STRING, node_rev_id);
177 return svn_fs__set_node_origins(fs, origins, pool);
180 svn_error_t *
181 svn_fs__get_node_origin(const char **origin_id,
182 svn_fs_t *fs,
183 const char *node_id,
184 apr_pool_t *pool)
186 sqlite3 *db;
187 svn_error_t *err;
189 SVN_ERR(svn_fs__sqlite_open(&db, fs->path, pool));
191 err = get_origin(origin_id, db, node_id, pool);
193 return svn_fs__sqlite_close(db, err);