public static long GetOptionLong(this Ast.OptionsList optionsList, string name, ScriptRunner runner,
                                     ScriptEnv env, long defaultValue, long?minValue = null, long?maxValue = null)
    {
        var  num        = optionsList.GetOption <long>(name, runner, env, defaultValue);
        bool outOfRange =
            (minValue.HasValue && num < minValue.Value) ||
            (maxValue.HasValue && num > maxValue.Value);

        if (outOfRange)
        {
            if (minValue.HasValue && !maxValue.HasValue)
            {
                throw new Exception($"{name} must be an integer ≥ {minValue.Value}.");
            }
            else if (minValue.HasValue && maxValue.HasValue)
            {
                throw new Exception($"{name} must be an integer between {minValue.Value} and {maxValue.Value}.");
            }
            else if (!minValue.HasValue && maxValue.HasValue)
            {
                throw new Exception($"{name} must be an integer ≤ {maxValue.Value}.");
            }
        }
        return(num);
    }
예제 #2
0
    public static void Import(
        IReadOnlyList <string> srcColNames,
        IEnumerable <object[]> dataRows,
        Ast.ImportTable importTable,
        bool temporaryTable,
        bool truncateExistingTable,
        bool stopAtFirstBlankRow,
        IfConversionFails ifConversionFails,
        BlankValuesOption blankValuesMethod,
        Notebook notebook,
        ScriptRunner runner,
        ScriptEnv env
        )
    {
        var dstTableName = runner.EvaluateIdentifierOrExpr(importTable.TableName, env);
        var mappings     = GetImportColumnMappings(importTable.ImportColumns, runner, env, srcColNames);

        if (!mappings.Any())
        {
            throw new Exception("No columns chosen for import.");
        }
        CreateOrTruncateTable(mappings, dstTableName, temporaryTable, truncateExistingTable, notebook);
        VerifyColumnsExist(mappings.Select(x => x.DstColumnName), dstTableName, notebook);
        InsertDataRows(dataRows, srcColNames, mappings, dstTableName, ifConversionFails, stopAtFirstBlankRow,
                       blankValuesMethod, notebook);
    }
예제 #3
0
    private ExportTxtStmtRunner(Notebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ExportTxtStmt stmt)
    {
        _notebook = notebook;
        _env      = env;
        _runner   = runner;
        _stmt     = stmt;

        _filePath = GetFilePath();

        foreach (var option in _stmt.OptionsList.GetOptionKeys())
        {
            switch (option)
            {
            case "TRUNCATE_EXISTING_FILE":
                _truncateExistingFile = _stmt.OptionsList.GetOptionBool(option, _runner, _env, false);
                break;

            case "FILE_ENCODING":
                _fileEncoding =
                    _stmt.OptionsList.GetOptionEncoding(option, _runner, _env);
                break;

            default:
                throw new Exception($"\"{option}\" is not a recognized option name.");
            }
        }

        if (_fileEncoding == null)
        {
            _fileEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
        }
    }
예제 #4
0
    private void ExecuteWhileStmt(Ast.WhileStmt stmt, ScriptEnv env)
    {
        long condition;

        do
        {
            condition = EvaluateExpr <long>(stmt.Condition, env);
            if (condition == 1)
            {
                ExecuteBlock(stmt.Block, env);
                if (env.DidReturn)
                {
                    return;
                }
                else if (env.DidBreak)
                {
                    env.DidBreak = false;
                    break;
                }
                else if (env.DidContinue)
                {
                    env.DidContinue = false;
                }
            }
            else if (condition != 0)
            {
                throw new ScriptException(
                          $"Evaluation of WHILE condition expression \"{stmt.Condition.Sql}\" " +
                          $"produced a value of {condition} instead of the expected 0 or 1.");
            }
        } while (condition == 1);
    }
