public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/106732] New: lock cannot be generated in a special case
@ 2022-08-24  7:57 benni.probst at gmx dot de
  0 siblings, 0 replies; only message in thread
From: benni.probst at gmx dot de @ 2022-08-24  7:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106732

            Bug ID: 106732
           Summary: lock cannot be generated in a special case
           Product: gcc
           Version: 12.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: benni.probst at gmx dot de
  Target Milestone: ---

Created attachment 53500
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53500&action=edit
CLion bug analysis picture

when using a recursive mutex and a scoped lock or unique lock or lock guard
(does not matter) on the recursive mutex, code cannot be generated even if it
worked in the function above.

//
// Created by benjamin-elias on 09.05.22.
//

#include "config_files.h"
#include "global_custom_functions.h"

#ifndef SCHOOL_PROJECT_DATABASE_CALL_OPS_H
#define SCHOOL_PROJECT_DATABASE_CALL_OPS_H


class database_call_ops {
    bool connection_set=false;
    std::recursive_mutex database_mutex{};
    pqxx::connection *connection;
protected:
    std::string addr, p, user, pass, datab;
    //TODO: set up connection and custom database call ops
public:
    std::string schem, tab;
protected:
    bool open=false;

    virtual std::string currentSchema() {
        const std::lock_guard lock(database_mutex);
        return schem;
    }

    virtual std::string currentTableName() {
        const std::lock_guard lock(database_mutex);
        return tab;
    }

    [[nodiscard]] bool isOpen(const std::string &table) const {
        const std::scoped_lock lock(database_mutex);
        return open and tab==table;
    }

    std::string currentDatabase() {
        return datab;
    }

    bool checkSchemaExists(const std::string &schema) {
        try{
            std::string sql = "SELECT EXISTS(SELECT schema_name FROM
information_schema.schemata WHERE schema_name = '"+schema+"');";
            custom_function::replace_string_occurencies(sql,"  "," ");
            pqxx::nontransaction n(connection);
            pqxx::result r(n.exec(sql));
            n.commit();
            for (pqxx::result::const_iterator c = r.begin(); c != r.end();) {
                auto it = c;
                if(++c == r.end())[[likely]]{ return it[0].as<bool>();}
                else break;
            }
        }
        catch (std::exception &e){
            std::cerr << "checkSchemaExists on " << schema << " failed for this
reason: " << e.what();
        }
        return false;
    }

    //returns if schema exists now
    bool createSchema(const std::string &schema) {
        if (checkSchemaExists(schema))[[likely]]return true;
        try{
            std::string sql = "CREATE SCHEMA IF NOT EXISTS " + schema + "
AUTHORIZATION " + user + " ; GRANT ALL ON SCHEMA " + schema + " TO " + datab +
" ; GRANT ALL ON SCHEMA " + schema + " TO public;";
            custom_function::replace_string_occurencies(sql,"  "," ");
            pqxx::work n(connection);
            n.exec(sql);
            n.commit();
        }
        catch (std::exception &e){
            std::cerr << "createSchema on " << schema << " failed for this
reason: " << e.what();
            exit(EXIT_FAILURE);
        }

        return checkSchemaExists(schema);
    }

    bool deleteSchema(const std::string &schema) {
        if (!checkSchemaExists(schema))[[unlikely]]{return false;}
        try{
            std::string sql = "DROP SCHEMA IF EXISTS "+schema+" CASCADE;";
            custom_function::replace_string_occurencies(sql,"  "," ");
            pqxx::work n(connection);
            n.exec(sql);
            n.commit();
        }
        catch (std::exception &e){
            std::cerr << "deleteSchema on " << schema << " failed for this
reason: " << e.what();
        }

        return !checkSchemaExists(schema);
    }

    bool checkTableExists(const std::string &schema, const std::string &table)
{
        if (!checkSchemaExists(schema))[[unlikely]]{return false;}
        try{
            std::string sql = "SELECT EXISTS (SELECT FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n"
                              " ON n.oid = c.relnamespace WHERE n.nspname =
'"+schema+"' AND c.relname = '"+table+
                              "' AND c.relkind = 'r' );";
            custom_function::replace_string_occurencies(sql,"  "," ");
            pqxx::nontransaction n(connection);
            pqxx::result r(n.exec(sql));
            n.commit();
            for (pqxx::result::const_iterator c = r.begin(); c != r.end();) {
                auto it = c;
                if(++c == r.end())[[likely]]{return it[0].as<bool>();}
                else break;
            }
        }
        catch (std::exception &e){
            std::cerr << "checkTableExists on (Schema: " << schema << ", Table:
" << table << ") failed for this reason: " << e.what();
        }
        return false;
    }


    std::vector<boost::tuple<std::string, std::string>>
    table_info(const std::string &schema, const std::string &table) {
        std::vector<boost::tuple<std::string,std::string>> out;
        try{
            //table_name, column_name, data_type
            if(!checkTableExists(schema,table))[[unlikely]]{return out;}
            std::string sql = "SELECT column_name, data_type FROM
information_schema.columns WHERE table_schema like '"+schema+"%' AND table_name
like '"+table+"%' ;";
            custom_function::replace_string_occurencies(sql,"  "," ");
            pqxx::nontransaction n(connection);
            pqxx::result r(n.exec(sql));
            n.commit();
            for (pqxx::result::const_iterator c = r.begin(); c != r.end();) {
               
out.emplace_back(c[0].as<std::string>(),c[1].as<std::string>());
                if(++c == r.end())[[unlikely]]{return out;}
            }
        }
        catch (std::exception &e){
            std::cerr << "table_info on (Schema: " << schema << ", Table: " <<
table << ") failed for this reason: " << e.what();
            return out;
        }
        return out;
    }

    bool deleteTable(const std::string &schema, const std::string &table) {
        if (!checkTableExists(schema,table))[[unlikely]]{return false;}
        try{
            std::string sql = "DROP TABLE IF EXISTS "+schema+"."+table+";";
            custom_function::replace_string_occurencies(sql,"  "," ");
            pqxx::work n(connection);
            n.exec(sql);
            n.commit();
        }
        catch (std::exception &e){
            std::cerr << "deleteTable on (Schema: " << schema << ", Table: " <<
table << ") failed for this reason: " << e.what();
        }

        return !checkTableExists(schema,table);
    }
