Files
VisualSapfor/src/Common/Database/SQLITE/SQLiteDatabase.java
2025-03-13 00:32:20 +03:00

258 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package Common.Database.SQLITE;
import Common.Database.Database;
import Common.Database.Objects.DBObject;
import Common.Database.Tables.DBTable;
import Common.Database.Tables.DBTableColumn;
import Common.Passes.PassException;
import Common.Utils.Utils_;
import Common.Visual.UI;
import javafx.util.Pair;
import java.io.File;
import java.sql.*;
import java.util.LinkedHashMap;
import java.util.Vector;
import static Common.Utils.Utils_.requireNonNullElse;
public abstract class SQLiteDatabase extends Database {
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<>();
protected Connection conn = null;
protected Statement statement = null;
protected ResultSet resSet = null;
//->>
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();
Utils_.sleep(2000);
}
}
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());
cmd += Utils_.RBrackets(String.join(",", columns_names));
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() + " " +
Utils_.RBrackets(String.join(",", column_names)) + " " + "VALUES " +
Utils_.RBrackets(String.join(",", column_values))));
//------------------------------------------------------------------------------->>
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
throw new PassException("Ошибка при загрузке поля " + Utils_.Brackets(column.Name) + " класса " + Utils_.Brackets(table.d.getSimpleName()));
}
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)
UI.Info("INSERT NULL");
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)
UI.Info("UPDATE NULL");
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
}