예제 #5
0
        public ScriptOutput ExecuteScriptEx(string code, IReadOnlyDictionary <string, object> args,
                                            TransactionType transactionType, out Dictionary <string, object> vars)
        {
            var env    = new ScriptEnv();
            var output = Invoke(() => {
                var parser = new ScriptParser(Notebook);
                var script = parser.Parse(code);
                var runner = new ScriptRunner(Notebook, Notebook.GetScripts());
                if (transactionType == TransactionType.Transaction)
                {
                    return(SqlUtil.WithTransaction(Notebook,
                                                   () => runner.Execute(script, env, args ?? new Dictionary <string, object>())));
                }
                else if (transactionType == TransactionType.RollbackTransaction)
                {
                    return(SqlUtil.WithRollbackTransaction(Notebook,
                                                           () => runner.Execute(script, env, args ?? new Dictionary <string, object>())));
                }
                else
                {
                    return(runner.Execute(script, env, args ?? new Dictionary <string, object>()));
                }
            });

            vars = env.Vars;
            return(output);
        }
    // must be run from the SQLite thread
    public static void Run(Notebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ImportDatabaseStmt stmt,
                           CancellationToken cancel
                           )
    {
        ImportDatabaseStmtRunner importer = new(notebook, env, runner, stmt, cancel);

        SqlUtil.WithTransaction(notebook, importer.Import);
    }
예제 #7
0
 private void ExecuteReturnStmt(Ast.ReturnStmt stmt, ScriptEnv env)
 {
     if (stmt.Value != null)
     {
         env.Output.ScalarResult = EvaluateExpr(stmt.Value, env);
     }
     env.DidReturn = true;
 }
예제 #8
0
    // must be run from the SQLite thread
    public static void Run(Notebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ExportCsvStmt stmt,
                           CancellationToken cancel
                           )
    {
        ExportCsvStmtRunner exporter = new(notebook, env, runner, stmt, cancel);

        exporter.Export();
    }
예제 #9
0
 private void ExecuteTryCatchStmt(Ast.TryCatchStmt stmt, ScriptEnv env)
 {
     try {
         ExecuteBlock(stmt.TryBlock, env);
     } catch (Exception ex) {
         Notebook.ErrorMessage = ex.GetExceptionMessage();
         ExecuteBlock(stmt.CatchBlock, env);
     }
 }
예제 #10
0
 public ScriptOutput Execute(Ast.Script script, ScriptEnv env, IReadOnlyDictionary <string, object> args)
 {
     foreach (var arg in args)
     {
         var lowercaseKey = arg.Key.ToLower();
         env.Vars[lowercaseKey] = arg.Value;
     }
     Execute(script, env);
     return(env.Output);
 }
예제 #11
0
 public string EvaluateIdentifierOrExpr(Ast.IdentifierOrExpr idOrExpr, ScriptEnv env)
 {
     if (idOrExpr.Expr != null)
     {
         return(EvaluateExpr <string>(idOrExpr.Expr, env));
     }
     else
     {
         return(idOrExpr.Identifier);
     }
 }
예제 #12
0
 private void ExecuteBlock(Ast.Block block, ScriptEnv env)
 {
     foreach (var stmt in block.Statements)
     {
         ExecuteStmt(stmt, env);
         if (env.DidReturn || env.DidBreak || env.DidContinue)
         {
             return;
         }
     }
 }
예제 #13
0
 private void ExecuteThrowStmt(Ast.ThrowStmt stmt, ScriptEnv env)
 {
     if (stmt.HasErrorValues)
     {
         var errorMessage = EvaluateExpr(stmt.Message, env);
         Throw(errorMessage.ToString());
     }
     else
     {
         Throw(Notebook.ErrorMessage);
     }
 }
예제 #14
0
    private void ExecutePrintStmt(Ast.PrintStmt stmt, ScriptEnv env)
    {
        var value = EvaluateExpr(stmt.Value, env);

        if (value is byte[] byteArray)
        {
            env.Output.TextOutput.Add(BlobUtil.ToString(byteArray));
            return;
        }

        env.Output.TextOutput.Add(value.ToString());
    }