private:
    /*
     * this is a variadic function to transform requested types into string
literals that tell the SQL database
     * to generate tables with certain data types
     */
    template<typename T1, typename T2, typename T3, typename... Args>
    std::string createTableRecursiveVariadicDefinition(T1 &&arg1, T2 &&arg2, T3
&&arg3, Args &&... args) {
        std::string out;
        if constexpr(String<T2>){
            if (boost::ifind_first(std::forward<T2>(arg2),
std::string("character varying")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("varchar")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("character")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("char"))
or
                boost::ifind_first(std::forward<T2>(arg2), std::string("text"))
or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("bytea")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("smallint")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("integer")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("bigint")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("decimal")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("numeric")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("real"))
or
                boost::ifind_first(std::forward<T2>(arg2), std::string("double
precision")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("smallserial")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("serial")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("bigserial")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("money")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("timestamp")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("TIMESTAMPTZ")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("date"))
or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("a_var")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("interval")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("boolean")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("point")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("line"))
or
                boost::ifind_first(std::forward<T2>(arg2), std::string("lseg"))
or
                boost::ifind_first(std::forward<T2>(arg2), std::string("box"))
or
                boost::ifind_first(std::forward<T2>(arg2), std::string("path"))
or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("polygon")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("circle")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("cidr"))
or
                boost::ifind_first(std::forward<T2>(arg2), std::string("inet"))
or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("macaddr")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("tsvector")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("tsquery")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("any"))
or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("anyelement")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("anyarray")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("anynonarray")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("anyenum")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("anyrange")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("cstring")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("internal")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("language_handler")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("fdw_handler")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("record")) or
                boost::ifind_first(std::forward<T2>(arg2),
std::string("trigger")) or
                boost::ifind_first(std::forward<T2>(arg2), std::string("void"))
                    ){
                out+=(std::string) std::forward<T1>(arg1)+" "+(std::string)
std::forward<T2>(arg2)+" "+(std::string) std::forward<T3>(arg3);
            }
            else{
                if constexpr(sizeof...(args)==0){
                    out+=(std::string) std::forward<T1>(arg1)+" "+(std::string)
std::forward<T2>(arg2)+" "+(std::string) std::forward<T3>(arg3);
                }
                else{
                    out+=(std::string) std::forward<T1>(arg1)+" text
"+(std::string) std::forward<T3>(arg3);
                }
            }
        }
        else{
            if constexpr(std::is_same_v<typename std::decay<T2>::type,unsigned
char> or
                         std::is_same_v<typename std::decay<T2>::type,unsigned
short> or
                         std::is_same_v<typename std::decay<T2>::type,char> or
                         std::is_same_v<typename std::decay<T2>::type,short>
                    ){
                out+=(std::string) std::forward<T1>(arg1)+" smallint
"+(std::string) std::forward<T3>(arg3);
            }
            if constexpr(std::is_same_v<typename std::decay<T2>::type,unsigned
int> or
                         std::is_same_v<typename std::decay<T2>::type,int>
                    ){
                out+=(std::string) std::forward<T1>(arg1)+" integer
"+(std::string) std::forward<T3>(arg3);
            }
            if constexpr(std::is_same_v<typename std::decay<T2>::type,unsigned
long int> or
                         std::is_same_v<typename std::decay<T2>::type,unsigned
long long int> or
                         std::is_same_v<typename std::decay<T2>::type,long int>
or
                         std::is_same_v<typename std::decay<T2>::type,long long
int>
                    ){
                out+=(std::string) std::forward<T1>(arg1)+" bigint
"+(std::string) std::forward<T3>(arg3);
            }
            if constexpr(std::is_same_v<typename std::decay<T2>::type,float>){
                out+=(std::string) std::forward<T1>(arg1)+" real
"+(std::string) std::forward<T3>(arg3);
            }
            if constexpr(std::is_same_v<typename std::decay<T2>::type,double>
or
                         std::is_same_v<typename std::decay<T2>::type,long
double>
                    ){
                out+=(std::string) std::forward<T1>(arg1)+" double precision
"+(std::string) std::forward<T3>(arg3);
            }
            if constexpr(std::is_same_v<typename std::decay<T2>::type,bool>){
                out+=(std::string) std::forward<T1>(arg1)+" boolean
"+(std::string) std::forward<T3>(arg3);
            }
        }
        if constexpr(sizeof...(args)==0){
            return out;
        }
        else{
            return out+", "+createTableRecursiveVariadicDefinition(args...);
        }
    }
