using System; using System.Collections; using System.ComponentModel; using System.Data.SQLite; using NLua; using System.Collections.Generic; namespace BizHawk.Client.Common { [Description("A library for performing SQLite operations.")] public sealed class SQLLuaLibrary : LuaLibraryBase { public SQLLuaLibrary(Lua lua) : base(lua) { } public SQLLuaLibrary(Lua lua, Action logOutputCallback) : base(lua, logOutputCallback) { } public override string Name => "SQL"; SQLiteConnection m_dbConnection; string connectionString; [LuaMethodExample("local stSQLcre = SQL.createdatabase( \"eg_db\" );")] [LuaMethod("createdatabase", "Creates a SQLite Database. Name should end with .db")] public string CreateDatabase(string name) { try { SQLiteConnection.CreateFile(name); return "Database Created Successfully"; } catch (SQLiteException sqlEX) { return sqlEX.Message; } } [LuaMethodExample("local stSQLope = SQL.opendatabase( \"eg_db\" );")] [LuaMethod("opendatabase", "Opens a SQLite database. Name should end with .db")] public string OpenDatabase(string name) { try { SQLiteConnectionStringBuilder connBuilder = new SQLiteConnectionStringBuilder(); connBuilder.DataSource = name; connBuilder.Version = 3; //SQLite version connBuilder.JournalMode = SQLiteJournalModeEnum.Wal; //Allows for reads and writes to happen at the same time connBuilder.DefaultIsolationLevel = System.Data.IsolationLevel.ReadCommitted; //This only helps make the database lock left. May be pointless now connBuilder.SyncMode = SynchronizationModes.Off; //This shortens the delay for do synchronous calls. m_dbConnection = new SQLiteConnection(connBuilder.ToString()); connectionString = connBuilder.ToString(); m_dbConnection.Open(); m_dbConnection.Close(); return "Database Opened Successfully"; } catch (SQLiteException sqlEX) { return sqlEX.Message; } } [LuaMethodExample("local stSQLwri = SQL.writecommand( \"CREATE TABLE eg_tab ( eg_tab_id integer PRIMARY KEY, eg_tab_row_name text NOT NULL ); INSERT INTO eg_tab ( eg_tab_id, eg_tab_row_name ) VALUES ( 1, 'Example table row' );\" );")] [LuaMethod("writecommand", "Runs a SQLite write command which includes CREATE,INSERT, UPDATE. " + "Ex: create TABLE rewards (ID integer PRIMARY KEY, action VARCHAR(20)) ")] public string WriteCommand(string query = "") { if (query == "") { return "query is empty"; } try { m_dbConnection.Open(); string sql = query; SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection); command.ExecuteNonQuery(); m_dbConnection.Close(); return "Command ran successfully"; } catch (NullReferenceException nullEX) { return "Database not open."; } catch (SQLiteException sqlEX) { m_dbConnection.Close(); return sqlEX.Message; } } [LuaMethodExample("local obSQLrea = SQL.readcommand( \"SELECT * FROM eg_tab WHERE eg_tab_id = 1;\" );")] [LuaMethod("readcommand", "Run a SQLite read command which includes Select. Returns all rows into a LuaTable." + "Ex: select * from rewards")] public dynamic ReadCommand(string query = "") { if (query == "") { return "query is empty"; } try { var table = Lua.NewTable(); m_dbConnection.Open(); string sql = "PRAGMA read_uncommitted =1;" + query; SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection); SQLiteDataReader reader = command.ExecuteReader(); bool rows = reader.HasRows; long rowCount = 0; var columns = new List(); for (int i = 0; i < reader.FieldCount; ++i) //Add all column names into list { columns.Add(reader.GetName(i)); } while (reader.Read()) { for (int i = 0; i < reader.FieldCount; ++i) { table[columns[i] + " " + rowCount.ToString()] = reader.GetValue(i); } rowCount += 1; } reader.Close(); m_dbConnection.Close(); if (rows == false) { return "No rows found"; } return table; } catch (NullReferenceException) { return "Database not opened."; } catch (SQLiteException sqlEX) { m_dbConnection.Close(); return sqlEX.Message; } } } }