예제 #15
0
    private void ExecuteForStmt(Ast.ForStmt stmt, ScriptEnv env)
    {
        var firstNumber = EvaluateExpr <long>(stmt.FirstNumberExpr, env);
        var lastNumber  = EvaluateExpr <long>(stmt.LastNumberExpr, env);

        long step = firstNumber <= lastNumber ? 1 : -1;

        if (stmt.StepExpr != null)
        {
            step = EvaluateExpr <long>(stmt.StepExpr, env);
        }

        if (step == 0)
        {
            throw new ScriptException("The STEP value in a FOR statement must not be zero.");
        }
        else if (step < 0 && firstNumber < lastNumber)
        {
            throw new ScriptException(
                      "The STEP value in a FOR statement must be positive if \"first-number\" < \"last-number\".");
        }
        else if (step > 0 && firstNumber > lastNumber)
        {
            throw new ScriptException(
                      "The STEP value in a FOR statement must be negative if \"first-number\" > \"last-number\".");
        }

        var  upward  = step > 0;
        long counter = firstNumber;

        while ((upward && counter <= lastNumber) || (!upward && counter >= lastNumber))
        {
            env.Vars[stmt.VariableName] = counter;

            ExecuteBlock(stmt.Block, env);
            if (env.DidReturn)
            {
                return;
            }
            else if (env.DidBreak)
            {
                env.DidBreak = false;
                break;
            }
            else if (env.DidContinue)
            {
                env.DidContinue = false;
            }

            counter += step;
        }
    }
예제 #16
0
 public object EvaluateExpr(Ast.Expr expr, ScriptEnv env)
 {
     using var dt = _notebook.Query($"SELECT ({expr.Sql})", env.Vars);
     if (dt.Columns.Count == 1 && dt.Rows.Count == 1)
     {
         return(dt.Rows[0][0]);
     }
     else
     {
         throw new ScriptException(
                   $"Evaluation of expression \"{expr.Sql}\" did not produce a value.");
     }
 }
예제 #17
0
    private void ExecuteExecuteStmt(Ast.ExecuteStmt stmt, ScriptEnv env)
    {
        var subOutput = ExecuteSubScript(stmt.ScriptName, stmt.Arguments, env);

        env.Output.Append(subOutput);
        var returnCode = subOutput.ScalarResult;

        if (stmt.ReturnVariableName != null)
        {
            var name = stmt.ReturnVariableName.ToLower();
            env.Vars[name] = returnCode ?? DBNull.Value;
        }
    }
예제 #18
0
    private void ExecuteSetStmt(Ast.SetStmt stmt, ScriptEnv env)
    {
        var name = stmt.VariableName.ToLower();

        if (env.Vars.ContainsKey(name))
        {
            env.Vars[name] = EvaluateExpr(stmt.InitialValue, env);
        }
        else
        {
            throw new ScriptException($"Attempted to SET the undeclared variable \"{stmt.VariableName}\".");
        }
    }
    public static bool GetOptionBool(this Ast.OptionsList optionsList, string name, ScriptRunner runner,
                                     ScriptEnv env, bool defaultValue)
    {
        long num = optionsList.GetOption <long>(name, runner, env, defaultValue ? 1 : 0);

        if (num != 0 && num != 1)
        {
            throw new Exception($"{name} must be 0 or 1.");
        }
        else
        {
            return(num == 1);
        }
    }
    public static int GetOptionInt(this Ast.OptionsList optionsList, string name, ScriptRunner runner,
                                   ScriptEnv env, int defaultValue, int?minValue = null, int?maxValue = null)
    {
        var longValue = GetOptionLong(optionsList, name, runner, env, defaultValue, minValue, maxValue);

        if (longValue < int.MinValue || longValue > int.MaxValue)
        {
            throw new Exception($"{name} must be a 32-bit integer.");
        }
        else
        {
            return((int)longValue);
        }
    }
예제 #21
0
    public T EvaluateExpr <T>(Ast.Expr expr, ScriptEnv env)
    {
        var value = EvaluateExpr(expr, env);

        if (typeof(T).IsAssignableFrom(value.GetType()))
        {
            return((T)value);
        }
        else
        {
            throw new ScriptException(
                      $"Evaluation of expression \"{expr.Sql}\" produced a value of type " +
                      $"\"{value.GetType().Name}\" instead of the expected \"{typeof(T).Name}\".");
        }
    }
