From 1a1c8e71fcd14858f595029f089b2d4a00202b32 Mon Sep 17 00:00:00 2001
From: ogi <Administrator@S-OGI-PC>
Date: Fri, 05 Dec 2025 09:24:16 +0900
Subject: [PATCH] プロジェクトファイルを追加。

---
 HotelPms.Share/Data/PostgreSqlNet.cs |  381 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 381 insertions(+), 0 deletions(-)

diff --git a/HotelPms.Share/Data/PostgreSqlNet.cs b/HotelPms.Share/Data/PostgreSqlNet.cs
new file mode 100644
index 0000000..16374d5
--- /dev/null
+++ b/HotelPms.Share/Data/PostgreSqlNet.cs
@@ -0,0 +1,381 @@
+using HotelPms.Share.IO;
+using Npgsql;
+using System.Data;
+using System.Data.Common;
+
+namespace HotelPms.Share.Data;
+
+public class PostgreSqlNet : DataAccess
+{
+    #region  ★★★★★ Declartions ★★★★★
+
+    public string ConnectionString { get; set; } = string.Empty;
+
+    /// <summary>ユーザー</summary>
+    public override string UseID { get; set; } = string.Empty;
+
+    /// <summary>パスワード</summary>
+    public override string PassWord { get; set; } = string.Empty;
+
+    /// <summary>データベース所在のパソコン名</summary>
+    public override string DataSource { get; set; } = string.Empty;
+
+    /// <summary>データベース名</summary>
+    public override string Catalog { get; set; } = string.Empty;
+
+    public override string Schema { get; set; } = "public";
+
+    public override int Port { get; set; } = 5432;
+
+    /// <summary>
+    /// デッドロック関連: 1205,3635,5231,5252,17888,22840,23424
+    /// </summary>
+    public int Message_id { get; set; } = 0;
+
+    public string SqlState { get; set; } = string.Empty;
+
+    /// <summary>エラー情報</summary>
+    public override string ErrInfo { get; set; } = string.Empty;
+
+    /// <summary>エラーコード</summary>
+    public override int ErrNo { get; set; } = 0;
+
+    public bool PoolEnabled { get; set; } = false;
+
+    public int MaxPoolSize { get; set; } = 1000;
+
+    public int RetryCount { get; set; } = 12;
+
+    public int RetryInterval { get; set; } = 5;
+
+    /// <summary>
+    /// タイマー単位のSQL
+    /// </summary>
+    public bool IsTimerAccess { get; set; } = false;
+
+    public bool FireInfoMessageEventOnUserErrors { get; set; } = false;
+
+    public bool MessageEventEnabled { get; set; } = false;
+
+    #endregion
+
+
+    public PostgreSqlNet(string connectionString)
+    {
+        ConnectionString = connectionString;
+        NpgsqlConnectionStringBuilder ssb = new NpgsqlConnectionStringBuilder(connectionString);
+        DataSource = ssb.Host;
+        Port = ssb.Port;
+        UseID = ssb.Username;
+        PassWord = ssb.Password;
+        Catalog = ssb.Database;
+        MaxPoolSize = ssb.MaxPoolSize;
+    }
+
+    public PostgreSqlNet(DBConnectItem connecitem) : this(connecitem.HostName, connecitem.UserID, connecitem.Password, connecitem.Port, connecitem.DBName)
+    { }
+
+    public PostgreSqlNet(string dataSource, string userID, string passWord) : this(dataSource, userID, passWord, 5432, "postgres")
+    {
+    }
+
+    public PostgreSqlNet(string dataSource, string userID, string passWord, int port) : this(dataSource, userID, passWord, port, "postgres")
+    { }
+
+    public PostgreSqlNet(string dataSource, string userID, string passWord, int port,  string catalog)
+    {
+        DataSource = dataSource;
+        Port = port;
+        UseID = userID;
+        PassWord = passWord;
+        Catalog = catalog;
+        ResetConnectionString();
+    }
+
+    public override void Dispose()
+    {
+
+    }
+
+    public void ResetConnectionString()
+    {
+        NpgsqlConnectionStringBuilder ssb = new NpgsqlConnectionStringBuilder();
+        ssb.Host = DataSource;
+        ssb.Port = Port;
+        ssb.Username = UseID;
+        ssb.Password = PassWord;
+        ssb.Database = Catalog;
+        ssb.Enlist = true;
+        //ssb.MaxPoolSize = MaxPoolSize;
+        ssb.ApplicationName = System.IO.Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
+        ssb.Encoding = "UTF8";
+        //ssb.ApplicationName = System.IO.Path.GetFileNameWithoutExtension(Application.ExecutablePath);
+        ConnectionString = ssb.ToString();
+    }
+
+    public static bool CreateDataBase(DBConnectItem item)
+    {
+        using (PostgreSqlNet dbAccess = new PostgreSqlNet(item.HostName, item.UserID, item.Password, item.Port))
+        {
+            if (dbAccess.ErrNo != 0) { return false; }
+            return (dbAccess.ExecuteNonQuery($"CREATE DATABASE \"{item.DBName}\" ENCODING 'UTF8'") != -1);
+        }
+    }
+
+    /// 可変戻り値
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="sql"></param>
+    /// <param name="fillReaderHandler"></param>
+    /// <returns></returns>
+    public override T GetDataReader<T>(string sql, Action<DbDataReader, T> Fetch)
+    {
+        OperationLog.Instance.WriteLog(string.Format("MsSqlNet.GetDataReader({0})", sql), GetLogLevel());
+        for (int i = 0; i < RetryCount; i++)
+        {
+            if (i > 0) { OperationLog.Instance.WriteLog(string.Format("{1}⇒MsSqlNet.GetDataReader({0})", sql, i), OperationLog.LogLevelType.Normal); }
+            try
+            {
+                ErrClear();
+                T t = new T();
+                using (NpgsqlConnection dbConnect = Open())
+                {
+                    using (NpgsqlCommand command = new NpgsqlCommand(sql, dbConnect))
+                    {
+                        command.CommandTimeout = 6000;
+                        using (NpgsqlDataReader reader = command.ExecuteReader(CommandBehavior.Default))
+                        {
+                            
+                            Fetch(reader, t);
+                        }  //自動クロス
+                    }
+                }
+                return t;
+            }
+            catch (Exception ex)
+            {
+                if (!IsTransient(ex, sql)) { return default; }
+            }
+            Thread.Sleep(RetryInterval * 1000);
+        }
+        return default;
+    }
+
+    public override DataSet GetDataSet(string sql)
+    {
+        throw new NotImplementedException();
+    }
+
+    public override DataSet GetDataSetWithTran(string sql)
+    {
+        throw new NotImplementedException();
+    }
+
+    public override DataTable GetDataTable(string sql)
+    {
+        OperationLog.Instance.WriteLog(string.Format("GetDataTable({0})", sql), GetLogLevel());
+        for (int i = 0; i < RetryCount; i++)
+        {
+            if (i > 0) { OperationLog.Instance.WriteLog(string.Format("{1}⇒GetDataTable({0})", sql, i), OperationLog.LogLevelType.Normal); }
+            try
+            {
+                ErrClear();
+                using (NpgsqlConnection dbConnect = Open())
+                {
+                    using (NpgsqlCommand command = new NpgsqlCommand(sql, dbConnect))
+                    {
+                        command.CommandTimeout = 60000;
+                        DataTable dataTable = new DataTable();
+                        using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter())
+                        {
+                            adapter.SelectCommand = command;
+                            adapter.Fill(dataTable);
+                        }
+                        return dataTable;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                if (!IsTransient(ex, sql)) { return null; }
+            }
+            Thread.Sleep(RetryInterval * 1000);
+        }
+        return null;
+    }
+
+    public override object ExecuteScalar(string sql)
+    {
+        OperationLog.Instance.WriteLog($"ExecuteScalar({sql})", GetLogLevel());
+
+        for (int i = 0; i < RetryCount; i++)
+        {
+            if (i > 0) { OperationLog.Instance.WriteLog($"{i}⇒ExecuteScalar({sql})", OperationLog.LogLevelType.Normal); }
+            try
+            {
+                ErrClear();
+                using (NpgsqlConnection dbConnect = Open())
+                {
+                    using (NpgsqlCommand command = new NpgsqlCommand(sql, dbConnect))
+                    {
+                        return command.ExecuteReader();
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                if (!IsTransient(ex, sql)) { return null; }
+            }
+            Thread.Sleep(RetryInterval * 1000);
+        }
+        return null;
+    }
+
+    public override int ExecuteGetID(string sql)
+    {
+        throw new NotImplementedException();
+    }
+
+    public override int ExecuteNonQuery(string sql)
+    {
+        OperationLog.Instance.WriteLog($"ExecuteNonQuery({sql})", GetLogLevel());
+
+        for (int i = 0; i < RetryCount; i++)
+        {
+            if (i > 0) { OperationLog.Instance.WriteLog($"{i}⇒ExecuteNonQuery({sql})", OperationLog.LogLevelType.Normal); }
+            try
+            {
+                ErrClear();
+                using (NpgsqlConnection dbConnect = Open())
+                {
+                    using (NpgsqlCommand command = new NpgsqlCommand(sql, dbConnect))
+                    {
+                        int row = command.ExecuteNonQuery();
+                        return (row == -1 ? 0 : row);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                if (!IsTransient(ex, sql)) { return -1; }
+            }
+            Thread.Sleep(RetryInterval * 1000);
+        }
+        return -1;
+    }
+
+    public override bool ExecuteNonQueryWithTran(string sql)
+    {
+        OperationLog.Instance.WriteLog($"ExecuteNonQuery({sql})", GetLogLevel());
+
+        for (int i = 0; i < RetryCount; i++)
+        {
+            if (i > 0) { OperationLog.Instance.WriteLog($"{i}⇒ExecuteNonQuery({sql})", OperationLog.LogLevelType.Normal); }
+            NpgsqlTransaction tran = null;
+            try
+            {
+                ErrClear();
+                using (NpgsqlConnection dbConnect = Open())
+                {
+                    tran = dbConnect.BeginTransaction();
+                    using (NpgsqlCommand command = new NpgsqlCommand(sql, dbConnect))
+                    {
+                        int row = command.ExecuteNonQuery();
+                        if (row == -1)
+                        {
+                            tran.Rollback();
+                            return false;
+                        }
+                        else
+                        {
+                            tran.Commit();
+                            return true;
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                tran?.Rollback(); 
+                if (!IsTransient(ex, sql)) { return false; }
+            }
+            Thread.Sleep(RetryInterval * 1000);
+        }
+        return false;
+    }
+
+    public NpgsqlConnection Open()
+    {
+        NpgsqlConnection dbConnect = new NpgsqlConnection();
+        dbConnect.ConnectionString = ConnectionString;
+        dbConnect.Open();
+        return dbConnect;
+    }
+
+    /// <summary>
+    /// 一時的なエラー
+    /// </summary>
+    /// <param name="ex"></param>
+    /// <returns></returns>
+    private bool IsTransient(Exception ex, string sql)
+    {
+        NpgsqlException exSql = null;
+        if (ex is NpgsqlException)
+        {
+            exSql = ex as NpgsqlException;
+            Message_id = exSql.HResult;
+            ErrNo = exSql.ErrorCode;
+            SqlState = exSql.SqlState;
+        }
+        else
+        {
+            ErrNo = -1;
+        }
+        ErrInfo = ex.Message;
+        OperationLog.Instance.WriteLog(string.Format("IsTransient({0},{1},{2},{3})", Message_id, ErrNo, ErrInfo, sql), OperationLog.LogLevelType.Normal);
+
+        if (exSql != null)
+        {
+            //Specifies whether the exception is considered transient, that is, whether retrying the operation could succeed (e.g. a network error or a timeout).
+            if (exSql.IsTransient) { return true; }
+            if (exSql.SqlState == "40P01") { return true; }  //デッドロックの検出
+        }
+        else if (ex is TimeoutException)
+        {
+            return true;
+        }
+        return false;
+    }
+
+    private void ErrClear()
+    {
+        ErrNo = 0;
+        ErrInfo = string.Empty;
+        SqlState = string.Empty;
+        Message_id = 0;
+    }
+
+    private OperationLog.LogLevelType GetLogLevel()
+    {
+        return IsTimerAccess ? OperationLog.LogLevelType.Level8 : OperationLog.LogLevelType.Level7;
+    }
+
+    /// <summary>
+    /// テーブル一覧を取得
+    /// ※一般的にschema = publicですが
+    /// </summary>
+    /// <returns></returns>
+    public override DataTable GetTableList()
+    {
+        return GetDataTable($"SELECT \"table_name\" AS \"Name\" FROM \"information_schema\".\"tables\" WHERE \"table_schema\"='{Schema}';");
+    }
+
+    /// <summary>
+    /// テーブル一覧を取得
+    /// </summary>
+    /// <returns></returns>
+    public override DataTable GetTableList(string whereAdding)
+    {
+        return GetDataTable($"SELECT \"table_name\" AS \"Name\" FROM \"information_schema\".\"tables\" WHERE \"table_schema\"='{Schema}' AND {whereAdding};");
+    }
+}

--
Gitblit v1.10.0