Files
VisualSapfor/src/Common/Database/SQLITE/SQLiteDatabase.java

259 lines
11 KiB
Java
Raw Normal View History

2023-09-17 22:13:42 +03:00
package Common.Database.SQLITE;
import Common.Database.Objects.DBObject;
import Common.Database.Tables.DBTable;
import Common.Database.Tables.DBTableColumn;
2023-09-17 22:13:42 +03:00
import Common.Database.Database;
2024-10-11 00:00:30 +03:00
import Common.Utils.Utils_;
import Common.Visual.UI_;
2024-10-10 23:57:36 +03:00
import Common.Passes.PassException;
2023-09-17 22:13:42 +03:00
import javafx.util.Pair;
import java.io.File;
import java.sql.*;
import java.util.LinkedHashMap;
import java.util.Vector;
2024-10-11 00:00:30 +03:00
import static Common.Utils.Utils_.requireNonNullElse;
2023-09-17 22:13:42 +03:00
public abstract class SQLiteDatabase extends Database {
protected Connection conn = null;
protected Statement statement = null;
protected ResultSet resSet = null;
public LinkedHashMap<Class<? extends DBObject>, PreparedStatement> insertStatements = new LinkedHashMap<>();
public LinkedHashMap<Class<? extends DBObject>, PreparedStatement> updateStatements = new LinkedHashMap<>();
public LinkedHashMap<Class<? extends DBObject>, PreparedStatement> deleteStatements = new LinkedHashMap<>();
//->>
public SQLiteDatabase(File file_in) {
super(file_in);
}
@Override
protected void connect() throws Exception {
Class.forName("org.sqlite.JDBC");
for (int i = 0; i < 5; ++i) {
try {
conn = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath());
break;
} catch (Exception ex) {
ex.printStackTrace();
conn = null;
System.gc();
2024-10-11 00:00:30 +03:00
Utils_.sleep(2000);
2023-09-17 22:13:42 +03:00
}
}
if (conn == null)
throw new PassException("Внутренняя ошибка sqlite. Не удалось установить соединение за 5 попыток.");
statement = conn.createStatement();
}
@Override
protected void disconnect() throws Exception {
if (conn != null) {
conn.close();
conn = null;
}
if (statement != null) {
statement.close();
statement = null;
}
if (resSet != null) {
resSet.close();
resSet = null;
}
for (PreparedStatement preparedStatement : insertStatements.values()) {
if (preparedStatement != null)
preparedStatement.close();
}
for (PreparedStatement preparedStatement : updateStatements.values()) {
if (preparedStatement != null)
preparedStatement.close();
}
for (PreparedStatement preparedStatement : deleteStatements.values()) {
if (preparedStatement != null)
preparedStatement.close();
}
insertStatements.clear();
updateStatements.clear();
deleteStatements.clear();
//-->>
System.gc();
//->>
}
@Override
protected void beginTransaction() throws Exception {
conn.setAutoCommit(false);
}
@Override
protected void commit() throws Exception {
conn.commit();
conn.setAutoCommit(true);
}
@Override
protected boolean TableExists(DBTable table) throws Exception {
int count = 0;
resSet = statement.executeQuery("SELECT count(*) FROM 'sqlite_master' WHERE type=\"table\" AND name=" + table.QName());
if (resSet.next())
count = resSet.getInt(1);
return count > 0;
}
@Override
public void CreateTable(DBTable table) throws Exception {
if (table.columns.size() > 0) {
if (TableExists(table)) {
Vector<String> existing_columns = new Vector<>();
Vector<String> columns_to_create = new Vector<>();
//предполагаем что первичный ключ и атрибуты не изменятся.
//и что не будет столбов с одинаковыми именами но разными типами.
resSet = statement.executeQuery("pragma table_info(" + table.QName() + ")");
while (resSet.next())
existing_columns.add(resSet.getString(2));
//-
for (String target_column : table.columns.keySet()) {
if (!existing_columns.contains(target_column))
columns_to_create.add(target_column);
}
for (String cn : columns_to_create)
statement.execute("ALTER TABLE " + table.QName() + " ADD COLUMN " + table.columns.get(cn));
} else {
String cmd = "CREATE TABLE if not exists " + table.QName() + " ";
Vector<String> columns_names = new Vector<>();
for (DBTableColumn column : table.columns.values())
columns_names.add(column.toString());
2024-10-11 00:00:30 +03:00
cmd += Utils_.RBrackets(String.join(",", columns_names));
2023-09-17 22:13:42 +03:00
statement.execute(cmd);
}
}
}
@Override
public void prepareTablesStatements() throws Exception {
for (DBTable table : tables.values()) {
//---
Vector<String> column_names = new Vector<>();
Vector<String> column_values = new Vector<>();
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
column_names.add(column.QName());
column_values.add("?");
}
}
insertStatements.put(table.d, conn.prepareStatement(
"INSERT OR REPLACE INTO " + table.QName() + " " +
2024-10-11 00:00:30 +03:00
Utils_.RBrackets(String.join(",", column_names)) + " " + "VALUES " +
Utils_.RBrackets(String.join(",", column_values))));
2023-09-17 22:13:42 +03:00
//------------------------------------------------------------------------------->>
Vector<String> new_values = new Vector();
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
new_values.add(column.QName() + "=?");
}
}
updateStatements.put(table.d, conn.prepareStatement(
"UPDATE " + table.QName() + " " +
"SET " + String.join(",", new_values) + " " +
"WHERE (" + table.PK.QName() + "=?)"
));
//---------------------------------------------------------------------------------->>>
deleteStatements.put(table.d, conn.prepareStatement("DELETE FROM " + table.QName() + " WHERE " + table.PK.QName() + " = ?"));
}
}
@Override
protected void delete(DBTable table, DBObject o) throws Exception {
PreparedStatement ps = deleteStatements.get(table.d);
ps.setObject(1, o.getPK());
ps.executeUpdate();
}
protected <K, D extends DBObject> Pair<K, D> readRecord(DBTable<K, D> table) throws Exception {
D o = table.d.newInstance();
for (DBTableColumn column : table.columns.values()) {
Object field_value = null;
switch (column.type) {
case DOUBLE:
field_value = requireNonNullElse(resSet.getDouble(column.Name), 0);
break;
case UNDEFINED:
break;
case INT:
field_value = requireNonNullElse(resSet.getInt(column.Name), 0);
break;
case LONG:
field_value = requireNonNullElse(resSet.getLong(column.Name), 0);
break;
case STRING:
if (table.d.getField(column.Name).getType().isEnum()) {
Class enum_class = Class.forName(table.d.getField(column.Name).getType().getName());
String string = resSet.getString(column.Name);
Object[] enum_constants = enum_class.getEnumConstants();
if (string != null) {
try {
field_value = Enum.valueOf(enum_class, string);
} catch (Exception ignore) {
field_value = enum_constants[0];
}
} else field_value = enum_constants[0];
} else
field_value = requireNonNullElse(resSet.getString(column.Name), "");
break;
}
if (field_value != null) {
table.d.getField(column.Name).set(o, field_value);
} else
2024-10-11 00:00:30 +03:00
throw new PassException("Ошибка при загрузке поля " + Utils_.Brackets(column.Name) + " класса " + Utils_.Brackets(table.d.getSimpleName()));
2023-09-17 22:13:42 +03:00
}
return new Pair<>((K) o.getPK(), o);
}
@Override
protected <K, D extends DBObject> void loadAll(DBTable<K, D> table) throws Exception {
resSet = statement.executeQuery("SELECT * FROM " + table.QName());
while (resSet.next()) {
Pair<K, D> record = readRecord(table);
table.Data.put(record.getKey(), record.getValue());
}
}
@Override
protected void insert(DBTable table, DBObject o) throws Exception {
PreparedStatement ps = insertStatements.get(table.d);
if (ps == null)
2024-10-11 00:00:30 +03:00
UI_.Info("INSERT NULL");
2023-09-17 22:13:42 +03:00
int i = 1;
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
ps.setObject(i, o.getClass().getField(column.Name).get(o));
++i;
}
}
ps.execute();
//-->
for (DBTableColumn column : table.columns.values()) {
if (column.AutoIncrement) {
resSet = statement.executeQuery("SELECT MAX(" + column.QName() + ") AS LAST FROM " + table.QName());
String maxId = resSet.getString("LAST");
int intMaxId = Integer.parseInt(maxId);
o.getClass().getField(column.Name).set(o, intMaxId);
break;
}
}
}
@Override
protected void update(DBTable table, DBObject o) throws Exception {
PreparedStatement ps = updateStatements.get(table.d);
if (ps == null)
2024-10-11 00:00:30 +03:00
UI_.Info("UPDATE NULL");
2023-09-17 22:13:42 +03:00
int i = 1;
for (DBTableColumn column : table.columns.values()) {
if (!column.AutoIncrement) {
ps.setObject(i, o.getClass().getField(column.Name).get(o));
++i;
}
}
ps.setObject(i, o.getPK());
ps.executeUpdate();
}
@Override
protected void deleteAll(DBTable table) throws Exception {
statement.executeUpdate("DELETE FROM " + table.QName());
}
@Override
protected void resetAI(DBTable table) throws Exception {
statement.executeUpdate("UPDATE SQLITE_SEQUENCE SET SEQ = 0 WHERE NAME =" + table.QName());
}
//--
//https://stackoverflow.com/questions/8558099/sqlite-query-with-byte-where-clause
}