예제 #22
0
    private ExportCsvStmtRunner(Notebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ExportCsvStmt stmt,
                                CancellationToken cancel
                                )
    {
        _notebook = notebook;
        _env      = env;
        _runner   = runner;
        _stmt     = stmt;
        _cancel   = cancel;
        _filePath = GetFilePath();

        foreach (var option in _stmt.OptionsList.GetOptionKeys())
        {
            switch (option)
            {
            case "HEADER_ROW":
                _headerRow = _stmt.OptionsList.GetOptionBool(option, _runner, _env, true);
                break;

            case "SEPARATOR":
            {
                var separator = _stmt.OptionsList.GetOption(option, _runner, _env, ",");
                if (separator.Length != 1)
                {
                    throw new Exception("EXPORT CSV: The separator must be a single character.");
                }
                _separator = separator[0];
                break;
            }

            case "TRUNCATE_EXISTING_FILE":
                _truncateExistingFile = _stmt.OptionsList.GetOptionBool(option, _runner, _env, false);
                break;

            case "FILE_ENCODING":
                _fileEncoding = _stmt.OptionsList.GetOptionEncoding(option, _runner, _env);
                break;

            default:
                throw new Exception($"EXPORT CSV: \"{option}\" is not a recognized option name.");
            }
        }

        if (_fileEncoding == null)
        {
            _fileEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
        }
    }
예제 #23
0
        public static void Import(string[] srcColNames, IEnumerable <object[]> dataRows, Ast.ImportTable importTable,
                                  bool temporaryTable, bool truncateExistingTable, IfConversionFails ifConversionFails, INotebook notebook,
                                  ScriptRunner runner, ScriptEnv env)
        {
            Ast.ImportColumn[] dstColNodes;
            string[]           dstColNames;

            var dstTableName = runner.EvaluateIdentifierOrExpr(importTable.TableName, env);

            GetDestinationColumns(importTable.ImportColumns, runner, env, srcColNames,
                                  out dstColNodes, out dstColNames);
            CreateOrTruncateTable(srcColNames, dstColNodes, dstColNames, dstTableName, temporaryTable,
                                  truncateExistingTable, notebook);
            VerifyColumnsExist(dstColNames, dstTableName, notebook);
            InsertDataRows(dataRows, dstColNames, dstColNodes, dstTableName, ifConversionFails, notebook);
        }
예제 #24
0
    private void ExecuteDeclareStmt(Ast.DeclareStmt stmt, ScriptEnv env)
    {
        var name = stmt.VariableName.ToLower();
        var declarationExists = env.Vars.ContainsKey(name);

        if (stmt.IsParameter)
        {
            if (env.ParNames.Contains(name))
            {
                throw new ScriptException($"Duplicate DECLARE for parameter \"{stmt.VariableName}\".");
            }
            else
            {
                env.ParNames.Add(name);
            }

            if (declarationExists)
            {
                // do nothing; the parameter value was specified by the caller
            }
            else if (stmt.InitialValue != null)
            {
                // the caller did not specify a value, but there is an initial value in the DECLARE statement.
                env.Vars[name] = EvaluateExpr(stmt.InitialValue, env);
            }
            else
            {
                throw new ScriptException(
                          $"An argument value was not provided for parameter \"{stmt.VariableName}\".");
            }
        }
        else if (declarationExists)
        {
            throw new ScriptException($"Duplicate DECLARE for variable \"{stmt.VariableName}\".");
        }
        else
        {
            if (stmt.InitialValue != null)
            {
                env.Vars[name] = EvaluateExpr(stmt.InitialValue, env);
            }
            else
            {
                env.Vars[name] = DBNull.Value;
            }
        }
    }
예제 #25
0
    protected virtual void OnDestroy()
    {
        if (_luaOnDestroy != null)
        {
            _luaOnDestroy();
        }

        if (ScriptEnv != null)
        {
            ScriptEnv.Dispose();
            _scriptEnv = null;
        }

        _luaStart     = null;
        _luaUpdate    = null;
        _luaOnDestroy = null;
    }
