rugged-mysql 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }