LCOV - code coverage report
Current view: top level - libgnucash/backend/dbi - gnc-dbiproviderimpl.hpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 0.0 % 179 0
Test Date: 2025-02-07 16:25:45 Functions: 0.0 % 16 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /************************************************************************
       2                 :             :  * gnc-dbiproviderimpl.hpp: Encapsulate differences among Dbi backends. *
       3                 :             :  *                                                                      *
       4                 :             :  * Copyright 2016 John Ralls <jralls@ceridwen.us>                       *
       5                 :             :  *                                                                      *
       6                 :             :  * This program is free software; you can redistribute it and/or        *
       7                 :             :  * modify it under the terms of the GNU General Public License as       *
       8                 :             :  * published by the Free Software Foundation; either version 2 of       *
       9                 :             :  * the License, or (at your option) any later version.                  *
      10                 :             :  *                                                                      *
      11                 :             :  * This program is distributed in the hope that it will be useful,      *
      12                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
      13                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
      14                 :             :  * GNU General Public License for more details.                         *
      15                 :             :  *                                                                      *
      16                 :             :  * You should have received a copy of the GNU General Public License    *
      17                 :             :  * along with this program; if not, contact:                            *
      18                 :             :  *                                                                      *
      19                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942           *
      20                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652           *
      21                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                       *
      22                 :             : \***********************************************************************/
      23                 :             : #ifndef __GNC_DBISQLPROVIDERIMPL_HPP__
      24                 :             : #define __GNC_DBISQLPROVIDERIMPL_HPP__
      25                 :             : #include <guid.hpp>
      26                 :             : #include <config.h>
      27                 :             : 
      28                 :             : #include <string>
      29                 :             : #include <algorithm>
      30                 :             : #include <vector>
      31                 :             : 
      32                 :             : #include "gnc-backend-dbi.hpp"
      33                 :             : #include "gnc-dbiprovider.hpp"
      34                 :             : #include "gnc-backend-dbi.h"
      35                 :             : #include <gnc-sql-column-table-entry.hpp>
      36                 :             : 
      37                 :             : using StrVec = std::vector<std::string>;
      38                 :             : 
      39                 :             : template <DbType T>
      40                 :             : class GncDbiProviderImpl : public GncDbiProvider
      41                 :             : {
      42                 :             : public:
      43                 :             :     StrVec get_table_list(dbi_conn conn, const std::string& table);
      44                 :             :     void append_col_def(std::string& ddl, const GncSqlColumnInfo& info);
      45                 :             :     StrVec get_index_list (dbi_conn conn);
      46                 :             :     void drop_index(dbi_conn conn, const std::string& index);
      47                 :             : };
      48                 :             : 
      49                 :             : template <DbType T> GncDbiProviderPtr
      50                 :           0 : make_dbi_provider()
      51                 :             : {
      52                 :           0 :     return GncDbiProviderPtr(new GncDbiProviderImpl<T>);
      53                 :             : }
      54                 :             : 
      55                 :             : template<> void
      56                 :           0 : GncDbiProviderImpl<DbType::DBI_SQLITE>::append_col_def(std::string& ddl,
      57                 :             :                                            const GncSqlColumnInfo& info)
      58                 :             : {
      59                 :           0 :     const char* type_name = nullptr;
      60                 :             : 
      61                 :           0 :     if (info.m_type == BCT_INT)
      62                 :             :     {
      63                 :           0 :         type_name = "integer";
      64                 :             :     }
      65                 :           0 :     else if (info.m_type == BCT_INT64)
      66                 :             :     {
      67                 :           0 :         type_name = "bigint";
      68                 :             :     }
      69                 :           0 :     else if (info.m_type == BCT_DOUBLE)
      70                 :             :     {
      71                 :           0 :         type_name = "float8";
      72                 :             :     }
      73                 :           0 :     else if (info.m_type == BCT_STRING || info.m_type == BCT_DATE
      74                 :           0 :               || info.m_type == BCT_DATETIME)
      75                 :             :     {
      76                 :           0 :         type_name = "text";
      77                 :             :     }
      78                 :             :     else
      79                 :             :     {
      80                 :           0 :         PERR ("Unknown column type: %d\n", info.m_type);
      81                 :           0 :         type_name = "";
      82                 :             :     }
      83                 :           0 :     ddl += (info.m_name + " " + type_name);
      84                 :           0 :     if (info.m_size != 0)
      85                 :             :     {
      86                 :           0 :         ddl += "(" + std::to_string(info.m_size) + ")";
      87                 :             :     }
      88                 :           0 :     if (info.m_primary_key)
      89                 :             :     {
      90                 :           0 :         ddl += " PRIMARY KEY";
      91                 :             :     }
      92                 :           0 :     if (info.m_autoinc)
      93                 :             :     {
      94                 :           0 :         ddl += " AUTOINCREMENT";
      95                 :             :     }
      96                 :           0 :     if (info.m_not_null)
      97                 :             :     {
      98                 :           0 :         ddl += " NOT NULL";
      99                 :             :     }
     100                 :           0 : }
     101                 :             : 
     102                 :             : 
     103                 :             : template<> void
     104                 :           0 : GncDbiProviderImpl<DbType::DBI_MYSQL>::append_col_def (std::string& ddl,
     105                 :             :                                            const GncSqlColumnInfo& info)
     106                 :             : {
     107                 :           0 :     const char* type_name = nullptr;
     108                 :             : 
     109                 :           0 :     if (info.m_type == BCT_INT)
     110                 :             :     {
     111                 :           0 :         type_name = "integer";
     112                 :             :     }
     113                 :           0 :     else if (info.m_type == BCT_INT64)
     114                 :             :     {
     115                 :           0 :         type_name = "bigint";
     116                 :             :     }
     117                 :           0 :     else if (info.m_type == BCT_DOUBLE)
     118                 :             :     {
     119                 :           0 :         type_name = "double";
     120                 :             :     }
     121                 :           0 :     else if (info.m_type == BCT_STRING)
     122                 :             :     {
     123                 :           0 :         type_name = "varchar";
     124                 :             :     }
     125                 :           0 :     else if (info.m_type == BCT_DATE)
     126                 :             :     {
     127                 :           0 :         type_name = "date";
     128                 :             :     }
     129                 :           0 :     else if (info.m_type == BCT_DATETIME)
     130                 :             :     {
     131                 :           0 :         type_name = "DATETIME NULL DEFAULT '1970-01-01 00:00:00'";
     132                 :             :     }
     133                 :             :     else
     134                 :             :     {
     135                 :           0 :         PERR ("Unknown column type: %d\n", info.m_type);
     136                 :           0 :         type_name = "";
     137                 :             :     }
     138                 :           0 :     ddl += info.m_name + " " + type_name;
     139                 :           0 :     if (info.m_size != 0 && info.m_type == BCT_STRING)
     140                 :             :     {
     141                 :           0 :         ddl += "(" + std::to_string(info.m_size) + ")";
     142                 :             :     }
     143                 :           0 :     if (info.m_unicode)
     144                 :             :     {
     145                 :           0 :         ddl += " CHARACTER SET utf8";
     146                 :             :     }
     147                 :           0 :     if (info.m_primary_key)
     148                 :             :     {
     149                 :           0 :         ddl += " PRIMARY KEY";
     150                 :             :     }
     151                 :           0 :     if (info.m_autoinc)
     152                 :             :     {
     153                 :           0 :         ddl += " AUTO_INCREMENT";
     154                 :             :     }
     155                 :           0 :     if (info.m_not_null)
     156                 :             :     {
     157                 :           0 :         ddl += " NOT NULL";
     158                 :             :     }
     159                 :           0 : }
     160                 :             : 
     161                 :             : 
     162                 :             : template<> void
     163                 :           0 : GncDbiProviderImpl<DbType::DBI_PGSQL>::append_col_def (std::string& ddl,
     164                 :             :                                            const GncSqlColumnInfo& info)
     165                 :             : {
     166                 :           0 :     const char* type_name = nullptr;
     167                 :             : 
     168                 :           0 :     if (info.m_type == BCT_INT)
     169                 :             :     {
     170                 :           0 :         if (info.m_autoinc)
     171                 :             :         {
     172                 :           0 :             type_name = "serial";
     173                 :             :         }
     174                 :             :         else
     175                 :             :         {
     176                 :           0 :             type_name = "integer";
     177                 :             :         }
     178                 :             :     }
     179                 :           0 :     else if (info.m_type == BCT_INT64)
     180                 :             :     {
     181                 :           0 :         type_name = "int8";
     182                 :             :     }
     183                 :           0 :     else if (info.m_type == BCT_DOUBLE)
     184                 :             : 
     185                 :             :     {
     186                 :           0 :         type_name = "double precision";
     187                 :             :     }
     188                 :           0 :     else if (info.m_type == BCT_STRING)
     189                 :             :     {
     190                 :           0 :         type_name = "varchar";
     191                 :             :     }
     192                 :           0 :     else if (info.m_type == BCT_DATE)
     193                 :             :     {
     194                 :           0 :         type_name = "date";
     195                 :             :     }
     196                 :           0 :     else if (info.m_type == BCT_DATETIME)
     197                 :             :     {
     198                 :           0 :         type_name = "timestamp without time zone";
     199                 :             :     }
     200                 :             :     else
     201                 :             :     {
     202                 :           0 :         PERR ("Unknown column type: %d\n", info.m_type);
     203                 :           0 :         type_name = "";
     204                 :             :     }
     205                 :           0 :     ddl += info.m_name + " " + type_name;
     206                 :           0 :     if (info.m_size != 0 && info.m_type == BCT_STRING)
     207                 :             :     {
     208                 :           0 :         ddl += "(" + std::to_string(info.m_size) + ")";
     209                 :             :     }
     210                 :           0 :     if (info.m_primary_key)
     211                 :             :     {
     212                 :           0 :         ddl += " PRIMARY KEY";
     213                 :             :     }
     214                 :           0 :     if (info.m_not_null)
     215                 :             :     {
     216                 :           0 :         ddl += " NOT NULL";
     217                 :             :     }
     218                 :           0 : }
     219                 :             : 
     220                 :             : static StrVec
     221                 :           0 : conn_get_table_list (dbi_conn conn, const std::string& dbname,
     222                 :             :                      const std::string& table)
     223                 :             : {
     224                 :           0 :     StrVec retval;
     225                 :           0 :     const char* tableptr = (table.empty() ? nullptr : table.c_str());
     226                 :           0 :     auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), tableptr);
     227                 :           0 :     while (dbi_result_next_row (tables) != 0)
     228                 :             :     {
     229                 :           0 :         std::string table_name {dbi_result_get_string_idx (tables, 1)};
     230                 :           0 :         retval.push_back(table_name);
     231                 :           0 :     }
     232                 :           0 :     dbi_result_free (tables);
     233                 :           0 :     return retval;
     234                 :           0 : }
     235                 :             : 
     236                 :             : template<> StrVec
     237                 :           0 : GncDbiProviderImpl<DbType::DBI_SQLITE>::get_table_list (dbi_conn conn,
     238                 :             :                                                         const std::string& table)
     239                 :             : {
     240                 :             :     /* Return the list, but remove the tables that sqlite3 adds for
     241                 :             :      * its own use. */
     242                 :           0 :     std::string dbname (dbi_conn_get_option (conn, "dbname"));
     243                 :           0 :     auto list = conn_get_table_list (conn, dbname, table);
     244                 :           0 :     auto end = std::remove(list.begin(), list.end(), "sqlite_sequence");
     245                 :           0 :     list.erase(end, list.end());
     246                 :           0 :     return list;
     247                 :           0 : }
     248                 :             : 
     249                 :             : template<> StrVec
     250                 :           0 : GncDbiProviderImpl<DbType::DBI_MYSQL>::get_table_list (dbi_conn conn,
     251                 :             :                                                        const std::string& table)
     252                 :             : {
     253                 :           0 :     std::string dbname (dbi_conn_get_option (conn, "dbname"));
     254                 :           0 :     dbname.insert((std::string::size_type)0, 1, '`');
     255                 :           0 :     dbname += '`';
     256                 :           0 :     return conn_get_table_list (conn, dbname, table);
     257                 :           0 : }
     258                 :             : 
     259                 :             : template<> StrVec
     260                 :           0 : GncDbiProviderImpl<DbType::DBI_PGSQL>::get_table_list (dbi_conn conn,
     261                 :             :                                                        const std::string& table)
     262                 :             : {
     263                 :           0 :     const char* query_no_regex = "SELECT relname FROM pg_class WHERE relname"
     264                 :             :                           "!~ '^(pg|sql)_' AND relkind = 'r' ORDER BY relname";
     265                 :           0 :     std::string query_with_regex = "SELECT relname FROM pg_class WHERE relname LIKE '";
     266                 :           0 :     query_with_regex += table + "' AND relkind = 'r' ORDER BY relname";
     267                 :             :     dbi_result result;
     268                 :           0 :     if (table.empty())
     269                 :           0 :         result = dbi_conn_query (conn, query_no_regex);
     270                 :             :     else
     271                 :           0 :         result = dbi_conn_query (conn, query_with_regex.c_str());
     272                 :             : 
     273                 :           0 :     StrVec list;
     274                 :             :     const char* errmsg;
     275                 :           0 :     if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
     276                 :             :     {
     277                 :           0 :         PWARN ("Table List Retrieval Error: %s\n", errmsg);
     278                 :           0 :         return list;
     279                 :             :     }
     280                 :             : 
     281                 :           0 :     while (dbi_result_next_row (result) != 0)
     282                 :             :     {
     283                 :           0 :         std::string index_name {dbi_result_get_string_idx (result, 1)};
     284                 :           0 :         list.push_back(index_name);
     285                 :           0 :     }
     286                 :           0 :     dbi_result_free (result);
     287                 :           0 :     return list;
     288                 :           0 : }
     289                 :             : 
     290                 :             : template<> StrVec
     291                 :           0 : GncDbiProviderImpl<DbType::DBI_SQLITE>::get_index_list (dbi_conn conn)
     292                 :             : {
     293                 :           0 :     StrVec retval;
     294                 :             :     const char* errmsg;
     295                 :           0 :     dbi_result result = dbi_conn_query (conn,
     296                 :             :                                         "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'");
     297                 :           0 :     if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
     298                 :             :     {
     299                 :           0 :         PWARN ("Index Table Retrieval Error: %s\n", errmsg);
     300                 :           0 :         return retval;
     301                 :             :     }
     302                 :           0 :     while (dbi_result_next_row (result) != 0)
     303                 :             :     {
     304                 :           0 :         std::string index_name {dbi_result_get_string_idx (result, 1)};
     305                 :           0 :         retval.push_back(index_name);
     306                 :           0 :     }
     307                 :           0 :     dbi_result_free (result);
     308                 :           0 :     return retval;
     309                 :           0 : }
     310                 :             : 
     311                 :             : template<> StrVec
     312                 :           0 : GncDbiProviderImpl<DbType::DBI_MYSQL>::get_index_list (dbi_conn conn)
     313                 :             : {
     314                 :           0 :     StrVec retval;
     315                 :             :     const char* errmsg;
     316                 :           0 :     auto tables = get_table_list(conn, "");
     317                 :           0 :     for (auto table_name : tables)
     318                 :             :     {
     319                 :           0 :         auto result = dbi_conn_queryf (conn,
     320                 :             :                                        "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'",
     321                 :             :                                        table_name.c_str());
     322                 :           0 :         if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
     323                 :             :         {
     324                 :           0 :             PWARN ("Index Table Retrieval Error: %s on table %s\n",
     325                 :             :                    errmsg, table_name.c_str());
     326                 :           0 :             continue;
     327                 :             :         }
     328                 :             : 
     329                 :           0 :         while (dbi_result_next_row (result) != 0)
     330                 :             :         {
     331                 :           0 :             std::string index_name {dbi_result_get_string_idx (result, 3)};
     332                 :           0 :             retval.push_back(index_name + " " + table_name);
     333                 :           0 :         }
     334                 :           0 :         dbi_result_free (result);
     335                 :           0 :     }
     336                 :             : 
     337                 :           0 :     return retval;
     338                 :           0 : }
     339                 :             : 
     340                 :             : template<> StrVec
     341                 :           0 : GncDbiProviderImpl<DbType::DBI_PGSQL>::get_index_list (dbi_conn conn)
     342                 :             : {
     343                 :           0 :     StrVec retval;
     344                 :             :     const char* errmsg;
     345                 :           0 :     PINFO ("Retrieving postgres index list\n");
     346                 :           0 :     auto result = dbi_conn_query (conn,
     347                 :             :                                   "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'");
     348                 :           0 :     if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
     349                 :             :     {
     350                 :           0 :         PWARN("Index Table Retrieval Error: %s\n", errmsg);
     351                 :           0 :         return retval;
     352                 :             :     }
     353                 :           0 :     while (dbi_result_next_row (result) != 0)
     354                 :             :     {
     355                 :           0 :         std::string index_name {dbi_result_get_string_idx (result, 1)};
     356                 :           0 :         retval.push_back(index_name);
     357                 :           0 :     }
     358                 :           0 :     dbi_result_free (result);
     359                 :           0 :     return retval;
     360                 :           0 : }
     361                 :             : 
     362                 :             : template <DbType P> void
     363                 :           0 : GncDbiProviderImpl<P>::drop_index(dbi_conn conn, const std::string& index)
     364                 :             : {
     365                 :           0 :     dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index.c_str());
     366                 :           0 :     if (result)
     367                 :           0 :         dbi_result_free (result);
     368                 :           0 : }
     369                 :             : 
     370                 :             : template<> void
     371                 :           0 : GncDbiProviderImpl<DbType::DBI_MYSQL>::drop_index (dbi_conn conn, const std::string& index)
     372                 :             : {
     373                 :             : 
     374                 :           0 :     auto sep = index.find(' ', 0);
     375                 :           0 :     if (index.find(' ', sep + 1) != std::string::npos)
     376                 :             :     {
     377                 :           0 :         PWARN("Drop index error: invalid MySQL index format (<index> <table>): %s",
     378                 :             :               index.c_str());
     379                 :           0 :         return;
     380                 :             :     }
     381                 :             : 
     382                 :           0 :     auto result = dbi_conn_queryf (conn, "DROP INDEX %s ON %s",
     383                 :           0 :                                    index.substr(0, sep).c_str(),
     384                 :           0 :                                    index.substr(sep + 1).c_str());
     385                 :           0 :     if (result)
     386                 :           0 :         dbi_result_free (result);
     387                 :             : }
     388                 :             : #endif //__GNC_DBISQLPROVIDERIMPL_HPP__
        

Generated by: LCOV version 2.0-1