From e5e577b282b9a16ef49ca836c04a85f07048e08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=B5=AB=E7=84=B6?= Date: Tue, 10 Oct 2023 15:05:32 +0800 Subject: [PATCH] Support dm8 database --- common/branch-mgr.c | 10 +- common/group-mgr.c | 86 ++- common/org-mgr.c | 42 ++ common/seaf-db.c | 714 +++++++++++++++++- common/seaf-db.h | 7 + common/seaf-utils.c | 112 +++ common/user-mgr.c | 62 ++ configure.ac | 13 + fuse/Makefile.am | 2 +- server/Makefile.am | 2 +- server/gc/Makefile.am | 4 +- server/gc/repo-mgr.c | 4 +- server/quota-mgr.c | 32 +- server/repo-mgr.c | 187 ++++- server/seafile-session.c | 2 +- server/share-mgr.c | 15 + server/size-sched.c | 1 + .../test_repo_manipulation.py | 3 + 18 files changed, 1249 insertions(+), 49 deletions(-) diff --git a/common/branch-mgr.c b/common/branch-mgr.c index 45ac56ce..32b17744 100644 --- a/common/branch-mgr.c +++ b/common/branch-mgr.c @@ -141,6 +141,13 @@ open_db (SeafBranchManager *mgr) char *sql; switch (seaf_db_type (mgr->seaf->db)) { + case SEAF_DB_TYPE_DM: + sql = "CREATE TABLE IF NOT EXISTS Branch (" + "id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, " + "name VARCHAR(10), repo_id VARCHAR(41), commit_id VARCHAR(41))"; + if (seaf_db_query (mgr->seaf->db, sql) < 0) + return -1; + break; case SEAF_DB_TYPE_MYSQL: sql = "CREATE TABLE IF NOT EXISTS Branch (" "id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, " @@ -200,7 +207,7 @@ seaf_branch_manager_add_branch (SeafBranchManager *mgr, SeafBranch *branch) char *sql; SeafDB *db = mgr->seaf->db; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean exists, err; int rc; @@ -382,6 +389,7 @@ seaf_branch_manager_test_and_update_branch (SeafBranchManager *mgr, switch (seaf_db_type (mgr->seaf->db)) { case SEAF_DB_TYPE_MYSQL: case SEAF_DB_TYPE_PGSQL: + case SEAF_DB_TYPE_DM: sql = "SELECT commit_id FROM Branch WHERE name=? " "AND repo_id=? FOR UPDATE"; break; diff --git a/common/group-mgr.c b/common/group-mgr.c index 2c1f915b..1ed2bb12 100644 --- a/common/group-mgr.c +++ b/common/group-mgr.c @@ -87,6 +87,7 @@ open_db (CcnetGroupManager *manager) db = open_sqlite_db (manager); break; case SEAF_DB_TYPE_PGSQL: + case SEAF_DB_TYPE_DM: case SEAF_DB_TYPE_MYSQL: db = manager->session->ccnet_db; break; @@ -225,6 +226,46 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) // return -1; //} + } else if (db_type == SEAF_DB_TYPE_DM) { + g_string_printf (group_sql, + "CREATE TABLE IF NOT EXISTS \"%s\" (group_id INTEGER" + " PRIMARY KEY AUTO_INCREMENT, group_name VARCHAR(255)," + " creator_name VARCHAR(255), timestamp BIGINT," + " type VARCHAR(32), parent_group_id INTEGER)", table_name); + if (seaf_db_query (db, group_sql->str) < 0) { + g_string_free (group_sql, TRUE); + return -1; + } + + sql = "CREATE TABLE IF NOT EXISTS GroupUser (group_id INTEGER, " + "user_name VARCHAR(255), is_staff tinyint)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS groupid_username_indx on " + "GroupUser (group_id, user_name)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS username_indx on " + "GroupUser (user_name)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS GroupDNPair (group_id INTEGER," + " dn VARCHAR(255))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS GroupStructure (group_id INTEGER PRIMARY KEY, " + "path VARCHAR(1024))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS path_indx on " + "GroupStructure (path)"; + if (seaf_db_query (db, sql) < 0) + return -1; } g_string_free (group_sql, TRUE); @@ -267,7 +308,7 @@ create_group_common (CcnetGroupManager *mgr, char *user_name_l = g_ascii_strdown (user_name, -1); - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "INSERT INTO \"%s\"(group_name, " "creator_name, timestamp, parent_group_id) VALUES(?, ?, ?, ?)", table_name); @@ -281,7 +322,7 @@ create_group_common (CcnetGroupManager *mgr, "int64", now, "int", parent_group_id) < 0) goto error; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT group_id FROM \"%s\" WHERE " "group_name = ? AND creator_name = ? " @@ -472,7 +513,7 @@ int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, * can remove group. */ if (remove_anyway != TRUE) { - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT 1 FROM \"%s\" WHERE parent_group_id=?", table_name); else g_string_printf (sql, "SELECT 1 FROM `%s` WHERE parent_group_id=?", table_name); @@ -489,7 +530,7 @@ int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, } } - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "DELETE FROM \"%s\" WHERE group_id=?", table_name); else g_string_printf (sql, "DELETE FROM `%s` WHERE group_id=?", table_name); @@ -499,7 +540,7 @@ int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, seaf_db_statement_query (db, sql->str, 1, "int", group_id); g_string_printf (sql, "DELETE FROM GroupStructure WHERE group_id=?"); - seaf_db_statement_query (db, sql->str, 1, "int", group_id); + int ret = seaf_db_statement_query (db, sql->str, 1, "int", group_id); g_string_free (sql, TRUE); @@ -513,7 +554,7 @@ check_group_exists (CcnetGroupManager *mgr, CcnetDB *db, int group_id) const char *table_name = mgr->priv->table_name; gboolean exists, err; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { g_string_printf (sql, "SELECT group_id FROM \"%s\" WHERE group_id=?", table_name); exists = seaf_db_statement_exists (db, sql->str, &err, 1, "int", group_id); } else { @@ -622,7 +663,7 @@ int ccnet_group_manager_set_group_name (CcnetGroupManager *mgr, GString *sql = g_string_new (""); CcnetDB *db = mgr->priv->db; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { g_string_printf (sql, "UPDATE \"%s\" SET group_name = ? " "WHERE group_id = ?", table_name); seaf_db_statement_query (db, sql->str, 2, "string", group_name, "int", group_id); @@ -697,7 +738,7 @@ ccnet_group_manager_get_ancestor_groups (CcnetGroupManager *mgr, int group_id) char *path = seaf_db_statement_get_string (db, sql->str, 1, "int", group_id); if (path) { - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " "\"%s\" g WHERE g.group_id IN(%s) " "ORDER BY g.group_id", @@ -768,7 +809,7 @@ ccnet_group_manager_get_groups_by_user (CcnetGroupManager *mgr, CcnetGroup *group; int parent_group_id = 0, group_id = 0; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " "\"%s\" g, GroupUser u WHERE g.group_id = u.group_id AND user_name=? ORDER BY g.group_id DESC", @@ -827,9 +868,14 @@ ccnet_group_manager_get_groups_by_user (CcnetGroupManager *mgr, goto out; } - g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " - "`%s` g WHERE g.group_id IN (%s) ORDER BY g.group_id DESC", - table_name, paths->str); + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) + g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "\"%s\" g WHERE g.group_id IN (%s) ORDER BY g.group_id DESC", + table_name, paths->str); + else + g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "`%s` g WHERE g.group_id IN (%s) ORDER BY g.group_id DESC", + table_name, paths->str); if (seaf_db_statement_foreach_row (db, sql->str, get_user_groups_cb, @@ -888,7 +934,7 @@ ccnet_group_manager_get_child_groups (CcnetGroupManager *mgr, int group_id, GList *ret = NULL; const char *table_name = mgr->priv->table_name; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT group_id, group_name, creator_name, timestamp, parent_group_id FROM " "\"%s\" WHERE parent_group_id=?", table_name); @@ -916,7 +962,7 @@ ccnet_group_manager_get_descendants_groups(CcnetGroupManager *mgr, int group_id, const char *table_name = mgr->priv->table_name; GString *sql = g_string_new(""); - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, " "parent_group_id FROM \"%s\" g, GroupStructure s " "WHERE g.group_id=s.group_id " @@ -952,7 +998,7 @@ ccnet_group_manager_get_group (CcnetGroupManager *mgr, int group_id, CcnetGroup *ccnetgroup = NULL; const char *table_name = mgr->priv->table_name; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) g_string_printf (sql, "SELECT group_id, group_name, creator_name, timestamp, parent_group_id FROM " "\"%s\" WHERE group_id = ?", table_name); @@ -1174,7 +1220,7 @@ ccnet_group_manager_get_top_groups (CcnetGroupManager *mgr, const char *table_name = mgr->priv->table_name; int rc; - if (seaf_db_type(mgr->priv->db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(mgr->priv->db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(mgr->priv->db) == SEAF_DB_TYPE_DM) { if (including_org) g_string_printf (sql, "SELECT group_id, group_name, " "creator_name, timestamp, parent_group_id FROM \"%s\" " @@ -1217,7 +1263,7 @@ ccnet_group_manager_list_all_departments (CcnetGroupManager *mgr, int rc; int db_type = seaf_db_type(db); - if (db_type == SEAF_DB_TYPE_PGSQL) { + if (db_type == SEAF_DB_TYPE_PGSQL || db_type == SEAF_DB_TYPE_DM) { g_string_printf (sql, "SELECT group_id, group_name, " "creator_name, timestamp, type, " "parent_group_id FROM \"%s\" " @@ -1251,7 +1297,7 @@ ccnet_group_manager_get_all_groups (CcnetGroupManager *mgr, const char *table_name = mgr->priv->table_name; int rc; - if (seaf_db_type(mgr->priv->db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(mgr->priv->db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(mgr->priv->db) == SEAF_DB_TYPE_DM) { if (start == -1 && limit == -1) { g_string_printf (sql, "SELECT group_id, group_name, " "creator_name, timestamp, parent_group_id FROM \"%s\" " @@ -1301,7 +1347,7 @@ ccnet_group_manager_set_group_creator (CcnetGroupManager *mgr, const char *table_name = mgr->priv->table_name; GString *sql = g_string_new (""); - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { g_string_printf (sql, "UPDATE \"%s\" SET creator_name = ? WHERE group_id = ?", table_name); } else { @@ -1329,7 +1375,7 @@ ccnet_group_manager_search_groups (CcnetGroupManager *mgr, int rc; char *db_patt = g_strdup_printf ("%%%s%%", keyword); - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { if (start == -1 && limit == -1) { g_string_printf (sql, "SELECT group_id, group_name, " diff --git a/common/org-mgr.c b/common/org-mgr.c index ba8cd0db..646f18d4 100644 --- a/common/org-mgr.c +++ b/common/org-mgr.c @@ -77,6 +77,7 @@ open_db (CcnetOrgManager *manager) db = open_sqlite_db (manager); break; case SEAF_DB_TYPE_PGSQL: + case SEAF_DB_TYPE_DM: case SEAF_DB_TYPE_MYSQL: db = manager->session->ccnet_db; break; @@ -203,6 +204,47 @@ static int check_db_table (CcnetDB *db) // if (seaf_db_query (db, sql) < 0) // return -1; //} + } else if (db_type == SEAF_DB_TYPE_DM) { + sql = "CREATE TABLE IF NOT EXISTS Organization (org_id INTEGER" + " PRIMARY KEY, org_name VARCHAR(255)," + " url_prefix VARCHAR(255), " + " creator VARCHAR(255), ctime BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS url_prefix_indx on " + "Organization (url_prefix)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS OrgUser (org_id INTEGER, " + "email VARCHAR(255), is_staff INTEGER NOT NULL)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS email_indx on " + "OrgUser (email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS orgid_email_indx on " + "OrgUser (org_id, email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS OrgGroup (org_id INTEGER, " + "group_id INTEGER)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS groupid_indx on OrgGroup (group_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS org_group_indx on " + "OrgGroup (org_id, group_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; } return 0; diff --git a/common/seaf-db.c b/common/seaf-db.c index 4093b444..58e246f4 100644 --- a/common/seaf-db.c +++ b/common/seaf-db.c @@ -13,6 +13,12 @@ #include #include +#ifdef HAVE_ODBC +#include +#include +#include +#endif + struct DBConnPool { GPtrArray *connections; pthread_mutex_t lock; @@ -38,6 +44,7 @@ struct SeafDBRow { struct SeafDBTrans { DBConnection *conn; gboolean need_close; + int type; }; typedef struct DBOperations { @@ -320,6 +327,210 @@ seaf_db_new_sqlite (const char *db_path, int max_connections) return db; } +#ifdef HAVE_ODBC + +#define BUFFER_NOT_ENOUGH -70018 +#define SUCCESS(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO || (rc) == SQL_NO_DATA || (rc) == SQL_NO_DATA_FOUND) + +typedef struct DMDBConnection { + struct DBConnection parent; + HDBC db_conn; +} DMDBConnection; + +/* MySQL Ops */ +static SeafDB * +dm_db_new (const char *user, + const char *password, + const char *db_name); +static DBConnection * +dm_db_get_connection (SeafDB *db); +static void +dm_db_release_connection (DBConnection *vconn); +static int +dm_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql, gboolean *retry); +static int +dm_db_execute_sql (DBConnection *vconn, const char *sql, int n, va_list args, gboolean *retry); +static int +dm_db_query_foreach_row (DBConnection *vconn, const char *sql, + SeafDBRowFunc callback, void *data, + int n, va_list args, gboolean *retry); +static int +dm_db_row_get_column_count (SeafDBRow *row); +static const char * +dm_db_row_get_column_string (SeafDBRow *row, int idx); +static int +dm_db_row_get_column_int (SeafDBRow *row, int idx); +static gint64 +dm_db_row_get_column_int64 (SeafDBRow *row, int idx); + +static DBConnPool * +init_dm_conn_pool_common (int max_connections) +{ + DBConnPool *pool = g_new0(DBConnPool, 1); + pool->connections = g_ptr_array_sized_new (max_connections); + pthread_mutex_init (&pool->lock, NULL); + pool->max_connections = max_connections; + + return pool; +} + +static DBConnection * +dm_conn_pool_get_connection (SeafDB *db) +{ + DBConnPool *pool = db->pool; + DBConnection *conn = NULL; + DBConnection *d_conn = NULL; + + if (pool->max_connections == 0) { + conn = dm_db_get_connection (db); + conn->pool = pool; + return conn; + } + + pthread_mutex_lock (&pool->lock); + + guint i, size = pool->connections->len; + for (i = 0; i < size; ++i) { + conn = g_ptr_array_index (pool->connections, i); + if (!conn->is_available) { + continue; + } + conn->is_available = FALSE; + goto out; + } + conn = NULL; + if (size < pool->max_connections) { + conn = dm_db_get_connection (db); + if (conn) { + conn->pool = pool; + conn->is_available = FALSE; + g_ptr_array_add (pool->connections, conn); + } + } + +out: + size = pool->connections->len; + if (size > 0) { + int index; + for (index = size - 1; index >= 0; index--) { + d_conn = g_ptr_array_index (pool->connections, index); + if (d_conn->delete_pending) { + g_ptr_array_remove (conn->pool->connections, d_conn); + dm_db_release_connection (d_conn); + } + } + } + pthread_mutex_unlock (&pool->lock); + return conn; +} + +static void +dm_conn_pool_release_connection (DBConnection *conn, gboolean need_close) +{ + if (!conn) + return; + + if (conn->pool->max_connections == 0) { + dm_db_release_connection (conn); + return; + } + + if (need_close) { + pthread_mutex_lock (&conn->pool->lock); + g_ptr_array_remove (conn->pool->connections, conn); + pthread_mutex_unlock (&conn->pool->lock); + dm_db_release_connection (conn); + return; + } + + pthread_mutex_lock (&conn->pool->lock); + conn->is_available = TRUE; + pthread_mutex_unlock (&conn->pool->lock); +} + +#define KEEPALIVE_INTERVAL 30 +static void * +dm_conn_keepalive (void *arg) +{ + DBConnPool *pool = arg; + DBConnection *conn = NULL; + DBConnection *d_conn = NULL; + char *sql = "SELECT 1;"; + int rc = 0; + va_list args; + + while (1) { + pthread_mutex_lock (&pool->lock); + + guint i, size = pool->connections->len; + for (i = 0; i < size; ++i) { + conn = g_ptr_array_index (pool->connections, i); + if (conn->is_available) { + rc = db_ops.execute_sql (conn, sql, 0, args, NULL); + if (rc < 0) { + conn->is_available = FALSE; + conn->delete_pending = TRUE; + } + } + } + + if (size > 0) { + int index; + for (index = size - 1; index >= 0; index--) { + d_conn = g_ptr_array_index (pool->connections, index); + if (d_conn->delete_pending) { + g_ptr_array_remove (pool->connections, d_conn); + dm_db_release_connection (d_conn); + } + } + } + + pthread_mutex_unlock (&pool->lock); + + sleep (KEEPALIVE_INTERVAL); + } + + return NULL; +} + +SeafDB * +seaf_db_new_dm (const char *user, + const char *passwd, + const char *db_name, + int max_connections) +{ + SeafDB *db; + + db = dm_db_new (user, passwd, db_name); + if (!db) + return NULL; + db->type = SEAF_DB_TYPE_DM; + + db_ops.get_connection = dm_conn_pool_get_connection; + db_ops.release_connection = dm_conn_pool_release_connection; + db_ops.execute_sql_no_stmt = dm_db_execute_sql_no_stmt; + db_ops.execute_sql = dm_db_execute_sql; + db_ops.query_foreach_row = dm_db_query_foreach_row; + db_ops.row_get_column_count = dm_db_row_get_column_count; + db_ops.row_get_column_string = dm_db_row_get_column_string; + db_ops.row_get_column_int = dm_db_row_get_column_int; + db_ops.row_get_column_int64 = dm_db_row_get_column_int64; + + db->pool = init_dm_conn_pool_common (max_connections); + + pthread_t tid; + int ret = pthread_create (&tid, NULL, dm_conn_keepalive, db->pool); + if (ret != 0) { + seaf_warning ("Failed to create dm connection keepalive thread.\n"); + return NULL; + } + pthread_detach (tid); + + return db; +} + +#endif + int seaf_db_type (SeafDB *db) { @@ -635,13 +846,21 @@ seaf_db_begin_transaction (SeafDB *db) return trans; } - if (db_ops.execute_sql_no_stmt (conn, "BEGIN", NULL) < 0) { - db_ops.release_connection (conn, TRUE); - return trans; + if (db->type == SEAF_DB_TYPE_DM) { +#ifdef HAVE_ODBC + DMDBConnection *dm_conn = (DMDBConnection *)conn; + SQLSetConnectAttr(dm_conn->db_conn, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER); +#endif + } else { + if (db_ops.execute_sql_no_stmt (conn, "BEGIN", NULL) < 0) { + db_ops.release_connection (conn, TRUE); + return trans; + } } trans = g_new0 (SeafDBTrans, 1); trans->conn = conn; + trans->type = db->type; return trans; } @@ -649,6 +868,12 @@ seaf_db_begin_transaction (SeafDB *db) void seaf_db_trans_close (SeafDBTrans *trans) { + if (trans->type == SEAF_DB_TYPE_DM) { +#ifdef HAVE_ODBC + DMDBConnection *dm_conn = (DMDBConnection *)trans->conn; + SQLSetConnectAttr(dm_conn->db_conn, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_INTEGER); +#endif + } db_ops.release_connection (trans->conn, trans->need_close); g_free (trans); } @@ -658,9 +883,21 @@ seaf_db_commit (SeafDBTrans *trans) { DBConnection *conn = trans->conn; - if (db_ops.execute_sql_no_stmt (conn, "COMMIT", NULL) < 0) { - trans->need_close = TRUE; - return -1; + if (trans->type == SEAF_DB_TYPE_DM) { +#ifdef HAVE_ODBC + DMDBConnection *dm_conn = (DMDBConnection *)conn; + SQLRETURN ret; + ret = SQLEndTran (SQL_HANDLE_DBC, dm_conn->db_conn, SQL_COMMIT); + if (!SUCCESS(ret)) { + trans->need_close = TRUE; + return -1; + } +#endif + } else { + if (db_ops.execute_sql_no_stmt (conn, "COMMIT", NULL) < 0) { + trans->need_close = TRUE; + return -1; + } } return 0; @@ -671,9 +908,21 @@ seaf_db_rollback (SeafDBTrans *trans) { DBConnection *conn = trans->conn; - if (db_ops.execute_sql_no_stmt (conn, "ROLLBACK", NULL) < 0) { - trans->need_close = TRUE; - return -1; + if (trans->type == SEAF_DB_TYPE_DM) { +#ifdef HAVE_ODBC + DMDBConnection *dm_conn = (DMDBConnection *)conn; + SQLRETURN ret; + ret = SQLEndTran (SQL_HANDLE_DBC, dm_conn->db_conn, SQL_ROLLBACK); + if (!SUCCESS(ret)) { + trans->need_close = TRUE; + return -1; + } +#endif + } else { + if (db_ops.execute_sql_no_stmt (conn, "ROLLBACK", NULL) < 0) { + trans->need_close = TRUE; + return -1; + } } return 0; @@ -1575,3 +1824,450 @@ sqlite_db_row_get_column_int64 (SeafDBRow *vrow, int idx) return sqlite3_column_int64 (row->stmt, idx); } + +#ifdef HAVE_ODBC + +/* DM DB */ + +static int +dm_get_error_state (SQLSMALLINT type, SQLHANDLE handle) +{ + SQLINTEGER native_err; + unsigned char errmsg[255]; + SQLGetDiagRec(type, handle, 1, NULL, &native_err, errmsg, sizeof(errmsg), NULL); + + return native_err; +} + +char * +dm_db_error (SQLSMALLINT type, SQLHANDLE handle) +{ + SQLINTEGER native_err; + unsigned char errmsg[255]; + SQLGetDiagRec(type, handle, 1, NULL, &native_err, errmsg, sizeof(errmsg), NULL); + + return g_strdup(errmsg); +} + +typedef struct DMDB { + struct SeafDB parent; + char *user; + char *password; + char *db_name; + HENV env; +} DMDB; + +typedef struct DM_BIND { + void *buffer; + int buffer_length; + SQLLEN length; +} DM_BIND; + +static SeafDB * +dm_db_new (const char *user, + const char *password, + const char *db_name) +{ + DMDB *db = g_new0 (DMDB, 1); + + db->user = g_strdup (user); + db->password = g_strdup (password); + db->db_name = g_strdup(db_name); + + SQLAllocHandle(SQL_HANDLE_ENV, NULL, &db->env); + SQLSetEnvAttr(db->env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); + + return (SeafDB *)db; +} + +typedef char my_bool; + +static DBConnection * +dm_db_get_connection (SeafDB *vdb) +{ + DMDB *db = (DMDB *)vdb; + HDBC db_conn; + DMDBConnection *conn = NULL; + SQLRETURN ret; + + SQLAllocHandle(SQL_HANDLE_DBC, db->env, &db_conn); + ret = SQLConnect(db_conn, (SQLCHAR *)db->db_name, SQL_NTS, (SQLCHAR *)db->user, SQL_NTS, (SQLCHAR *)db->password, SQL_NTS); + if (!SUCCESS(ret)) { + char *errmsg = dm_db_error (SQL_HANDLE_DBC, db_conn); + seaf_warning ("Failed to connect dm server: %s\n", errmsg); + g_free (errmsg); + SQLFreeHandle(SQL_HANDLE_DBC, db_conn); + return NULL; + } + + conn = g_new0 (DMDBConnection, 1); + conn->db_conn = db_conn; + + return (DBConnection *)conn; +} + +static void +dm_db_release_connection (DBConnection *vconn) +{ + if (!vconn) + return; + + DMDBConnection *conn = (DMDBConnection *)vconn; + + SQLDisconnect(conn->db_conn); + SQLFreeHandle(SQL_HANDLE_DBC, conn->db_conn); + + g_free (conn); +} + +static int +dm_db_execute_sql_no_stmt (DBConnection *vconn, const char *sql, gboolean *retry) +{ + DMDBConnection *conn = (DMDBConnection *)vconn; + HSTMT stmt; + SQLRETURN ret; + + SQLAllocHandle(SQL_HANDLE_STMT, conn->db_conn, &stmt); + + ret = SQLExecDirect(stmt, (SQLCHAR *)sql, SQL_NTS); + if (!SUCCESS(ret)) { + char *errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to execute sql %s: %s\n", sql, errmsg); + g_free (errmsg); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return -1; + } + + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return 0; +} + +static HSTMT +_prepare_stmt_dm (HDBC db, const char *sql, gboolean *retry) +{ + HSTMT stmt; + SQLRETURN ret; + + SQLAllocHandle(SQL_HANDLE_STMT, db, &stmt); + ret = SQLPrepare(stmt, sql, SQL_NTS); + if (!SUCCESS(ret)) { + char * errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to prepare sql %s: %s\n", sql, errmsg); + g_free (errmsg); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return NULL; + } + + return stmt; +} + +static int +_bind_params_dm (HSTMT stmt, DM_BIND *params, int n, va_list args) +{ + int i; + const char *type; + SQLRETURN ret; + char *errmsg = NULL; + + for (i = 0; i < n; ++i) { + type = va_arg (args, const char *); + if (strcmp(type, "int") == 0) { + int x = va_arg (args, int); + int *pval = g_new (int, 1); + *pval = x; + params[i].buffer = pval; + ret = SQLBindParameter(stmt, i+1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(x), 0, params[i].buffer, sizeof(x), NULL); + if (!SUCCESS(ret)) { + errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to bid params: %s\n", errmsg); + g_free (errmsg); + return -1; + } + } else if (strcmp (type, "int64") == 0) { + gint64 x = va_arg (args, gint64); + gint64 *pval = g_new (gint64, 1); + *pval = x; + params[i].buffer = pval; + ret = SQLBindParameter(stmt, i+1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, sizeof(x), 0, params[i].buffer, sizeof(x), NULL); + if (!SUCCESS(ret)) { + errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to bid params: %s\n", errmsg); + g_free (errmsg); + return -1; + } + } else if (strcmp (type, "string") == 0) { + const char *s = va_arg (args, const char *); + int len = 0; + if (s) { + len = strlen(s); + } + params[i].buffer = g_strdup(s); + ret = SQLBindParameter(stmt, i+1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, len, 0, params[i].buffer, len, NULL); + if (!SUCCESS(ret)) { + errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to bid params: %s\n", errmsg); + g_free (errmsg); + return -1; + } + } else { + seaf_warning ("BUG: invalid prep stmt parameter type %s.\n", type); + g_return_val_if_reached (-1); + } + } + + return 0; +} + +static int +dm_db_execute_sql (DBConnection *vconn, const char *sql, int n, va_list args, gboolean *retry) +{ + DMDBConnection *conn = (DMDBConnection *)vconn; + HDBC db = conn->db_conn; + HSTMT stmt = NULL; + DM_BIND *params = NULL; + SQLRETURN rc; + int ret = 0; + + stmt = _prepare_stmt_dm (db, sql, retry); + if (!stmt) { + return -1; + } + + if (n > 0) { + params = g_new0 (DM_BIND, n); + if (_bind_params_dm(stmt, params, n, args) < 0) { + seaf_warning ("Failed to bind parameters for %s.\n", sql); + ret = -1; + goto out; + } + } + + rc = SQLExecute (stmt); + if (!SUCCESS(rc)) { + char *errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to execute sql %s: %s\n", sql, errmsg); + g_free (errmsg); + ret = -1; + goto out; + } + +out: + if (stmt) { + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + if (params) { + int i; + for (i = 0; i < n; ++i) { + g_free (params[i].buffer); + } + g_free (params); + } + return ret; +} + +typedef struct DMDBRow { + SeafDBRow parent; + int column_count; + HSTMT stmt; + DM_BIND *results; + gboolean over_buffer; +} DMDBRow; + +#define DEFAULT_DM_COLUMN_SIZE 1024 + +static int +dm_db_query_foreach_row (DBConnection *vconn, const char *sql, + SeafDBRowFunc callback, void *data, + int n, va_list args, gboolean *retry) +{ + DMDBConnection *conn = (DMDBConnection *)vconn; + HDBC db = conn->db_conn; + HSTMT stmt = NULL; + DM_BIND *params = NULL; + DMDBRow row; + SQLRETURN rc; + short cols; + int nrows = 0; + int i; + + memset (&row, 0, sizeof(row)); + + stmt = _prepare_stmt_dm (db, sql, retry); + if (!stmt) { + return -1; + } + + if (n > 0) { + params = g_new0 (DM_BIND, n); + if (_bind_params_dm (stmt, params, n, args) < 0) { + nrows = -1; + goto out; + } + } + + rc = SQLExecute (stmt); + if (!SUCCESS(rc)) { + char *errmsg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to execute sql %s: error: %s\n", sql, errmsg); + g_free (errmsg); + nrows = -1; + goto out; + } + + SQLNumResultCols(stmt, &cols); + row.column_count = cols; + row.stmt = stmt; + row.results = g_new0 (DM_BIND, row.column_count); + for (i = 0; i < row.column_count; ++i) { + row.results[i].buffer = g_new0(char, DEFAULT_DM_COLUMN_SIZE + 1); + /* Ask DM to convert fields to string, to avoid the trouble of + * checking field types. + */ + row.results[i].buffer_length = DEFAULT_DM_COLUMN_SIZE; + row.results[i].length = 0; + SQLBindCol(stmt, i+1, SQL_C_CHAR, row.results[i].buffer, row.results[i].buffer_length, &row.results[i].length); + } + + gboolean next_row = TRUE; + while (1) { + rc = SQLFetch(stmt); + if (!SUCCESS(rc)) { + if (rc != SQL_ERROR || dm_get_error_state(SQL_HANDLE_STMT, stmt) != BUFFER_NOT_ENOUGH) { + char *err_msg = dm_db_error (SQL_HANDLE_STMT, stmt); + seaf_warning ("Failed to fetch result for sql %s: %s\n", + sql, err_msg); + g_free (err_msg); + nrows = -1; + goto out; + } else { + row.over_buffer = TRUE; + } + } else { + row.over_buffer = FALSE; + } + if (rc == SQL_NO_DATA_FOUND || rc == SQL_NO_DATA) + break; + + ++nrows; + if (callback) + next_row = callback ((SeafDBRow *)&row, data); + + if (!next_row) + break; + } + +out: + if (stmt) { + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + if (params) { + int i; + for (i = 0; i < n; ++i) { + g_free (params[i].buffer); + } + g_free (params); + } + if (row.results) { + for (i = 0; i < row.column_count; ++i) { + g_free (row.results[i].buffer); + } + g_free (row.results); + } + return nrows; +} + +static int +dm_db_row_get_column_count (SeafDBRow *vrow) +{ + DMDBRow *row = (DMDBRow *)vrow; + return row->column_count; +} + +static const char * +dm_db_row_get_column_string (SeafDBRow *vrow, int i) +{ + DMDBRow *row = (DMDBRow *)vrow; + + if (row->results[i].length == -1) { + return NULL; + } + + + SQLRETURN rc; + char *ret = NULL; + int j = 1; + /* If column size is larger then allocated buffer size, re-allocate a new buffer + * and fetch the column directly. + */ +alloc_buffer: + if (row->results[i].length == 0 && row->over_buffer) { + g_free (row->results[i].buffer); + row->results[i].buffer = g_new0 (char, 2*j * DEFAULT_DM_COLUMN_SIZE + 1); + row->results[i].buffer_length = 2*j * DEFAULT_DM_COLUMN_SIZE; + + rc = SQLGetData(row->stmt, i+1, SQL_C_CHAR, row->results[i].buffer, row->results[i].buffer_length, &row->results[i].length); + if (SUCCESS(rc)) { + ret = row->results[i].buffer; + } else { + if (dm_get_error_state(SQL_HANDLE_STMT, row->stmt) != BUFFER_NOT_ENOUGH) { + return NULL; + } else { + j++; + goto alloc_buffer; + } + } + } else { + ret = row->results[i].buffer; + } + ret[row->results[i].length] = 0; + + return ret; +} + +static int +dm_db_row_get_column_int (SeafDBRow *vrow, int idx) +{ + const char *str; + char *e; + int ret; + + str = dm_db_row_get_column_string (vrow, idx); + if (!str) { + return 0; + } + + errno = 0; + ret = strtol (str, &e, 10); + if (errno || (e == str)) { + seaf_warning ("Number conversion failed.\n"); + return -1; + } + + return ret; +} + +static gint64 +dm_db_row_get_column_int64 (SeafDBRow *vrow, int idx) +{ + const char *str; + char *e; + gint64 ret; + + str = dm_db_row_get_column_string (vrow, idx); + if (!str) { + return 0; + } + + errno = 0; + ret = strtoll (str, &e, 10); + if (errno || (e == str)) { + seaf_warning ("Number conversion failed.\n"); + return -1; + } + + return ret; +} + +#endif /* HAVE_ODBC */ diff --git a/common/seaf-db.h b/common/seaf-db.h index f33eab82..9d548d3a 100644 --- a/common/seaf-db.h +++ b/common/seaf-db.h @@ -5,6 +5,7 @@ enum { SEAF_DB_TYPE_SQLITE, SEAF_DB_TYPE_MYSQL, SEAF_DB_TYPE_PGSQL, + SEAF_DB_TYPE_DM, }; typedef struct SeafDB SeafDB; @@ -44,6 +45,12 @@ seaf_db_new_pgsql (const char *host, SeafDB * seaf_db_new_sqlite (const char *db_path, int max_connections); +SeafDB * +seaf_db_new_dm (const char *user, + const char *passwd, + const char *db_name, + int max_connections); + int seaf_db_type (SeafDB *db); diff --git a/common/seaf-utils.c b/common/seaf-utils.c index e8db8ee5..5cfd9ac1 100644 --- a/common/seaf-utils.c +++ b/common/seaf-utils.c @@ -145,6 +145,58 @@ mysql_db_start (SeafileSession *session) #endif +#ifdef HAVE_ODBC + +static int +dm_db_start (SeafileSession *session) +{ + char *user, *passwd, *db; + int max_connections = 0; + GError *error = NULL; + + user = seaf_key_file_get_string (session->config, "database", "user", &error); + if (!user) { + seaf_warning ("DB user not set in config.\n"); + return -1; + } + + passwd = seaf_key_file_get_string (session->config, "database", "password", &error); + if (!passwd) { + seaf_warning ("DB passwd not set in config.\n"); + return -1; + } + + db = seaf_key_file_get_string (session->config, "database", "db_name", &error); + if (!db) { + seaf_warning ("DB name not set in config.\n"); + return -1; + } + + if (error) + g_clear_error (&error); + max_connections = g_key_file_get_integer (session->config, + "database", "max_connections", + &error); + if (error || max_connections < 0) { + g_clear_error (&error); + max_connections = DEFAULT_MAX_CONNECTIONS; + } + + session->db = seaf_db_new_dm (user, passwd, db, max_connections); + if (!session->db) { + seaf_warning ("Failed to start dm db.\n"); + return -1; + } + + g_free (user); + g_free (passwd); + g_free (db); + + return 0; +} + +#endif + #ifdef HAVE_POSTGRESQL static int @@ -223,6 +275,11 @@ load_database_config (SeafileSession *session) ret = mysql_db_start (session); } #endif +#ifdef HAVE_ODBC + else if (strcasecmp (type, "dm") == 0) { + ret = dm_db_start (session); + } +#endif #ifdef HAVE_POSTGRESQL else if (strcasecmp (type, "pgsql") == 0) { ret = pgsql_db_start (session); @@ -341,6 +398,56 @@ ccnet_init_mysql_database (SeafileSession *session) #endif +#ifdef HAVE_ODBC + +static int +ccnet_init_dm_database (SeafileSession *session) +{ + char *user, *passwd, *db; + int max_connections = 0; + + user = ccnet_key_file_get_string (session->ccnet_config, "Database", "USER"); + passwd = ccnet_key_file_get_string (session->ccnet_config, "Database", "PASSWD"); + db = ccnet_key_file_get_string (session->ccnet_config, "Database", "DB"); + + if (!user) { + seaf_warning ("DB user not set in config.\n"); + return -1; + } + if (!passwd) { + seaf_warning ("DB passwd not set in config.\n"); + return -1; + } + if (!db) { + seaf_warning ("DB name not set in config.\n"); + return -1; + } + + GError *error = NULL; + + max_connections = g_key_file_get_integer (session->ccnet_config, + "Database", "MAX_CONNECTIONS", + &error); + if (error || max_connections < 0) { + max_connections = DEFAULT_MAX_CONNECTIONS; + g_clear_error (&error); + } + + session->ccnet_db = seaf_db_new_dm (user, passwd, db, max_connections); + if (!session->ccnet_db) { + seaf_warning ("Failed to open ccnet database.\n"); + return -1; + } + + g_free (user); + g_free (passwd); + g_free (db); + + return 0; +} + +#endif + int load_ccnet_database_config (SeafileSession *session) { @@ -359,6 +466,11 @@ load_ccnet_database_config (SeafileSession *session) ret = ccnet_init_mysql_database (session); } #endif +#ifdef HAVE_ODBC + else if (strcasecmp (engine, "dm") == 0) { + ret = ccnet_init_dm_database (session); + } +#endif #if 0 else if (strncasecmp (engine, DB_PGSQL, sizeof(DB_PGSQL)) == 0) { ccnet_debug ("Use database PostgreSQL\n"); diff --git a/common/user-mgr.c b/common/user-mgr.c index 74d14d13..4cb6fcfd 100644 --- a/common/user-mgr.c +++ b/common/user-mgr.c @@ -707,6 +707,67 @@ static int check_db_table (SeafDB *db) // return -1; //} + sql = "CREATE TABLE IF NOT EXISTS LDAPConfig (cfg_group VARCHAR(255) NOT NULL," + "cfg_key VARCHAR(255) NOT NULL, value VARCHAR(255), property INTEGER)"; + if (seaf_db_query (db, sql) < 0) + return -1; + } else if (db_type == SEAF_DB_TYPE_DM) { + sql = "CREATE TABLE IF NOT EXISTS EmailUser (" + "id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT," + "email VARCHAR(255), passwd VARCHAR(256), is_staff INTEGER NOT NULL, " + "is_active INTEGER NOT NULL, ctime BIGINT, " + "reference_id VARCHAR(255))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS email_index on EmailUser (email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS reference_id_index on EmailUser (reference_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS Binding (email VARCHAR(255), peer_id VARCHAR(41))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS email_index on Binding (email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS peer_index on Binding (peer_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS UserRole (email VARCHAR(255), role VARCHAR(255))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS userrole_email_index on UserRole (email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS userrole_userrole_index on UserRole (email, role)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS LDAPUsers (" + "id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, " + "email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, " + "is_staff INTEGER NOT NULL, is_active INTEGER NOT NULL, extra_attrs TEXT, " + "reference_id VARCHAR(255))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS ldapusers_email_index on LDAPUsers(email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS ldapusers_reference_id_index on LDAPUsers(reference_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + sql = "CREATE TABLE IF NOT EXISTS LDAPConfig (cfg_group VARCHAR(255) NOT NULL," "cfg_key VARCHAR(255) NOT NULL, value VARCHAR(255), property INTEGER)"; if (seaf_db_query (db, sql) < 0) @@ -754,6 +815,7 @@ open_db (CcnetUserManager *manager) db = open_sqlite_db (manager); break; case SEAF_DB_TYPE_PGSQL: + case SEAF_DB_TYPE_DM: case SEAF_DB_TYPE_MYSQL: db = manager->session->ccnet_db; break; diff --git a/configure.ac b/configure.ac index 93c445a3..05a37de0 100644 --- a/configure.ac +++ b/configure.ac @@ -86,6 +86,11 @@ AC_ARG_ENABLE(python, [compile_python=$enableval], [compile_python=yes]) +AC_ARG_ENABLE(odbc, + AC_HELP_STRING([--enable-odbc],[build seafile with odbc]), + [compile_odbc=$enableval], + [compile_odbc=yes]) + AC_ARG_WITH(mysql, AC_HELP_STRING([--with-mysql],[path to mysql_config]), [MYSQL_CONFIG=$with_mysql], @@ -287,6 +292,14 @@ if test "${compile_fuse}" = "yes"; then AC_SUBST(FUSE_LIBS) fi +if test "${compile_odbc}" = "yes"; then + PKG_CHECK_MODULES(ODBC, [odbc]) + AC_SUBST(ODBC_FLAGS) + AC_SUBST(ODBC_LIBS) + AC_DEFINE([DM64], [1], [Define to 1 if dm support is enabled]) + AC_DEFINE([HAVE_ODBC], [1], [Define to 1 if dm support is enabled]) +fi + dnl check libarchive LIBARCHIVE_REQUIRED=2.8.5 PKG_CHECK_MODULES(LIBARCHIVE, [libarchive >= $LIBARCHIVE_REQUIRED]) diff --git a/fuse/Makefile.am b/fuse/Makefile.am index 3f3f1766..c79a152e 100644 --- a/fuse/Makefile.am +++ b/fuse/Makefile.am @@ -42,5 +42,5 @@ seaf_fuse_LDADD = @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ \ -lsqlite3 @LIBEVENT_LIBS@ \ $(top_builddir)/common/cdc/libcdc.la \ @SEARPC_LIBS@ @JANSSON_LIBS@ @FUSE_LIBS@ @ZLIB_LIBS@ \ - @LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3 + @LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3 @ODBC_LIBS@ diff --git a/server/Makefile.am b/server/Makefile.am index 88783c26..b69c1a35 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -86,4 +86,4 @@ seaf_server_LDADD = $(top_builddir)/lib/libseafile_common.la \ @SEARPC_LIBS@ @JANSSON_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \ @LIBARCHIVE_LIBS@ @LIB_ICONV@ \ @LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3 \ - @CURL_LIBS@ @JWT_LIBS@ + @CURL_LIBS@ @JWT_LIBS@ @ODBC_LIBS@ diff --git a/server/gc/Makefile.am b/server/gc/Makefile.am index e45a4cbb..375b8a42 100644 --- a/server/gc/Makefile.am +++ b/server/gc/Makefile.am @@ -48,7 +48,7 @@ seafserv_gc_LDADD = $(top_builddir)/common/cdc/libcdc.la \ $(top_builddir)/lib/libseafile_common.la \ @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \ @SEARPC_LIBS@ @JANSSON_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \ - @MYSQL_LIBS@ -lsqlite3 + @MYSQL_LIBS@ -lsqlite3 @ODBC_LIBS@ seaf_fsck_SOURCES = \ seaf-fsck.c \ @@ -59,4 +59,4 @@ seaf_fsck_LDADD = $(top_builddir)/common/cdc/libcdc.la \ $(top_builddir)/lib/libseafile_common.la \ @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \ @SEARPC_LIBS@ @JANSSON_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \ - @MYSQL_LIBS@ -lsqlite3 + @MYSQL_LIBS@ -lsqlite3 @ODBC_LIBS@ diff --git a/server/gc/repo-mgr.c b/server/gc/repo-mgr.c index 58f21cce..250216dd 100644 --- a/server/gc/repo-mgr.c +++ b/server/gc/repo-mgr.c @@ -427,7 +427,7 @@ seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, return 0; } - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean err; snprintf(sql, sizeof(sql), "SELECT repo_id FROM RepoHistoryLimit " @@ -512,7 +512,7 @@ seaf_repo_manager_set_repo_valid_since (SeafRepoManager *mgr, SeafDB *db = mgr->seaf->db; char sql[256]; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean err; snprintf(sql, sizeof(sql), "SELECT repo_id FROM RepoValidSince WHERE " diff --git a/server/quota-mgr.c b/server/quota-mgr.c index e33097f4..81dc4c6d 100644 --- a/server/quota-mgr.c +++ b/server/quota-mgr.c @@ -154,6 +154,28 @@ seaf_quota_manager_init (SeafQuotaManager *mgr) if (seaf_db_query (db, sql) < 0) return -1; + break; + case SEAF_DB_TYPE_DM: + sql = "CREATE TABLE IF NOT EXISTS UserQuota (\"user\" VARCHAR(255) PRIMARY KEY," + "quota BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS UserShareQuota (\"user\" VARCHAR(255) PRIMARY KEY," + "quota BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS OrgQuota (org_id INTEGER PRIMARY KEY," + "quota BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS OrgUserQuota (org_id INTEGER," + "\"user\" VARCHAR(255), quota BIGINT, PRIMARY KEY (org_id, \"user\"))"; + if (seaf_db_query (db, sql) < 0) + return -1; + break; } @@ -166,7 +188,7 @@ seaf_quota_manager_set_user_quota (SeafQuotaManager *mgr, gint64 quota) { SeafDB *db = mgr->session->db; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean exists, err; int rc; @@ -203,7 +225,7 @@ seaf_quota_manager_get_user_quota (SeafQuotaManager *mgr, char *sql; gint64 quota; - if (seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_PGSQL && seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_DM) sql = "SELECT quota FROM UserQuota WHERE user=?"; else sql = "SELECT quota FROM UserQuota WHERE \"user\"=?"; @@ -223,7 +245,7 @@ seaf_quota_manager_set_org_quota (SeafQuotaManager *mgr, { SeafDB *db = mgr->session->db; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean exists, err; int rc; @@ -274,7 +296,7 @@ seaf_quota_manager_set_org_user_quota (SeafQuotaManager *mgr, SeafDB *db = mgr->session->db; int rc; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean exists, err; exists = seaf_db_statement_exists (db, @@ -313,7 +335,7 @@ seaf_quota_manager_get_org_user_quota (SeafQuotaManager *mgr, char *sql; gint64 quota; - if (seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_PGSQL) + if (seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_PGSQL && seaf_db_type(mgr->session->db) != SEAF_DB_TYPE_DM) sql = "SELECT quota FROM OrgUserQuota WHERE org_id=? AND user=?"; else sql = "SELECT quota FROM OrgUserQuota WHERE org_id=? AND \"user\"=?"; diff --git a/server/repo-mgr.c b/server/repo-mgr.c index 84d4fe61..ca991673 100644 --- a/server/repo-mgr.c +++ b/server/repo-mgr.c @@ -380,7 +380,7 @@ seaf_repo_manager_add_repo (SeafRepoManager *manager, static int add_deleted_repo_record (SeafRepoManager *mgr, const char *repo_id) { - if (seaf_db_type(seaf->db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(seaf->db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(seaf->db) == SEAF_DB_TYPE_DM) { gboolean exists, err; exists = seaf_db_statement_exists (seaf->db, @@ -803,7 +803,7 @@ seaf_repo_manager_repo_exists (SeafRepoManager *manager, const gchar *id) static int save_branch_repo_map (SeafRepoManager *manager, SeafBranch *branch) { - if (seaf_db_type(seaf->db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(seaf->db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(seaf->db) == SEAF_DB_TYPE_DM) { gboolean exists, err; int rc; @@ -1240,6 +1240,160 @@ create_tables_sqlite (SeafRepoManager *mgr) return 0; } +static int +create_tables_dm (SeafRepoManager *mgr) +{ + SeafDB *db = mgr->seaf->db; + char *sql; + + sql = "CREATE TABLE IF NOT EXISTS Repo (repo_id VARCHAR(37) PRIMARY KEY)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + /* Owner */ + + sql = "CREATE TABLE IF NOT EXISTS RepoOwner (" + "repo_id VARCHAR(37) PRIMARY KEY, " + "owner_id VARCHAR(255))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + /* Group repo */ + + sql = "CREATE TABLE IF NOT EXISTS RepoGroup (repo_id VARCHAR(37), " + "group_id INTEGER, user_name VARCHAR(255), permission VARCHAR(15))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS groupid_repoid_indx on " + "RepoGroup (group_id, repo_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS repogroup_repoid_index on " + "RepoGroup (repo_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS repogroup_username_indx on " + "RepoGroup (user_name)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + /* Public repo */ + + sql = "CREATE TABLE IF NOT EXISTS InnerPubRepo (" + "repo_id VARCHAR(37) PRIMARY KEY," + "permission VARCHAR(15))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoUserToken (" + "repo_id VARCHAR(37), " + "email VARCHAR(255), " + "token VARCHAR(41))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE UNIQUE INDEX IF NOT EXISTS repo_token_indx on " + "RepoUserToken (repo_id, token)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS repo_token_email_indx on " + "RepoUserToken (email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoTokenPeerInfo (" + "token VARCHAR(41) PRIMARY KEY, " + "peer_id VARCHAR(41), " + "peer_ip VARCHAR(50), " + "peer_name VARCHAR(255), " + "sync_time BIGINT, " + "client_ver VARCHAR(20))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoHead (" + "repo_id VARCHAR(37) PRIMARY KEY, branch_name VARCHAR(10))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoSize (" + "repo_id VARCHAR(37) PRIMARY KEY," + "size BIGINT," + "head_id VARCHAR(41))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoHistoryLimit (" + "repo_id VARCHAR(37) PRIMARY KEY, days INTEGER)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoValidSince (" + "repo_id VARCHAR(37) PRIMARY KEY, timestamp BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS WebAP (repo_id VARCHAR(37) PRIMARY KEY, " + "access_property VARCHAR(10))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS VirtualRepo (repo_id VARCHAR(36) PRIMARY KEY," + "origin_repo VARCHAR(36), path TEXT, base_commit VARCHAR(40))"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS virtualrepo_origin_repo_idx " + "ON VirtualRepo (origin_repo)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS GarbageRepos (repo_id VARCHAR(36) PRIMARY KEY)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoTrash (repo_id VARCHAR(36) PRIMARY KEY," + "repo_name VARCHAR(255), head_id VARCHAR(40), owner_id VARCHAR(255), size BIGINT," + "org_id INTEGER, del_time BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS repotrash_owner_id_idx ON RepoTrash(owner_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS repotrash_org_id_idx ON RepoTrash(org_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoFileCount (" + "repo_id VARCHAR(36) PRIMARY KEY," + "file_count BIGINT)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS RepoInfo (repo_id VARCHAR(36) PRIMARY KEY, " + "name VARCHAR(255) NOT NULL, update_time INTEGER, version INTEGER, " + "is_encrypted INTEGER, last_modifier VARCHAR(255), status INTEGER DEFAULT 0)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE TABLE IF NOT EXISTS WebUploadTempFiles (repo_id VARCHAR(40) NOT NULL, " + "file_path TEXT NOT NULL, tmp_file_path TEXT NOT NULL)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + sql = "CREATE INDEX IF NOT EXISTS webuploadtempfiles_repo_id_idx ON WebUploadTempFiles(repo_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + + return 0; +} + /* static int */ /* create_tables_pgsql (SeafRepoManager *mgr) */ /* { */ @@ -1402,6 +1556,8 @@ create_db_tables_if_not_exist (SeafRepoManager *mgr) return create_tables_mysql (mgr); else if (db_type == SEAF_DB_TYPE_SQLITE) return create_tables_sqlite (mgr); + else if (db_type == SEAF_DB_TYPE_DM) + return create_tables_dm (mgr); /* else if (db_type == SEAF_DB_TYPE_PGSQL) */ /* return create_tables_pgsql (mgr); */ @@ -1745,7 +1901,7 @@ seaf_repo_manager_delete_repo_tokens_by_peer_id (SeafRepoManager *mgr, g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "DB error"); goto out; } - } else if (db_type == SEAF_DB_TYPE_SQLITE) { + } else if (db_type == SEAF_DB_TYPE_SQLITE || db_type == SEAF_DB_TYPE_DM) { GString *sql = g_string_new (""); GList *iter; int i = 0; @@ -1922,7 +2078,7 @@ seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, return 0; } - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean exists, err; int rc; @@ -2004,7 +2160,7 @@ seaf_repo_manager_set_repo_valid_since (SeafRepoManager *mgr, { SeafDB *db = mgr->seaf->db; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean exists, err; int rc; @@ -2086,7 +2242,7 @@ seaf_repo_manager_set_repo_owner (SeafRepoManager *mgr, if (g_strcmp0 (orig_owner, email) == 0) goto out; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean err; snprintf(sql, sizeof(sql), "SELECT repo_id FROM RepoOwner WHERE repo_id=?"); @@ -2463,6 +2619,21 @@ seaf_repo_manager_search_repos_by_name (SeafRepoManager *mgr, const char *name) char *db_patt = g_strdup_printf ("%%%s%%", name); switch (seaf_db_type(seaf->db)) { + case SEAF_DB_TYPE_DM: + g_free (db_patt); + db_patt = g_strdup(name); + sql = "SELECT i.repo_id, s.size, b.commit_id, i.name, i.update_time, " + "i.version, i.is_encrypted, i.last_modifier, i.status, fc.file_count FROM " + "RepoInfo i LEFT JOIN RepoSize s ON i.repo_id = s.repo_id " + "LEFT JOIN Branch b ON i.repo_id = b.repo_id " + "LEFT JOIN RepoFileCount fc ON i.repo_id = fc.repo_id " + "LEFT JOIN Repo r ON i.repo_id = r.repo_id " + "LEFT JOIN VirtualRepo v ON i.repo_id = v.repo_id " + "WHERE REGEXP_LIKE(i.name, ?, 'i') AND " + "r.repo_id IS NOT NULL AND " + "v.repo_id IS NULL " + "ORDER BY i.update_time DESC, i.repo_id"; + break; case SEAF_DB_TYPE_MYSQL: sql = "SELECT i.repo_id, s.size, b.commit_id, i.name, i.update_time, " "i.version, i.is_encrypted, i.last_modifier, i.status, fc.file_count FROM " @@ -2540,6 +2711,7 @@ seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit, con if (start == -1 && limit == -1) { switch (seaf_db_type(mgr->seaf->db)) { + case SEAF_DB_TYPE_DM: case SEAF_DB_TYPE_MYSQL: g_string_append (sql, "SELECT i.repo_id, s.size, b.commit_id, i.name, i.update_time, " "i.version, i.is_encrypted, i.last_modifier, i.status, f.file_count FROM " @@ -2586,6 +2758,7 @@ seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit, con 0); } else { switch (seaf_db_type(mgr->seaf->db)) { + case SEAF_DB_TYPE_DM: case SEAF_DB_TYPE_MYSQL: g_string_append (sql, "SELECT i.repo_id, s.size, b.commit_id, i.name, i.update_time, " "i.version, i.is_encrypted, i.last_modifier, i.status, f.file_count FROM " @@ -3518,7 +3691,7 @@ seaf_repo_manager_set_inner_pub_repo (SeafRepoManager *mgr, SeafDB *db = mgr->seaf->db; char sql[256]; - if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { + if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL || seaf_db_type(db) == SEAF_DB_TYPE_DM) { gboolean err; snprintf(sql, sizeof(sql), "SELECT repo_id FROM InnerPubRepo WHERE repo_id=?"); diff --git a/server/seafile-session.c b/server/seafile-session.c index bf586f5a..feea6c58 100644 --- a/server/seafile-session.c +++ b/server/seafile-session.c @@ -470,7 +470,7 @@ schedule_create_system_default_repo (SeafileSession *session) int db_type = seaf_db_type (session->db); char *sql; - if (db_type == SEAF_DB_TYPE_MYSQL) + if (db_type == SEAF_DB_TYPE_MYSQL || db_type == SEAF_DB_TYPE_DM) sql = "CREATE TABLE IF NOT EXISTS SystemInfo " "(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, " "info_key VARCHAR(256), info_value VARCHAR(1024))"; diff --git a/server/share-mgr.c b/server/share-mgr.c index 370b9dad..3ad1bd1e 100644 --- a/server/share-mgr.c +++ b/server/share-mgr.c @@ -56,6 +56,21 @@ seaf_share_manager_start (SeafShareManager *mgr) sql = "CREATE INDEX IF NOT EXISTS ToEmailIndex on SharedRepo (to_email)"; if (seaf_db_query (db, sql) < 0) return -1; + } else if (db_type == SEAF_DB_TYPE_DM) { + sql = "CREATE TABLE IF NOT EXISTS SharedRepo " + "(repo_id VARCHAR(37) , from_email VARCHAR(255), to_email VARCHAR(255), " + "permission VARCHAR(15))"; + if (seaf_db_query (db, sql) < 0) + return -1; + sql = "CREATE INDEX IF NOT EXISTS RepoIdIndex on SharedRepo (repo_id)"; + if (seaf_db_query (db, sql) < 0) + return -1; + sql = "CREATE INDEX IF NOT EXISTS FromEmailIndex on SharedRepo (from_email)"; + if (seaf_db_query (db, sql) < 0) + return -1; + sql = "CREATE INDEX IF NOT EXISTS ToEmailIndex on SharedRepo (to_email)"; + if (seaf_db_query (db, sql) < 0) + return -1; } /* else if (db_type == SEAF_DB_TYPE_PGSQL) { */ /* sql = "CREATE TABLE IF NOT EXISTS SharedRepo " */ diff --git a/server/size-sched.c b/server/size-sched.c index 64807434..d04ed7f0 100644 --- a/server/size-sched.c +++ b/server/size-sched.c @@ -256,6 +256,7 @@ get_old_repo_info_from_db (SeafDB *db, const char *repo_id, gboolean *is_db_err) switch (seaf_db_type (db)) { case SEAF_DB_TYPE_MYSQL: case SEAF_DB_TYPE_PGSQL: + case SEAF_DB_TYPE_DM: sql = "select s.head_id,s.size,f.file_count FROM " "RepoSize s LEFT JOIN RepoFileCount f ON " "s.repo_id=f.repo_id WHERE " diff --git a/tests/test_repo_manipulation/test_repo_manipulation.py b/tests/test_repo_manipulation/test_repo_manipulation.py index 0ecdced2..a1cde90f 100644 --- a/tests/test_repo_manipulation/test_repo_manipulation.py +++ b/tests/test_repo_manipulation/test_repo_manipulation.py @@ -123,3 +123,6 @@ def test_repo_manipulation(): api.remove_repo(t_repo_id) t_repo = api.get_repo(t_repo_id) assert t_repo == None + api.remove_repo(t_enc_repo_id) + t_enc_repo = api.get_repo(t_enc_repo_id) + assert t_enc_repo == None