rugged-mysql 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ce274abfec7be172fce34784845f6965c7d24abb
4
+ data.tar.gz: 0d23e7f09c4c85d512e1431273b2215fa517e5e0
5
+ SHA512:
6
+ metadata.gz: d6acfd623e6b3dfcee07240a44d9baeb8e4bd08a121e3d5803510c66559fe87ff4d4c7da0d402a46b710334b88b1e89283717314c48f790a1b35bbfdf29defe9
7
+ data.tar.gz: 65fb60e0dbfc890f0c9dbe4aa04582452e200b47d993963cda2c6b4555d5f81235b90b93a8a0d30ee8cfa03355917994b10e82331769ccea0e816b50cde93b93
@@ -0,0 +1,5 @@
1
+ .idea
2
+ pkg
3
+ tmp
4
+ *.so
5
+ *~
@@ -0,0 +1 @@
1
+ 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rugged-mysql.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rugged-mysql (0.0.1)
5
+ rugged (~> 0.21.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ rake (10.3.2)
11
+ rake-compiler (0.9.3)
12
+ rake
13
+ rugged (0.21.2)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ bundler (~> 1.7)
20
+ rake (~> 10.0)
21
+ rake-compiler
22
+ rugged-mysql!
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 重楼
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,40 @@
1
+ rugged-mysql
2
+ ============
3
+
4
+ Enables rugged to store git objects and references into MySQL.
5
+
6
+
7
+
8
+ ## Installation
9
+
10
+ Add this line to you application's Gemfile:
11
+
12
+ gem 'rugged-mysql'
13
+ Or:
14
+
15
+ gem 'rugged-mysql', chonglou/rugged-mysql
16
+
17
+ And then execute:
18
+
19
+ bundle install
20
+
21
+
22
+ ## Usage
23
+
24
+ Create the backend:
25
+
26
+ require 'rugged-mysql'
27
+ mysql_backend = Rugged::MySql::Backend.new(host:'localhost', port:3306, username:'git', password:'tig', database:'git')
28
+
29
+ And pass it to rugged:
30
+
31
+ repo = Rugged::Repository.bare('repo-name', backend:mysql_backend)
32
+
33
+ Or
34
+
35
+ repo = Rugged::Repository.init_at('repo-name', :bare, backend:mysql_backend)
36
+
37
+
38
+ Each instance of the backend consumes a single MySql connection.
39
+
40
+ Enjoy it!
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/extensiontask'
3
+
4
+ Rake::ExtensionTask.new 'rugged-mysql' do |ext|
5
+ ext.lib_dir = 'lib/rugged/mysql'
6
+ ext.ext_dir = 'ext/rugged/mysql'
7
+ end
8
+
@@ -0,0 +1,24 @@
1
+ require 'mkmf'
2
+
3
+
4
+ $CFLAGS << " #{ENV['CFLAGS']}"
5
+ $CFLAGS << ' -I/usr/include/mysql'
6
+
7
+ RUGGED_EXT_DIR = Gem::Specification.find_by_name('rugged').gem_dir
8
+ puts "Using rugged headers from #{RUGGED_EXT_DIR}\n"
9
+ $CFLAGS << " -I#{RUGGED_EXT_DIR}/ext/rugged"
10
+ $CFLAGS << " -I#{RUGGED_EXT_DIR}/vendor/libgit2/include"
11
+ $CFLAGS << " -I#{RUGGED_EXT_DIR}/vendor/libgit2/src"
12
+
13
+ $CFLAGS << ' -g'
14
+ $CFLAGS << ' -O3' unless $CFLAGS[/-O\d/]
15
+ $CFLAGS << ' -Wall -Wno-comment -Wno-sizeof-pointer-memaccess'
16
+
17
+
18
+ MAKE = find_executable('gmake') || find_executable('make')
19
+ unless MAKE
20
+ abort 'ERROR: GNU make is required to build Rugged.'
21
+ end
22
+
23
+ create_makefile('rugged/mysql/rugged-mysql')
24
+
@@ -0,0 +1,478 @@
1
+ /*
2
+ * source: https://github.com/libgit2/libgit2-backends/blob/master/mysql/mysql.c
3
+ */
4
+
5
+ #include <assert.h>
6
+ #include <string.h>
7
+ #include <git2.h>
8
+ #include <git2/sys/odb_backend.h>
9
+ #include <mysql.h>
10
+
11
+ #define GIT2_ODB_TABLE_NAME "git2_odb"
12
+ #define GIT2_STORAGE_ENGINE "InnoDB"
13
+
14
+ typedef struct {
15
+ git_odb_backend parent;
16
+ MYSQL *db;
17
+ MYSQL_STMT *st_read;
18
+ MYSQL_STMT *st_write;
19
+ MYSQL_STMT *st_read_header;
20
+ } mysql_odb_backend;
21
+
22
+ int
23
+ mysql_odb_backend__read_header(size_t * len_p, git_otype * type_p,
24
+ git_odb_backend * _backend, const git_oid * oid)
25
+ {
26
+ mysql_odb_backend *backend;
27
+ int error;
28
+ MYSQL_BIND bind_buffers[1];
29
+ MYSQL_BIND result_buffers[2];
30
+
31
+ assert(len_p && type_p && _backend && oid);
32
+
33
+ backend = (mysql_odb_backend *) _backend;
34
+ error = GIT_ERROR;
35
+
36
+ memset(bind_buffers, 0, sizeof(bind_buffers));
37
+ memset(result_buffers, 0, sizeof(result_buffers));
38
+
39
+ // bind the oid passed to the statement
40
+ bind_buffers[0].buffer = (void *)oid->id;
41
+ bind_buffers[0].buffer_length = 20;
42
+ bind_buffers[0].length = &bind_buffers[0].buffer_length;
43
+ bind_buffers[0].buffer_type = MYSQL_TYPE_BLOB;
44
+ if (mysql_stmt_bind_param(backend->st_read_header, bind_buffers) != 0) {
45
+ return 0;
46
+ }
47
+ // execute the statement
48
+ if (mysql_stmt_execute(backend->st_read_header) != 0) {
49
+ return 0;
50
+ }
51
+ if (mysql_stmt_store_result(backend->st_read_header) != 0) {
52
+ return 0;
53
+ }
54
+ // this should either be 0 or 1
55
+ // if it's > 1 MySQL's unique index failed and we should all fear for our lives
56
+ if (mysql_stmt_num_rows(backend->st_read_header) == 1) {
57
+ result_buffers[0].buffer_type = MYSQL_TYPE_TINY;
58
+ result_buffers[0].buffer = type_p;
59
+ result_buffers[0].buffer_length = sizeof(type_p);
60
+ memset(type_p, 0, sizeof(type_p));
61
+
62
+ result_buffers[1].buffer_type = MYSQL_TYPE_LONGLONG;
63
+ result_buffers[1].buffer = len_p;
64
+ result_buffers[1].buffer_length = sizeof(len_p);
65
+ memset(len_p, 0, sizeof(len_p));
66
+
67
+ if (mysql_stmt_bind_result
68
+ (backend->st_read_header, result_buffers) != 0) {
69
+ return GIT_ERROR;
70
+ }
71
+ // this should populate the buffers at *type_p and *len_p
72
+ if (mysql_stmt_fetch(backend->st_read_header) != 0) {
73
+ return GIT_ERROR;
74
+ }
75
+
76
+ error = GIT_OK;
77
+ } else {
78
+ error = GIT_ENOTFOUND;
79
+ }
80
+
81
+ // reset the statement for further use
82
+ if (mysql_stmt_reset(backend->st_read_header) != 0) {
83
+ return 0;
84
+ }
85
+
86
+ return error;
87
+ }
88
+
89
+ int
90
+ mysql_odb_backend__read(void **data_p, size_t * len_p, git_otype * type_p,
91
+ git_odb_backend * _backend, const git_oid * oid)
92
+ {
93
+ mysql_odb_backend *backend;
94
+ int error;
95
+ MYSQL_BIND bind_buffers[1];
96
+ MYSQL_BIND result_buffers[3];
97
+ unsigned long data_len;
98
+
99
+ assert(len_p && type_p && _backend && oid);
100
+
101
+ backend = (mysql_odb_backend *) _backend;
102
+ error = GIT_ERROR;
103
+
104
+ memset(bind_buffers, 0, sizeof(bind_buffers));
105
+ memset(result_buffers, 0, sizeof(result_buffers));
106
+
107
+ // bind the oid passed to the statement
108
+ bind_buffers[0].buffer = (void *)oid->id;
109
+ bind_buffers[0].buffer_length = 20;
110
+ bind_buffers[0].length = &bind_buffers[0].buffer_length;
111
+ bind_buffers[0].buffer_type = MYSQL_TYPE_BLOB;
112
+ if (mysql_stmt_bind_param(backend->st_read, bind_buffers) != 0) {
113
+ return 0;
114
+ }
115
+ // execute the statement
116
+ if (mysql_stmt_execute(backend->st_read) != 0) {
117
+ return 0;
118
+ }
119
+
120
+ if (mysql_stmt_store_result(backend->st_read) != 0) {
121
+ return 0;
122
+ }
123
+ // this should either be 0 or 1
124
+ // if it's > 1 MySQL's unique index failed and we should all fear for our lives
125
+ if (mysql_stmt_num_rows(backend->st_read) == 1) {
126
+ result_buffers[0].buffer_type = MYSQL_TYPE_TINY;
127
+ result_buffers[0].buffer = type_p;
128
+ result_buffers[0].buffer_length = sizeof(type_p);
129
+ memset(type_p, 0, sizeof(type_p));
130
+
131
+ result_buffers[1].buffer_type = MYSQL_TYPE_LONGLONG;
132
+ result_buffers[1].buffer = len_p;
133
+ result_buffers[1].buffer_length = sizeof(len_p);
134
+ memset(len_p, 0, sizeof(len_p));
135
+
136
+ // by setting buffer and buffer_length to 0, this tells libmysql
137
+ // we want it to set data_len to the *actual* length of that field
138
+ // this way we can malloc exactly as much memory as we need for the buffer
139
+ //
140
+ // come to think of it, we can probably just use the length set in *len_p
141
+ // once we fetch the result?
142
+ result_buffers[2].buffer_type = MYSQL_TYPE_LONG_BLOB;
143
+ result_buffers[2].buffer = 0;
144
+ result_buffers[2].buffer_length = 0;
145
+ result_buffers[2].length = &data_len;
146
+
147
+ if (mysql_stmt_bind_result(backend->st_read, result_buffers) !=
148
+ 0) {
149
+ return GIT_ERROR;
150
+ }
151
+ // this should populate the buffers at *type_p, *len_p and &data_len
152
+ error = mysql_stmt_fetch(backend->st_read);
153
+ // if(error != 0 || error != MYSQL_DATA_TRUNCATED)
154
+ // return GIT_ERROR;
155
+
156
+ if (data_len > 0) {
157
+ *data_p = malloc(data_len);
158
+ result_buffers[2].buffer = *data_p;
159
+ result_buffers[2].buffer_length = data_len;
160
+
161
+ if (mysql_stmt_fetch_column
162
+ (backend->st_read, &result_buffers[2], 2, 0) != 0) {
163
+ return GIT_ERROR;
164
+ }
165
+ }
166
+
167
+ error = GIT_OK;
168
+ } else {
169
+ error = GIT_ENOTFOUND;
170
+ }
171
+
172
+ // reset the statement for further use
173
+ if (mysql_stmt_reset(backend->st_read) != 0) {
174
+ return 0;
175
+ }
176
+
177
+ return error;
178
+ }
179
+
180
+ int mysql_odb_backend__exists(git_odb_backend * _backend, const git_oid * oid)
181
+ {
182
+ mysql_odb_backend *backend;
183
+ int found;
184
+ MYSQL_BIND bind_buffers[1];
185
+
186
+ assert(_backend && oid);
187
+
188
+ backend = (mysql_odb_backend *) _backend;
189
+ found = 0;
190
+
191
+ memset(bind_buffers, 0, sizeof(bind_buffers));
192
+
193
+ // bind the oid passed to the statement
194
+ bind_buffers[0].buffer = (void *)oid->id;
195
+ bind_buffers[0].buffer_length = 20;
196
+ bind_buffers[0].length = &bind_buffers[0].buffer_length;
197
+ bind_buffers[0].buffer_type = MYSQL_TYPE_BLOB;
198
+ if (mysql_stmt_bind_param(backend->st_read_header, bind_buffers) != 0) {
199
+ return 0;
200
+ }
201
+ // execute the statement
202
+ if (mysql_stmt_execute(backend->st_read_header) != 0) {
203
+ return 0;
204
+ }
205
+
206
+ if (mysql_stmt_store_result(backend->st_read_header) != 0) {
207
+ return 0;
208
+ }
209
+ // now lets see if any rows matched our query
210
+ // this should either be 0 or 1
211
+ // if it's > 1 MySQL's unique index failed and we should all fear for our lives
212
+ if (mysql_stmt_num_rows(backend->st_read_header) == 1) {
213
+ found = 1;
214
+ }
215
+ // reset the statement for further use
216
+ if (mysql_stmt_reset(backend->st_read_header) != 0) {
217
+ return 0;
218
+ }
219
+
220
+ return found;
221
+ }
222
+
223
+ int
224
+ mysql_odb_backend__write(git_odb_backend * _backend, const git_oid * oid,
225
+ const void *data, size_t len, git_otype type)
226
+ {
227
+ int error;
228
+ mysql_odb_backend *backend;
229
+ MYSQL_BIND bind_buffers[4];
230
+ my_ulonglong affected_rows;
231
+
232
+ assert(oid && _backend && data);
233
+
234
+ backend = (mysql_odb_backend *) _backend;
235
+
236
+ if ((error = git_odb_hash(oid, data, len, type)) < 0) {
237
+ return error;
238
+ }
239
+
240
+ memset(bind_buffers, 0, sizeof(bind_buffers));
241
+
242
+ // bind the oid
243
+ bind_buffers[0].buffer = (void *)oid->id;
244
+ bind_buffers[0].buffer_length = 20;
245
+ bind_buffers[0].length = &bind_buffers[0].buffer_length;
246
+ bind_buffers[0].buffer_type = MYSQL_TYPE_BLOB;
247
+
248
+ // bind the type
249
+ bind_buffers[1].buffer = &type;
250
+ bind_buffers[1].buffer_type = MYSQL_TYPE_TINY;
251
+
252
+ // bind the size of the data
253
+ bind_buffers[2].buffer = &len;
254
+ bind_buffers[2].buffer_type = MYSQL_TYPE_LONG;
255
+
256
+ // bind the data
257
+ bind_buffers[3].buffer = (void *)data;
258
+ bind_buffers[3].buffer_length = len;
259
+ bind_buffers[3].length = &bind_buffers[3].buffer_length;
260
+ bind_buffers[3].buffer_type = MYSQL_TYPE_BLOB;
261
+
262
+ if (mysql_stmt_bind_param(backend->st_write, bind_buffers) != 0) {
263
+ return GIT_ERROR;
264
+ }
265
+ // TODO: use the streaming backend API so this actually makes sense to use :P
266
+ // once we want to use this we should comment out
267
+ // if (mysql_stmt_send_long_data(backend->st_write, 2, data, len) != 0)
268
+ // return GIT_ERROR;
269
+
270
+ // execute the statement
271
+ if (mysql_stmt_execute(backend->st_write) != 0) {
272
+ return GIT_ERROR;
273
+ }
274
+ // now lets see if the insert worked
275
+ affected_rows = mysql_stmt_affected_rows(backend->st_write);
276
+ if (affected_rows != 1) {
277
+ return GIT_ERROR;
278
+ }
279
+ // reset the statement for further use
280
+ if (mysql_stmt_reset(backend->st_read_header) != 0) {
281
+ return GIT_ERROR;
282
+ }
283
+
284
+ return GIT_OK;
285
+ }
286
+
287
+ void mysql_odb_backend__free(git_odb_backend * _backend)
288
+ {
289
+ mysql_odb_backend *backend;
290
+ assert(_backend);
291
+ backend = (mysql_odb_backend *) _backend;
292
+
293
+ if (backend->st_read) {
294
+ mysql_stmt_close(backend->st_read);
295
+ }
296
+ if (backend->st_read_header) {
297
+ mysql_stmt_close(backend->st_read_header);
298
+ }
299
+ if (backend->st_write) {
300
+ mysql_stmt_close(backend->st_write);
301
+ }
302
+
303
+ mysql_close(backend->db);
304
+
305
+ free(backend);
306
+ }
307
+
308
+ static int create_table(MYSQL * db)
309
+ {
310
+ static const char *sql_create =
311
+ "CREATE TABLE `" GIT2_ODB_TABLE_NAME "` ("
312
+ " `oid` binary(20) NOT NULL DEFAULT '',"
313
+ " `type` tinyint(1) unsigned NOT NULL,"
314
+ " `size` bigint(20) unsigned NOT NULL,"
315
+ " `data` longblob NOT NULL,"
316
+ " PRIMARY KEY (`oid`),"
317
+ " KEY `type` (`type`),"
318
+ " KEY `size` (`size`)"
319
+ ") ENGINE=" GIT2_STORAGE_ENGINE
320
+ " DEFAULT CHARSET=utf8 COLLATE=utf8_bin;";
321
+
322
+ if (mysql_real_query(db, sql_create, strlen(sql_create)) != 0) {
323
+ return GIT_ERROR;
324
+ }
325
+
326
+ return GIT_OK;
327
+ }
328
+
329
+ static int init_db(MYSQL * db)
330
+ {
331
+ static const char *sql_check =
332
+ "SHOW TABLES LIKE '" GIT2_ODB_TABLE_NAME "';";
333
+
334
+ MYSQL_RES *res;
335
+ int error;
336
+ my_ulonglong num_rows;
337
+
338
+ if (mysql_real_query(db, sql_check, strlen(sql_check)) != 0)
339
+ return GIT_ERROR;
340
+
341
+ res = mysql_store_result(db);
342
+ if (res == NULL)
343
+ return GIT_ERROR;
344
+
345
+ num_rows = mysql_num_rows(res);
346
+ if (num_rows == 0) {
347
+ /* the table was not found */
348
+ error = create_table(db);
349
+ } else if (num_rows > 0) {
350
+ /* the table was found */
351
+ error = GIT_OK;
352
+ } else {
353
+ error = GIT_ERROR;
354
+ }
355
+
356
+ mysql_free_result(res);
357
+ return error;
358
+ }
359
+
360
+ static int init_statements(mysql_odb_backend * backend)
361
+ {
362
+ my_bool truth = 1;
363
+
364
+ static const char *sql_read =
365
+ "SELECT `type`, `size`, UNCOMPRESS(`data`) FROM `"
366
+ GIT2_ODB_TABLE_NAME "` WHERE `oid` = ?;";
367
+
368
+ static const char *sql_read_header =
369
+ "SELECT `type`, `size` FROM `" GIT2_ODB_TABLE_NAME
370
+ "` WHERE `oid` = ?;";
371
+
372
+ static const char *sql_write =
373
+ "INSERT IGNORE INTO `" GIT2_ODB_TABLE_NAME
374
+ "` VALUES (?, ?, ?, COMPRESS(?));";
375
+
376
+ backend->st_read = mysql_stmt_init(backend->db);
377
+ if (backend->st_read == NULL) {
378
+ return GIT_ERROR;
379
+ }
380
+
381
+ if (mysql_stmt_attr_set
382
+ (backend->st_read, STMT_ATTR_UPDATE_MAX_LENGTH, &truth) != 0) {
383
+ return GIT_ERROR;
384
+ }
385
+
386
+ if (mysql_stmt_prepare(backend->st_read, sql_read, strlen(sql_read)) !=
387
+ 0) {
388
+ return GIT_ERROR;
389
+ }
390
+
391
+ backend->st_read_header = mysql_stmt_init(backend->db);
392
+ if (backend->st_read_header == NULL) {
393
+ return GIT_ERROR;
394
+ }
395
+
396
+ if (mysql_stmt_attr_set
397
+ (backend->st_read_header, STMT_ATTR_UPDATE_MAX_LENGTH, &truth) != 0)
398
+ {
399
+ return GIT_ERROR;
400
+ }
401
+
402
+ if (mysql_stmt_prepare
403
+ (backend->st_read_header, sql_read_header, strlen(sql_read)) != 0) {
404
+ return GIT_ERROR;
405
+ }
406
+
407
+ backend->st_write = mysql_stmt_init(backend->db);
408
+ if (backend->st_write == NULL) {
409
+ return GIT_ERROR;
410
+ }
411
+
412
+ if (mysql_stmt_attr_set
413
+ (backend->st_write, STMT_ATTR_UPDATE_MAX_LENGTH, &truth) != 0) {
414
+ return GIT_ERROR;
415
+ }
416
+
417
+ if (mysql_stmt_prepare(backend->st_write, sql_write, strlen(sql_read))
418
+ != 0) {
419
+ return GIT_ERROR;
420
+ }
421
+
422
+ return GIT_OK;
423
+ }
424
+
425
+ int
426
+ git_odb_backend_mysql(git_odb_backend ** backend_out, const char *mysql_host,
427
+ unsigned int mysql_port,
428
+ const char *mysql_unix_socket,
429
+ const char *mysql_db,
430
+ const char *mysql_user, const char *mysql_passwd,
431
+ unsigned long mysql_client_flag)
432
+ {
433
+ mysql_odb_backend *backend;
434
+ int error;
435
+ my_bool reconnect;
436
+
437
+ backend = calloc(1, sizeof(mysql_odb_backend));
438
+ if (backend == NULL) {
439
+ return GITERR_NOMEMORY;
440
+ }
441
+
442
+ backend->db = mysql_init(backend->db);
443
+
444
+ reconnect = 1;
445
+ // allow libmysql to reconnect gracefully
446
+ if (mysql_options(backend->db, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
447
+ goto cleanup;
448
+ }
449
+ // make the connection
450
+ if (mysql_real_connect
451
+ (backend->db, mysql_host, mysql_user, mysql_passwd, mysql_db,
452
+ mysql_port, mysql_unix_socket, mysql_client_flag) != backend->db) {
453
+ goto cleanup;
454
+ }
455
+ // check for and possibly create the database
456
+ error = init_db(backend->db);
457
+ if (error < 0) {
458
+ goto cleanup;
459
+ }
460
+
461
+ error = init_statements(backend);
462
+ if (error < 0) {
463
+ goto cleanup;
464
+ }
465
+
466
+ backend->parent.read = &mysql_odb_backend__read;
467
+ backend->parent.read_header = &mysql_odb_backend__read_header;
468
+ backend->parent.write = &mysql_odb_backend__write;
469
+ backend->parent.exists = &mysql_odb_backend__exists;
470
+ backend->parent.free = &mysql_odb_backend__free;
471
+
472
+ *backend_out = (git_odb_backend *) backend;
473
+ return GIT_OK;
474
+
475
+ cleanup:
476
+ mysql_odb_backend__free((git_odb_backend *) backend);
477
+ return GIT_ERROR;
478
+ }