using DevExpress.Utils.Drawing; using LFP_Manager.DataStructure; using System; using System.Data; using System.Data.SQLite; using System.IO; using System.Text; using System.Windows.Forms; namespace LFP_Manager.Utils { class csDbUtils { // Query - SELECT * FROM TABLE_NAME like('%neon%',field_name) - 문자를 포함하는 데이터 검색 public static string DbFileName = @"LFPS-48100S-J_INV.db"; public static string DbFilePathFormat = @"\db\"; public static string DbFileNameFormat = @"\db\{0}_{1}.db"; public static string DbSchemaTableFileName = @"\sql\DB_SCHEMA_TABLE.sql"; public static string ModuleTableName = @"TModule"; public static string LogDbFilePath = @"db"; public static string LogDbFileNameFormat = @"{0}\{1}_{2}_LOG.DB"; public static string LogDbSchemaTableFileName = @"sql\LOG_DB_SCHEMA_TABLE.sql"; public static DateTime Delay(int ms) { DateTime thisMoment = DateTime.Now; TimeSpan duration = new TimeSpan(0, 0, 0, 0, ms); DateTime afterMoment = thisMoment.Add(duration); while (afterMoment >= thisMoment) { Application.DoEvents(); thisMoment = DateTime.Now; } return DateTime.Now; } //트랜잭션 시작 public static void BeginTran(SQLiteConnection conn) { SQLiteCommand command = new SQLiteCommand("Begin", conn); command.ExecuteNonQuery(); command.Dispose(); } //트랜잭션 완료 public static void CommitTran(SQLiteConnection conn) { SQLiteCommand command = new SQLiteCommand("Commit", conn); command.ExecuteNonQuery(); command.Dispose(); } #region COMMON DB HELPERS private static DataTable ExecSelect(string dbPath, string sql) { var dt = new DataTable(); using (var conn = new SQLiteConnection(@"Data Source=" + dbPath)) using (var adp = new SQLiteDataAdapter(sql, conn)) { conn.Open(); adp.AcceptChangesDuringFill = false; adp.Fill(dt); } return dt; } #endregion #region CREATE DATABASE public static void DbCreate(string mSN, string bName) { string result = ""; string dbFilename = String.Format(DbFileNameFormat, MakeLotNumber(mSN, bName), bName); string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false) Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilePath)); if (File.Exists(dbFilePath) == true) { //throw new Exception("Already have db file - Failed to create db file"); return; } else { // Create database SQLiteConnection.CreateFile(dbFilePath); } // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Create table using (SQLiteCommand command = connection.CreateCommand()) { string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + DbSchemaTableFileName; string query = File.ReadAllText(schemaFile); command.CommandText = query; SQLiteDataReader reader = null; reader = command.ExecuteReader(); } } catch (Exception e) { result = e.Message; } finally { connection.Close(); if (result != "") throw new Exception(result); } } return; } public static void LogDbCreate(string aModel) { string result = ""; string ModelName = aModel; //public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB"; string dbFilename = String.Format(LogDbFileNameFormat , String.Format("{0:yyMM}", DateTime.Now) , String.Format("{0:yyMMdd}", DateTime.Now) , ModelName ); string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false) Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilePath)); if (File.Exists(dbFilePath) == true) { //throw new Exception("Already have db file - Failed to create db file"); return; } else { // Create database SQLiteConnection.CreateFile(dbFilePath); } // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Create table using (SQLiteCommand command = connection.CreateCommand()) { string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + LogDbSchemaTableFileName; string query = File.ReadAllText(schemaFile); command.CommandText = query; SQLiteDataReader reader = null; reader = command.ExecuteReader(); } } catch (Exception e) { result = e.Message; } finally { connection.Close(); if (result != "") throw new Exception(result); } } return; } #endregion #region DB CREATE FUNCTION (LOG) public static void DbCreateLOG(CommConfig aConfig) { string modelName = csConstData.UART_MODEL[aConfig.UartModelIndex]; string folder = string.Format("{0:yyMM}", DateTime.Now); string file = string.Format("{0}_{1}_LOG.DB", string.Format("{0:yyMMdd}", DateTime.Now), modelName); string exeDir = Path.GetDirectoryName(Application.ExecutablePath); string dbFilePath = csUtils.CombineApp(exeDir, LogDbFilePath, folder, file); string dir = Path.GetDirectoryName(dbFilePath); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); if (File.Exists(dbFilePath)) return; SQLiteConnection.CreateFile(dbFilePath); string schemaFile = csUtils.CombineApp(LogDbSchemaTableFileName); string query = File.ReadAllText(schemaFile); using (var connection = new SQLiteConnection(@"Data Source=" + dbFilePath)) { connection.Open(); using (var command = connection.CreateCommand()) { command.CommandText = query; using (var reader = command.ExecuteReader()) { /* schema create */ } } } } #endregion #region MAKE LOT NUMBER public static string MakeLotNumber(string mSN) { string LotNo = mSN.Substring(1, 11) + "000"; return LotNo; } public static string MakeLotNumber(string mSN, string bName) { string LotNo; if (bName == "BMCB_J") LotNo = mSN.Substring(0, 10) + "0000"; else LotNo = mSN.Substring(1, 11) + "000"; return LotNo; } #endregion #region Excute Database public static DataTable DbSqlExcute(string path, string query, bool create_db_flag = false) { string result = ""; DataTable dtResult = null; string dbFilename = Path.GetDirectoryName(path) + DbFileName; if (Directory.Exists(Path.GetDirectoryName(dbFilename)) == false) Directory.CreateDirectory(Path.GetDirectoryName(dbFilename)); // Create database if (File.Exists(dbFilename) == false) { if (create_db_flag == true) SQLiteConnection.CreateFile(dbFilename); else throw new Exception("No database file - " + DbFileName); } // Open database string strConn = @"Data Source=" + dbFilename; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Create table using (SQLiteCommand command = connection.CreateCommand()) { //command.CommandText = "CREATE TABLE File (Name text, Size bigint, Modified datetime);"; command.CommandText = query; SQLiteDataReader reader = null; //command.ExecuteNonQuery(); reader = command.ExecuteReader(); dtResult = new DataTable(); dtResult.Load(reader); } } catch (Exception e) { result = e.Message; } finally { connection.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable DbSqlExcuteA1(string path, string query) { DataTable dtResult = null; string dbFilename = System.IO.Path.GetDirectoryName(path) + DbFileName; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilename)) == false) Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilename)); if (File.Exists(dbFilename) == false) // Create database SQLiteConnection.CreateFile(dbFilename); // Open database string strConn = @"Data Source=" + dbFilename; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Excute Query var adpt = new SQLiteDataAdapter(query, connection); DataSet ds = new DataSet(); adpt.Fill(ds); dtResult = ds.Tables[0]; } catch (Exception e) { throw e; } finally { connection.Close(); } } return dtResult; } public static DataTable DbSqlExcuteA(string lot, string query, string bName, bool create_db_flag = false) { string result = ""; DataTable dtResult = new DataTable(); string lotNo = lot; string dbFilename = String.Format(DbFileNameFormat, lotNo, bName); string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename; if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false) { if (create_db_flag) Directory.CreateDirectory(Path.GetDirectoryName(dbFilePath)); else throw new Exception("No DB file path - " + Path.GetDirectoryName(dbFilePath)); } if (File.Exists(dbFilePath) == false) { if (create_db_flag) SQLiteConnection.CreateFile(dbFilePath); else throw new Exception(String.Format("No DB file - DbSqlExcuteA ({0})", dbFilename)); } // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Excute Query var adpt = new SQLiteDataAdapter(query, connection); DataSet ds = new DataSet(); adpt.Fill(ds); if (ds.Tables.Count > 0) dtResult = ds.Tables[0]; } catch (Exception ex) { result = ex.Message; } finally { connection.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable DbSqlExcuteA2(string dbFileName, string query, bool create_db_flag = false) { string result = ""; DataTable dtResult = new DataTable(); string lotNo = dbFileName.Substring(0, 9); string dbFilename = String.Format(DbFilePathFormat, lotNo) + dbFileName; string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename; if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false) { if (create_db_flag) Directory.CreateDirectory(Path.GetDirectoryName(dbFilePath)); else throw new Exception("No DB file path - " + Path.GetDirectoryName(dbFilePath)); } if (File.Exists(dbFilePath) == false) { if (create_db_flag) SQLiteConnection.CreateFile(dbFilePath); else throw new Exception(String.Format("No DB file - DbSqlExcuteA ({0})", dbFilename)); } // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Excute Query var adpt = new SQLiteDataAdapter(query, connection); DataSet ds = new DataSet(); adpt.Fill(ds); if (ds.Tables.Count > 0) dtResult = ds.Tables[0]; } catch (Exception ex) { result = ex.Message; } finally { connection.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable DbSqlExcuteA3(string dbFileName, string query, bool create_db_flag = false) { string result = ""; DataTable dtResult = new DataTable(); string dbFilePath = dbFileName; if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false) { if (create_db_flag) Directory.CreateDirectory(Path.GetDirectoryName(dbFilePath)); else throw new Exception("No DB file path - " + Path.GetDirectoryName(dbFilePath)); } if (File.Exists(dbFilePath) == false) { if (create_db_flag) SQLiteConnection.CreateFile(dbFilePath); else throw new Exception(String.Format("No DB file - DbSqlExcuteA ({0})", dbFileName)); } // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { connection.Open(); try { // Excute Query var adpt = new SQLiteDataAdapter(query, connection); DataSet ds = new DataSet(); adpt.Fill(ds); if (ds.Tables.Count > 0) dtResult = ds.Tables[0]; } catch (Exception ex) { result = ex.Message; } finally { connection.Close(); if (result != "") throw new Exception(result); } } return dtResult; } #endregion #region BMS DATA INSERT AND UPDATE public static string GetDbFilePath(string modelName, DateTime dateTime) { string folder = string.Format("{0:yyMM}", dateTime); // 2512 string file = string.Format("{0}_{1}_LOG.DB", string.Format("{0:yyMMdd}", dateTime), modelName); // 251221_LFPM-48100SB_LOG.DB string exeDir = Path.GetDirectoryName(Application.ExecutablePath); string dbPath = csUtils.CombineApp(exeDir, LogDbFilePath, folder, file); // db\2512\251221_LFPM-48100SB_LOG.DB return dbPath; } public static void BmsLogDataInsert(string ModelName, ref CsDeviceData.DeviceModuleData mData, DateTime dateTime, int cvUnit, int log_type = 0) { string result = ""; string dbFilePath = GetDbFilePath(ModelName, dateTime); if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false) throw new Exception("No Log DB file path"); if (File.Exists(dbFilePath) == false) throw new Exception(String.Format("No Log DB file - BmsLogDataInsert ({0})", dbFilePath)); // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { SQLiteTransaction tran = null; try { connection.Open(); // 기존 BeginTran/CommitTran을 유지하고 싶으면 tran 대신 그걸 쓰셔도 됩니다. // 다만 C# 7.3에서는 아래 표준 방식이 제일 안전합니다. tran = connection.BeginTransaction(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { command.Transaction = tran; // 스키마 기준: cell 15, temp 4 고정 const int CELL_MAX = 15; const int TEMP_MAX = 4; //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = "INSERT INTO TModuleValue (" + "create_date" + ", log_type" + ", module_no" + ", model_name" + ", module_sn" + ", fw_ver" + ", comm_fail" + ", op_status" + ", alarm_status" + ", warning" + ", fault" + ", module_voltage" + ", module_current" + ", module_soc" + ", module_soh" + ", module_cyclecount" + ", cv_diff"; for (int i = 0; i < CELL_MAX; i++) command.CommandText += $", cell_voltage_{i + 1:00}"; command.CommandText += ", tp_diff"; for (int i = 0; i < TEMP_MAX; i++) command.CommandText += $", temperature_{i + 1:00}"; command.CommandText += "" + ", ext1_temp" + ", ext2_temp" + ", chg_option" + ") VALUES ("; int total = 16 + 1 + CELL_MAX + 1 + TEMP_MAX + 3; // 16(기본 0~15) + cv_diff(1) + cell15 + tp_diff(1) + temp4 + ext1/ext2/chg(3) for (int i = 0; i < total - 1; i++) command.CommandText += "?,"; command.CommandText += "?);"; for (int i = 0; i < total; i++) command.Parameters.Add(new SQLiteParameter()); int j = 0; command.Parameters[j++].Value = dateTime; // create_date command.Parameters[j++].Value = log_type; // log_type command.Parameters[j++].Value = mData.mNo; // module_no command.Parameters[j++].Value = (object)mData.Information.ModelName ?? DBNull.Value; command.Parameters[j++].Value = (object)mData.Information.HwSerialNumber ?? DBNull.Value; command.Parameters[j++].Value = (object)mData.Information.SwProductRev ?? DBNull.Value; command.Parameters[j++].Value = mData.ShelfCommFail; // comm_fail (bool -> 0/1도 가능) command.Parameters[j++].Value = mData.StatusData.status; // op_status command.Parameters[j++].Value = mData.StatusData.batteryStatus; // alarm_status command.Parameters[j++].Value = mData.StatusData.warning; // warning command.Parameters[j++].Value = mData.StatusData.protect; // fault command.Parameters[j++].Value = mData.ValueData.voltage / 10.0; // module_voltage command.Parameters[j++].Value = mData.ValueData.current / 10.0; // module_current command.Parameters[j++].Value = mData.ValueData.SOC / 10.0; // module_soc command.Parameters[j++].Value = mData.ValueData.SOH / 10.0; // module_soh command.Parameters[j++].Value = mData.ValueData.cycleCount; // module_cyclecount // cv_diff = 셀 전압 max-min (V) object cvDiffValue = DBNull.Value; if (mData.ValueData.CellVoltage != null && mData.cellQty > 0) { int n = Math.Min(mData.cellQty, CELL_MAX); double minV = double.MaxValue; double maxV = double.MinValue; for (int i = 0; i < n; i++) { double v = mData.ValueData.CellVoltage[i] / (double)cvUnit; if (v < minV) minV = v; if (v > maxV) maxV = v; } if (minV != double.MaxValue) cvDiffValue = (maxV - minV); } command.Parameters[j++].Value = cvDiffValue; // cv_diff // cell_voltage_01..15 (없으면 NULL) for (int i = 0; i < CELL_MAX; i++) { if (mData.ValueData.CellVoltage != null && i < mData.cellQty) command.Parameters[j++].Value = mData.ValueData.CellVoltage[i] / (double)cvUnit; else command.Parameters[j++].Value = DBNull.Value; } // tp_diff = 온도 max-min (°C) object tpDiffValue = DBNull.Value; if (mData.ValueData.CellTemperature != null && mData.tempQty > 0) { int n = Math.Min(mData.tempQty, TEMP_MAX); double minT = double.MaxValue; double maxT = double.MinValue; for (int i = 0; i < n; i++) { double t = mData.ValueData.CellTemperature[i] / 10.0; if (t < minT) minT = t; if (t > maxT) maxT = t; } if (minT != double.MaxValue) tpDiffValue = (maxT - minT); } command.Parameters[j++].Value = tpDiffValue; // tp_diff // temperature_01..04 (없으면 NULL) for (int i = 0; i < TEMP_MAX; i++) { if (mData.ValueData.CellTemperature != null && i < mData.tempQty) command.Parameters[j++].Value = mData.ValueData.CellTemperature[i] / 10.0; else command.Parameters[j++].Value = DBNull.Value; } command.Parameters[j++].Value = mData.ValueData.MosTemperature / 10.0; // ext1_temp command.Parameters[j++].Value = mData.ValueData.AmbTemperature / 10.0; // ext2_temp command.Parameters[j++].Value = (short)mData.CalibrationData.Current.ChargeOption; // chg_option if (j != total) throw new Exception(string.Format("Parameter mismatch: j={0}, total={1}", j, total)); command.ExecuteNonQuery(); } tran.Commit(); } catch (Exception e) { try { if (tran != null) tran.Rollback(); } catch { /* rollback 실패는 무시 or 로그 */ } result = e.Message; } finally { if (tran != null) tran.Dispose(); if (connection.State == ConnectionState.Open) connection.Close(); if (result != "") throw new Exception(result); } } } public static DataTable GetDataTable(string bSN, string aTableName, string bName) { string result = ""; DataTable dtResult = null; string dbFilename = String.Format(DbFileNameFormat, MakeLotNumber(bSN, bName), bName); string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename; if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFilePath) == false) throw new Exception("No DB file"); // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { Forms.fmxWait WaitForm = new Forms.fmxWait(); WaitForm.StartPosition = FormStartPosition.CenterScreen; try { connection.Open(); BeginTran(connection); WaitForm.Show(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = String.Format("SELECT * FROM {0}", aTableName); SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); adapter.AcceptChangesDuringFill = false; dtResult = new DataTable(); adapter.Fill(dtResult); dtResult.TableName = aTableName; CommitTran(connection); System.Windows.Forms.Application.DoEvents(); WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1)); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (WaitForm != null) WaitForm.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable GetDataTableBySelect(string bSN, string sql, string aTableName, string bName) { string result = ""; DataTable dtResult = null; string dbFilename = String.Format(DbFileNameFormat, MakeLotNumber(bSN, bName), bName); string dbFilePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + dbFilename; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFilePath) == false) throw new Exception(String.Format("No DB file - {0}", dbFilePath)); // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { Forms.fmxWait WaitForm = new Forms.fmxWait(); WaitForm.StartPosition = FormStartPosition.CenterScreen; try { connection.Open(); BeginTran(connection); WaitForm.Show(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = sql; SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); adapter.AcceptChangesDuringFill = false; dtResult = new DataTable(); adapter.Fill(dtResult); dtResult.TableName = aTableName; System.Windows.Forms.Application.DoEvents(); WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1)); CommitTran(connection); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (WaitForm != null) WaitForm.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable GetDataTableBySelectFromDbName(string dbFileName, string sql, string aTableName, string bName) { string result = ""; DataTable dtResult = null; string lotNo = csDbUtils.MakeLotNumber(dbFileName.Substring(0, 8), bName); string dbFilename = String.Format(@"\db\{0}\{1}", lotNo, dbFileName); string dbFilePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + dbFilename; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFilePath) == false) throw new Exception(String.Format("No DB file - {0}", dbFilePath)); // Open database string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { Forms.fmxWait WaitForm = new Forms.fmxWait(); WaitForm.StartPosition = FormStartPosition.CenterScreen; try { connection.Open(); BeginTran(connection); WaitForm.Show(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = sql; SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); adapter.AcceptChangesDuringFill = false; dtResult = new DataTable(); adapter.Fill(dtResult); dtResult.TableName = aTableName; System.Windows.Forms.Application.DoEvents(); WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1)); CommitTran(connection); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (WaitForm != null) WaitForm.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable GetDataTableByFileName(string fileName, string sql, string aTableName) { string result = ""; DataTable dtResult = null; if (Directory.Exists(System.IO.Path.GetDirectoryName(fileName)) == false) throw new Exception("No DB file path"); if (File.Exists(fileName) == false) throw new Exception("No DB file"); // Open database string strConn = @"Data Source=" + fileName; using (var connection = new SQLiteConnection(strConn)) { Forms.fmxWait WaitForm = new Forms.fmxWait(); WaitForm.StartPosition = FormStartPosition.CenterScreen; try { connection.Open(); BeginTran(connection); WaitForm.Show(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = sql; SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); adapter.AcceptChangesDuringFill = false; dtResult = new DataTable(); adapter.Fill(dtResult); dtResult.TableName = aTableName; System.Windows.Forms.Application.DoEvents(); WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1)); CommitTran(connection); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (WaitForm != null) WaitForm.Close(); if (result != "") throw new Exception(result); } } return dtResult; } public static DataTable GetModuleMatchTableByFgNo(string fg_no, string bName) { DataTable dtResult = null; int a, b, c; a = Convert.ToInt32(fg_no); b = a / 300 + 1; c = a % 300; if ((c == 0) && (b > 0)) b--; string mSN = String.Format("1{0:yy}{1:00}{2:000}", DateTime.Now, b, c); string lotNo = csDbUtils.MakeLotNumber(mSN, bName); string dbfilePath = Path.GetDirectoryName(Application.ExecutablePath) + String.Format(DbFilePathFormat, lotNo); string[] filePaths = Directory.GetFiles(dbfilePath, "*.db"); if (filePaths.Length > 0) { for (int i = 0; i < filePaths.Length; i++) { string fileName = Path.GetFileName(filePaths[i]); byte[] bfilName = Encoding.ASCII.GetBytes(fileName); dtResult = GetDataTableByFileName(filePaths[i], String.Format("SELECT * FROM TModuleMatch where fg_no={0}", fg_no), "TModuleMatch"); if ((dtResult != null) && (dtResult.Rows.Count == 1)) break; } } if ((dtResult == null) || (dtResult.Rows.Count == 0)) throw new Exception(String.Format("No match data - {0}", fg_no)); return dtResult; } public static void BmsPcbMatchDataInsert(string dbFileName, DataRow sRow) { string result = ""; int resultCode = (int)SQLiteErrorCode.Unknown; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFileName)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFileName) == false) throw new Exception(String.Format("No DB file - BmsDataInsert ({0})", dbFileName)); // Open database string strConn = @"Data Source=" + dbFileName; using (var connection = new SQLiteConnection(strConn)) { Forms.fmxWait WaitForm = new Forms.fmxWait { StartPosition = FormStartPosition.CenterScreen }; try { connection.Open(); BeginTran(connection); WaitForm.Show(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = "INSERT INTO" + " TBmsPcbMatchTable" + " (PCB1_SERIAL_NUMBER, MODULE_SERIAL_NUMBER, create_date, modify_date)" // 2 + " Values (?,?,?,?);"; SQLiteParameter[] p = new SQLiteParameter[4]; for (int i = 0; i < 4; i++) { p[i] = new SQLiteParameter(); command.Parameters.Add(p[i]); } int j = 0; p[j++].Value = sRow["PCB1_SERIAL_NUMBER"]; // pcb_sn p[j++].Value = sRow["MODULE_SERIAL_NUMBER"]; // module_sn p[j++].Value = DateTime.Now; // create_date p[j++].Value = DateTime.Now; // modify_date command.ExecuteNonQuery(); WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1)); System.Windows.Forms.Application.DoEvents(); CommitTran(connection); } } catch (SQLiteException sqle) { // Handle DB exception result = sqle.Message; resultCode = sqle.ErrorCode; } catch (IndexOutOfRangeException ie) { // If you think there might be a problem with index range in the loop, for example result = ie.Message; resultCode = 9999; } catch (Exception ex) { result = ex.Message; resultCode = 9998; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (WaitForm != null) WaitForm.Close(); if (result != "") { if (resultCode == 9998) throw new Exception(result); else if (resultCode == 9999) throw new IndexOutOfRangeException(result); else throw new SQLiteException((SQLiteErrorCode)resultCode, result); } } } } public static void ErrorLogInsert(string dbFileName, DataRow sRow, string Process, string ErrType, string ErrMsg) { string result = ""; if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFileName)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFileName) == false) throw new Exception(String.Format("No DB file - ErrorLogInsert ({0})", dbFileName)); // Open database string strConn = @"Data Source=" + dbFileName; using (var connection = new SQLiteConnection(strConn)) { try { connection.Open(); BeginTran(connection); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = "INSERT INTO" + " TErrorLogTable" + " (create_date, MODULE_SERIAL_NUMBER, PCB1_SERIAL_NUMBER, PROCESS, ERROR_TYPE, ERROR_MSG)" // 2 + " Values (?,?,?,?,?,?);"; SQLiteParameter[] p = new SQLiteParameter[6]; for (int i = 0; i < 6; i++) { p[i] = new SQLiteParameter(); command.Parameters.Add(p[i]); } int j = 0; p[j++].Value = DateTime.Now; // create_date p[j++].Value = sRow["MODULE_SERIAL_NUMBER"]; // module_sn p[j++].Value = sRow["PCB1_SERIAL_NUMBER"]; // pcb_sn p[j++].Value = Process; // process p[j++].Value = ErrType; // error type p[j++].Value = ErrMsg; // error message command.ExecuteNonQuery(); CommitTran(connection); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (result != "") throw new Exception(result); } } } #endregion #region ALARM HISTROTY DB FUNCTION public static DataTable GetBmsAlarmDataByDataTable(CommConfig aConfig, DateTime aDateTime, string qry) { string modelName = csConstData.UART_MODEL[aConfig.UartModelIndex]; // LFPM-48100SB string folder = string.Format("{0:yyMM}", aDateTime); // 2512 string file = string.Format("{0}_{1}_LOG.DB", string.Format("{0:yyMMdd}", aDateTime), modelName); // 251221_LFPM-48100SB_LOG.DB string exeDir = Path.GetDirectoryName(Application.ExecutablePath); string dbPath = csUtils.CombineApp(exeDir, LogDbFilePath, folder, file); // db\2512\251221_LFPM-48100SB_LOG.DB if (!File.Exists(dbPath)) return null; string sql = string.IsNullOrWhiteSpace(qry) ? "SELECT * FROM TAlarmHistory ORDER BY create_date DESC" : "SELECT * FROM TAlarmHistory " + qry; var dt = ExecSelect(dbPath, sql); dt.TableName = "TAlarmHistory"; return dt; } public static DataTable GetBmsAlarmDataByDataTable1(string modelName, DateTime aDateTime, string qry) { // 결과 테이블(항상 non-null 반환) var dtResult = new DataTable("TAlarmHistory"); // 일자 기준 DB 파일명 (yyMM/yyMMdd) string dbFilename = string.Format( LogDbFileNameFormat, aDateTime.ToString("yyMM"), aDateTime.ToString("yyMMdd"), modelName); // \2512\{1}_{2}_LOG.DB"; // 실행파일 경로 + 로그 DB 상대경로 + 파일명 안전 결합 string exeDir = Path.GetDirectoryName(Application.ExecutablePath); if (string.IsNullOrEmpty(exeDir)) exeDir = AppDomain.CurrentDomain.BaseDirectory; string logPath = (LogDbFilePath ?? string.Empty) .TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); string dbDir = csUtils.CombineSafe(exeDir, logPath); string dbFilePath = csUtils.CombineSafe(dbDir, dbFilename); if (!File.Exists(dbFilePath)) return dtResult; // 빈 테이블 반환 // 당일 범위(00:00:00 ~ 다음날 00:00:00) DateTime start = aDateTime.Date; DateTime end = start.AddDays(1); // 조회 컬럼 지정 (SELECT * 지양) string cols = string.Join(", ", new[] { "create_date","alarm_code","alarm_status","alarm_cname","alarm_sname", "module_no","ct_no","alarm_param_1","alarm_param_2","alarm_param_3" }); // 기본 WHERE (날짜 범위) string sql = $"SELECT {cols} FROM TAlarmHistory " + $"WHERE create_date >= @start AND create_date < @end"; // 주의) qry는 그대로 붙이면 인젝션 위험. 반드시 신뢰 가능한 내부 생성 문자열만 사용하세요. if (!string.IsNullOrWhiteSpace(qry)) { sql += " AND (" + qry + ")"; } sql += " ORDER BY create_date DESC"; using (var connection = new SQLiteConnection(@"Data Source=" + dbFilePath)) { connection.Open(); // ★ 성능/동시성 PRAGMA 적용 (WAL + busy_timeout 등) — C# 7.3 호환 csDbUtils.SqlitePragmaHelper.ApplyPragmas(connection, false); // forReader: false using (var command = connection.CreateCommand()) { command.CommandText = sql; // 날짜 파라미터 바인딩 (SQLite는 TEXT/REAL/INTEGER 저장 허용. DbType.DateTime 사용) var pStart = new SQLiteParameter("@start", DbType.DateTime) { Value = start }; var pEnd = new SQLiteParameter("@end", DbType.DateTime) { Value = end }; command.Parameters.Add(pStart); command.Parameters.Add(pEnd); using (var adapter = new SQLiteDataAdapter(command)) { adapter.AcceptChangesDuringFill = false; adapter.Fill(dtResult); } } if (connection.State == ConnectionState.Open) connection.Close(); } return dtResult; } #endregion #region SELECT QUARY public static int DbQuaryExcuteToDataTable(string dbFileName, string Quary, ref DataTable rDT) { int result = 0; string resultStr = String.Empty; string strConn = @"Data Source=" + dbFileName; using (var connection = new SQLiteConnection(strConn)) { try { connection.Open(); BeginTran(connection); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = Quary; SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); adapter.AcceptChangesDuringFill = false; rDT = new DataTable(); adapter.Fill(rDT); //rDT.TableName = "TModuleValue"; CommitTran(connection); result = rDT.Rows.Count; System.Windows.Forms.Application.DoEvents(); } } catch (Exception e) { resultStr = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (resultStr != "") throw new Exception(resultStr); } } return result; } public static void CreateLogDbFile(string dbFileName) { string result = ""; if (Directory.Exists(Path.GetDirectoryName(dbFileName)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFileName) == true) throw new Exception(String.Format("Already have DB file - DbQuaryExcuteToDbFile({0})", dbFileName)); // Create database SQLiteConnection.CreateFile(dbFileName); // Open database string strConn = @"Data Source=" + dbFileName; using (var connection = new SQLiteConnection(strConn)) { Forms.fmxWait WaitForm = new Forms.fmxWait(); WaitForm.StartPosition = FormStartPosition.CenterScreen; try { connection.Open(); BeginTran(connection); WaitForm.Show(); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + LogDbSchemaTableFileName; string query = File.ReadAllText(schemaFile); command.CommandText = query; SQLiteDataReader reader = null; reader = command.ExecuteReader(); WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1)); System.Windows.Forms.Application.DoEvents(); CommitTran(connection); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (WaitForm != null) WaitForm.Close(); if (result != "") throw new Exception(result); } } } public static void DbInsertDataToDbFile(string dbFileName, DataRow dtRow) { string result = ""; if (Directory.Exists(Path.GetDirectoryName(dbFileName)) == false) throw new Exception("No DB file path"); if (File.Exists(dbFileName) == false) throw new Exception(String.Format("No DB file - DbInsertDataToDbFile({0})", dbFileName)); // Open database string strConn = @"Data Source=" + dbFileName; using (var connection = new SQLiteConnection(strConn)) { try { connection.Open(); BeginTran(connection); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { command.CommandText = String.Format("INSERT INTO TModuleValue ("); command.CommandText += "create_date" // 0 + ", module_no" // 1 + ", pcb_sn" // 2 + ", module_sn" // 3 + ", fw_ver" // 4 + ", comm_fail" // 5 + ", op_status" // 6 + ", alarm_status" // 7 + ", warning" // 8 + ", fault" // 9 + ", module_voltage" // 10 + ", module_current" // 11 + ", module_soc" // 12 + ", module_soh" // 13 ; for (int i = 0; i < 15; i++) { command.CommandText += String.Format(", cell_voltage_{0:00}", i + 1); // 14 ~ 28; 15 cells } for (int i = 0; i < 6; i++) { command.CommandText += String.Format(", temperature_{0:00}", i + 1); // 29 ~ 34; 6 temps } command.CommandText += "" + ", chg_option" // 35 + ", chg_cal" // 36 + ", dch_cal" // 37 + ")" + " Values ("; int total = dtRow.Table.Columns.Count; for (int i = 0; i < (total - 1); i++) command.CommandText += "?,"; command.CommandText += "?);"; SQLiteParameter[] p = new SQLiteParameter[total]; for (int i = 0; i < total; i++) { if (i == 0) p[i] = new SQLiteParameter(DbType.DateTime); else p[i] = new SQLiteParameter(); command.Parameters.Add(p[i]); } int j = 0; p[j++].Value = String.Format("{0:yyyy/MM/dd HH:mm:ss}", dtRow["create_date"]); // 0 create_date p[j++].Value = dtRow["module_no"]; // 1 module_no p[j++].Value = dtRow["pcb_sn"]; // 2 pcb_sn p[j++].Value = dtRow["module_sn"]; // 3 module_sn p[j++].Value = dtRow["fw_ver"]; // 4 fw_ver p[j++].Value = dtRow["comm_fail"]; // 5 comm_fail p[j++].Value = dtRow["op_status"]; // 6 op_status p[j++].Value = dtRow["alarm_status"]; // 7 alarm_status p[j++].Value = dtRow["warning"]; // 8 warning p[j++].Value = dtRow["fault"]; // 9 fault p[j++].Value = dtRow["module_voltage"]; // 10 module_voltage p[j++].Value = dtRow["module_current"]; // 11 module_current p[j++].Value = dtRow["module_soc"]; // 12 module_soc p[j++].Value = dtRow["module_soh"]; // 13 module_soh for (int i = 0; i < 15; i++) { p[j++].Value = dtRow[String.Format("cell_voltage_{0:00}", i + 1)]; // 14 cell_voltage_01 28 } for (int i = 0; i < 6; i++) { p[j++].Value = dtRow[String.Format("temperature_{0:00}", i + 1)]; // 29 cell_voltage_01 36 } p[j++].Value = dtRow["chg_option"]; // 37 chg_option p[j++].Value = dtRow["chg_cal"]; // 38 chg_cal p[j++].Value = dtRow["dch_cal"]; // 39 dch_cal command.ExecuteNonQuery(); CommitTran(connection); } } catch (SQLiteException se) { if (se.ResultCode != SQLiteErrorCode.Constraint) result = se.Message; } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (result != "") throw new Exception(result); } } } public static DataTable BmsDataSelectToDataTable(CommConfig aConfig, DateTime aDate, string qry) { string result = ""; DataTable dtResult = null; string ModelName = csConstData.UART_MODEL[aConfig.UartModelIndex]; string dbFilePath = GetDbFilePath(ModelName, aDate); if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false) return dtResult; if (File.Exists(dbFilePath) == false) return dtResult; string strConn = @"Data Source=" + dbFilePath; using (var connection = new SQLiteConnection(strConn)) { try { connection.Open(); BeginTran(connection); // Insert data using (SQLiteCommand command = connection.CreateCommand()) { //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");"; command.CommandText = String.Format("SELECT * FROM TModuleValue {0}", qry); SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); adapter.AcceptChangesDuringFill = false; dtResult = new DataTable(); adapter.Fill(dtResult); dtResult.TableName = "TModuleValue"; CommitTran(connection); System.Windows.Forms.Application.DoEvents(); } } catch (Exception e) { result = e.Message; } finally { if (connection.State == ConnectionState.Open) connection.Close(); if (result != "") throw new Exception(result); } } return dtResult; } #endregion #region DB PRAGMA FUNCTION public static class SqlitePragmaHelper { /// /// SQLite PRAGMA 설정을 적용합니다. /// - forWriter = true : 로그 쓰기 스레드(INSERT)용 프로파일 /// - forWriter = false: UI 조회(SELECT)용 프로파일 /// public static void ApplyPragmas(SQLiteConnection conn, bool forWriter) { // C# 7.3: using(var ...) 패턴 사용 using (var cmd = conn.CreateCommand()) { var sb = new StringBuilder(); // 공통 권장값 sb.AppendLine("PRAGMA journal_mode=WAL;"); // 동시 읽기/쓰기 sb.AppendLine("PRAGMA busy_timeout=3000;"); // 잠금 대기(ms) sb.AppendLine("PRAGMA temp_store=MEMORY;"); // 임시 테이블 메모리 sb.AppendLine("PRAGMA cache_size=-8000;"); // 8MB(음수=KB) if (forWriter) { // 쓰기 성능/안정성 균형 sb.AppendLine("PRAGMA synchronous=NORMAL;"); sb.AppendLine("PRAGMA locking_mode=NORMAL;"); // sb.AppendLine("PRAGMA foreign_keys=OFF;"); // FK 미사용 시만 } else { // 읽기 전용 커넥션(조회) sb.AppendLine("PRAGMA synchronous=OFF;"); // 읽기에는 의미 거의 없음 sb.AppendLine("PRAGMA locking_mode=NORMAL;"); } cmd.CommandText = sb.ToString(); cmd.ExecuteNonQuery(); } } /// /// 환경/현장에 맞게 타임아웃/캐시 크기를 조절해서 적용하고 싶을 때. /// cacheSizeKB: 음수면 KB 단위(권장), 예: -8000 = 8MB /// public static void ApplyPragmas(SQLiteConnection conn, bool forWriter, int busyTimeoutMs, int cacheSizeKB) { using (var cmd = conn.CreateCommand()) { var sb = new StringBuilder(); sb.AppendLine("PRAGMA journal_mode=WAL;"); sb.AppendLine("PRAGMA busy_timeout=" + busyTimeoutMs + ";"); sb.AppendLine("PRAGMA temp_store=MEMORY;"); sb.AppendLine("PRAGMA cache_size=" + cacheSizeKB + ";"); if (forWriter) { sb.AppendLine("PRAGMA synchronous=NORMAL;"); sb.AppendLine("PRAGMA locking_mode=NORMAL;"); } else { sb.AppendLine("PRAGMA synchronous=OFF;"); sb.AppendLine("PRAGMA locking_mode=NORMAL;"); } cmd.CommandText = sb.ToString(); cmd.ExecuteNonQuery(); } } /// /// 현재 PRAGMA 상태를 로깅(디버깅용). /// public static void LogPragmas(SQLiteConnection conn, System.Action log) { var names = new[] { "journal_mode","synchronous","busy_timeout","temp_store", "cache_size","locking_mode","wal_autocheckpoint","page_size","mmap_size" }; using (var cmd = conn.CreateCommand()) { for (int i = 0; i < names.Length; i++) { cmd.CommandText = "PRAGMA " + names[i] + ";"; object val = cmd.ExecuteScalar(); if (log != null) log("PRAGMA " + names[i] + " = " + (val ?? "(null)")); } } } /// /// WAL 파일을 DB로 반영하고 WAL 파일을 truncate 합니다. /// 프로그램 종료 시 1회 또는 하루 1회 등으로 호출 권장. /// public static void WalCheckpointTruncate(SQLiteConnection conn) { using (var cmd = conn.CreateCommand()) { cmd.CommandText = "PRAGMA wal_checkpoint(TRUNCATE);"; cmd.ExecuteNonQuery(); } } } #endregion #region GRID VIEW COLUMN HIDE // 바인딩 끝난 뒤(예: DataSource 설정 직후)에 실행 public static void HideColumns(DataGridView grid, params string[] names) { foreach (var name in names) { if (grid.Columns.Contains(name)) grid.Columns[name].Visible = false; // 칼럼 자체 숨김 } } #endregion public class SQLITE { private SQLiteConnection con; private SQLiteCommand cmd; private SQLiteDataAdapter adapter; public SQLITE(string databasename) { con = new SQLiteConnection(string.Format("Data Source={0};Compress=True;", databasename)); } public int Execute(string sql_statement) { con.Open(); cmd = con.CreateCommand(); cmd.CommandText = sql_statement; int row_updated; try { row_updated = cmd.ExecuteNonQuery(); } catch { con.Close(); return 0; } con.Close(); return row_updated; } public DataTable GetDataTable(string tablename) { DataTable DT = new DataTable(); con.Open(); cmd = con.CreateCommand(); cmd.CommandText = string.Format("SELECT * FROM {0}", tablename); adapter = new SQLiteDataAdapter(cmd); adapter.AcceptChangesDuringFill = false; adapter.Fill(DT); con.Close(); DT.TableName = tablename; return DT; } public void SaveDataTable(DataTable DT) { try { Execute(string.Format("DELETE FROM {0}", DT.TableName)); con.Open(); cmd = con.CreateCommand(); cmd.CommandText = string.Format("SELECT * FROM {0}", DT.TableName); adapter = new SQLiteDataAdapter(cmd); SQLiteCommandBuilder builder = new SQLiteCommandBuilder(adapter); adapter.Update(DT); con.Close(); } catch (Exception Ex) { MessageBox.Show(Ex.Message); } } } } }