public:

    bool connect(const std::string &database) {
        if(connection.is_open())[[likely]]{
            std::cout << "Database " << database << " was already open.";
            return true;
        }
        INFO << "Connecting on Database " << database;
        for (char i = 0; i < 3; i++) {
            try {
                std::string out =
                        "user=" + user + " password=" + pass + " host=" + addr
+ " port=" + p + " dbname=postgres" + " target_settion_attrs=read-write";
                connection = pqxx::connection(out);
                if (connection.is_open())[[likely]]{
                    std::cout << "Opened database successfully: " <<
this->datab;
                    datab = database;
                    return true;
                } else {
                    CUSTOM_THROW(1,"Can't open database")
                }
            } catch (const std::exception &e) {
                std::cerr << "connect on Database " << database << " failed for
this reason: " << e.what();
                std::system("service postgresql restart");
                std::cout << "Restart of database done!";
            }
        }
        if(!connection.is_open())[[likely]]{
            std::cerr << "Database " << database << " could finally not be
connected to!";
            exit(EXIT_FAILURE);
        }
        return false;
    }

    void disconnect() {
        connection.close();
    }

    //this function creates a table and will also create the schema if it does
not exist
    template<typename... Args>
    bool createTable(const std::string &schema, const std::string &table, const
std::string &pre_options,
                     const std::string &options, Args &&... args) {
        if(!checkSchemaExists(schema))[[unlikely]]{
            if(!createSchema(schema))[[unlikely]]{
                std::cerr << "The following schema could not be created: " <<
schema;
                exit(EXIT_FAILURE);
            }
        }
        if(checkTableExists(schema,table))[[likely]]{return false;}
        std::string sql = "CREATE "+pre_options+" TABLE "+options+"
"+schema+"."+table+" ( "+createTableRecursiveVariadicDefinition(args...)+" )
;";
        while(boost::algorithm::contains(sql,"  ")){
            custom_function::replace_string_occurencies(sql,"  "," ");
        }

        try{
            pqxx::work n(connection);
            n.exec(sql);
            n.commit();
        }
        catch (std::exception &e){
            std::cerr << "createTable on (SQL command: " << sql << ") failed
for this reason: " << e.what();
            exit(EXIT_FAILURE);
        }

        return checkTableExists(schema,table);
    }

    /*
     * automatically open table and create scheme or table if it does not
exists
     */
    template<typename... Args>
    bool openTable(const std::string &database, const std::string &schema,
const std::string &table,Args &&...args) {
        if(!connect(database))[[unlikely]]{
            std::cerr << "Could not connect to database and clName: " <<
database << " at " << schema << "." << table << " !!!";
            std::exit(EXIT_FAILURE);
        }
        schem=schema;
        tab=table;
        if (checkTableExists(schema,table))[[likely]]{
            open = true;
            return open;
        }
        else{
            open=this->createTable(schema,table,args...);
            if (!open){
                std::cerr << "Cannot create tabel for open request (database:
"<< database << ", schema: "
                          << schema << ", table: "<< table << ")";
                return open;
            }
            return open;
        }
    }

    //check if the block can be reader
    bool check_block_exists(const std::string& identifier) {
        std::string sql = "SELECT identifier FROM " + schem + "." + tab + "
WHERE identifier = decodeInit('"+ identifier + "', 'hex');";
        custom_function::replace_string_occurencies(sql,"  "," ");
        pqxx::nontransaction nf(connection);
        pqxx::result rf(nf.exec(sql));
        nf.commit();
        if (rf.empty()) {
            return false;
        }
        return rf[0][0].as<std::string>()==identifier;
    }
    //get the value of the sha id, so basically retrieve/return block
    std::string read_block(const std::string& identifier) {
        if(!check_block_exists(identifier))[[unlikely]]{
            std::cerr << "The block "+identifier+"was not found on the
database." << std::endl;
            std::exit(EXIT_FAILURE);
        }
        std::string sql = "SELECT identifier,block FROM " + schem + "." + tab +
" WHERE identifier = decodeInit('" + identifier + "', 'hex');";
        custom_function::replace_string_occurencies(sql,"  "," ");
        pqxx::nontransaction nf(connection);
        pqxx::result rf(nf.exec(sql));
        nf.commit();
        if(rf.size()>1){
            std::cerr << "The block hash "+identifier+"was found multiple times
on the database." << std::endl;
        }
        return rf[0][1].as<std::string>();
    }
    //write block by setting a string to the sha_id
    bool write_block(const std::string& identifier, const std::string& block) {
        if(check_block_exists(identifier))[[unlikely]]{
            std::cerr << "The block "+identifier+"was found on the database and
will be updated." << std::endl;
        }
        std::string sql =
                "INSERT INTO " + this->schem + "." + this->tab + "
(identifier,block) VALUES (decodeInit('" + identifier +"', 'hex'),
decodeInit('" + block +"', 'hex')) ON CONFLICT (identifier) DO UPDATE SET block
= excluded.block ;";
        custom_function::replace_string_occurencies(sql,"  "," ");
        pqxx::work n2(connection);
        n2.exec(sql);
        n2.commit();

        return true;
    }