예제 #26
0
    private ImportTxtStmtRunner(Notebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ImportTxtStmt stmt)
    {
        _notebook = notebook;
        _env      = env;
        _runner   = runner;
        _stmt     = stmt;

        _tableName            = _runner.EvaluateIdentifierOrExpr(_stmt.TableName, _env);
        _lineNumberColumnName = _stmt.LineNumberColumnName == null ? null : _runner.EvaluateIdentifierOrExpr(_stmt.LineNumberColumnName, _env);
        _textColumnName       = _stmt.TextColumnName == null ? null : _runner.EvaluateIdentifierOrExpr(_stmt.TextColumnName, _env);

        foreach (var option in _stmt.OptionsList.GetOptionKeys())
        {
            switch (option)
            {
            case "SKIP_LINES":
                _skipLines = _stmt.OptionsList.GetOptionLong(option, _runner, _env, 0, minValue: 0);
                break;

            case "TAKE_LINES":
                _takeLines = _stmt.OptionsList.GetOptionLong(option, _runner, _env, -1, minValue: -1);
                if (_takeLines == -1)
                {
                    _takeLines = null;
                }
                break;

            case "TRUNCATE_EXISTING_TABLE":
                _truncateExistingTable = _stmt.OptionsList.GetOptionBool(option, _runner, _env, false);
                break;

            case "TEMPORARY_TABLE":
                _temporaryTable = _stmt.OptionsList.GetOptionBool(option, _runner, _env, false);
                break;

            case "FILE_ENCODING":
                _fileEncoding = _stmt.OptionsList.GetOptionEncoding(option, _runner, _env);
                break;

            default:
                throw new Exception($"\"{option}\" is not a recognized option name.");
            }
        }
    }
예제 #27
0
    public ScriptOutput ExecuteSubScript(string scriptName, List <Ast.ArgumentPair> arguments, ScriptEnv env)
    {
        var parser = new ScriptParser(_notebook);
        var runner = new ScriptRunner(_notebook, _scripts);
        var script = parser.Parse(GetScriptCode(scriptName));
        var subEnv = new ScriptEnv {
            OnRow = env.OnRow
        };

        foreach (var arg in arguments)
        {
            if (arg.Value != null)
            {
                subEnv.Vars[arg.Name.ToLower()] = EvaluateExpr(arg.Value, env);
            }
        }
        runner.Execute(script, subEnv);
        return(subEnv.Output);
    }
예제 #28
0
    private const float GcInterval   = 1; //1 second

    protected virtual void Awake()
    {
        var meta = LuaEnv.NewTable();

        meta.Set("__index", LuaEnv.Global);
        ScriptEnv.SetMetaTable(meta);
        meta.Dispose();

        ScriptEnv.Set("self", this);
        foreach (var injection in Injections)
        {
            ScriptEnv.Set(injection.Name, injection.Value);
        }

        var content = LuaEnv.DoString(string.Format(@"
local content = require '{0}'
return content",
                                                    _luaFilePath),
                                      "LuaMonoBehaviour", ScriptEnv);

        if (content != null)
        {
            LuaTable luaTable = (LuaTable)content[0];

            var contentMeta = LuaEnv.NewTable();
            contentMeta.Set("__index", ScriptEnv);
            luaTable.SetMetaTable(contentMeta);

            contentMeta.Dispose();

            var luaAwake = luaTable.Get <Action>("awake");
            _luaStart     = luaTable.Get <Action>("start");
            _luaUpdate    = luaTable.Get <Action>("update");
            _luaOnDestroy = luaTable.Get <Action>("destroy");

            if (luaAwake != null)
            {
                luaAwake();
            }
        }
    }
예제 #29
0
    public void Execute(Ast.Script script, ScriptEnv env)
    {
        try {
            ExecuteBlock(script.Block, env);

            if (env.DidBreak)
            {
                throw new ScriptException($"Attempted to BREAK outside of a WHILE loop.");
            }
            else if (env.DidContinue)
            {
                throw new ScriptException($"Attempted to CONTINUE outside of a WHILE loop.");
            }
        } catch (Exception ex) {
            var snippet = ex is SqliteException s ? s.Snippet : null;
            throw new UncaughtErrorScriptException(ex.GetExceptionMessage(), ex)
                  {
                      Snippet = snippet
                  };
        }
    }
예제 #30
0
    private void ExecuteIfStmt(Ast.IfStmt stmt, ScriptEnv env)
    {
        var condition = EvaluateExpr <long>(stmt.Condition, env);

        if (condition == 0)
        {
            if (stmt.ElseBlock != null)
            {
                ExecuteBlock(stmt.ElseBlock, env);
            }
        }
        else if (condition == 1)
        {
            ExecuteBlock(stmt.Block, env);
        }
        else
        {
            throw new ScriptException(
                      $"Evaluation of IF condition expression \"{stmt.Condition.Sql}\" " +
                      $"produced a value of {condition} instead of the expected 0 or 1.");
        }
    }