//auto create block table
    explicit database_call_ops(const std::string &db_config_file) {//:
postgresSQL(db_config_file) {
        try{
            std::filesystem::path config(db_config_file);
            config_files configuration = config_files(config);
            unsigned char count=0;
            for(auto &r:configuration.read()){
                switch(count){
                    case 0:addr=r;break;
                    case 1:p=r;break;
                    case 2:user=r;break;
                    case 3:pass=r;break;
                    case 4:datab=r;break;
                    case 5:schem=r;break;
                    default:tab=r;break;
                }
                count++;
            }
            std::cout << "Successfully reader Database configuration file at
postgreSQL \'" << config.c_str() << "\' module." ;
        }
        catch (std::exception &e){
            try{
                std::fstream file;
                file.exceptions(std::ofstream::failbit |
std::ofstream::badbit);
                file.open(db_config_file, std::ios_base::binary);
                (void) file.write(std::string().c_str(), 0);
                file.close();
                std::cerr<<"Could not configure Database, because there was a
file error (check please) at postgreSQL \'config_database\' (address: "+addr+",
port: "+p+", user: "+user+", password: "+pass+") error: " << e.what();
                std::cout<<"Created a new database config file at the spot you
chose. Hopefully this was not by accident so you should not forget to delete
the file at the wrong spot.";
            }
            catch(std::exception& e){
                std::cerr<<"Could not configure Database, because there was a
file error (check please) at postgreSQL \'config_database\' (address: "+addr+",
port: "+p+", user: "+user+", password: "+pass+") error: " << e.what();
                std::exit(EXIT_FAILURE);
            }
        }
        if (!this->openTable(datab, schem, tab, "", "IF NOT EXISTS",
                             "id", (unsigned long long int) 0, "GENERATED
ALWAYS AS IDENTITY",
                             "identifier", "bytea", "UNIQUE NOT NULL",
                             "block", "bytea", "NOT NULL",
                             "", "", "PRIMARY KEY(id)"
        )) {
            std::cerr << "Database table could not be created or opened!";
            std::exit(EXIT_FAILURE);
        }
    }
};


#endif //SCHOOL_PROJECT_DATABASE_CALL_OPS_H

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-08-24  7:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-24  7:57 [Bug c++/106732] New: lock cannot be generated in a special case benni.probst at gmx dot de

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).